단일 클러스터에 여러 Istio 컨트롤 플레인 설치하기

단일 클러스터에 여러 Istio 컨트롤 플레인 설치하기

discoverySelectors와 revisions를 사용해서 단일 클러스터에 여러 Istio 컨트롤 플레인을 설치하고, 워크로드를 특정 컨트롤 플레인으로 범위를 지정하는 방법을 알려드려요.

출처: Istio 문서

본문

이 가이드는 단일 클러스터 안에 여러 Istio 컨트롤 플레인을 설치하고, 워크로드를 특정 컨트롤 플레인으로 범위를 지정하는 방법을 안내해요. 이 배포 모델은 하나의 Kubernetes 컨트롤 플레인과 여러 Istio 컨트롤 플레인 및 메시를 가져요. 메시 간 분리는 Kubernetes 네임스페이스와 RBAC로 제공돼요.

discoverySelectors를 사용하면 클러스터의 Kubernetes 리소스를 특정 Istio 컨트롤 플레인이 관리하는 특정 네임스페이스로 범위를 지정할 수 있어요. 여기에는 메시 설정에 사용되는 Istio 커스텀 리소스(예: Gateway, VirtualService, DestinationRule 등)가 포함돼요. 또한 discoverySelectors를 사용해서 특정 Istio 컨트롤 플레인의 istio-ca-root-cert config map을 포함할 네임스페이스를 설정할 수 있어요. 이러한 기능들을 함께 사용하면 메시 운영자가 주어진 컨트롤 플레인에 대한 네임스페이스를 지정할 수 있어서, 하나 이상의 네임스페이스 경계를 기준으로 여러 메시에 대한 소프트 멀티테넌시가 가능해져요. 이 가이드는 discoverySelectors와 Istio의 revisions 기능을 함께 사용해서 클러스터 리소스의 적절히 범위가 지정된 하위 집합과 각각 동작하는 두 메시를 단일 클러스터에 배포하는 방법을 보여줘요.

시작하기 전에

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

이 클러스터는 서로 다른 두 시스템 네임스페이스에 설치된 두 개의 컨트롤 플레인을 호스팅할 거예요. 메시 애플리케이션 워크로드는 여러 애플리케이션별 네임스페이스에서 실행되고, 각 네임스페이스는 revision과 discovery selector 설정에 따라 둘 중 하나의 컨트롤 플레인에 연결돼요.

클러스터 구성

여러 컨트롤 플레인 배포

단일 클러스터에 여러 Istio 컨트롤 플레인을 배포하는 것은 각 컨트롤 플레인에 대해 서로 다른 시스템 네임스페이스를 사용해서 달성할 수 있어요. 그런 다음 Istio revisions와 discoverySelectors를 사용해서 각 컨트롤 플레인이 관리하는 리소스와 워크로드의 범위를 지정해요.

  1. 첫 번째 시스템 네임스페이스 usergroup-1을 만들고 그 안에 istiod를 배포해요:
$ kubectl create ns usergroup-1
$ kubectl label ns usergroup-1 usergroup=usergroup-1
$ istioctl install -y -f - <<EOF
apiVersion: install.istio.io/v1alpha1
kind: IstioOperator
metadata:
  namespace: usergroup-1
spec:
  profile: minimal
  revision: usergroup-1
  meshConfig:
    discoverySelectors:
      - matchLabels:
          usergroup: usergroup-1
  values:
    global:
      istioNamespace: usergroup-1
EOF
  1. 두 번째 시스템 네임스페이스 usergroup-2를 만들고 그 안에 istiod를 배포해요:
$ kubectl create ns usergroup-2
$ kubectl label ns usergroup-2 usergroup=usergroup-2
$ istioctl install -y -f - <<EOF
apiVersion: install.istio.io/v1alpha1
kind: IstioOperator
metadata:
  namespace: usergroup-2
spec:
  profile: minimal
  revision: usergroup-2
  meshConfig:
    discoverySelectors:
      - matchLabels:
          usergroup: usergroup-2
  values:
    global:
      istioNamespace: usergroup-2
EOF
  1. usergroup-1 네임스페이스의 워크로드가 상호 TLS 트래픽만 허용하도록 정책을 배포해요:
$ kubectl apply -f - <<EOF
apiVersion: security.istio.io/v1
kind: PeerAuthentication
metadata:
  name: "usergroup-1-peerauth"
  namespace: "usergroup-1"
spec:
  mtls:
    mode: STRICT
EOF
  1. usergroup-2 네임스페이스의 워크로드가 상호 TLS 트래픽만 허용하도록 정책을 배포해요:
$ kubectl apply -f - <<EOF
apiVersion: security.istio.io/v1
kind: PeerAuthentication
metadata:
  name: "usergroup-2-peerauth"
  namespace: "usergroup-2"
spec:
  mtls:
    mode: STRICT
EOF

여러 컨트롤 플레인 생성 검증

  1. 각 컨트롤 플레인의 시스템 네임스페이스 라벨을 확인해요:
$ kubectl get ns usergroup-1 usergroup-2 --show-labels
NAME              STATUS   AGE     LABELS
usergroup-1       Active   13m     kubernetes.io/metadata.name=usergroup-1,usergroup=usergroup-1
usergroup-2       Active   12m     kubernetes.io/metadata.name=usergroup-2,usergroup=usergroup-2
  1. 컨트롤 플레인이 배포되어 실행 중인지 확인해요:
$ kubectl get pods -n usergroup-1
NAMESPACE     NAME                                     READY   STATUS    RESTARTS         AGE
usergroup-1   istiod-usergroup-1-5ccc849b5f-wnqd6      1/1     Running   0                12m
$ kubectl get pods -n usergroup-2
NAMESPACE     NAME                                     READY   STATUS    RESTARTS         AGE
usergroup-2   istiod-usergroup-2-658d6458f7-slpd9      1/1     Running   0                12m

지정된 네임스페이스 각각에 하나씩의 istiod 배포가 생성된 것을 볼 수 있을 거예요. 3. 다음 명령을 실행해서 설치된 웹훅을 나열해요:

$ kubectl get validatingwebhookconfiguration
NAME                                      WEBHOOKS   AGE
istio-validator-usergroup-1-usergroup-1   1          18m
istio-validator-usergroup-2-usergroup-2   1          18m
istiod-default-validator                  1          18m
$ kubectl get mutatingwebhookconfiguration
NAME                                             WEBHOOKS   AGE
istio-revision-tag-default-usergroup-1           4          18m
istio-sidecar-injector-usergroup-1-usergroup-1   2          19m
istio-sidecar-injector-usergroup-2-usergroup-2   2          18m

출력에는 istiod-default-validator와 istio-revision-tag-default-usergroup-1이 포함돼 하나의 revision과도 연결되지 않은 리소스에서 오는 요청을 처리하는 기본 웹훅 설정임을 알 수 있어요. 모든 컨트롤 플레인이 적절한 네임스페이스 라벨링을 통해 자기 리소스와 연결되는 완전히 범위가 지정된 환경에서는 이러한 기본 웹훅 설정이 필요 없어요. 호출되어서는 안 돼요.

usergroup별 애플리케이션 워크로드 배포

  1. 애플리케이션 네임스페이스 세 개를 만들어요:
$ kubectl create ns app-ns-1
$ kubectl create ns app-ns-2
$ kubectl create ns app-ns-3
  1. 각 네임스페이스에 해당 컨트롤 플레인과 연결되도록 라벨을 붙여요:
$ kubectl label ns app-ns-1 usergroup=usergroup-1 istio.io/rev=usergroup-1
$ kubectl label ns app-ns-2 usergroup=usergroup-2 istio.io/rev=usergroup-2
$ kubectl label ns app-ns-3 usergroup=usergroup-2 istio.io/rev=usergroup-2
  1. 각 네임스페이스에 curl과 httpbin 애플리케이션을 하나씩 배포해요:
$ kubectl -n app-ns-1 apply -f samples/curl/curl.yaml
$ kubectl -n app-ns-1 apply -f samples/httpbin/httpbin.yaml
$ kubectl -n app-ns-2 apply -f samples/curl/curl.yaml
$ kubectl -n app-ns-2 apply -f samples/httpbin/httpbin.yaml
$ kubectl -n app-ns-3 apply -f samples/curl/curl.yaml
$ kubectl -n app-ns-3 apply -f samples/httpbin/httpbin.yaml
  1. httpbin과 curl pod가 sidecar와 함께 주입되어 실행될 때까지 몇 초 기다려요:
$ kubectl get pods -n app-ns-1
NAME                      READY   STATUS    RESTARTS   AGE
httpbin-9dbd644c7-zc2v4   2/2     Running   0          115m
curl-78ff5975c6-fml7c     2/2     Running   0          115m
$ kubectl get pods -n app-ns-2
NAME                      READY   STATUS    RESTARTS   AGE
httpbin-9dbd644c7-sd9ln   2/2     Running   0          115m
curl-78ff5975c6-sz728     2/2     Running   0          115m
$ kubectl get pods -n app-ns-3
NAME                      READY   STATUS    RESTARTS   AGE
httpbin-9dbd644c7-8ll27   2/2     Running   0          115m
curl-78ff5975c6-sg4tq     2/2     Running   0          115m

애플리케이션과 컨트롤 플레인 매핑 검증

이제 애플리케이션이 배포되었으니 istioctl ps 명령으로 애플리케이션 워크로드가 각자의 컨트롤 플레인에 의해 관리되는지 확인할 수 있어요. 즉, app-ns-1은 usergroup-1이, app-ns-2와 app-ns-3은 usergroup-2가 관리해요:

$ istioctl ps -i usergroup-1
NAME                                 CLUSTER        CDS        LDS        EDS        RDS          ECDS         ISTIOD                                  VERSION
httpbin-9dbd644c7-hccpf.app-ns-1     Kubernetes     SYNCED     SYNCED     SYNCED     SYNCED       NOT SENT     istiod-usergroup-1-5ccc849b5f-wnqd6     1.17-alpha.f5212a6f7df61fd8156f3585154bed2f003c4117
curl-78ff5975c6-9zb77.app-ns-1       Kubernetes     SYNCED     SYNCED     SYNCED     SYNCED       NOT SENT     istiod-usergroup-1-5ccc849b5f-wnqd6     1.17-alpha.f5212a6f7df61fd8156f3585154bed2f003c4117
$ istioctl ps -i usergroup-2
NAME                                 CLUSTER        CDS        LDS        EDS        RDS          ECDS         ISTIOD                                  VERSION
httpbin-9dbd644c7-vvcqj.app-ns-3     Kubernetes     SYNCED     SYNCED     SYNCED     SYNCED       NOT SENT     istiod-usergroup-2-658d6458f7-slpd9     1.17-alpha.f5212a6f7df61fd8156f3585154bed2f003c4117
httpbin-9dbd644c7-xzgfm.app-ns-2     Kubernetes     SYNCED     SYNCED     SYNCED     SYNCED       NOT SENT     istiod-usergroup-2-658d6458f7-slpd9     1.17-alpha.f5212a6f7df61fd8156f3585154bed2f003c4117
curl-78ff5975c6-fthmt.app-ns-2       Kubernetes     SYNCED     SYNCED     SYNCED     SYNCED       NOT SENT     istiod-usergroup-2-658d6458f7-slpd9     1.17-alpha.f5212a6f7df61fd8156f3585154bed2f003c4117
curl-78ff5975c6-nxtth.app-ns-3       Kubernetes     SYNCED     SYNCED     SYNCED     SYNCED       NOT SENT     istiod-usergroup-2-658d6458f7-slpd9     1.17-alpha.f5212a6f7df61fd8156f3585154bed2f003c4117

애플리케이션 연결이 각자 usergroup 내에서만 이루어지는지 검증

  1. usergroup-1의 app-ns-1에 있는 curl pod에서 usergroup-2의 app-ns-2에 있는 httpbin 서비스로 요청을 보내요. 통신은 실패해야 해요:
$ kubectl -n app-ns-1 exec "$(kubectl -n app-ns-1 get pod -l app=curl -o jsonpath={.items..metadata.name})" -c curl -- curl -sIL http://httpbin.app-ns-2.svc.cluster.local:8000
HTTP/1.1 503 Service Unavailable
content-length: 95
content-type: text/plain
date: Sat, 24 Dec 2022 06:54:54 GMT
server: envoy
  1. usergroup-2의 app-ns-2에 있는 curl pod에서 usergroup-2의 app-ns-3에 있는 httpbin 서비스로 요청을 보내요. 통신은 동작해야 해요:
$ kubectl -n app-ns-2 exec "$(kubectl -n app-ns-2 get pod -l app=curl -o jsonpath={.items..metadata.name})" -c curl -- curl -sIL http://httpbin.app-ns-3.svc.cluster.local:8000
HTTP/1.1 200 OK
server: envoy
date: Thu, 22 Dec 2022 15:01:36 GMT
content-type: text/html; charset=utf-8
content-length: 9593
access-control-allow-origin: *
access-control-allow-credentials: true
x-envoy-upstream-service-time: 3

정리

  1. 첫 번째 usergroup을 정리해요:
$ istioctl uninstall --revision usergroup-1 --set values.global.istioNamespace=usergroup-1
$ kubectl delete ns app-ns-1 usergroup-1
  1. 두 번째 usergroup을 정리해요:
$ istioctl uninstall --revision usergroup-2 --set values.global.istioNamespace=usergroup-2
$ kubectl delete ns app-ns-2 app-ns-3 usergroup-2

더 알아보기 (Learn more)