Istio Sidecar 시작 시퀀스로 인한 애플리케이션 컨테이너 네트워크 장애

1. 문제점

온라인 애플리케이션은 Spring Cloud K8S Config 모듈을 통합합니다.애플리케이션이 시작되면 K8S ConfigMap을 구성으로 읽습니다.최근에 온라인 애플리케이션이 시작할 때 다음과 같은 예외 로그를 ​​보고하는 것이 관찰되었습니다(때때로, 항상은 아님). 애플리케이션이 K8S ConfigMap 구성을 가져올 수 없고 K8s ConfigMap의 구성이 실제로 적용되지 않았음을 나타냅니다.

2023-02-28 11:18:16.950+0800 [main] WARN  o.s.c.k.f.c.Fabric8ConfigMapPropertySource - 
`Can't read configMap with name: [my-app] in namespace: [my-app-ns]. Ignoring.`
io.fabric8.kubernetes.client.KubernetesClientException: 
`Operation: [get]  for kind: [ConfigMap]  with name: [my-app]  in namespace: [my-app-ns]  failed`.
...
Caused by: java.net.ConnectException: `Failed to connect to /10.96.0.1:443`
	at okhttp3.internal.connection.RealConnection.connectSocket(RealConnection.kt:297)
...
Caused by: java.net.ConnectException: `Connection refused (Connection refused)`
	at java.base/java.net.PlainSocketImpl.socketConnect(Native Method)
	at java.base/java.net.AbstractPlainSocketImpl.doConnect(Unknown Source)	
...

K8S RBAC 권한 구성 문제와 K8S 클러스터 네트워크 문제를 해결한 후 마침내 백엔드 애플리케이션이 Istio 통합으로 배포됨, 즉 Istio Sidecar가 자동으로 주입되었음을 알게 되었습니다.
pod의 컨테이너는 spec.containers의 선언 순서에 따라 순차적으로 시작되고 모든 컨테이너가 시작되기 전에 initContainers가 실행되므로 컨테이너의 시작 순서는 다음과 같습니다.

istio-init
app
istio-proxy

즉, istio-init는 포드의 iptables를 수정하여 istio-proxy가 포드의 모든 트래픽을 인계하고(앱의 모든 네트워크 요청이 istio-proxy를 거쳐야 함) 네트워크 요청이 도중에 시작되는 경우 앱 시작 프로세스 istio-proxy has 아직 시작이 완료되지 않아 네트워크 예외가 발생할 수 있습니다.
즉, 애플리케이션이 K8S ConfigMap을 읽을 때 istio-proxy가 아직 시작되지 않았으며 네트워크 연결이 거부됩니다.
위의 문제에 대한 해결책은 네트워크 이상을 피하기 위해 istio-proxy가 성공적으로 시작된 후 애플리케이션 컨테이너가 시작되도록 하는 것입니다.

2. Istio 1.7 이상 버전용 솔루션

istio 1.7의 변경 사항에서 사이드카가 먼저 시작되도록 설정하는 것을 지원하기 위해 values.global.proxy.holdApplicationUntilProxyStarts 구성 옵션이 지원된다고 발표했습니다.
values.global.proxy.holdApplicationUntilProxyStarts는 기본적으로 비활성화되어 있으며 다음 설정:

--set values.global.proxy.holdApplicationUntilProxyStarts=true

2.1 방법 1: Istio 설치 시 전역 설정

# 默认使用default profile(可通过--set profile=default|demo|...调整)
istioctl install
# 设置sidecar优先启动(且sidecar启动成功后再启动其他应用容器) - 1.7新特性
--set values.global.proxy.holdApplicationUntilProxyStarts=true

2.2 방법 2: 주석을 통해 애플리케이션 배포에서 설정

참고:
이 방법은 아직 실제로 테스트되지 않았으며 Istio 1.7+ 환경이 없습니다. Istio 공식 문서에 따라 컴파일됩니다. 특정 Istio 공식 문서 설명은 https://istio.io/latest/docs/
를 참조하세요.
reference/config/istio.mesh.v1alpha1/#ProxyConfig

핵심 주석은 다음과 같습니다.

annotations:
  # 重点:配置proxy - 设置proxy启动成功后再启动其他应用
  proxy.istio.io/config: |
    holdApplicationUntilProxyStarts: true

구체적인 설정은 다음과 같습니다.

apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-app
  labels:
    app: my-app
    version: v1
spec:
  selector:
    matchLabels:
      app: my-app
      version: v1
  replicas: 1
  template:
    metadata:
      labels:
        app: my-app
        version: v1
      annotations:
        # 开启Istio Sidecar自动注入
        sidecar.istio.io/inject: true
        # 重点:配置proxy - 设置proxy启动成功后再启动其他应用
        proxy.istio.io/config: |
          holdApplicationUntilProxyStarts: true
    spec:
      containers:
        - name: app
          image: registry/app:latest
          ports:
            - name: http-port
              containerPort: 8080
              protocol: TCP       

2.3 holdApplicationUntilProxyStarts 활성화 효과

holdApplicationUntilProxyStarts를 true로 활성화하면 실제 효과는 다음과 같습니다.
(1) 사이드카 istio-proxy 컨테이너를 포드 컨테이너에 먼저 넣습니다(즉, 먼저 시작).
여기에 이미지 설명 삽입

(2) 성공적으로 시작될 때까지 사이드카 컨테이너가 차단되도록 istio-proxy 수명 주기를 설정합니다(Pod의 다른 컨테이너가 시작되지 않도록 차단).
여기에 이미지 설명 삽입

3. Istio 1.7 이전 솔루션


Istio 1.7 이전 버전은 동일한 목적, 즉 애플리케이션 컨테이너를 차단하고 애플리케이션 컨테이너가 istio-proxy 시작 포트를 모니터링하도록 하기 위해 K8S 수명 주기와 결합할 수 있는 holdApplicationUntilProxyStarts 구성을 제공하지 않았습니다. ).
구체적인 지침은 https://github.com/istio/istio/issues/11130#issuecomment-506659562
여기에 이미지 설명 삽입
를 참조하십시오 . 핵심 구성은 다음과 같습니다.

# 注:此处配置需结合Istio Sidecar注入一起使用,若未开启Istio Sidecar,则移除此配置
lifecycle:
  postStart:
    httpGet:
      path: /healthz/ready
      port: 15020
      scheme: HTTP

구체적인 설정은 다음과 같습니다.

apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-app
  labels:
    app: my-app
    version: v1
spec:
  selector:
    matchLabels:
      app: my-app
      version: v1
  replicas: 1
  template:
    metadata:
      labels:
        app: my-app
        version: v1
      annotations:
        # 开启Istio Sidecar自动注入
        sidecar.istio.io/inject: true
    spec:
      containers:
        - name: app
          image: registry/app:latest
          ports:
            - name: http-port
              containerPort: 8080
              protocol: TCP
          # 阻塞app容器,使app容器监听sidecar启动端口,若监听sidecar启动端口不通,则重启app容器(直到sidecar启动就绪)
          lifecycle:
            postStart:
              httpGet:
                path: /healthz/ready
                port: 15020
          

실제 배포 시 이전에 K8S ConfigMap을 읽을 수 없었던 로그도 함께 나타나는 것을 관찰할 수 있는데, 이 로그가 나타나면 Istio Sidecar가 성공적으로 시작되지 않은(네트워크가 연결되지 않은 상태) 것을 의미하며, 그 다음에는 K8S가 나타납니다. 애플리케이션 컨테이너를 다시 시작합니다. 로그를 다시 관찰하고 K8S ConfigMap 성공(오류 로그 없음)을 읽습니다. 이러한 방식으로 애플리케이션 컨테이너가 Istio Sidecar 준비 프로브를 모니터링하게 함으로써 애플리케이션 컨테이너는 Istio Sidecar가 성공적으로 시작되지 않기 전에 반복적으로 애플리케이션 컨테이너 자체를 다시 시작해야 합니다. 최종 애플리케이션 컨테이너가 시작됩니다.


참조:
포드에서 컨테이너의 실행 순서를 제어하는 ​​여러 자세
Istio 1.7이 사이드카의 시작 순서를 보장하는 방법
Github - issues - 사이드카가 완전히 실행되기 전에 네트워크에 연결할 수 없는 앱 컨테이너 #11130

рекомендация

отblog.csdn.net/luo15242208310/article/details/129257489