Linkerd MultiCluster는 여러 Kubernetes 클러스터를 하나의 서비스 메시로 연결하여, 클러스터 간 안전하고 신뢰성 높은 통신을 가능하게 한다. 이를 통해 서로 다른 클러스터에 있는 Pod 간의 통신이 가능해지며, 고가용성, 확장성, 격리 등 다양한 이점을 제공한다.
멀티클러스터 통신 흐름은 아래와 같다.
본 글에서는 멀티클러스터 간 통신 및 트래픽 흐름을 실습을 통해 확인해 보려 한다.
실습 절차
1. 공유 Trust anchor를 위한 인증서 업데이트2. 멀티클러스터 통신을 위한 linkerd gateway 구성
3. 서비스 내보내기
4. 멀티클러스터 통신
5. 구간별 패킷 흐름 검증
전제 조건
- 두 개의 Kubernetes 클러스터
- 두 개의 클러스터에 Linkerd-Control-Plane, Linkerd-viz, Cert-manager, Linkerd-crd, ngress-nginx-controller 구성
- 두 개의 클러스터에 linkerd cli 툴 설치
linkerd 관련 구성은 [Service Mesh/Linkerd] - Linkerd 설치] 글을 참고하면 된다.
실습
1. 공유 Trust anchor를 위한 인증서 업데이트
각 cluster의 ca.crt 파일 추출한다.
## cluster1, cluster2 에서 진행
$ kubectl -n linkerd get cm linkerd-config -ojsonpath="{.data.values}" | \
yq e .identityTrustAnchorsPEM -
추출된 cluster1, cluster2의 ca.crt 파일로 linkerd 설치 시 사용한 Helm values.yaml 파일에 추가한다.
## cluster1, cluster2 values.yaml
identityTrustAnchorsPEM: |
-----BEGIN CERTIFICATE-----
# ...
# cluster1 ca.crt파일
# ...
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
# ...
# cluster2 ca.crt 파일
# ...
-----END CERTIFICATE-----
위 vaule.yaml 파일로 cluster1, cluster2 Helm 업그레이드를 한다.
$ helm upgrade linkerd-control-plane linkerd/linkerd-control-plane -n linkerd -f values.yaml --atomic
참고
linkerd 인증서를 변경했기 때문에 linkerd-proxy를 사용하는 pod는 전부 restart가 필요하다.
2. 멀티클러스터 통신을 위한 linkerd gateway 구성
cluster1, cluster2에서 멀티클러스터 통신용 linkerd-gateway를 구성한다.
$ helm install linkerd-multicluster -n linkerd-multicluster --create-namespace linkerd/linkerd-multicluster
linkerd-gateway의 service는 다른 클러스터와 통신이 되어야 하기 때문에 LoadBalancer 타입으로 생성된다.
$ kubectl get po -n linkerd-multicluster
NAME READY STATUS RESTARTS AGE
linkerd-gateway-556988bf96-cr88d 2/2 Running 0 30m
$ kubectl get svc -n linkerd-multicluster
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
linkerd-gateway LoadBalancer 172.20.52.163 xxxxxxxxxxxxxxxxt-2.elb.amazonaws.com 4143:31954/TCP,4191:30960/TCP 3h57m
cluster1에서 linkerd cli 도구를 이용해 자격 증명을 위한 내용을 추출하여 cluster2에 적용한다.
# cluster1에서 정보 추출
$ linkerd multicluster link --cluster-name cluster1 > cluster1.yaml
# cluster2에서 위에서 추출한 파일 적용
$ kubectl apply -f cluster1.yaml
위 명령은 서비스를 감시하는데 필요한 자격 증명을 위해 ServiceAccount와 ClusterRole, ClusterRoleBinding을 생성한다.
또한 Secret, Link 리소스 및 서비스 미러 컨트롤러를 생성한다.
- Secret : cluster1의 Kubernetes API에 액세스 할 수 있는 kubeconfig이다.
- Link : 서비스 미러링을 구성하는 사용자 정의 리소스이며, 게이트웨이 주소, 게이트웨이 식별자 및 미러링 할 서비스를 결정하는 데 사용할 Label selector 등을 포함한다.
- 서비스 미러 컨트롤러 : Link 및 Secret 정보를 사용하여 cluster1(대상) 클러스터에서 Label selector와 일치하는 서비스를 찾아 cluster2(로컬) 클러스터로 복사한다.
적용한 리소스들이 생성되었는지 확인한다.
$ kubectl get -f cluster1.yaml
NAME TYPE DATA AGE
secret/cluster-credentials-cluster1 mirror.linkerd.io/remote-kubeconfig 1 39s
NAME AGE
link.multicluster.linkerd.io/cluster1 39s
NAME CREATED AT
clusterrole.rbac.authorization.k8s.io/linkerd-service-mirror-access-local-resources-cluster1 2023-04-27T16:13:55Z
NAME ROLE AGE
clusterrolebinding.rbac.authorization.k8s.io/linkerd-service-mirror-access-local-resources-cluster1 ClusterRole/linkerd-service-mirror-access-local-resources-cluster1 39s
NAME CREATED AT
role.rbac.authorization.k8s.io/linkerd-service-mirror-read-remote-creds-cluster1 2023-04-27T16:13:55Z
NAME ROLE AGE
rolebinding.rbac.authorization.k8s.io/linkerd-service-mirror-read-remote-creds-cluster1 Role/linkerd-service-mirror-read-remote-creds-cluster1 39s
NAME SECRETS AGE
serviceaccount/linkerd-service-mirror-cluster1 1 39s
NAME READY UP-TO-DATE AVAILABLE AGE
deployment.apps/linkerd-service-mirror-cluster1 1/1 1 1 39s
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/probe-gateway-cluster1 ClusterIP 172.20.177.81 <none> 4191/TCP 39s
3. 서비스 내보내기
cluster1에서 static-server를 띄운다.
## cluster1
apiVersion: v1
kind: Service
metadata:
name: static-server
spec:
selector:
app: static-server
ports:
- protocol: TCP
port: 8080
targetPort: 8080
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: static-server
spec:
replicas: 1
selector:
matchLabels:
app: static-server
template:
metadata:
name: static-server
labels:
app: static-server
annotations:
linkerd.io/inject: enabled
spec:
containers:
- name: static-server
image: wlsdn3004/http-echo:latest
resources:
requests:
memory: "64Mi"
cpu: "25m"
limits:
memory: "100Mi"
cpu: "50m"
args:
- -text="hello static-server"
- -listen=:8080
ports:
- containerPort: 8080
name: http
static-server의 service에 label을 추가하여 서비스를 내보낸다.
## cluster1
$ kubectl label svc static-server mirror.linkerd.io/exported=true
service/static-server labeled
cluster2에서 아래와 같이 service가 생성된 것을 확인할 수 있다.
## cluster2
$ kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
static-server-cluster1 ClusterIP 172.20.244.165 <none> 8080/TCP 43s
static-server 서비스의 endpoint를 보면 cluster1의 linkerd gateway ip이다.
## cluster2
$ kubectl get ep static-server-cluster1
NAME ENDPOINTS AGE
static-server-cluster1 {cluster1-linkerd_gateway-ip}:4143 105s
cluister2의 linkerd 대시보드에서 cluster1의 1개의 서비스와 페어링 된 것을 확인할 수 있다.
4. 멀티클러스터 통신
cluster2에 static-client를 배포하고 호출 테스트 해보자.
## cluster2
apiVersion: v1
kind: Service
metadata:
name: static-client
spec:
selector:
app: static-client
ports:
- port: 80
---
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: static-client
name: static-client
spec:
replicas: 1
selector:
matchLabels:
app: static-client
template:
metadata:
annotations:
linkerd.io/inject: enabled
labels:
app: static-client
spec:
containers:
- name: static-client
image: wlsdn3004/curl:latest
command: ['/bin/sh', '-c', '--']
args: ['while true; do sleep 30; done;']
cluster1의 Pod와 정상적으로 통신하는 것을 확인할 수 있다.
## cluster2
$ curl static-server-cluster1:8080
"hello static-server1"
5. 구간별 패킷 흐름 검증
멀티클러스터 패킷 흐름을 linkerd cli 툴을 사용하여 검증해 보자.
cluster2의 static-client 기준 패킷
[src] static-client (10.79.40.243) -> [dst] cluster1 linkerd gateway LoadBalancer (1.1.1.1)
## cluster2
$ linkerd viz tap deploy/static-client2
req id=4:0 proxy=out src=10.79.40.243:56420 dst=1.1.1.1:4143 tls=true :method=GET :authority=static-server.default.svc.cluster.local:8080 :path=/
rsp id=4:0 proxy=out src=10.79.40.243:56420 dst=1.1.1.1:4143 tls=true :status=200 latency=7577µs
end id=4:0 proxy=out src=10.79.40.243:56420 dst=1.1.1.1:4143 tls=true duration=504µs response-length=23B
cluster1의 linkerd-gateway 기준 패킷
[src] worker node(192.168.6.144) -> [dst] static-server(192.168.6.226)
## cluster1
$ linkerd viz tap -n linkerd-multicluster deploy/linkerd-gateway
req id=7:0 proxy=out src=192.168.6.144:59570 dst=192.168.6.226:8080 tls=true :method=GET :authority=static-server.default.svc.cluster.local:8080 :path=/
rsp id=7:0 proxy=out src=192.168.6.144:59570 dst=192.168.6.226:8080 tls=true :status=200 latency=948µs
end id=7:0 proxy=out src=192.168.6.144:59570 dst=192.168.6.226:8080 tls=true duration=33µs response-length=23B
cluster1 static-server 기준 패킷
[src] linkerd-gateway(192.168.6.169) -> [dst] static-server(192.168.6.226)
## cluster1
$ linkerd viz tap -n linkerd-multicluster deploy/static-server
deployment.apps "static-server" not found
[root@ip-192-168-10-142 ~]# linkerd viz tap deploy/static-server
req id=3:0 proxy=in src=192.168.6.169:56942 dst=192.168.6.226:8080 tls=true :method=GET :authority=static-server.default.svc.cluster.local:8080 :path=/
rsp id=3:0 proxy=in src=192.168.6.169:56942 dst=192.168.6.226:8080 tls=true :status=200 latency=459µs
end id=3:0 proxy=in src=192.168.6.169:56942 dst=192.168.6.226:8080 tls=true duration=109µs response-length=23B
실제로 위 트래픽이 tls 통신으로 이루어지는지는 "tls=true" 부분을 통해 확인할 수 있다.
'Service Mesh > Linkerd' 카테고리의 다른 글
Linkerd 자동 Canary 배포 (with Flagger, Prometheus) (0) | 2023.04.29 |
---|---|
Linkerd + Prometheus 통합 구성 (0) | 2023.04.29 |
Linkerd 서킷 브레이킹 (Circuit Breaking) (1) | 2023.04.19 |
Linkerd 버전 업그레이드 (1) | 2023.04.19 |
Linkerd 트래픽 Retry, Timeout (0) | 2023.04.19 |
댓글