멀티클러스터 통신
Linkerd의 멀티클러스터 기능은 포드가 클러스터 경계를 넘어 Kubernetes 서비스에 보안되고 애플리케이션에 완전히 투명한 방식으로 연결되게 해 줘요. 이 기능은 세 가지 모드를 지원해요: 계층적(hierarchical, 게이트웨이 사용), 평면(flat, 게이트웨이 없음), 페더레이션(federated). 각 모드의 네트워크 요구 사항이 다르며 서로 섞어 쓸 수도 있어요. 핵심에는 서비스 미러링(service mirroring) 개념이 있어요.
본문
Linkerd의 멀티클러스터 기능은 포드가 클러스터 경계를 넘어 Kubernetes 서비스에 보안되고 애플리케이션에 완전히 투명한 방식으로 연결되게 해 줘요. 이 기능은 세 가지 모드를 지원해요: 계층적 (게이트웨이 사용), 평면 (게이트웨이 없음), 페더레이션.
- 계층적 모드는 대상 클러스터의 게이트웨이 IP가 소스 클러스터의 포드에서 도달 가능하기만 하면 돼요.
- 평면 모드는 소스 클러스터의 모든 포드가 대상 클러스터의 포드에 직접 연결할 수 있어야 해요.
- 페더레이션 모드는 평면 모드와 동일한 요구 사항을 가지지만, 여러 클러스터에 배포된 서비스를 클러스터에 구애받지 않는 단일 서비스로 취급할 수 있어요.
이 모드들은 서로 섞어 쓸 수 있어요.
계층적 모드는 게이트웨이 IP만 도달 가능하면 되므로 기반 네트워크에 최소한의 요구 사항만 둬요. 하지만 평면 모드는 계층적 모드에서 사용하는 게이트웨이 접근 방식보다 몇 가지 장점이 있는데, 지연을 줄이고 클라이언트 identity를 보존하는 것이 포함돼요.
서비스 미러링
Linkerd의 멀티클러스터 기능은 대상 클러스터의 서비스 업데이트를 감시하고 그 서비스 업데이트를 소스 클러스터에 로컬로 미러링하는 컨트롤러 컴포넌트를 사용해요.
멀티클러스터 지원은 서비스 미러링이라는 개념에 기반해요. 미러링은 다른 클러스터에서 서비스 정의를 가져오는 것을 말하며, 애플리케이션이 멀티클러스터 서비스를 주소 지정하고 소비할 수 있게 해 줘요. 컨트롤러는 소스 클러스터에서 실행되며, 대상 클러스터의 서비스 업데이트를 감시하고 그 업데이트를 소스 클러스터에 로컬로 미러링해요. 레이블 셀렉터와 일치하는 Kubernetes 서비스 객체만 내보내집니다.
레이블 셀렉터는 서비스가 내보내지는 모드도 제어해요. 예를 들어 기본적으로 mirror.linkerd.io/exported=true 레이블이 붙은 서비스는 계층적(게이트웨이) 모드로 내보내지고, mirror.linkerd.io/exported=remote-discovery 레이블이 붙은 서비스는 평면(포드-투-포드) 모드로 내보내져요. 구성이 서비스 중심이므로 게이트웨이에서 포드-투-포드 모드로 전환하는 것은 간단하며 확장을 다시 설치할 필요가 없어요.
참고
평면 모드에서는 Linkerd 제어 플레인의 네임스페이스가 모든 클러스터에서 동일해야 해요. 기본값인 linkerd로 두는 것을 권장해요.
"remote-discovery"라는 용어는 가져온 서비스를 Linkerd 제어 플레인이 어떻게 해석해야 하는지를 가리켜요. 서비스 디스커버리는 destination 서비스가 수행해요. "remote-discovery" 모드로 가져온 대상으로 트래픽이 보내질 때마다 destination 서비스는 서비스가 내보내진 클러스터에서 모든 관련 정보를 찾아야 한다는 것을 알게 돼요. 반대로 계층적(게이트웨이 모드) 가져오기에 대한 서비스 디스커버리는 로컬로 수행돼요. 트래픽이 포드로 직접 라우팅되는 대신 대상 클러스터의 게이트웨이 주소로 보내져요.
Linkerd의 destination 서비스는 여러 Kubernetes API 서버에 직접 연결해 원격 디스커버리를 수행해요. 두 클러스터가 연결될 때마다 제어 플레인의 네임스페이스에 API 클라이언트를 구성할 수 있는 kubeconfig 파일이 담긴 Kubernetes Secret이 생성돼요. kubeconfig 파일은 RBAC를 사용해 "최소 권한 원칙"을 제공하며, destination 서비스가 필요한 리소스에만 접근할 수 있도록 보장해요.
페더레이션 서비스
페더레이션 서비스는 한 걸음 더 나아가, 여러 클러스터에 배포된 서비스를 단일 통합 서비스로 결합할 수 있게 해 줘요.
컨트롤러는 연결된 모든 클러스터에서 레이블 셀렉터(기본 mirror.linkerd.io/federated=member)와 일치하는 모든 서비스를 찾아 -federated라는 페더레이션 서비스를 만들고, 이 서비스가 그 이름을 가진 모든 서비스의 합집합(union) 역할을 해요. 예를 들어 store-web-federated 페더레이션 서비스로 보내진 모든 트래픽은 연결된 모든 클러스터에서 store-web이라는 모든 서비스의 모든 레플리카에 로드 밸런싱돼요.
"네임스페이스 동일성(namespace sameness)" 개념이 적용되는데, 페더레이션 서비스는 개별 서비스와 같은 네임스페이스에 생성되고 서비스는 같은 네임스페이스에서만 페더레이션 서비스에 가입할 수 있다는 뜻이에요.
Linkerd의 destination 서비스가 "remote-discovery"를 사용해 페더레이션 서비스의 엔드포인트를 발견하므로, 평면 모드의 모든 요구 사항이 페더레이션 서비스에도 적용돼요: 클러스터는 한 클러스터의 포드가 다른 클러스터의 포드에 연결할 수 있는 평면 네트워크 위에 있어야 하고, 클러스터는 같은 트러스트 루트를 가져야 하며, 페더레이션 서비스에 연결하는 모든 클라이언트는 메시되어야 해요.
메타데이터 복사
페더레이션 서비스(-federated)는 레이블, 주석, 포트 정의를 포함한 메타데이터를 합집합된 서비스에서 상속해요. 이 서비스들 사이에서 메타데이터가 다르면, Linkerd 2.18부터 컨트롤러는 가장 오래된 Link에 연결된 서비스를 진실의 원본(source of truth)으로 사용해요.
토폴로지 인식 힌트와 관련되거나 mirror.linkerd.io로 접두사가 붙은 것을 제외한 모든 레이블과 주석이 복사돼요. 특정 메타데이터가 복사되지 않도록 하려면 Link의 CR에서 excludeAnnotations와 excludeLabels 아래에 나열하면 돼요 (역시 Linkerd 2.18부터 사용 가능). linkerd multicluster link-gen 명령을 사용할 때는 --exclude-annotations와 --exclude-labels 플래그를 적용해요. 로컬 서비스를 페더레이션 서비스에 추가하는 것을 관리하는 컨트롤러인 local-service-mirror 컴포넌트가 이 제외 사항을 존중하게 하려면 Helm 값 localServiceMirror.excludeAnnotations와 localServiceMirror.excludeLabels에 구성해요.