사이드카 주입 — 자동·수동 방식과 커스터마이징

사이드카 주입 — 자동·수동 방식과 커스터마이징

Istio의 모든 기능을 쓰려면 메시 안의 파드마다 Istio 사이드카 프록시가 떠 있어야 해요. 이 프록시를 파드에 넣는 작업을 "주입(injection)"이라고 부르는데, 네임스페이스 단위로 자동으로 넣는 방식과 istioctl로 수동으로 넣는 방식 두 가지가 있어요. 어떤 걸 써야 할지 고민된다면 자동 주입을 권장해요.

출처: Installing the Sidecar — Istio 공식 문서

자동 사이드카 주입

Istio가 제공하는 mutating webhook admission controller가 적합한 쿠버네티스 파드에 사이드카를 자동으로 넣어줘요. 네임스페이스에 istio-injection=enabled 레이블을 달고 주입 웹훅이 켜져 있으면, 그 네임스페이스에 새로 생기는 파드는 자동으로 사이드카를 얻게 돼요.

자동 주입은 파드 레벨에서 일어나요. 배포(deployment) 자체에는 변화가 보이지 않고, 개별 파드를 kubectl describe로 봐야 주입된 프록시를 확인할 수 있어요.

예제 앱을 배포하고 컨테이너 수를 확인해 볼게요.

$ kubectl apply -f @samples/curl/curl.yaml@
$ kubectl get deployment -o wide
NAME   READY   UP-TO-DATE   AVAILABLE   AGE   CONTAINERS   IMAGES            SELECTOR
curl   1/1     1            1           12s   1            curlimages/curl   app=curl

파드도 하나만 떠 있죠.

$ kubectl get pod
NAME                     READY   STATUS      RESTARTS   AGE
curl-8f795f47d-hdcgs     1/1     Running     0          42s

이제 default 네임스페이스에 istio-injection=enabled 레이블을 붙여요.

$ kubectl label namespace default istio-injection=enabled --overwrite
$ kubectl get namespace -L istio-injection
NAME      STATUS   AGE   ISTIO-INJECTION
default   Active   5m9s  enabled

주입은 파드가 생성될 때 일어나요. 도는 파드를 지우고 새로 만들어 보면, 원래 파드가 컨테이너 1/1, 주입된 파드는 2/2인 걸 볼 수 있어요.

$ kubectl delete pod -l app=curl
pod "curl-776b7bcdcd-7hpnk" deleted
$ kubectl get pod -l app=curl
NAME                     READY   STATUS      RESTARTS   AGE
curl-776b7bcdcd-bhn9m    2/2     Running     0          7s

주입된 파드를 자세히 보면 istio-proxy 컨테이너와 그에 딸린 볼륨이 추가된 걸 확인할 수 있어요.

$ kubectl describe pod -l app=curl
...
Events:
  Type    Reason     Age    From               Message
  ----    ------     ----   ----               -------
  ...
  Normal  Created    11s    kubelet            Created container istio-init
  Normal  Started    11s    kubelet            Started container istio-init
  ...
  Normal  Created    10s    kubelet            Created container curl
  Normal  Started    10s    kubelet            Started container curl
  ...
  Normal  Created    9s     kubelet            Created container istio-proxy
  Normal  Started    8s     kubelet            Started container istio-proxy

주입을 끄려면 네임스페이스에서 istio-injection 레이블을 제거하고 파드를 새로 만들면 돼요.

$ kubectl label namespace default istio-injection-
$ kubectl delete pod -l app=curl
$ kubectl get pod
namespace/default labeled
pod "curl-776b7bcdcd-bhn9m" deleted
NAME                     READY   STATUS      RESTARTS   AGE
curl-776b7bcdcd-gmvnr    1/1     Running     0          2s

주입 정책 제어

네임스페이스뿐 아니라 파드마다 sidecar.istio.io/inject 레이블로 주입 여부를 제어할 수 있어요.

리소스 레이블 켜는 값 끄는 값
Namespace istio-injection enabled disabled
Pod sidecar.istio.io/inject "true" "false"

컨트롤 플레인 리비전(canary 업그레이드)을 쓰면 istio.io/rev 레이블로 리비전을 구분해요. 예를 들어 리비전 이름이 canary라면:

리소스 켜는 레이블 끄는 레이블
Namespace istio.io/rev=canary istio-injection=disabled
Pod istio.io/rev=canary sidecar.istio.io/inject="false"

같은 네임스페이스에 istio-injection 레이블과 istio.io/rev 레이블이 동시에 있으면 istio-injection 레이블이 우선해요. 주입기는 다음 논리로 동작해요.

  1. 둘 중 하나(istio-injection 또는 sidecar.istio.io/inject)가 꺼져 있으면 → 주입하지 않아요.
  2. 셋 중 하나(istio-injection, sidecar.istio.io/inject, istio.io/rev)가 켜져 있으면 → 주입해요.
  3. 아무 레이블도 없으면 → .values.sidecarInjectorWebhook.enableNamespacesByDefault가 켜져 있는 경우에만 주입해요. 기본값은 꺼져 있어서 대부분 파드는 주입되지 않아요.

수동 사이드카 주입

배포를 수동으로 주입하려면 istioctl kube-inject를 써요.

$ istioctl kube-inject -f @samples/curl/curl.yaml@ | kubectl apply -f -
serviceaccount/curl created
service/curl created
deployment.apps/curl created

기본적으로 클러스터 안의 설정을 사용하는데, 설정을 로컬로 받아 쓸 수도 있어요.

$ kubectl -n istio-system get configmap istio-sidecar-injector -o=jsonpath='{.data.config}' > inject-config.yaml
$ kubectl -n istio-system get configmap istio-sidecar-injector -o=jsonpath='{.data.values}' > inject-values.yaml
$ kubectl -n istio-system get configmap istio -o=jsonpath='{.data.mesh}' > mesh-config.yaml

파일을 명시해서 kube-inject를 실행하고 배포해요.

$ istioctl kube-inject \
    --injectConfigFile inject-config.yaml \
    --meshConfigFile mesh-config.yaml \
    --valuesFile inject-values.yaml \
    --filename @samples/curl/curl.yaml@ \
    | kubectl apply -f -
serviceaccount/curl created
service/curl created
deployment.apps/curl created

주입된 curl 파드가 READY 컬럼에 2/2로 보이면 성공이에요.

$ kubectl get pod -l app=curl
NAME                     READY   STATUS      RESTARTS   AGE
curl-64c6f57bc8-f5n4x    2/2     Running     0          24s

주입 커스터마이징

파드는 기본적으로 istio-sidecar-injector configmap에 정의된 사이드카 주입 템플릿으로 주입돼요. 파드에 직접 istio-proxy 컨테이너를 추가하면 그 설정이 기본 템플릿에 대한 오버라이드로 동작해요. 여기엔 주의가 필요한 게, 결과적으로 만들어지는 Pod 전체를 바꿀 수 있어서 사이드카 컨테이너가 제대로 동작하지 않게 만들 수도 있어요.

예를 들어 다음 설정은 CPU 요청을 낮추고 볼륨 마운트와 preStop 훅을 추가해요.

apiVersion: v1
kind: Pod
metadata:
  name: example
spec:
  containers:
  - name: hello
    image: alpine
  - name: istio-proxy
    image: auto
    resources:
      requests:
        cpu: "100m"
    volumeMounts:
    - mountPath: /etc/certs
      name: certs
    lifecycle:
      preStop:
        exec:
          command: ["curl", "10"]
  volumes:
  - name: certs
    secret:
      secretName: istio-certs

일반적으로 파드의 어떤 필드든 설정할 수 있지만 몇 가지는 조심해야 해요.

  • 쿠버네티스는 주입이 실행되기 전에 image 필드가 설정돼 있어야 해요. 특정 이미지를 오버라이드할 수도 있지만, auto로 두면 주입기가 자동으로 이미지를 골라줘요.
  • Pod의 일부 필드는 서로 의존해요. 예를 들어 CPU request는 limit보다 작아야 해요. 둘을 함께 설정하지 않으면 파드가 시작에 실패할 수 있어요.
  • securityContext.RunAsUsersecurityContext.RunAsGroup은 어떤 경우엔 반영되지 않을 수 있어요. TPROXY 모드라면 사이드카를 사용자 0으로 돌려야 하거든요. 이 필드를 잘못 덮어쓰면 트래픽이 끊길 수 있으니 극도로 조심해야 해요.

어떤 필드는 파드의 애너테이션으로도 설정할 수 있어요. 다음처럼 부분만 쓴 애너테이션 설정이 있을 때:

spec:
  template:
    metadata:
      annotations:
        sidecar.istio.io/proxyCPU: "200m"
        sidecar.istio.io/proxyMemoryLimit: "5Gi"

주입된 리소스는 이런 모습이 돼요. proxyCPU를 설정했으면 proxyCPULimit도 꼭 함께 설정해야 CPU limit이 무한대로 남지 않아요.

spec:
  containers:
  - name: istio-proxy
    resources:
      limits:
        memory: 5Gi
      requests:
        cpu: 200m
        memory: 5Gi
    securityContext:
      allowPrivilegeEscalation: false

커스텀 템플릿 (실험적)

설치 시점에 완전히 새로운 템플릿도 정의할 수 있어요. istio-proxy 컨테이너에 GREETING 환경변수를 주입하는 커스텀 템플릿을 예로 들어 볼게요.

apiVersion: install.istio.io/v1alpha1
kind: IstioOperator
metadata:
  name: istio
spec:
  values:
    sidecarInjectorWebhook:
      templates:
        custom: |
          spec:
            containers:
            - name: istio-proxy
              env:
              - name: GREETING
                value: hello-world

파드는 기본적으로 자동 생성된 sidecar 주입 템플릿을 사용해요. inject.istio.io/templates 애너테이션으로 덮어쓸 수 있는데, 기본 템플릿과 커스텀 템플릿을 함께 쓰려면 inject.istio.io/templates=sidecar,custom으로 설정하면 돼요. 기본 sidecar 외에 Gateway 배포용 프록시 주입을 지원하는 gateway 템플릿도 기본 제공돼요.

더 알아보기 (Learn more)