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