포드-투-포드 멀티클러스터 통신
기본적으로 Linkerd의 멀티클러스터 확장은 모든 교차-클러스터 트래픽을 대상 클러스터의 게이트웨이를 통해 보내요. 하지만 여러 Kubernetes 클러스터가 한 클러스터의 포드가 다른 클러스터의 포드와 직접 통신할 수 있는 평면 네트워크에 배포된 경우, Linkerd는 멀티클러스터 서비스를 포드-투-포드 모드로 내보낼 수 있어요. 이 모드에서는 교차-클러스터 트래픽이 게이트웨이를 거치지 않고 대상 포드로 직접 가요. 이 가이드에서는 포드-투-포드 모드로 멀티클러스터 서비스를 내보내고, 인가 정책을 설정하고, 트래픽을 모니터링하는 방법을 살펴볼게요.
본문
기본적으로 Linkerd의 멀티클러스터 확장은 모든 교차-클러스터 트래픽을 대상 클러스터의 게이트웨이를 통해 보내요. 하지만 여러 Kubernetes 클러스터가 한 클러스터의 포드가 다른 클러스터의 포드와 직접 통신할 수 있는 평면 네트워크에 배포된 경우, Linkerd는 멀티클러스터 서비스를 포드-투-포드 모드로 내보낼 수 있어요. 이때 교차-클러스터 트래픽은 게이트웨이를 거치지 않고 대상 포드로 직접 가요.
이 가이드는 포드-투-포드 모드로 멀티클러스터 서비스를 내보내고, 인가 정책을 설정하고, 트래픽을 모니터링하는 방법을 안내할게요.
사전 준비
- 두 개의 클러스터. 이 가이드에서는 동쪽(east)과 서쪽(west)이라고 부를게요.
- 클러스터는 평면 네트워크 위에 있어야 해요. 즉 한 클러스터의 포드는 다른 클러스터의 포드에 주소를 지정하고 연결할 수 있어야 해요.
- 각 클러스터는 kubectl 컨텍스트로 구성되어야 해요. 이 가이드를 따라가기 쉽도록 east와 west라는 이름을 쓰는 걸 권장해요. kubectl로 컨텍스트 이름을 바꾸는 것은 쉬우니, 계속 이 이름으로 두어야 한다고 느낄 필요는 없어요.
1단계: Linkerd와 Linkerd-Viz 설치
먼저 멀티클러스터 가이드에 설명된 대로 두 클러스터에 Linkerd와 Linkerd-Viz를 설치해요. 두 클러스터가 공통 트러스트 앵커를 공유하도록 주의해 주세요.
2단계: Linkerd-Multicluster 설치
두 클러스터에 멀티클러스터 확장을 설치할게요. 직접 포드-투-포드 통신을 사용할 것이므로 게이트웨이 없이 설치할 수 있어요. 서비스가 west 클러스터에서 미러링되므로 거기에 컨트롤러를 만들어요.
`> linkerd --context east multicluster install --gateway=false | kubectl --context east apply -f -
> linkerd --context east check
> linkerd --context west multicluster install --gateway=false \
> --set controllers[0].link.ref.name=east |
> kubectl --context west apply -f -
> linkerd --context west check
`
3단계: 클러스터 연결
linkerd multilcuster link-gen 명령으로 두 클러스터를 연결해요. 게이트웨이가 필요 없는 Link를 만들기 위해 --gateway=false 플래그를 전달한다는 점만 제외하면 일반적인 Multicluster 가이드와 정확히 같아요.
`> linkerd --context east multicluster link-gen --cluster-name=target --gateway=false | kubectl --context west apply -f -
`
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\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
`
그런 다음 소스 클러스터에 해당 네임스페이스를 만들어요.
`> kubectl --context west create ns mc-demo
`
그리고 대상 서비스에 레이블을 달아 내보내요. 보통의 mirror.linkerd.io/exported=true 레이블 대신 mirror.linkerd.io/exported=remote-discovery를 설정하는 것에 주목하세요. 이는 서비스를 원격 디스커버리 모드로 내보내라는 뜻이며, 게이트웨이를 건너뛰고 서로 다른 클러스터의 포드가 직접 통신할 수 있게 해 줘요.
`> kubectl --context east -n mc-demo label svc/bb mirror.linkerd.io/exported=remote-discovery
`
소스 클러스터에 미러 서비스가 즉시 생성되는 걸 볼 수 있어요.
`> kubectl --context west -n mc-demo get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
bb-target ClusterIP 10.43.56.245 8080/TCP 114s
`
5단계: 트래픽 보내기!
소스 클러스터의 로드 생성기로 slow-cooker를 사용해 대상 클러스터의 bb 서비스로 보낼게요. slow-cooker가 bb-target 미러 서비스로 보내도록 구성하는 것에 주목하세요.
`> cat ---
apiVersion: v1
kind: ServiceAccount
metadata:
name: slow-cooker
namespace: mc-demo
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: slow-cooker
namespace: mc-demo
spec:
replicas: 1
selector:
matchLabels:
app: slow-cooker
template:
metadata:
labels:
app: slow-cooker
spec:
serviceAccountName: slow-cooker
containers:
- args:
- -c
- |
sleep 5 # wait for pods to start
/slow_cooker/slow_cooker --qps 10 http://bb-target:8080
command:
- /bin/sh
image: buoyantio/slow_cooker:1.3.0
name: slow-cooker
EOF
`
이제 대상 클러스터에서 bb가 초당 약 10개 요청을 성공적으로 받는 것을 볼 수 있을 거예요.
`> linkerd --context east viz stat -n mc-demo deploy
NAME MESHED SUCCESS RPS LATENCY_P50 LATENCY_P95 LATENCY_P99 TCP_CONN
bb 1/1 100.00% 10.3rps 1ms 1ms 1ms 3
`
6단계: 인가 정책
직접 포드-투-포드 통신의 한 가지 장점은 서버가 특정 클라이언트만 연결하도록 허용하는 인가 정책을 사용할 수 있다는 거예요. 게이트웨이를 사용할 때는 클라이언트 identity가 게이트웨이를 통과하면서 사라지기 때문에 이는 불가능해요. 인가 정책이 어떻게 동작하는지 자세한 배경은 Restricting Access To Services 문서를 참고해 주세요.
slow-cooker 서비스 계정만 bb에 연결하도록 허용하는 인가 정책을 만들어 그걸 증명해 볼게요.
`> kubectl --context east apply -f - ---
apiVersion: policy.linkerd.io/v1beta1
kind: Server
metadata:
namespace: mc-demo
name: bb
spec:
podSelector:
matchLabels:
app: bb
port: 8080
---
apiVersion: policy.linkerd.io/v1alpha1
kind: AuthorizationPolicy
metadata:
namespace: mc-demo
name: bb-authz
spec:
targetRef:
group: policy.linkerd.io
kind: Server
name: bb
requiredAuthenticationRefs:
- group: policy.linkerd.io
kind: MeshTLSAuthentication
name: bb-good
---
apiVersion: policy.linkerd.io/v1alpha1
kind: MeshTLSAuthentication
metadata:
namespace: mc-demo
name: bb-good
spec:
identities:
- 'slow-cooker.mc-demo.serviceaccount.identity.linkerd.cluster.local'
EOF
`
정책이 적용된 상태에서 bb가 slow-cooker의 모든 트래픽을 허용하는 것을 볼 수 있어요.
`> linkerd --context east viz authz -n mc-demo deploy
ROUTE SERVER AUTHORIZATION UNAUTHORIZED SUCCESS RPS LATENCY_P50 LATENCY_P95 LATENCY_P99
default bb authorizationpolicy/bb-authz 0.0rps 100.00% 10.0rps 1ms 1ms 1ms
default default:all-unauthenticated default/all-unauthenticated 0.0rps 100.00% 0.1rps 1ms 1ms 1ms
probe default:all-unauthenticated default/probe 0.0rps 100.00% 0.2rps 1ms 1ms 1ms
`
slow-cooker가 bb로 보낼 수 있는 유일한 서비스 계정임을 보여주기 위해, 서로 다른 서비스 계정을 사용하며 거부되어야 하는 두 번째 로드 생성기 slow-cooker-evil을 만들게요.
`> cat ---
apiVersion: v1
kind: ServiceAccount
metadata:
name: slow-cooker-evil
namespace: mc-demo
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: slow-cooker-evil
namespace: mc-demo
spec:
replicas: 1
selector:
matchLabels:
app: slow-cooker-evil
template:
metadata:
labels:
app: slow-cooker-evil
spec:
serviceAccountName: slow-cooker-evil
containers:
- args:
- -c
- |
sleep 5 # wait for pods to start
/slow_cooker/slow_cooker --qps 10 http://bb-target:8080
command:
- /bin/sh
image: buoyantio/slow_cooker:1.3.0
name: slow-cooker
EOF
`
악성 버전의 slow-cooker가 잠시 실행된 후, bb가 10rps를 받아들이고(slow-cooker에서) 10rps를 거부하는(slow-cooker-evil에서) 것을 볼 수 있어요.
`> linkerd --context east viz authz -n mc-demo deploy
ROUTE SERVER AUTHORIZATION UNAUTHORIZED SUCCESS RPS LATENCY_P50 LATENCY_P95 LATENCY_P99
default bb 10.0rps 0.00% 0.0rps 0ms 0ms 0ms
default bb authorizationpolicy/bb-authz 0.0rps 100.00% 10.0rps 1ms 1ms 1ms
default default:all-unauthenticated default/all-unauthenticated 0.0rps 100.00% 0.1rps 1ms 1ms 1ms
probe default:all-unauthenticated default/probe 0.0rps 100.00% 0.2rps 1ms 1ms 1ms
`