1W - 네이티브 사이드카 컨테이너 이용

개요

1주차에 마지막으로 해볼 실습은 쿠버네티스 네이티브 사이드카 컨테이너 활용이다.
쿠버네티스 최신 버전에서는 사이드카 컨테이너 기능을 제공한다.
그리고 이스티오에서도 이 사이드카를 그대로 사용할 수 있다.[^11]

사전 지식

사이드카 컨테이너란

기본적으로 사이드카 컨테이너는 사이드카 패턴을 컨테이너 형태로 만든 것을 말한다.
공식 문서에서는 사이드카 컨테이너라고 페이지를 아예 하나 빼서 설명하지만, 아예 sidecarContainer 이런 식으로 별도의 스펙이 만들어진 것은 아니라는 점을 유념할 필요가 있다.
사이드카 컨테이너는 메인 컨테이너들의 옆에 꼭 달라붙어 로깅, 프록시 등의 보조적인 기능을 수행하는 컨테이너를 일컫는 표현일 뿐이다.

1.28 버전 이후로부터 쿠버네티스에서는 자체적으로 사이드카 구현 방식을 제공하고 있다.
초기화 컨테이너restartPolicy를 Always로 걸어서 만드는 방식으로..
이 문서에서 설명하는 사이드카 컨테이너는 바로 이 쿠버네티스 네이티브 사이드카 컨테이너이다.
엄밀한 구조로 보자면 초기화 컨테이너의 한 종류이며, 이 글에서 언급할 초기화 컨테이너는 사이드카 컨테이너가 아닌 초기화 컨테이너를 한정하여 표현한다.

기능

일단 사이드카 패턴 자체는, 비즈니스 로직을 담당하는 프로세스와 별개로 보조적인 기능을 하는 프로세스를 둘 때 사용한다.
대표적으로 다음의 기능들을 위해 패턴을 활용할 수 있겠다.

앱 컨테이너 상위의 라이프사이클

사이드카 패턴을 왜 쓰는지는 알겠고, 그래서 쿠버네티스 네이티브 사이드카 컨테이너는 왜 쓰는가?
파드에는 여러 개의 컨테이너를 둘 수 있으니, 그냥 따로 컨테이너를 하나 더 설정하여 위의 기능들을 충족하는 컨테이너를 두는 것이 가능하다.

사이드카 컨테이너의 가장 큰 장점은, 사이드카 컨테이너가 파드의 전체 생애 주기와 함께 한다는 것에 있다.
일반적인 방식으로 컨테이너를 설정하는 방식에서 발생할 수 있는 상황을 짚어보자.

사이드카 컨테이너는 완벽하게 파드와 라이프사이클을 함께 하며, 앱 컨테이너에 영향이 가지 않는 것이 보장된다!
일단 초기화 컨테이너로서 앱 컨테이너보다 먼저 실행되는 것이 완벽하게 보장된다.
나름 초기화 컨테이너이기 때문에 사이드카 컨테이너가 종료되는 불상사가 있다면 앱 컨테이너는 절대 시작되지 않는다.
또한 파드가 성공이나 실패를 통해 종료된다 해도 사이드카 컨테이너는 메인 컨테이너가 종료되기 이전까지는 무조건 기능한다.
여기에 사이드카 컨테이너의 프로브는 절대 파드 전체에 영향을 주지 않는다!
이것이 사이드카 컨테이너를 사용하는 핵심 이유 되시겠다.
사이드카로 데이터 플레인을 구성하는 이스티오에서도 이 네이티브 사이드카 컨테이너를 이용한 설정 방법을 제공해주고 있다.

예시

apiVersion: batch/v1
kind: Job
metadata:
  name: myjob
spec:
  template:
    spec:
      containers:
        - name: myjob
          image: alpine:latest
          command: ['sh', '-c', 'echo "logging" > /opt/logs.txt']
          volumeMounts:
            - name: data
              mountPath: /opt
      initContainers:
        - name: logshipper
          image: alpine:latest
          restartPolicy: Always
          command: ['sh', '-c', 'tail -F /opt/logs.txt']
          volumeMounts:
            - name: data
              mountPath: /opt
      restartPolicy: Never
      volumes:
        - name: data
          emptyDir: {}

사이드카 컨테이너의 진미가 드러나는 예시.
은 종료가 보장되는 앱 컨테이너를 두고 사용하는 리소스인데 여기에 위처럼 로깅 설정을 한다면!
위처럼 로깅 기능을 하는 컨테이너랑 상관 없이 잡이 종료되도록 보장하는 것이 중요한데 이럴 때 사이드카 컨테이너가 매우 유용하다!
이 덕분에, 파드의 생애 주기 자체에 영향을 조금도 주지 않으면서 생애 주기를 함께 하는 컨테이너를 만들 수 있게 되는 것이다.

실습 진행

이제 이 갓벽한 사이드카 컨테이너로 데이터 플레인의 엔보이가 설정되도록 만들어보자.

이스티오 설정

apiVersion: install.istio.io/v1alpha1
kind: IstioOperator
spec:
  profile: demo
  components:
    ingressGateways:
    - name: istio-ingressgateway
      enabled: true
      k8s:
        service:
          type: NodePort
          ports:
          - port: 80
            targetPort: 8080
            nodePort: 30000
          externalTrafficPolicy: Local
    egressGateways:
    - name: istio-egressgateway
      enabled: false
  meshConfig:
    defaultProviders:
      metrics:
      - prometheus
      tracing: []
  values:
    pilot:
      env:
        ENABLE_NATIVE_SIDECARS: true

istio operator에서 헬름 values 파일에 넣는 설정을 넣는 필드가 있다.
여기에 values.pilot.env에 설정값을 넣어주면 된다.

istioctl upgrade -f initstio.yaml

업그레이드를 하고, 샘플 파일을 재기동 해준다.
image.png
기본 상태를 보면 별 차이가 없어보인다.
image.png
그러나 막상 container 부분에는 하나의 컨테이너만 띄워져 있는 것이 보인다!

Init Containers:
  istio-init:
    Image:         docker.io/istio/proxyv2:1.25.1
    ...
    State:          Terminated
      Reason:       Completed
      Exit Code:    0
      Started:      Thu, 10 Apr 2025 19:16:39 +0900
      Finished:     Thu, 10 Apr 2025 19:16:39 +0900
    Ready:          True
    Restart Count:  0
  istio-proxy:
    Image:         docker.io/istio/proxyv2:1.25.1
    Port:          15090/TCP
    Host Port:     0/TCP
    Args:
      proxy
      sidecar
      --domain
      $(POD_NAMESPACE).svc.cluster.local
      --proxyLogLevel=warning
      --proxyComponentLogLevel=misc:error
      --log_output_level=default:info
    State:          Running
      Started:      Thu, 10 Apr 2025 19:16:40 +0900
    Ready:          True
    Readiness:  http-get http://:15021/healthz/ready delay=0s timeout=3s period=15s #success=1 #failure=4
    Startup:    http-get http://:15021/healthz/ready delay=0s timeout=3s period=1s #success=1 #failure=600
    ...

init container 쪽을 보면, 기존에 컨테이너 쪽에서 돌아가던 프록시 컨테이너가 들어있는 것을 볼 수 있다.
어디에 설정됐냐 해서 실제 동작에서 달라지는 것은 없다.
다만 이제 이 프록시는 명확하게 앱 컨테이너가 실행되기 이전에 실행되고, 종료될 때도 앱 컨테이너 종료 이후에 종료되는 것이 보장된다.
그래서 파드 실행 간에 미연의 오작동을 원천 봉쇄할 수 있게 된다.

결론

위에서 봤듯이, 사이드카 컨테이너로서 활용할 프로세스가 있다면 이제 쿠버네티스 네이티브 사이드카 컨테이너를 활용하는 게 좋다.
솔직히 쓰고 안 쓰고 트레이드오프를 비교할 거리도 없이 사이드카 패턴을 사용하는 이상 안 쓸 이유가 그다지 없다고 생각한다.
그럴 일이야 있겠냐마는 막말로 엔보이 프록시가 뜨기 이전에 앱 컨테이너가 기동이 돼서 애매한 오작동이 생길 여지를 남길 바에는 안전하게 네이티브 사이드카 츄라이츄라이
(쿠버 1.28 버전 미만이라면, 피쳐게이트에서 기능을 반드시 활성화해야 한다!)

막간 실험

실습을 하다가 두 가지를 실험해보고 싶어졌다.

이런 케이스에 대해서 당연히 검증 에러를 내뿜거나, 알아서 다른 포트를 설정하도록 자동화를 해두었을 것이라 생각하지만 그래도 궁금한 건 참을 수 없다.

apiVersion: v1
kind: Pod
metadata:
  name: bad-pod
  labels:
    role: bad-pod
spec:
  containers:
    - name: istio-proxy
      image: nginx:1.21
      imagePullPolicy: IfNotPresent
      ports:
        - containerPort: 80
          protocol: TCP
        - containerPort: 15001
          protocol: TCP

대놓고 멀쩡한 이스티오 데이터 플레인 설정을 괴롭히기 위해 컨테이너 이름과 포트를 점유하는 아주 못된 파드다.
image.png
(아직 goland로 보는 게 익숙치 않은 이슈)
컨테이너 로그에다 이벤트 로그까지 한꺼번에 보여주고 있는 것 같은데, 이건 나중에 조금 더 파보기로 하고, 아무튼 문제가 발생한 상황을 볼 수 있다.
image.png
나는 당연히 istio-proxy라는 이름을 먼저 써버리면 승인 웹훅을 통해 검증 에러를 내줄 거라 생각했는데, 단순하게 변형 웹훅만 걸려있는 것으로 보인다.
image.png
원래는 내가 만든 컨테이너와 변형 웹훅을 통해 주입된 컨테이너로 2개의 컨테이너가 떠야 정상이나, 내 예상과 다르게 그냥 내가 설정한 컨테이너에 덮어씌우기를 시전했다;;
이스티오 일해라
사실 누가 컨테이너 이름을 istio-proxy로 하겠냐마는.. 검증 웹훅을 통해 휴먼 에러를 막는 로직이 있으면 좋겠다는 생각은 든다.

apiVersion: v1
kind: Pod
metadata:
  name: bad-pod
  labels:
    role: bad-pod
spec:
  containers:
    - name: istio
	  image:  docker.io/istio/proxyv2:1.25.1
      imagePullPolicy: IfNotPresent
      ports:
        - containerPort: 80
          protocol: TCP
        - containerPort: 15001
          protocol: TCP
        - containerPort: 15006
          protocol: TCP

이번에는 이름은 그대로 두고, 이미지를 아예 변경했다.
사실 파드 양식에 포트를 설정하는 것은 어차피 실제 프로세스에 아무런 영향을 주지 않는다.
그냥 클러스터 내에서 포트 매핑을 빠르게 하기 위해 가시성 작업에 지나지 않고, 끽해야 포트 이름 설정 정도.
사용되는 이미지가 해당 포트를 사용하고 있을 때만 같은 네트워크 상에서 포트가 바인딩됐다던가 하는 에러가 나올 것이다.
그래서 아예 주입되는 컨테이너 이미지를 내가 먼저 넣어봤다.
image.png
이번에도 에러가 발생한다.
이 에러는 뭔가 했는데, 그냥 단순히 인자를 전달하지 않고 이미지를 사용하여 컨테이너가 완료돼서 크룹백에 빠진 이슈였다.
image.png
초기화 컨테이너의 설정에는 아무런 변화가 발생하지 않았다.

istio-proxy라는 컨테이너 이름을 사용하는 실무 케이스는 절대 흔하지 않을 것이라 생각하고 그래서 저런 부분에 대한 이슈 대응이 크게 필요하지 않다고 생각한다.
그런데 포트는 조금 더 엄밀하게 제한을 둬야 하는 걸 필요성이 있지 않을까 싶기도 하다.
15001, 15006 포트가 well-known 포트마냥 전세계적으로 잘 알려진 이스티오 전용 포트라도 되는 건가?
설령 그렇다고 해도 해당 포트를 사용하는 어플리케이션이 있다면 이에 대한 경고나 에러를 사전에 띄우는 식으로라도 제한을 걸어둬야 디버깅에 도움이 될 것 같다.

아무튼 어거지로 이스티오 괴롭히기 실험이었지만, 생각보다 사이드카 설정이 경직돼있다는 것을 알 수 있었다..
아마 추후에 데이터 플레인 설정 방법을 조금 더 파다보면 이런 것들도 커스텀하는 방법이 있을지도 모르겠다.

이전 글, 다음 글

다른 글 보기

이름 index noteType created
1W - 서비스 메시와 이스티오 1 published 2025-04-10
1W - 간단한 장애 상황 구현 후 대응 실습 2 published 2025-04-10
1W - Gateway API를 활용한 설정 3 published 2025-04-10
1W - 네이티브 사이드카 컨테이너 이용 4 published 2025-04-10
2W - 엔보이 5 published 2025-04-19
2W - 인그레스 게이트웨이 실습 6 published 2025-04-17
3W - 버츄얼 서비스를 활용한 기본 트래픽 관리 7 published 2025-04-22
3W - 트래픽 가중치 - flagger와 argo rollout을 이용한 점진적 배포 8 published 2025-04-22
3W - 트래픽 미러링 패킷 캡쳐 9 published 2025-04-22
3W - 서비스 엔트리와 이그레스 게이트웨이 10 published 2025-04-22
3W - 데스티네이션 룰을 활용한 네트워크 복원력 11 published 2025-04-26
3W - 타임아웃, 재시도를 활용한 네트워크 복원력 12 published 2025-04-26
4W - 이스티오 메트릭 확인 13 published 2025-05-03
4W - 이스티오 메트릭 커스텀, 프로메테우스와 그라파나 14 published 2025-05-03
4W - 오픈텔레메트리 기반 트레이싱 예거 시각화, 키알리 시각화 15 published 2025-05-03
4W - 번외 - 트레이싱용 심플 메시 서버 개발 16 published 2025-05-03
5W - 이스티오 mTLS와 SPIFFE 17 published 2025-05-11
5W - 이스티오 JWT 인증 18 published 2025-05-11
5W - 이스티오 인가 정책 설정 19 published 2025-05-11
6W - 이스티오 설정 트러블슈팅 20 published 2025-05-18
6W - 이스티오 컨트롤 플레인 성능 최적화 21 published 2025-05-18
8W - 가상머신 통합하기 22 published 2025-06-01
8W - 엔보이와 iptables 뜯어먹기 23 published 2025-06-01
9W - 앰비언트 모드 구조, 원리 24 published 2025-06-07
9W - 앰비언트 헬름 설치, 각종 리소스 실습 25 published 2025-06-07
7W - 이스티오 메시 스케일링 26 published 2025-06-09
7W - 엔보이 필터를 통한 기능 확장 27 published 2025-06-09

관련 문서

이름 noteType created
사이드카 컨테이너 knowledge 2024-08-22
1W - 네이티브 사이드카 컨테이너 이용 published 2025-04-10
E-초기화 컨테이너보다 앞서는 사이드카 컨테이너 topic/explain 2024-08-30

참고