외부 컨트롤 플레인으로 Istio 설치하기

외부 컨트롤 플레인으로 Istio 설치하기

외부 클러스터에 Istio 컨트롤 플레인을 설치하고, 하나 이상의 remote 클러스터를 그 컨트롤 플레인에 연결하는 방법을 알려드려요.

출처: Istio 문서

본문

이 가이드는 외부 컨트롤 플레인을 설치하고, 그 컨트롤 플레인에 하나 이상의 remote 클러스터를 연결하는 과정을 안내해요. 외부 컨트롤 플레인 배포 모델은 메시 운영자가 메시를 구성하는 데이터 플레인 클러스터(또는 여러 클러스터)와 분리된 외부 클러스터에 컨트롤 플레인을 설치하고 관리할 수 있게 해줘요. 이 배포 모델은 메시 운영자와 메시 관리자를 명확히 분리할 수 있게 해줘요. 메시 운영자는 Istio 컨트롤 플레인을 설치하고 관리하고, 메시 관리자는 메시만 설정하면 돼요.

remote 클러스터에서 실행되는 Envoy 프록시(sidecar 및 게이트웨이)는 discovery, CA, 주입(injection), 검증에 필요한 엔드포인트를 노출하는 ingress 게이트웨이를 통해 외부 istiod에 접근해요.

외부 컨트롤 플레인의 구성과 관리는 메시 운영자가 외부 클러스터에서 수행하지만, 외부 컨트롤 플레인에 연결되는 첫 번째 remote 클러스터는 메시 자체의 config 클러스터 역할을 해요. 메시 관리자는 config 클러스터를 사용해서 메시 서비스들 외에도 메시 리소스(게이트웨이, VirtualService 등)를 설정하게 돼요. 외부 컨트롤 플레인은 위 다이어그램에서 보듯이 Kubernetes API server에서 이 구성을 원격으로 접근해요.

시작하기 전에

클러스터

이 가이드는 지원되는 Kubernetes 버전 1.32, 1.33, 1.34, 1.35, 1.36 중 하나를 갖춘 Kubernetes 클러스터가 두 개 필요해요.

첫 번째 클러스터는 external-istiod 네임스페이스에 설치된 외부 컨트롤 플레인을 호스팅해요. 외부 컨트롤 플레인에 대한 클러스터 간 접근을 제공하기 위해 istio-system 네임스페이스에 ingress 게이트웨이도 설치돼요.

두 번째 클러스터는 메시 애플리케이션 워크로드를 실행할 remote 클러스터예요. 그 Kubernetes API server는 외부 컨트롤 플레인(istiod)이 워크로드 프록시를 설정하는 데 사용하는 메시 구성도 제공해요.

API server 접근

remote 클러스터의 Kubernetes API server는 외부 컨트롤 플레인 클러스터에서 접근 가능해야 해요. 많은 클라우드 제공업체가 네트워크 로드 밸런서(NLB)를 통해 API server를 공개적으로 접근 가능하게 만들어요. API server에 직접 접근할 수 없다면, 접근을 활성화하도록 설치 절차를 수정해야 해요. 예를 들어 멀티클러스터 구성에서 사용되는 east-west 게이트웨이를 API server에 대한 접근을 활성화하는 데도 사용할 수 있어요.

환경 변수

안내를 단순화하기 위해 다음 환경 변수들을 전반에서 사용해요:

변수 설명
CTX_EXTERNAL_CLUSTER 기본 Kubernetes 설정 파일에서 외부 컨트롤 플레인 클러스터에 접근하는 데 사용하는 컨텍스트 이름
CTX_REMOTE_CLUSTER 기본 Kubernetes 설정 파일에서 remote 클러스터에 접근하는 데 사용하는 컨텍스트 이름
REMOTE_CLUSTER_NAME remote 클러스터의 이름
EXTERNAL_ISTIOD_ADDR 외부 컨트롤 플레인 클러스터의 ingress 게이트웨이 호스트 이름. remote 클러스터가 외부 컨트롤 플레인에 접근하는 데 사용해요.
SSL_SECRET_NAME 외부 컨트롤 플레인 클러스터의 ingress 게이트웨이용 TLS 인증서를 담은 시크릿의 이름

지금 CTX_EXTERNAL_CLUSTER, CTX_REMOTE_CLUSTER, REMOTE_CLUSTER_NAME을 설정하세요. 나머지는 나중에 설정할 거예요.

$ export CTX_EXTERNAL_CLUSTER=<your external cluster context>
$ export CTX_REMOTE_CLUSTER=<your remote cluster context>
$ export REMOTE_CLUSTER_NAME=<your remote cluster name>

클러스터 구성

메시 운영자 단계

메시 운영자는 외부 클러스터에 외부 Istio 컨트롤 플레인을 설치하고 관리할 책임이 있어요. 여기에는 remote 클러스터가 컨트롤 플레인에 접근할 수 있게 해주는 외부 클러스터의 ingress 게이트웨이 설정과, remote 클러스터가 외부 컨트롤 플레인을 사용하도록 하는 sidecar 주입기 웹훅 설정 설치가 포함돼요.

외부 클러스터에 게이트웨이 설정

  1. 외부 컨트롤 플레인 포트를 다른 클러스터에 노출할 ingress 게이트웨이용 Istio 설치 설정을 만들어요:
$ cat <<EOF > controlplane-gateway.yaml
apiVersion: install.istio.io/v1alpha1
kind: IstioOperator
metadata:
  namespace: istio-system
spec:
  components:
    ingressGateways:
      - name: istio-ingressgateway
        enabled: true
        k8s:
          service:
            ports:
              - port: 15021
                targetPort: 15021
                name: status-port
              - port: 15012
                targetPort: 15012
                name: tls-xds
              - port: 15017
                targetPort: 15017
                name: tls-webhook
EOF

그런 다음 외부 클러스터의 istio-system 네임스페이스에 게이트웨이를 설치해요:

$ istioctl install -f controlplane-gateway.yaml --context="${CTX_EXTERNAL_CLUSTER}"
  1. ingress 게이트웨이가 실행 중인지 다음 명령으로 확인해요:
$ kubectl get po -n istio-system --context="${CTX_EXTERNAL_CLUSTER}"
NAME                                   READY   STATUS    RESTARTS   AGE
istio-ingressgateway-9d4c7f5c7-7qpzz   1/1     Running   0          29s
istiod-68488cd797-mq8dn                1/1     Running   0          38s

istio-system 네임스페이스에 istiod 배포도 생성된 것을 볼 수 있을 거예요. 이는 ingress 게이트웨이를 설정하는 데 사용되며, remote 클러스터가 사용하는 컨트롤 플레인이 아님에 주의하세요. 3. TLS를 사용하는 공개 호스트 이름으로 Istio ingress 게이트웨이 서비스를 노출하도록 환경을 설정해요.

EXTERNAL_ISTIOD_ADDR 환경 변수를 호스트 이름으로, SSL_SECRET_NAME 환경 변수를 TLS 인증서를 담은 시크릿으로 설정해요:

$ export EXTERNAL_ISTIOD_ADDR=<your external istiod host>
$ export SSL_SECRET_NAME=<your external istiod secret>

이 안내는 프로덕션 환경에서 권장되는 접근 방식이므로, 외부 클러스터의 게이트웨이를 올바르게 서명된 DNS 인증서가 있는 호스트 이름으로 노출한다고 가정해요. 보안 게이트웨이 노출에 대한 자세한 내용은 보안 ingress 작업을 참고하세요.

환경 변수는 다음과 비슷해야 해요:

$ echo "$EXTERNAL_ISTIOD_ADDR" "$SSL_SECRET_NAME"
myhost.example.com myhost-example-credential

원격 config 클러스터 설정

  1. remote 프로필을 사용해서 remote 클러스터의 Istio 설치를 구성해요. 이것은 로컬에 배포된 주입기가 아니라 외부 컨트롤 플레인의 주입기를 사용하는 주입 웹훅을 설치해요. 이 클러스터가 config 클러스터 역할도 하기 때문에, remote 클러스터에 필요할 Istio CRD와 다른 리소스들도 global.configCluster와 pilot.configMap을 true로 설정해서 설치돼요:
$ cat <<EOF > remote-config-cluster.yaml
apiVersion: install.istio.io/v1alpha1
kind: IstioOperator
metadata:
  namespace: external-istiod
spec:
  profile: remote
  values:
    global:
      istioNamespace: external-istiod
      configCluster: true
    pilot:
      configMap: true
    istiodRemote:
      injectionURL: https://${EXTERNAL_ISTIOD_ADDR}:15017/inject/cluster/${REMOTE_CLUSTER_NAME}/net/network1
    base:
      validationURL: https://${EXTERNAL_ISTIOD_ADDR}:15017/validate
EOF
  1. EXTERNAL_ISTIOD_ADDR에 적절한 DNS 호스트 이름 대신 IP 주소를 사용한다면, URL 대신 discovery 주소와 경로를 지정하도록 구성을 수정해요:
$ sed  -i'.bk' \
  -e "s|injectionURL: https://${EXTERNAL_ISTIOD_ADDR}:15017|injectionPath: |" \
  -e "/istioNamespace:/a\
      remotePilotAddress: ${EXTERNAL_ISTIOD_ADDR}" \
  -e '/base:/,+1d' \
  remote-config-cluster.yaml; rm remote-config-cluster.yaml.bk
  1. remote 클러스터에 구성을 설치해요:
$ kubectl create namespace external-istiod --context="${CTX_REMOTE_CLUSTER}"
$ istioctl install -f remote-config-cluster.yaml --set values.defaultRevision=default --context="${CTX_REMOTE_CLUSTER}"
  1. remote 클러스터의 주입 웹훅 설정이 설치되었는지 확인해요:
$ kubectl get mutatingwebhookconfiguration --context="${CTX_REMOTE_CLUSTER}"
NAME                                         WEBHOOKS   AGE
istio-revision-tag-default-external-istiod   4          2m2s
istio-sidecar-injector-external-istiod       4          2m5s
  1. remote 클러스터의 검증 웹훅 설정이 설치되었는지 확인해요:
$ kubectl get validatingwebhookconfiguration --context="${CTX_REMOTE_CLUSTER}"
NAME                              WEBHOOKS   AGE
istio-validator-external-istiod   1          6m53s
istiod-default-validator          1          6m53s

외부 클러스터에 컨트롤 플레인 설정

  1. 외부 컨트롤 플레인을 호스팅할 external-istiod 네임스페이스를 만들어요:
$ kubectl create namespace external-istiod --context="${CTX_EXTERNAL_CLUSTER}"
  1. 외부 클러스터의 컨트롤 플레인은 서비스, 엔드포인트, pod 속성을 발견하려면 remote 클러스터에 접근해야 해요. remote 클러스터의 kube-apiserver에 접근할 수 있는 자격 증명이 담긴 시크릿을 만들어서 외부 클러스터에 설치해요:
$ istioctl create-remote-secret \
  --context="${CTX_REMOTE_CLUSTER}" \
  --type=config \
  --namespace=external-istiod \
  --service-account=istiod \
  --create-service-account=false | \
  kubectl apply -f - --context="${CTX_EXTERNAL_CLUSTER}"
  1. 외부 클러스터의 external-istiod 네임스페이스에 컨트롤 플레인을 설치할 Istio 설정을 만들어요. istiod가 로컬에 마운트된 istio configmap을 사용하도록 설정되고 SHARED_MESH_CONFIG 환경 변수가 istio로 설정된 것에 주목하세요. 이것은 istiod가 config 클러스터의 configmap에서 메시 관리자가 설정한 값과, 여기에서 메시 운영자가 설정한 로컬 configmap의 값을 병합하도록 지시하며, 충돌이 있으면 로컬 값이 우선합니다:
$ cat <<EOF > external-istiod.yaml
apiVersion: install.istio.io/v1alpha1
kind: IstioOperator
metadata:
  namespace: external-istiod
spec:
  profile: empty
  meshConfig:
    rootNamespace: external-istiod
    defaultConfig:
      discoveryAddress: $EXTERNAL_ISTIOD_ADDR:15012
      proxyMetadata:
        XDS_ROOT_CA: /etc/ssl/certs/ca-certificates.crt
        CA_ROOT_CA: /etc/ssl/certs/ca-certificates.crt
  components:
    pilot:
      enabled: true
      k8s:
        overlays:
        - kind: Deployment
          name: istiod
          patches:
          - path: spec.template.spec.volumes[100]
            value: |-
              name: config-volume
              configMap:
                name: istio
          - path: spec.template.spec.volumes[100]
            value: |-
              name: inject-volume
              configMap:
                name: istio-sidecar-injector
          - path: spec.template.spec.containers[0].volumeMounts[100]
            value: |-
              name: config-volume
              mountPath: /etc/istio/config
          - path: spec.template.spec.containers[0].volumeMounts[100]
            value: |-
              name: inject-volume
              mountPath: /var/lib/istio/inject
        env:
        - name: INJECTION_WEBHOOK_CONFIG_NAME
          value: ""
        - name: VALIDATION_WEBHOOK_CONFIG_NAME
          value: ""
        - name: EXTERNAL_ISTIOD
          value: "true"
        - name: LOCAL_CLUSTER_SECRET_WATCHER
          value: "true"
        - name: CLUSTER_ID
          value: ${REMOTE_CLUSTER_NAME}
        - name: SHARED_MESH_CONFIG
          value: istio
  values:
    global:
      externalIstiod: true
      caAddress: $EXTERNAL_ISTIOD_ADDR:15012
      istioNamespace: external-istiod
      operatorManageWebhooks: true
      configValidation: false
      meshID: mesh1
      multiCluster:
        clusterName: ${REMOTE_CLUSTER_NAME}
      network: network1
EOF
  1. EXTERNAL_ISTIOD_ADDR에 적절한 DNS 호스트 이름 대신 IP 주소를 사용한다면, 구성에서 proxy metadata를 삭제하고 웹훅 구성 환경 변수를 업데이트해요:
$ sed  -i'.bk' \
  -e '/proxyMetadata:/,+2d' \
  -e '/INJECTION_WEBHOOK_CONFIG_NAME/{n;s/value: ""/value: istio-sidecar-injector-external-istiod/;}' \
  -e '/VALIDATION_WEBHOOK_CONFIG_NAME/{n;s/value: ""/value: istio-validator-external-istiod/;}' \
  external-istiod.yaml ; rm external-istiod.yaml.bk
  1. 외부 클러스터에 Istio 설정을 적용해요:
$ istioctl install -f external-istiod.yaml --context="${CTX_EXTERNAL_CLUSTER}"
  1. 외부 istiod가 성공적으로 배포되었는지 확인해요:
$ kubectl get po -n external-istiod --context="${CTX_EXTERNAL_CLUSTER}"
NAME                      READY   STATUS    RESTARTS   AGE
istiod-779bd6fdcf-bd6rg   1/1     Running   0          70s
  1. ingress 게이트웨이에서 외부 컨트롤 플레인으로 트래픽을 라우팅할 Istio Gateway, VirtualService, DestinationRule 설정을 만들어요:
$ cat <<EOF > external-istiod-gw.yaml
apiVersion: networking.istio.io/v1
kind: Gateway
metadata:
  name: external-istiod-gw
  namespace: external-istiod
spec:
  selector:
    istio: ingressgateway
  servers:
    - port:
        number: 15012
        protocol: https
        name: https-XDS
      tls:
        mode: SIMPLE
        credentialName: $SSL_SECRET_NAME
      hosts:
      - $EXTERNAL_ISTIOD_ADDR
    - port:
        number: 15017
        protocol: https
        name: https-WEBHOOK
      tls:
        mode: SIMPLE
        credentialName: $SSL_SECRET_NAME
      hosts:
      - $EXTERNAL_ISTIOD_ADDR
---
apiVersion: networking.istio.io/v1
kind: VirtualService
metadata:
   name: external-istiod-vs
   namespace: external-istiod
spec:
    hosts:
    - $EXTERNAL_ISTIOD_ADDR
    gateways:
    - external-istiod-gw
    http:
    - match:
      - port: 15012
      route:
      - destination:
          host: istiod.external-istiod.svc.cluster.local
          port:
            number: 15012
    - match:
      - port: 15017
      route:
      - destination:
          host: istiod.external-istiod.svc.cluster.local
          port:
            number: 443
---
apiVersion: networking.istio.io/v1
kind: DestinationRule
metadata:
  name: external-istiod-dr
  namespace: external-istiod
spec:
  host: istiod.external-istiod.svc.cluster.local
  trafficPolicy:
    portLevelSettings:
    - port:
        number: 15012
      tls:
        mode: SIMPLE
      connectionPool:
        http:
          h2UpgradePolicy: UPGRADE
    - port:
        number: 443
      tls:
        mode: SIMPLE
EOF
  1. EXTERNAL_ISTIOD_ADDR에 적절한 DNS 호스트 이름 대신 IP 주소를 사용한다면 구성을 수정해요. DestinationRule을 삭제하고, Gateway에서 TLS를 종료하지 말고, VirtualService에서 TLS 라우팅을 사용해요:
$ sed  -i'.bk' \
  -e '55,$d' \
  -e 's/mode: SIMPLE/mode: PASSTHROUGH/' -e '/credentialName:/d' -e "s/${EXTERNAL_ISTIOD_ADDR}/\"*\"/" \
  -e 's/http:/tls:/' -e 's/https/tls/' -e '/route:/i\
        sniHosts:\
        - "*"' \
  external-istiod-gw.yaml; rm external-istiod-gw.yaml.bk
  1. 외부 클러스터에 구성을 적용해요:
$ kubectl apply -f external-istiod-gw.yaml --context="${CTX_EXTERNAL_CLUSTER}"

메시 관리자 단계

이제 Istio가 실행 중이므로, 메시 관리자는 필요하면 게이트웨이를 포함해 메시 안의 서비스를 배포하고 설정하기만 하면 돼요.

샘플 애플리케이션 배포

  1. remote 클러스터에 sample 네임스페이스를 만들고 주입용으로 라벨을 붙여요:
$ kubectl create --context="${CTX_REMOTE_CLUSTER}" namespace sample
$ kubectl label --context="${CTX_REMOTE_CLUSTER}" namespace sample istio-injection=enabled
  1. helloworld (v1)과 curl 샘플을 배포해요:

ZipZipZip

$ kubectl apply -f @samples/helloworld/helloworld.yaml@ -l service=helloworld -n sample --context="${CTX_REMOTE_CLUSTER}"
$ kubectl apply -f @samples/helloworld/helloworld.yaml@ -l version=v1 -n sample --context="${CTX_REMOTE_CLUSTER}"
$ kubectl apply -f @samples/curl/curl.yaml@ -n sample --context="${CTX_REMOTE_CLUSTER}"
  1. helloworld와 curl pod가 sidecar와 함께 주입되어 실행될 때까지 몇 초 기다려요:
$ kubectl get pod -n sample --context="${CTX_REMOTE_CLUSTER}"
NAME                             READY   STATUS    RESTARTS   AGE
curl-64d7d56698-wqjnm            2/2     Running   0          9s
helloworld-v1-776f57d5f6-s7zfc   2/2     Running   0          10s
  1. curl pod에서 helloworld 서비스로 요청을 보내요:
$ kubectl exec --context="${CTX_REMOTE_CLUSTER}" -n sample -c curl \
    "$(kubectl get pod --context="${CTX_REMOTE_CLUSTER}" -n sample -l app=curl -o jsonpath='{.items[0].metadata.name}')" \
    -- curl -sS helloworld.sample:5000/hello
Hello version: v1, instance: helloworld-v1-776f57d5f6-s7zfc

게이트웨이 활성화

remote 클러스터에서 ingress 게이트웨이를 활성화해요:

$ cat <<EOF > istio-ingressgateway.yaml
apiVersion: install.istio.io/v1alpha1
kind: IstioOperator
metadata:
  name: ingress-install
spec:
  profile: empty
  components:
    ingressGateways:
    - namespace: external-istiod
      name: istio-ingressgateway
      enabled: true
  values:
    gateways:
      istio-ingressgateway:
        injectionTemplate: gateway
EOF
$ istioctl install -f istio-ingressgateway.yaml --set values.global.istioNamespace=external-istiod --context="${CTX_REMOTE_CLUSTER}"
$ helm install istio-ingressgateway istio/gateway -n external-istiod --kube-context="${CTX_REMOTE_CLUSTER}"

게이트웨이 설치에 대한 자세한 문서는 게이트웨이 설치를 참고하세요.

선택적으로 다른 게이트웨이도 활성화할 수 있어요. 예를 들어 egress 게이트웨이:

$ cat <<EOF > istio-egressgateway.yaml
apiVersion: install.istio.io/v1alpha1
kind: IstioOperator
metadata:
  name: egress-install
spec:
  profile: empty
  components:
    egressGateways:
    - namespace: external-istiod
      name: istio-egressgateway
      enabled: true
  values:
    gateways:
      istio-egressgateway:
        injectionTemplate: gateway
EOF
$ istioctl install -f istio-egressgateway.yaml --set values.global.istioNamespace=external-istiod --context="${CTX_REMOTE_CLUSTER}"
$ helm install istio-egressgateway istio/gateway -n external-istiod --kube-context="${CTX_REMOTE_CLUSTER}" --set service.type=ClusterIP

게이트웨이 설치에 대한 자세한 문서는 게이트웨이 설치를 참고하세요.

ingress 게이트웨이 설정 및 테스트

  1. 클러스터가 게이트웨이를 설정할 준비가 되었는지 확인해요:

Istio ingress 게이트웨이가 실행 중인지 확인해요:

$ kubectl get pod -l app=istio-ingressgateway -n external-istiod --context="${CTX_REMOTE_CLUSTER}"
NAME                                    READY   STATUS    RESTARTS   AGE
istio-ingressgateway-7bcd5c6bbd-kmtl4   1/1     Running   0          8m4s

Kubernetes Gateway API CRD는 대부분의 Kubernetes 클러스터에 기본으로 설치되지 않으므로, Gateway API를 사용하기 전에 설치되어 있는지 확인해요:

$ kubectl get crd gateways.gateway.networking.k8s.io --context="${CTX_REMOTE_CLUSTER}" &> /dev/null || \
  { kubectl kustomize "github.com/kubernetes-sigs/gateway-api/config/crd?ref=v1.6.0" | kubectl apply -f - --context="${CTX_REMOTE_CLUSTER}"; }
  1. ingress 게이트웨이에 helloworld 애플리케이션을 노출해요:
$ kubectl apply -f @samples/helloworld/helloworld-gateway.yaml@ -n sample --context="${CTX_REMOTE_CLUSTER}"
$ kubectl apply -f @samples/helloworld/gateway-api/helloworld-gateway.yaml@ -n sample --context="${CTX_REMOTE_CLUSTER}"
  1. GATEWAY_URL 환경 변수를 설정해요 (자세한 내용은 ingress IP와 포트 확인 참고):
$ export INGRESS_HOST=$(kubectl -n external-istiod --context="${CTX_REMOTE_CLUSTER}" get service istio-ingressgateway -o jsonpath='{.status.loadBalancer.ingress[0].ip}')
$ export INGRESS_PORT=$(kubectl -n external-istiod --context="${CTX_REMOTE_CLUSTER}" get service istio-ingressgateway -o jsonpath='{.spec.ports[?(@.name=="http2")].port}')
$ export GATEWAY_URL=$INGRESS_HOST:$INGRESS_PORT
$ kubectl -n sample --context="${CTX_REMOTE_CLUSTER}" wait --for=condition=programmed gtw helloworld-gateway
$ export INGRESS_HOST=$(kubectl -n sample --context="${CTX_REMOTE_CLUSTER}" get gtw helloworld-gateway -o jsonpath='{.status.addresses[0].value}')
$ export GATEWAY_URL=$INGRESS_HOST:80
  1. ingress 게이트웨이를 통해 helloworld 애플리케이션에 접근할 수 있는지 확인해요:
$ curl -s "http://${GATEWAY_URL}/hello"
Hello version: v1, instance: helloworld-v1-776f57d5f6-s7zfc

메시에 클러스터 추가 (선택)

이 섹션은 다른 remote 클러스터를 추가해서 기존 외부 컨트롤 플레인 메시를 멀티클러스터로 확장하는 방법을 보여줘요. 이렇게 하면 서비스를 쉽게 분산하고 위치 인식 라우팅 및 장애 조치를 사용해서 애플리케이션의 고가용성을 지원할 수 있어요.

같은 외부 컨트롤 플레인에 추가되는 두 번째 및 그 이후 클러스터는 첫 번째 remote 클러스터와 달리 메시 구성을 제공하지 않아요. 대신 primary-remote Istio 멀티클러스터 구성의 remote 클러스터처럼 단지 endpoint 구성의 원천일 뿐이에요.

진행하려면 메시의 두 번째 remote 클러스터용 Kubernetes 클러스터가 하나 더 필요해요. 클러스터의 컨텍스트 이름과 클러스터 이름으로 다음 환경 변수를 설정해요:

$ export CTX_SECOND_CLUSTER=<your second remote cluster context>
$ export SECOND_CLUSTER_NAME=<your second remote cluster name>

새 클러스터 등록

  1. 로컬에 배포된 주입기가 아니라 외부 컨트롤 플레인의 주입기를 사용하는 주입 웹훅을 설치하는 원격 Istio 설치 설정을 만들어요:
$ cat <<EOF > second-remote-cluster.yaml
apiVersion: install.istio.io/v1alpha1
kind: IstioOperator
metadata:
  namespace: external-istiod
spec:
  profile: remote
  values:
    global:
      istioNamespace: external-istiod
    istiodRemote:
      injectionURL: https://${EXTERNAL_ISTIOD_ADDR}:15017/inject/cluster/${SECOND_CLUSTER_NAME}/net/network2
EOF
  1. EXTERNAL_ISTIOD_ADDR에 적절한 DNS 호스트 이름 대신 IP 주소를 사용한다면, 주입 URL 대신 discovery 주소와 경로를 지정하도록 구성을 수정해요:
$ sed  -i'.bk' \
  -e "s|injectionURL: https://${EXTERNAL_ISTIOD_ADDR}:15017|injectionPath: |" \
  -e "/istioNamespace:/a\
      remotePilotAddress: ${EXTERNAL_ISTIOD_ADDR}" \
  second-remote-cluster.yaml; rm second-remote-cluster.yaml.bk
  1. remote 클러스터에 시스템 네임스페이스를 만들고 annotation을 붙여요:
$ kubectl create namespace external-istiod --context="${CTX_SECOND_CLUSTER}"
$ kubectl annotate namespace external-istiod "topology.istio.io/controlPlaneClusters=${REMOTE_CLUSTER_NAME}" --context="${CTX_SECOND_CLUSTER}"

topology.istio.io/controlPlaneClusters annotation은 이 remote 클러스터를 관리해야 하는 외부 컨트롤 플레인의 클러스터 ID를 지정해요. 이것은 앞서 외부 클러스터에 외부 컨트롤 플레인을 설치할 때 외부 컨트롤 플레인의 클러스터 ID를 설정하는 데 사용된 첫 번째 remote(config) 클러스터의 이름이라는 점에 주의하세요. 4. remote 클러스터에 구성을 설치해요:

$ istioctl install -f second-remote-cluster.yaml --context="${CTX_SECOND_CLUSTER}"
  1. remote 클러스터의 주입 웹훅 설정이 설치되었는지 확인해요:
$ kubectl get mutatingwebhookconfiguration --context="${CTX_SECOND_CLUSTER}"
NAME                                     WEBHOOKS   AGE
istio-sidecar-injector-external-istiod   4          4m13s
  1. 컨트롤 플레인이 두 번째 remote 클러스터의 endpoint에 접근할 수 있게 해주는 자격 증명이 담긴 시크릿을 만들고 설치해요:
$ istioctl create-remote-secret \
  --context="${CTX_SECOND_CLUSTER}" \
  --name="${SECOND_CLUSTER_NAME}" \
  --type=remote \
  --namespace=external-istiod \
  --create-service-account=false | \
  kubectl apply -f - --context="${CTX_EXTERNAL_CLUSTER}"

이번에는 config 클러스터 역할도 하는 메시의 첫 번째 remote 클러스터와 달리 --type 인자가 config가 아닌 remote로 설정된다는 점에 주의하세요.

east-west 게이트웨이 설정

  1. 두 remote 클러스터 모두에 east-west 게이트웨이를 배포해요:

Zip

$ @samples/multicluster/gen-eastwest-gateway.sh@ \
    --network network1 > eastwest-gateway-1.yaml
$ istioctl manifest generate -f eastwest-gateway-1.yaml \
    --set values.global.istioNamespace=external-istiod | \
    kubectl apply --context="${CTX_REMOTE_CLUSTER}" -f -

Zip

$ @samples/multicluster/gen-eastwest-gateway.sh@ \
    --network network2 > eastwest-gateway-2.yaml
$ istioctl manifest generate -f eastwest-gateway-2.yaml \
    --set values.global.istioNamespace=external-istiod | \
    kubectl apply --context="${CTX_SECOND_CLUSTER}" -f -
  1. east-west 게이트웨이에 외부 IP 주소가 할당될 때까지 기다려요:
$ kubectl --context="${CTX_REMOTE_CLUSTER}" get svc istio-eastwestgateway -n external-istiod
NAME                    TYPE           CLUSTER-IP    EXTERNAL-IP    PORT(S)   AGE
istio-eastwestgateway   LoadBalancer   10.0.12.121   34.122.91.98   ...       51s
$ kubectl --context="${CTX_SECOND_CLUSTER}" get svc istio-eastwestgateway -n external-istiod
NAME                    TYPE           CLUSTER-IP    EXTERNAL-IP    PORT(S)   AGE
istio-eastwestgateway   LoadBalancer   10.0.12.121   34.122.91.99   ...       51s
  1. east-west 게이트웨이를 통해 서비스를 노출해요:

Zip

$ kubectl --context="${CTX_REMOTE_CLUSTER}" apply -n external-istiod -f \
    @samples/multicluster/expose-services.yaml@

설치 검증

  1. remote 클러스터에 sample 네임스페이스를 만들고 주입용으로 라벨을 붙여요:
$ kubectl create --context="${CTX_SECOND_CLUSTER}" namespace sample
$ kubectl label --context="${CTX_SECOND_CLUSTER}" namespace sample istio-injection=enabled
  1. helloworld (v2)과 curl 샘플을 배포해요:

ZipZipZip

$ kubectl apply -f @samples/helloworld/helloworld.yaml@ -l service=helloworld -n sample --context="${CTX_SECOND_CLUSTER}"
$ kubectl apply -f @samples/helloworld/helloworld.yaml@ -l version=v2 -n sample --context="${CTX_SECOND_CLUSTER}"
$ kubectl apply -f @samples/curl/curl.yaml@ -n sample --context="${CTX_SECOND_CLUSTER}"
  1. helloworld와 curl pod가 sidecar와 함께 주입되어 실행될 때까지 몇 초 기다려요:
$ kubectl get pod -n sample --context="${CTX_SECOND_CLUSTER}"
NAME                            READY   STATUS    RESTARTS   AGE
curl-557747455f-wtdbr           2/2     Running   0          9s
helloworld-v2-54df5f84b-9hxgw   2/2     Running   0          10s
  1. curl pod에서 helloworld 서비스로 요청을 보내요:
$ kubectl exec --context="${CTX_SECOND_CLUSTER}" -n sample -c curl \
    "$(kubectl get pod --context="${CTX_SECOND_CLUSTER}" -n sample -l app=curl -o jsonpath='{.items[0].metadata.name}')" \
    -- curl -sS helloworld.sample:5000/hello
Hello version: v2, instance: helloworld-v2-54df5f84b-9hxgw
  1. ingress 게이트웨이를 통해 helloworld 애플리케이션에 여러 번 접근하면 이제 v1과 v2 두 버전이 모두 호출되는지 확인해요:
$ for i in {1..10}; do curl -s "http://${GATEWAY_URL}/hello"; done
Hello version: v1, instance: helloworld-v1-776f57d5f6-s7zfc
Hello version: v2, instance: helloworld-v2-54df5f84b-9hxgw
Hello version: v1, instance: helloworld-v1-776f57d5f6-s7zfc
Hello version: v2, instance: helloworld-v2-54df5f84b-9hxgw
...

정리

외부 컨트롤 플레인 클러스터를 정리해요:

$ kubectl delete -f external-istiod-gw.yaml --context="${CTX_EXTERNAL_CLUSTER}"
$ istioctl uninstall -y --purge -f external-istiod.yaml --context="${CTX_EXTERNAL_CLUSTER}"
$ kubectl delete ns istio-system external-istiod --context="${CTX_EXTERNAL_CLUSTER}"
$ rm controlplane-gateway.yaml external-istiod.yaml external-istiod-gw.yaml

원격 config 클러스터를 정리해요:

$ kubectl delete ns sample --context="${CTX_REMOTE_CLUSTER}"
$ istioctl uninstall -y --purge -f remote-config-cluster.yaml --set values.defaultRevision=default --context="${CTX_REMOTE_CLUSTER}"
$ kubectl delete ns external-istiod --context="${CTX_REMOTE_CLUSTER}"
$ rm remote-config-cluster.yaml istio-ingressgateway.yaml
$ rm istio-egressgateway.yaml eastwest-gateway-1.yaml || true

설치했다면 선택적인 두 번째 remote 클러스터를 정리해요:

$ kubectl delete ns sample --context="${CTX_SECOND_CLUSTER}"
$ istioctl uninstall -y --purge -f second-remote-cluster.yaml --context="${CTX_SECOND_CLUSTER}"
$ kubectl delete ns external-istiod --context="${CTX_SECOND_CLUSTER}"
$ rm second-remote-cluster.yaml eastwest-gateway-2.yaml

더 알아보기 (Learn more)