본문 바로가기
WIKI 기술 지식 베이스

멀티클러스터 연합 서비스

원문 보기 위키 갱신

멀티클러스터 연합 서비스 (Multi-cluster Federated Services)

Linkerd의 멀티클러스터 확장으로 이름과 네임스페이스가 같은 서로 다른 클러스터의 여러 서비스들의 합집합처럼 동작하는 연합 서비스(federated service)를 만들고, 3개 클러스터에 걸친 트래픽 로드밸런싱을 구성하는 방법을 알려드려요.

출처: Linkerd Multi-cluster Federated Services

본문

Linkerd의 멀티클러스터 확장은 서로 다른 클러스터에 같은 이름과 네임스페이스를 가진 여러 서비스들의 합집합처럼 동작하는 연합 서비스를 만들 수 있습니다. 연합 서비스로 트래픽을 보내면 그 트래픽은 연결된 모든 클러스터에서 그 서비스의 모든 엔드포인트 사이에 로드밸런싱됩니다. 덕분에 클라이언트는 클러스터를 몰라도 되고, 여러 클러스터에 걸쳐 트래픽을 분산시키며, 어떤 개별 클러스터가 실패해도 탄력적으로 대응할 수 있어요.

연합 서비스는 게이트웨이를 거치지 않고 멤버 서비스의 pod로 직접 트래픽을 보냅니다. 따라서 연합 서비스는 pod-to-pod 멀티클러스터 서비스와 같은 요구사항을 갖습니다:

  • 클러스터들이 플랫(flat) 네트워크에 있어야 합니다. 다시 말해 한 클러스터의 pod가 다른 클러스터의 pod에 주소를 지정하고 연결할 수 있어야 합니다.
  • 클러스터들이 같은 신뢰 루트(trust root)를 공유해야 합니다.
  • 연합 서비스에 연결하는 모든 클라이언트가 meshed 되어야 합니다.

이 가이드는 여러 클러스터에 존재하는 서비스로 트래픽을 로드밸런싱하는 연합 서비스를 만드는 과정을 안내해요. 연합 서비스는 어떤 수의 클러스터든 서비스를 포함할 수 있지만, 이 가이드에서는 3개 클러스터에 걸친 서비스용 연합 서비스를 만들 거예요.

사전 준비

  • 세 개의 클러스터. 이 가이드에서는 west, east, north라고 부를 거예요.
  • 클러스터들이 플랫 네트워크에 있어야 합니다. 다시 말해 한 클러스터의 pod가 다른 클러스터의 pod에 주소를 지정하고 연결할 수 있어야 합니다.
  • 각 클러스터가 kubectl 컨텍스트로 구성되어 있어야 합니다. 이 가이드를 따라오려면 west, east, north라는 이름을 사용하는 것을 권장해요. kubectl로 컨텍스트 이름을 바꾸는 것은 쉬우니 꼭 영구히 그렇게 이름을 유지할 필요는 없어요.

1단계: Linkerd와 Linkerd-Viz 설치하기

먼저 멀티클러스터 가이드에서 설명한 대로 세 클러스터 모두에 Linkerd와 Linkerd-Viz를 설치하세요. 모든 클러스터가 공통 신뢰 앵커를 공유하도록 주의하세요.

2단계: Linkerd-Multicluster 설치하기

세 클러스터 모두에 멀티클러스터 확장을 설치할 거예요. 연합 서비스는 pod-to-pod 직접 통신을 사용하므로 게이트웨이 없이 설치할 수 있어요. 서비스가 west 클러스터에 미러링되므로 컨트롤러는 거기서 만듭니다:

`> linkerd --context west multicluster install --gateway=false \
>   --set controllers[0].link.ref.name=east --set controllers[1].link.ref.name=north |
>   kubectl --context west apply -f -
> linkerd --context west check

> linkerd --context east multicluster install --gateway=false | kubectl --context east apply -f -
> linkerd --context east check

> linkerd --context north multicluster install --gateway=false | kubectl --context north apply -f -
> linkerd --context north check
`

3단계: 클러스터 연결하기

linkerd multicluster link-gen 명령으로 east와 north 클러스터를 west 클러스터에 연결합니다. 일반적인 Multicluster 가이드와 정확히 같지만, 게이트웨이가 필요 없는 Link를 만들기 위해 --gateway=false 플래그를 전달한다는 점만 다릅니다.

`> linkerd --context east multicluster link-gen --cluster-name=east --gateway=false | kubectl --context west apply -f -
> linkerd --context north multicluster link-gen --cluster-name=north --gateway=false | kubectl --context west apply -f -
> linkerd --context west check
`

4단계: 서비스 배포하기

이 가이드에서는 정적 응답만 반환하는 간단한 서버인 bb 서비스를 배포할 거예요. 세 클러스터 모두에 배포하되 각각 다른 응답 문자열로 구성해 응답을 구분할 수 있게 합니다:

`> cat ---
apiVersion: v1
kind: Namespace
metadata:
  name: mc-demo
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: bb
  namespace: mc-demo
spec:
  replicas: 1
  selector:
    matchLabels:
      app: bb
  template:
    metadata:
      labels:
        app: bb
    spec:
      containers:
      - name: terminus
        image: buoyantio/bb:v0.0.6
        args:
        - terminus
        - "--h1-server-port=8080"
        - "--response-text=hello from east\n"
        ports:
        - containerPort: 8080
---
apiVersion: v1
kind: Service
metadata:
  name: bb
  namespace: mc-demo
spec:
  ports:
  - name: http
    port: 8080
    targetPort: 8080
  selector:
    app: bb
EOF

> cat ---
apiVersion: v1
kind: Namespace
metadata:
  name: mc-demo
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: bb
  namespace: mc-demo
spec:
  replicas: 1
  selector:
    matchLabels:
      app: bb
  template:
    metadata:
      labels:
        app: bb
    spec:
      containers:
      - name: terminus
        image: buoyantio/bb:v0.0.6
        args:
        - terminus
        - "--h1-server-port=8080"
        - "--response-text=hello from north\n"
        ports:
        - containerPort: 8080
---
apiVersion: v1
kind: Service
metadata:
  name: bb
  namespace: mc-demo
spec:
  ports:
  - name: http
    port: 8080
    targetPort: 8080
  selector:
    app: bb
EOF

> cat ---
apiVersion: v1
kind: Namespace
metadata:
  name: mc-demo
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: bb
  namespace: mc-demo
spec:
  replicas: 1
  selector:
    matchLabels:
      app: bb
  template:
    metadata:
      labels:
        app: bb
    spec:
      containers:
      - name: terminus
        image: buoyantio/bb:v0.0.6
        args:
        - terminus
        - "--h1-server-port=8080"
        - "--response-text=hello from west\n"
        ports:
        - containerPort: 8080
---
apiVersion: v1
kind: Service
metadata:
  name: bb
  namespace: mc-demo
spec:
  ports:
  - name: http
    port: 8080
    targetPort: 8080
  selector:
    app: bb
EOF
`

5단계: 서비스에 라벨 붙이기

이제 서비스에 연합 서비스에 가입해야 한다는 라벨을 설정합니다.

`> kubectl --context east -n mc-demo label svc/bb mirror.linkerd.io/federated=member
> kubectl --context north -n mc-demo label svc/bb mirror.linkerd.io/federated=member
> kubectl --context west -n mc-demo label svc/bb mirror.linkerd.io/federated=member
`

west 클러스터에 연합 서비스가 생성된 것을 곧바로 볼 수 있어요:

`> kubectl --context west -n mc-demo get svc
NAME           TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)    AGE
bb-federated   ClusterIP   10.43.56.245           8080/TCP   114s
`

또한 각 Link 리소스의 status 하위 리소스를 확인해 어떤 서비스가 연합 서비스에 가입했는지 또는 오류가 있는지 볼 수 있습니다.

`> kubectl --context west -n linkerd-multicluster get link/east -ojsonpath='{.status.federatedServices}' | jq .
[
  {
    "conditions": [
      {
        "lastTransitionTime": "2024-11-07T19:53:01Z",
        "localRef": {
          "group": "",
          "kind": "Service",
          "name": "bb-federated",
          "namespace": "mc-demo"
        },
        "message": "",
        "reason": "Mirrored",
        "status": "True",
        "type": "Mirrored"
      }
    ],
    "controllerName": "linkerd.io/service-mirror",
    "remoteRef": {
      "group": "",
      "kind": "Service",
      "name": "bb",
      "namespace": "mc-demo"
    }
  }
]
> kubectl --context west -n linkerd-multicluster get link/north -ojsonpath='{.status.federatedService
s}' | jq .
[
  {
    "conditions": [
      {
        "lastTransitionTime": "2024-11-07T19:53:06Z",
        "localRef": {
          "group": "",
          "kind": "Service",
          "name": "bb-federated",
          "namespace": "mc-demo"
        },
        "message": "",
        "reason": "Mirrored",
        "status": "True",
        "type": "Mirrored"
      }
    ],
    "controllerName": "linkerd.io/service-mirror",
    "remoteRef": {
      "group": "",
      "kind": "Service",
      "name": "bb",
      "namespace": "mc-demo"
    }
  }
]
`

6단계: 트래픽을 보내요!

curl로 bb-federated 서비스에 트래픽을 생성하는 배포를 만들겠습니다.

`> cat ---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: traffic
  namespace: mc-demo
spec:
  replicas: 1
  selector:
    matchLabels:
      app: traffic
  template:
    metadata:
      labels:
        app: traffic
    spec:
      containers:
      - args:
        - -c
        - |
          while true
          do curl -s http://bb-federated:8080
          echo
          sleep 1
          done
        command:
        - /bin/sh
        image: curlimages/curl
        name: traffic
EOF
`

이 배포의 로그를 보면 연합 서비스가 요청을 세 클러스터에 걸쳐 분산하고 있음을 알 수 있어요:

`> kubectl --context west -n mc-demo logs deploy/traffic -c traffic
{"requestUID":"in:http-sid:terminus-grpc:-1-h1:8080-407945949","payload":"hello from east\n"}
{"requestUID":"in:http-sid:terminus-grpc:-1-h1:8080-420928530","payload":"hello from west\n"}
{"requestUID":"in:http-sid:terminus-grpc:-1-h1:8080-433442439","payload":"hello from north\n"}
{"requestUID":"in:http-sid:terminus-grpc:-1-h1:8080-445418175","payload":"hello from west\n"}
{"requestUID":"in:http-sid:terminus-grpc:-1-h1:8080-457469540","payload":"hello from west\n"}
{"requestUID":"in:http-sid:terminus-grpc:-1-h1:8080-469729132","payload":"hello from west\n"}
{"requestUID":"in:http-sid:terminus-grpc:-1-h1:8080-481971153","payload":"hello from west\n"}
{"requestUID":"in:http-sid:terminus-grpc:-1-h1:8080-496032705","payload":"hello from east\n"}
...
`

다음 단계

이제 세 클러스터의 서비스 간에 트래픽을 밸런싱하는 연합 서비스를 갖게 되었습니다. 추가 클러스터는 간단히 다음으로 추가할 수 있어요:

  • 필요한 컨트롤러를 추가하도록 west의 linkerd-multicluster 구성을 갱신하기
  • Link CR과 자격증명 시크릿 적용하기
  • 연합 서비스에 추가하려는 서비스에 mirror.linkerd.io/federated=member 라벨 붙이기

마찬가지로 라벨을 제거하면 언제든 서비스를 연합 서비스에서 뺄 수 있습니다.

bb-federated 연합 서비스가 west 클러스터에만 존재하고 east나 north 클러스터에는 없다는 점을 눈치챘을 거예요. Link는 방향성이 있고 이 가이드를 단순하게 유지하려고 north와 east를 west에만 연결했지 그 반대 방향은 아니기 때문이에요. 세 클러스터 사이에 양방향으로 링크를 만들면 세 클러스터 모두에 bb-federated 서비스가 생길 거예요.

문제 해결 (Troubleshooting)

  • 문제 해결의 첫 단계는 각 클러스터에서 linkerd check 명령을 실행하는 것입니다. 특히 linkerd-multicluster 체크를 보고 모든 연결된 클러스터가 나열되었는지 확인하세요:
`linkerd-multicluster
--------------------
√ Link CRD exists
√ Link resources are valid
        * east
        * north
√ remote cluster access credentials are valid
        * east
        * north
√ clusters share trust anchors
        * east
        * north
√ service mirror controller has required permissions
        * east
        * north
√ service mirror controllers are running
        * east
        * north
√ extension is managing controllers
        * east
        * north
`
  • Link 리소스의 status 하위 리소스를 확인하세요. 어떤 서비스가 연합 서비스에 가입하지 못했다면 여기에 오류로 나타납니다.
  • 연합 서비스에 가입해야 하는 서비스가 Link status에 없으면, 그 서비스가 연합 서비스 라벨 셀렉터(기본은 mirror.linkerd.io/federated=member)와 일치하는지 확인하세요.
  • linkerd diagnostics endpoints 명령으로 연합 서비스의 모든 엔드포인트를 볼 수 있어요:
`> linkerd --context west diagnostics endpoints bb-federated.mc-demo.svc.cluster.local:8080
NAMESPACE   IP            PORT   POD                   SERVICE
mc-demo     10.42.0.108   8080   bb-85f9bbc898-j7fbq   bb.mc-demo
mc-demo     10.23.1.43    8080   bb-7d9f44c6fd-9s848   bb.mc-demo
mc-demo     10.23.0.42    8080   bb-74c6c64948-j5drn   bb.mc-demo
`

더 알아보기 (Learn more)

  • 멀티클러스터 가이드 (Multicluster guide)
  • 멀티클러스터 확장 개념 문서