Linkerd 2.10 단계별 가이드 - 멀티 클러스터 통신 구성

Linkerd 2.10 시리즈 문서

  • Linkerd v2.10 Service Mesh 시작하기
  • 腾讯云 K8S 클러스터에서 Service Mesh 실습 - Linkerd2와 Traefik2로 emojivoto 배포
  • Linkerd 2.10 기초 기능详解 및 Service Mesh 마이크로서비스 아키텍처 도입
  • Linkerd 2.10 - 서비스를 Linkerd에 연결하기
  • Linkerd 2.10 - 자동화된 카나리 배포
  • Linkerd 2.10 - 컨트롤 플레인 TLS 및 Webhook TLS 자격 증명 자동 순환
  • Linkerd 2.10 - 외부 Prometheus 인스턴스 구성
  • Linkerd 2.10 - 프록시 동시성 설정
  • Linkerd 2.10 - 재시도 구성
  • Linkerd 2.10 - 타임아웃 설정
  • Linkerd 2.10 - 컨트롤 플레인 디버그 엔드포인트
  • Linkerd 2.10 - Kustomize로 Linkerd 설정 커스터마이징
  • Linkerd 2.10 - 분산 추적 구현
  • Linkerd 2.10 - 502 에러 디버깅
  • Linkerd 2.10 - 라우트별 지표를 활용한 HTTP 앱 디버깅
  • Linkerd 2.10 - 요청 추적으로 gRPC 앱 디버깅
  • Linkerd 2.10 - 지표 내보내기
  • Linkerd 2.10 - 대시보드 노출
  • Linkerd 2.10 - 자체 mTLS 루트 인증서 생성
  • Linkerd 2.10 - 라우트별 지표 확보
  • Linkerd 2.10 - 장애 주입을 통한 카오스 엔지니어링
  • Linkerd 2.10 - Pod优雅한 종료
  • Linkerd 2.10 - 인그레스 트래픽
  • Linkerd 2.10 - 멀티 클러스터 컴포넌트 설치
  • Linkerd 2.10 - Linkerd 설치
  • Linkerd 2.10 - Helm으로 Linkerd 설치
  • Linkerd 2.10 - Linkerd와 Pod 보안 정책
  • Linkerd 2.10 - 컨트롤 플레인 TLS 자격 증명 수동 순환
  • Linkerd 2.10 - 프록시 로그 레벨 수정

시작하기 전에

이 가이드에서는 두 클러스터에서 실행되는 서비스가 서로 통신할 수 있도록 Linkerd를 설치하고 구성하는 방법을 설명합니다. 완료 시점에는 서로 다른 클러스터에서 실행되는 서비스 간에 트래픽을 분산하는 방법을 이해하게 됩니다.

학습 목표

  1. 공유 트러스트 앵커를 가진 두 클러스터에 Linkerd 설치
  2. 클러스터 준비
  3. 클러스터 연결
  4. 데모 서비스 설치
  5. 데모 서비스 노출 및 가시성 제어
  6. 클러스터 보안 검증
  7. 트래픽 분할 설정 - 원본 클러스터의 Pod에서 대상 클러스터로 트래픽 라우팅

전제 조건

  • 두 개의 클러스터: 이 가이드에서는 이를 각각 sourcetarget으로 명명합니다. 개발 환경에서는 로컬에서 kind 또는 k3d 클러스터를 실행하고, 클라우드 제공자(AWS EKS, GCP GKE 등)에서 원격 클러스터를 실행하는 것이 가장 간단합니다.
  • kubectl 컨텍스트 구성: 각 클러스터는 별도의 kubectl 컨텍스트로 구성되어야 합니다. 이 가이드에서는 sourcetarget 네이밍을 사용하므로, kubectl 컨텍스트 이름 변경 기능을 활용하여 일관성을 유지하세요.
  • Elevated 권한: 서비스 계정 생성 및 확장 권한 부여가 필요하므로 테스트 클러스터에서 이러한 작업을 수행할 수 있어야 합니다.
  • Linkerd viz 확장 프로그램 설치: stat 명령 실행, Grafana 또는 Linkerd 대시보드 확인, linkerd multicluster gateways 명령 사용을 위해 필요합니다.
  • target 클러스터의 LoadBalancer 서비스 지원: source 클러스터가 게이트웨이를 통해 target과 통신하려면 LoadBalancer 타입 서비스가 필요합니다.

Linkerd 설치

Linkerd는 서로 통신하는 모든 클러스터 간에 공유 트러스트 앵커가 존재해야 합니다. 이 공유 앵커는 클러스터 간 트래픽을 암호화하고 게이트웨이로 오는 요청을 인증하여 클러스터가 공용 인터넷에 노출되지 않도록 합니다.

linkerd가 모든 것을 생성하게 하는 대신, 자격 증명을 생성하고 설치 명령의 구성으로 사용하겠습니다.

인증서 생성

이 가이드에서는 step CLI를 사용하여 인증서를 생성합니다. openssl을 선호하시면 자유롭게 사용하세요.

트러스트 앵커 생성:

step certificate create root.linkerd.cluster.local root.crt root.key \
  --profile root-ca --no-password --insecure

이 인증서는 모든 클러스터 간의 공통 신뢰 기반이 됩니다. 각 프록시는 이 인증서의 복사본을 얻고 mTLS 핸드shake의 일부로 피어로부터 받은 인증서를 검증합니다.

트러스트 앵커를 사용하여 각 클러스터에서 프록시에 인증서를 발급할 수 있는 자격 증명 생성:

step certificate create identity.linkerd.cluster.local issuer.crt issuer.key \
  --profile intermediate-ca --not-after 8760h --no-password --insecure \
  --ca root.crt --ca-key root.key

클러스터의 identity 서비스는 여기서 생성한 인증서와 키를 사용하여 각 프록시에서 사용되는 인증서를 발급합니다. 이 가이드에서는 각 클러스터에 동일한 발급자 자격 증명을 사용하지만, 실제로는 각 클러스터마다 다른 발급자 자격 증명을 사용하는 것이 좋습니다.

클러스터에 Linkerd 설치

트러스트 앵커와 발급자 자격 증명이 준비되었으니 source와 target 클러스터에 Linkerd를 설치할 수 있습니다:

linkerd install \
  --identity-trust-anchors-file root.crt \
  --identity-issuer-certificate-file issuer.crt \
  --identity-issuer-key-file issuer.key \
  | tee \
    >(kubectl --context=source apply -f -) \
    >(kubectl --context=target apply -f -)

설치 출력이 각 클러스터에 적용됩니다. 다음 명령으로 모든 것이 성공적으로 설치되었는지 확인하세요:

for ctx in source target; do
  echo "클러스터 확인: ${ctx} .........."
  linkerd --context=${ctx} check || break
  echo "-------------"
done

클러스터 준비

클러스터 간 트래픽 라우팅을 위해 Linkerd는 Kubernetes Services를 활용하므로 애플리케이션 코드 변경이 필요 없습니다. 이 기능은 수신 요청을 올바른 내부 서비스로 라우팅하는 게이트웨이 컴포넌트가 필요합니다.

게이트웨이는 LoadBalancer 타입의 Service를 통해 공용 인터넷에 노출됩니다. Linkerd의 mTLS(공유 트러스트 앵커 사용)를 통한 인증을 받은 요청만 이 게이트WAY를 통과할 수 있습니다.

멀티 클러스터 컴포넌트 설치

source와 target에서 멀티 클러스터 컴포넌트를 설치하려면:

for ctx in source target; do
  echo "클러스터에 설치 중: ${ctx} ........."
  linkerd --context=${ctx} multicluster install | \
    kubectl --context=${ctx} apply -f - || break
  echo "-------------"
done

게이트웨이는 linkerd-mult클러스터 네임스페이스에 설치되며, Linkerd 프록시가 주입된 간단한 NGINX 프록시입니다. 인바운드 측에서 Linkerd는 트러스트 앵커의 일부인 TLS 인증서를 사용한 연결인지 검증합니다. NGINX는 요청을 받아 Linkerd 프록시의 아웃바운드 측으로 전달합니다. 이 시점에서 Linkerd 프록시는 데이터 플레인의 다른 프록시처럼 작동하며 요청을 올바른 서비스로转发합니다.

게이트웨이가 성공적으로 시작되었는지 확인:

for ctx in source target; do
  echo "클러스터에서 게이트웨이 확인: ${ctx} ........."
  kubectl --context=${ctx} -n linkerd-multicluster \
    rollout status deploy/linkerd-gateway || break
  echo "-------------"
done

로드밸런서가 공용 IP를 할당할 수 있는지 확인:

for ctx in source target; do
  printf "클러스터 확인: ${ctx} ........."
  while [ "$(kubectl --context=${ctx} -n linkerd-multicluster get service \
    -o 'custom-columns=:.status.loadBalancer.ingress[0].ip' \
    --no-headers)" = "<none>" ]; do
      printf '.'
      sleep 1
  done
  printf "\n"
done

이제 각 클러스터에서 멀티 클러스터 컨트롤 플레인이 실행 중이며 이미지 서비스 시작 준비가 되었습니다!

클러스터 연결

source 클러스터가 target의 서비스를 미러링하려면, source 클러스터가 target에서 노출할 서비스를 감시할 수 있는 자격 증명이 필요합니다. 이는 클러스터에서 실행 중인 내용을 누구든지 검사할 수 있게 하려는 것이 아니기 때문입니다.

자격 증명에는 서비스 미러링을 인증하는 서비스 계정과 서비스 감시를 허용하는 ClusterRole 및 ClusterRoleBinding이 포함됩니다. 서비스 미러링 컴포넌트는 이러한 자격 증명을 사용하여 target 클러스터의 서비스를 관찰하고 source 클러스터에서 추가/제거합니다.

linkerd multicluster install의 일부로 기본 설정이 추가되지만, 각 클러스터마다 별도의 자격 증명을 원하시면 linkerd multicluster allow를 실행하세요.

클러스터 링크 생성

source를 target에 연결하려면 다음 명령을 실행하세요:

linkerd --context=target multicluster link --cluster-name target |
  kubectl --context=source apply -f -

Linkerd는 현재 target 컨텍스트를 보고 서버 위치와 CA 번들을 포함한 클러스터 구성을 추출합니다. 그런 다음 ServiceAccount 토큰을 가져와将这些 구성을 하나의 kubeconfig secret으로 병합합니다.

다시 한 번 check를 실행하여 서비스 미러링이 이 secret을 발견하고 target에 도달할 수 있는지 확인하세요:

linkerd --context=source multicluster check

target 게이트웨이가 목록에 표시되어야 합니다:

linkerd --context=source multicluster gateways

링크는 두 클러스터가 로컬에서 사용하는 것과 동일한 구성을 사용하여 서로 연결된다고 가정합니다. 그렇지 않은 경우 link--api-server-address 플래그를 사용해야 합니다.

테스트 서비스 설치

이제 모든 것을 테스트할 시간입니다! 첫 번째 단계는 미러링할 서비스를 추가하는 것입니다. 두 클러스터에 추가하려면:

for ctx in source target; do
  echo "클러스터에 테스트 서비스 추가: ${ctx} ........."
  kubectl --context=${ctx} apply \
    -k "github.com/linkerd/website/multicluster/${ctx}/"
  kubectl --context=${ctx} -n test \
    rollout status deploy/podinfo || break
  echo "-------------"
done

이제 각 클러스터에서 frontend와 podinfo 두 개의 디플로이먼트가 실행되는 test 네임스페이스가 있습니다. 각 클러스터의 podinfo는 서로 다른 이름과 색상을 가질,以便我们知道 요청이 어디로가는지 확인할 수 있습니다.

source 클러스터에서 서비스를 보려면:

kubectl --context=source -n test port-forward svc/frontend 8080

http://localhost:8080에서 제공되는 podinfo 로그인 페이지가 표시됩니다. 또는 curl http://localhost:8080를 실행하면 다음과 유사한 JSON 응답이 반환됩니다:

{
  "hostname": "podinfo-5c8cf55777-zbfls",
  "version": "4.0.2",
  "revision": "b4138fdb4dce7b34b6fc46069f70bb295aa8963c",
  "color": "#6c757d",
  "logo": "https://raw.githubusercontent.com/stefanprodan/podinfo/gh-pages/cuddle_clap.gif",
  "message": "greetings from source",
  "goos": "linux",
  "goarch": "amd64",
  "runtime": "go1.14.3",
  "num_goroutine": "8",
  "num_cpu": "4"
}

message에 source 클러스터 이름이 표시됩니다.

서비스 노출

민감한 서비스가 미러링되지 않고 클러스터 성능이 서비스 생성 또는 삭제의 영향을 받지 않도록 하려면 서비스를 명시적으로 노출해야 합니다.

이 가이드의 목적을 위해 target 클러스터의 podinfo 서비스를 source 클러스터로 내보내겠습니다. 먼저 target 클러스터에서 podinfo 서비스를 내보내야 합니다:

kubectl --context=target label svc -n test podinfo mirror.linkerd.io/exported=true

linkerd multicluster link 명령에 --selector 플래그를 사용하거나 linkerd multicluster link 명령으로 생성된 Link 리소스를 편집하여 다른 레이블 선택기를 구성할 수 있습니다.

서비스 미러링 컨트롤러가 방금 생성한 서비스를 확인하세요:

kubectl --context=source -n test get svc podinfo-target

아키텍처에서 기억하시겠지만, 서비스 미러링 컴포넌트는 단순히 서비스를 이동하는 것 이상을 수행합니다. 미러링된 서비스의 엔드포인트도 관리합니다. 설정이 올바른지 확인하려면 source의 엔드포인트를 확인하고 target 게이트웨이의 공용 IP 주소와 일치하는지 검증하세요:

kubectl --context=source -n test get endpoints podinfo-target \
  -o 'custom-columns=ENDPOINT_IP:.subsets[*].addresses[*].ip'
kubectl --context=target -n linkerd-multicluster get svc linkerd-gateway \
  -o "custom-columns=GATEWAY_IP:.status.loadBalancer.ingress[*].ip"

이제 source 클러스터에서 target의 podinfo 서비스에 접근할 수 있습니다. 클라이언트를 메싱해야 하므로 frontend pod에서 curl을 실행해 보겠습니다:

kubectl --context=source -n test exec -c nginx -it \
  $(kubectl --context=source -n test get po -l app=frontend \
    --no-headers -o custom-columns=:.metadata.name) \
  -- /bin/sh -c "apk add curl && curl http://podinfo-target:9898"

"greetings from target" 메시지가 표시됩니다! source에서 실행 중인 frontend pod로의 요청이 target으로 투명하게 전달됩니다.

이전 단계에서 포트 포워딩을 실행 중이면 http://localhost:8080/target에서도 브라우저에서 접근할 수 있습니다. 몇 번이고 새로고침하면 linkerd viz stat에서도 지표를 얻을 수 있습니다:

linkerd --context=source -n test viz stat --from deploy/frontend svc

发生的事情을 이해하기 위한 Grafana 대시보드도 제공됩니다. linkerd --context=source viz dashboard를 실행하고 http://localhost:50750/grafana/로 이동하여 접근하세요.

보안 검증

기본적으로 요청은 공용 인터넷을 통해 전송됩니다. Linkerd는 자동 mTLS를 클러스터 간으로 확장하여 공용 인터넷을 통한 통신이 암호화되도록 합니다. 그러나快速 확인을 위해 다음을 실행할 수 있습니다:

linkerd --context=source -n test tap deploy/frontend | \
  grep "$(kubectl --context=target -n linkerd-multicluster get svc linkerd-gateway \
    -o "custom-columns=GATEWAY_IP:.status.loadBalancer.ingress[*].ip")"

tls=true은 요청이 암호화되고 있음을 보여줍니다!

linkerd edge가 구체적인 리소스에서 작동하고 두 클러스터를 동시에 볼 수 없기 때문에 현재 source와 target의 Pod 간 에지를 표시할 수 없습니다. 그래서 여기서는 mTLS 검증을 위해 tap을 사용합니다.

모든 요청이 암호화되는지 확인하는 외에도 클러스터로의 임의 요청 차단을 중요합니다. 요청이 메시의 클라이언트에서 비롯된 것을 검증하여 이를 수행합니다. 이 검증을 위해 클러스터 간 공유 트러스트 앵커에 의존합니다. 클라이언트가 메시 외부에 있을 때 무슨 일이 발생하는지 보려면:

kubectl --context=source -n test run -it --rm --image=alpine:3 test -- \
  /bin/sh -c "apk add curl && curl -vv http://podinfo-target:9898"

트래픽 분할

클러스터에서 서비스가 자동으로 나타나고 명시적으로 처리할 수 있는 것은 매우 유용하지만, 이것은 여러 클러스터를 운영하는 하나의 사용 사례만 포함합니다. 멀티 클러스터의 또 다른 시나리오는 장애 복구입니다.

장애 복구 시나리오에서는 구성 업데이트 시간이 없습니다. 대신 애플리케이션을 무시하고 라우팅만 변경할 수 있으면 됩니다. 이것이 카나리 배포 방식과 매우 유사하게 들린다면 바로 그겁니다!

TrafficSplit을 사용하면 여러 서비스 간의 가중치를 정의하고 그 사이에서 트래픽을 분할할 수 있습니다. 장애 복구 시나리오에서는 다른 클러스터를 과부하시키거나 SLO를 위반하지 않도록 이를 천천히 수행하려고 합니다.

source와 target의 podinfo 서비스 간에 분할을 구성하려면:

cat <<EOF | kubectl --context=source apply -f -
apiVersion: split.smi-spec.io/v1alpha1
kind: TrafficSplit
metadata:
  name: podinfo
  namespace: test
spec:
  service: podinfo
  backends:
  - service: podinfo
    weight: 50
  - service: podinfo-target
    weight: 50
EOF
</code>

podinfo에 대한 요청은 이제 50%의 시간은 podinfo-target 클러스터로, 나머지 50%의 시간은 로컬 podinfo 서비스로 전달됩니다. podinfo-target으로 전송된 요청은 결국 target 클러스터에 도달하므로, 이제 source에서 target으로 50% 이상의 트래픽이 효과적으로 실패합니다.

여전히 port-forward를 실행 중인 경우 브라우저를 http://localhost:8080으로 보내세요. 페이지를 새로고침하면 두 클러스터가 표시됩니다. 또는 명령줄 방법의 경우 curl localhost:8080은 source와 target 모두에서 인사를 제공합니다.

지표를 통해 발생 상황을 관찰할 수도 있습니다. source(출발지)에서 상황을 보려면:

linkerd --context=source -n test viz stat trafficsplit

target(목적지) 측면에서 관찰할 수도 있습니다:

linkerd --context=target -n test viz stat \
  --from deploy/linkerd-gateway \
  --from-namespace linkerd-multicluster \
  deploy/podinfo

대시보드도 있습니다! linkerd viz dashboard를 실행하고 브라우저를 localhost:50750으로 보내세요.

정리

멀티 클러스터 컨트롤 플레인을 정리하려면:

for ctx in source target; do
  linkerd --context=${ctx} multicluster uninstall | kubectl --context=${ctx} delete -f -
done

Linkerd 설치도 삭제하려면:

for ctx in source target; do
  linkerd --context=${ctx} uninstall | kubectl --context=${ctx} delete -f -
done

태그: Linkerd service-mesh kubernetes multicluster microservices

8월 2일 05:53에 게시됨