본문 바로가기
Service Mesh/Linkerd

Linkerd 멀티클러스터 통신 구성

by wlsdn3004 2023. 4. 28.
728x90
반응형

 

 

Linkerd MultiCluster는 여러 Kubernetes 클러스터를 하나의 서비스 메시로 연결하여, 클러스터 간 안전하고 신뢰성 높은 통신을 가능하게 한다. 이를 통해 서로 다른 클러스터에 있는 Pod 간의 통신이 가능해지며, 고가용성, 확장성, 격리 등 다양한 이점을 제공한다.

 

 

멀티클러스터 통신 흐름은 아래와 같다.

 

본 글에서는 멀티클러스터 간 통신 및 트래픽 흐름을 실습을 통해 확인해 보려 한다.

 

 

전제 조건

  • 두 개의 Kubernetes 클러스터
  • 두 개의 클러스터에 Linkerd-Control-Plane, Linkerd-viz, Cert-manager, Linkerd-crd, ngress-nginx-controller 구성
  • 두 개의 클러스터에 linkerd cli 툴 설치

 

linkerd 관련 구성은 [Service Mesh/Linkerd] - Linkerd 설치] 글을 참고하면 된다.

 

 

실습

 

1. 공유 Trust anchor를 위한 인증서 업데이트


cluster 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
Information Panel

참고

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" 부분을 통해 확인할 수 있다.

 

 

 

반응형

댓글