Istio 서비스의 헬스 체크

Istio 서비스의 헬스 체크 (Health Checking of Istio Services)

Istio 서비스에 대한 liveness 및 readiness 프로브를 구성하는 방법을 배워요. 쿠버네티스의 command, HTTP, TCP, gRPC 프로브 접근 방식과 Istio의 프로브 재작성(rewrite)을 다뤄요.

출처: Istio 문서

본문

쿠버네티스 liveness 및 readiness 프로브는 liveness 및 readiness 프로브를 구성하는 여러 방법을 설명해요.

  1. Command
  2. HTTP request
  3. TCP probe
  4. gRPC probe

command 접근 방식은 변경 없이 작동하지만, HTTP 요청, TCP 프로브, gRPC 프로브는 Istio가 파드 구성을 변경해야 해요.

liveness-http 서비스에 대한 헬스 체크 요청은 Kubelet이 보내요. 상호 TLS가 활성화되면 문제가 되는데, Kubelet은 Istio가 발급한 인증서가 없기 때문이에요. 따라서 헬스 체크 요청이 실패할 거예요.

TCP 프로브 검사는 특별한 처리가 필요해요. Istio가 모든 인바운드 트래픽을 sidecar로 리디렉션하므로 모든 TCP 포트가 열려 있는 것처럼 보이기 때문이에요. Kubelet은 단순히 지정된 포트에 어떤 프로세스가 리슨 중인지 확인하고, 그래서 sidecar가 실행 중인 동안에는 프로브가 항상 성공해요.

Istio는 애플리케이션 PodSpec의 readiness/liveness 프로브를 다시 작성해서(rewrite) 프로브 요청이 sidecar agent로 보내지도록 함으로써 이 두 문제를 모두 해결해요.

Liveness 프로브 재작성 예제

readiness/liveness 프로브가 애플리케이션 PodSpec 수준에서 어떻게 다시 작성되는지 보여주기 위해 liveness-http-same-port 샘플을 사용해 보자.

먼저 예제를 위한 네임스페이스를 만들고 라벨링하세요.

$ kubectl create namespace istio-io-health-rewrite
$ kubectl label namespace istio-io-health-rewrite istio-injection=enabled

그리고 샘플 애플리케이션을 배포하세요.

$ kubectl apply -f - <<EOF
apiVersion: apps/v1
kind: Deployment
metadata:
  name: liveness-http
  namespace: istio-io-health-rewrite
spec:
  selector:
    matchLabels:
      app: liveness-http
      version: v1
  template:
    metadata:
      labels:
        app: liveness-http
        version: v1
    spec:
      containers:
      - name: liveness-http
        image: docker.io/istio/health:example
        ports:
        - containerPort: 8001
        livenessProbe:
          httpGet:
            path: /foo
            port: 8001
          initialDelaySeconds: 5
          periodSeconds: 5
EOF

배포 후 파드의 애플리케이션 컨테이너를 검사해서 변경된 경로를 볼 수 있어요.

$ kubectl get pod "$LIVENESS_POD" -n istio-io-health-rewrite -o json | jq '.spec.containers[0].livenessProbe.httpGet'
{
  "path": "/app-health/liveness-http/livez",
  "port": 15020,
  "scheme": "HTTP"
}

원래 livenessProbe 경로는 이제 sidecar 컨테이너 환경 변수 ISTIO_KUBE_APP_PROBERS의 새 경로에 매핑돼요.

$ kubectl get pod "$LIVENESS_POD" -n istio-io-health-rewrite -o=jsonpath="{.spec.containers[1].env[?(@.name=='ISTIO_KUBE_APP_PROBERS')]}"
{
  "name":"ISTIO_KUBE_APP_PROBERS",
  "value":"{\"/app-health/liveness-http/livez\":{\"httpGet\":{\"path\":\"/foo\",\"port\":8001,\"scheme\":\"HTTP\"},\"timeoutSeconds\":1}}"
}

HTTP와 gRPC 요청의 경우 sidecar agent가 요청을 애플리케이션으로 리디렉션하고 응답 본문은 제거한 후 응답 코드만 반환해요. TCP 프로브의 경우 sidecar agent는 트래픽 리디렉션을 피하면서 포트 검사를 수행해요.

문제가 되는 프로브의 재작성은 모든 내장 Istio 구성 프로필에서 기본으로 활성화되어 있지만, 아래 설명대로 비활성화할 수 있어요.

command 접근 방식을 사용한 liveness 및 readiness 프로브

Istio는 이 접근 방식을 구현하는 liveness 샘플을 제공해요. 상호 TLS가 활성화된 상태에서 작동하는 것을 보여주기 위해 먼저 예제를 위한 네임스페이스를 만드세요.

$ kubectl create ns istio-io-health

엄격한 상호 TLS를 구성하려면 다음을 실행하세요.

$ kubectl apply -f - <<EOF
apiVersion: security.istio.io/v1
kind: PeerAuthentication
metadata:
  name: "default"
  namespace: "istio-io-health"
spec:
  mtls:
    mode: STRICT
EOF

다음으로 Istio 설치의 루트로 디렉터리를 변경하고 다음 명령을 실행해 샘플 서비스를 배포하세요.

$ kubectl -n istio-io-health apply -f <(istioctl kube-inject -f @samples/health-check/liveness-command.yaml@)

liveness 프로브가 작동하는지 확인하려면 샘플 파드의 상태를 확인해 실행 중인지 검증하세요.

$ kubectl -n istio-io-health get pod
NAME                             READY     STATUS    RESTARTS   AGE
liveness-6857c8775f-zdv9r        2/2       Running   0           4m

HTTP, TCP, gRPC 접근 방식을 사용한 liveness 및 readiness 프로브

앞서 말했듯이 Istio는 기본적으로 프로브 재작성을 사용해 HTTP, TCP, gRPC 프로브를 구현해요. 이 기능을 특정 파드 또는 전역으로 비활성화할 수 있어요.

파드에 대한 프로브 재작성 비활성화

sidecar.istio.io/rewriteAppHTTPProbers: "false"로 파드에 어노테이션을 추가하면 프로브 재작성 옵션을 비활성화할 수 있어요. 어노테이션은 파드 리소스에 추가하세요. 다른 곳(예: 둘러싼 deployment 리소스)에서는 무시되기 때문이에요.

kubectl apply -f - <<EOF
apiVersion: apps/v1
kind: Deployment
metadata:
  name: liveness-http
spec:
  selector:
    matchLabels:
      app: liveness-http
      version: v1
  template:
    metadata:
      labels:
        app: liveness-http
        version: v1
      annotations:
        sidecar.istio.io/rewriteAppHTTPProbers: "false"
    spec:
      containers:
      - name: liveness-http
        image: docker.io/istio/health:example
        ports:
        - containerPort: 8001
        livenessProbe:
          httpGet:
            path: /foo
            port: 8001
          initialDelaySeconds: 5
          periodSeconds: 5
EOF
kubectl apply -f - <<EOF
apiVersion: apps/v1
kind: Deployment
metadata:
  name: liveness-grpc
spec:
  selector:
    matchLabels:
      app: liveness-grpc
      version: v1
  template:
    metadata:
      labels:
        app: liveness-grpc
        version: v1
      annotations:
        sidecar.istio.io/rewriteAppHTTPProbers: "false"
    spec:
      containers:
      - name: etcd
        image: registry.k8s.io/etcd:3.5.1-0
        command: ["--listen-client-urls", "http://0.0.0.0:2379", "--advertise-client-urls", "http://127.0.0.1:2379", "--log-level", "debug"]
        ports:
        - containerPort: 2379
        livenessProbe:
          grpc:
            port: 2379
          initialDelaySeconds: 10
          periodSeconds: 5
EOF

이 접근 방식은 Istio를 다시 설치하지 않고도 개별 deployment에서 헬스 체크 프로브 재작성을 점진적으로 비활성화할 수 있게 해줘요.

프로브 재작성을 전역으로 비활성화

--set values.sidecarInjectorWebhook.rewriteAppHTTPProbe=false를 사용해 Istio를 설치하면 프로브 재작성을 전역으로 비활성화할 수 있어요. 또는, Istio sidecar injector용 구성 맵을 업데이트하세요.

$ kubectl get cm istio-sidecar-injector -n istio-system -o yaml | sed -e 's/"rewriteAppHTTPProbe": true/"rewriteAppHTTPProbe": false/' | kubectl apply -f -

정리

예제에 사용된 네임스페이스를 제거하세요.

$ kubectl delete ns istio-io-health istio-io-health-rewrite

더 알아보기 (Learn more)