여러 Kubernetes 클러스터에 단일 Consul 데이터센터 배포
여러 Kubernetes 클러스터에 단일 Consul 데이터센터 배포 (Deploy Single Consul Datacenter Across Multiple Kubernetes Clusters)
이 페이지에서는 서버는 한 클러스터에서 실행되고 나머지 클러스터에서는 Consul on Kubernetes 구성 요소만 실행되는 여러 Kubernetes 클러스터에 단일 Consul 데이터센터를 배포하는 방법을 설명해요. 예제에서는 두 개의 Kubernetes 클러스터를 사용하지만 이 접근 방식은 두 개 이상으로 확장될 수 있어요.
출처: 문서
본문
참고 (Note): 여러 Kubernetes 클러스터에서 Consul을 실행할 때 프로덕션 환경에서는 admin partitions을 사용하는 것을 권장합니다. 이 Consul Enterprise 기능을 사용하면 클러스터를 대규모로 관리할 때 리소스 충돌 없이 여러 테넌트를 수용할 수 있습니다. Admin partitions는 또한 비플랫 네트워크에서 Kubernetes 클러스터에서 Consul을 실행할 수 있게 합니다.
이 페이지에서는 단일 Consul 데이터센터를 여러 Kubernetes 클러스터에 배포하는 방법을 설명합니다. 서버는 한 클러스터에서 실행되고 나머지 클러스터에서는 Consul on Kubernetes 구성 요소만 실행됩니다. 이 예제는 두 개의 Kubernetes 클러스터를 사용하지만 이 접근 방식은 두 개 이상으로 확장될 수 있습니다.
요구 사항 (Requirements)
consul-k8sv1.0.x 이상 및 Consul 1.14.x 이상- Kubernetes 클러스터는 플랫 네트워크에서 LAN을 통해 통신할 수 있어야 합니다.
- 각 Kubernetes 클러스터의 Helm 릴리스 이름이 고유하거나 각 Kubernetes 클러스터의
global.name이 고유해야 동일한 접두사의 ACL 리소스 간 충돌을 방지할 수 있습니다.
설치 전 Helm 릴리스 이름 준비 (Prepare Helm release name ahead of installs)
Helm 릴리스 이름은 각 Kubernetes 클러스터에 대해 고유해야 합니다. Helm 차트는 만드는 ACL 리소스(토큰, auth method 등)의 접두사로 Helm 릴리스 이름을 사용합니다. Helm 릴리스 이름이 동일하거나 각 클러스터의 global.name이 동일하면 후속 Consul on Kubernetes 클러스터가 기존 ACL 리소스를 덮어쓰고 클러스터가 실패하게 만듭니다.
설치를 진행하기 전에 서버 및 클라이언트 설치 모두에 대해 Helm 릴리스 이름을 환경 변수로 준비하세요.
$ export HELM_RELEASE_SERVER=server
$ export HELM_RELEASE_CONSUL=consul
...
$ export HELM_RELEASE_CONSUL2=consul2
첫 번째 클러스터에 Consul 서버 배포 (Deploying Consul servers in the first cluster)
먼저 다음 예제 Helm 구성에 따라 Consul 서버로 첫 번째 클러스터를 배포하세요.
cluster1-values.yaml
global:
datacenter: dc1
tls:
enabled: true
enableAutoEncrypt: true
acls:
manageSystemACLs: true
gossipEncryption:
secretName: consul-gossip-encryption-key
secretKey: key
server:
exposeService:
enabled: true
type: NodePort
nodePort:
## all are random nodePorts and you can set your own
http: 30010
https: 30011
serf: 30012
rpc: 30013
grpc: 30014
ui:
service:
type: NodePort
참고로 이 배포는 gossip 암호화, 모든 구성 요소에 대한 TLS 및 ACL을 갖춘 보안 구성을 배포합니다. 또한 Consul 서비스 메시와 나중에 클러스터 간 서비스 연결을 확인하는 데 사용할 수 있는 CRD용 컨트롤러를 활성화합니다.
UI의 서비스 유형은 NodePort로 설정됩니다. 이는 변경될 가능성이 있는 서버의 Pod IP를 사용하지 않고 다른 클러스터에서 서버에 연결하는 데 필요합니다.
다른 서비스는 NodePort 서비스로 노출되고 무작위 포트 번호로 구성됩니다. 이 예제에서 grpc 포트는 30014로 설정되어 다른 클러스터에서 연결할 때 서비스가 gRPC를 사용하여 Consul 서버를 검색할 수 있게 합니다.
배포하려면 먼저 Gossip 암호화 키를 생성하고 Kubernetes 시크릿으로 저장하세요.
$ kubectl create secret generic consul-gossip-encryption-key --from-literal=key=$(consul keygen)
이제 Helm으로 Consul 클러스터를 설치하세요:
$ helm install ${HELM_RELEASE_SERVER} --values cluster1-values.yaml hashicorp/consul
설치가 완료되고 모든 구성 요소가 실행 중이며 준비되면 다음 정보를 추출하여(아래 명령 사용) 두 번째 Kubernetes 클러스터에 적용해야 합니다.
- 설치 중 생성된 CA 인증서
- 설치 중 생성된 ACL 부트스트랩 토큰
$ kubectl get secret ${HELM_RELEASE_SERVER}-consul-ca-cert ${HELM_RELEASE_SERVER}-consul-bootstrap-acl-token --output yaml > cluster1-credentials.yaml
두 번째 클러스터에 Consul Kubernetes 배포 (Deploying Consul Kubernetes in the second cluster)
참고 (Note): 여러 Kubernetes 클러스터가 Consul 데이터센터에 조인되는 경우 각 추가 Kubernetes 클러스터에 대해 다음 지침을 반복해야 합니다.
첫 번째 Consul 클러스터에 조인할 Consul 클라이언트가 배포될 두 번째 Kubernetes 클러스터로 전환하세요.
$ kubectl config use-context <K8S_CONTEXT_NAME>
먼저 첫 번째 클러스터에서 추출한 자격 증명을 두 번째 클러스터에 적용하세요:
$ kubectl apply --filename cluster1-credentials.yaml
두 번째 클러스터에 배포하려면 다음 예제 Helm 구성이 사용됩니다:
cluster2-values.yaml
global:
enabled: false
datacenter: dc1
acls:
manageSystemACLs: true
bootstrapToken:
secretName: cluster1-consul-bootstrap-acl-token
secretKey: token
tls:
enabled: true
caCert:
secretName: cluster1-consul-ca-cert
secretKey: tls.crt
externalServers:
enabled: true
# This should be any node IP of the first k8s cluster or the load balancer IP if using LoadBalancer service type for the UI.
hosts: ["10.0.0.4"]
# The node port of the UI's NodePort service or the load balancer port.
httpsPort: 31557
# Matches the gRPC port of the Consul servers in the first cluster.
grpcPort: 30014
tlsServerName: server.dc1.consul
# The address of the kube API server of this Kubernetes cluster
k8sAuthMethodHost: https://kubernetes.example.com:443
connectInject:
enabled: true
ACL 및 TLS 구성에서 첫 번째 클러스터에서 추출하여 적용한 시크릿에 대한 참조를 확인하세요.
externalServers.hosts 및 externalServers.httpsPort는 첫 번째 클러스터에 배포된 UI의 NodePort 서비스의 IP와 포트를 참조합니다. externalServers.hosts를 첫 번째 클러스터의 노드 IP(임의)로 설정하세요. 이는 kubectl get nodes --output wide를 실행하여 확인할 수 있습니다. externalServers.httpsPort를 cluster1-consul-ui 서비스의 nodePort로 설정하세요. 예제에서 포트는 31557입니다.
$ kubectl get service cluster1-consul-ui --context cluster1
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
cluster1-consul-ui NodePort 10.0.240.80 <none> 443:31557/TCP 40h
grpcPort: 30014 구성은 첫 번째 클러스터의 NodePort 구성에 지정된 gRPC 포트 번호를 참조합니다.
externalServer.tlsServerName을 server.dc1.consul로 설정하세요. 이는 Consul 서버의 인증서에 있는 DNS SAN(주체 대체 이름)입니다. Consul 서버에 대한 연결이 노드 IP를 사용하지만 해당 IP가 서버의 인증서에 없기 때문에 필요합니다. TLS 핸드셰이크 중 호스트 이름 검증이 성공하도록 인증서에 있는 DNS 이름으로 TLS 서버 이름을 설정하세요.
다음으로 externalServers.k8sAuthMethodHost를 두 번째 Kubernetes API 서버의 주소로 설정하세요. 이는 첫 번째 클러스터에서 도달할 수 있는 주소여야 하므로 각 Kubernetes 클러스터에서 사용할 수 있는 내부 DNS일 수 없습니다. Consul은 두 번째 클러스터에서 consul login이 Kubernates auth method로 작동하도록 하기 위해 필요합니다. 더 구체적으로, Consul 서버는 consul login이 호출될 때마다 Kubernetes 서비스 계정의 검증을 수행해야 하며, 두 번째 클러스터의 서비스 계정을 검증하려면 해당 클러스터의 Kubernetes API에 도달해야 합니다. 가장 쉬운 방법은 kubectl config view를 실행하고 두 번째 클러스터의 cluster.server 값을 가져오는 것입니다.
이제 두 번째 클러스터의 설치를 진행하세요.
$ helm install ${HELM_RELEASE_CONSUL} --values cluster2-values.yaml hashicorp/consul
Consul 서비스 메시가 작동하는지 확인 (Verifying the Consul Service Mesh works)
투명 프록시가 활성화되면 한 Kubernetes 클러스터의 서비스가 다른 Kubernetes 클러스터의 서비스와 통신해야 하는 경우 "consul.hashicorp.com/connect-service-upstreams" 주석을 통해 명시적 업스트림을 구성해야 합니다.
이제 여러 k8s 클러스터에 걸쳐 있는 Consul 클러스터가 실행 중이므로 별도의 k8s 클러스터에 두 개의 서비스를 배포하고 서로 연결할 수 있는지 확인하세요.
먼저 첫 번째 클러스터에 static-server 서비스를 배포하세요:
static-server.yaml
---
apiVersion: consul.hashicorp.com/v1alpha1
kind: ServiceIntentions
metadata:
name: static-server
spec:
destination:
name: static-server
sources:
- name: static-client
action: allow
---
apiVersion: v1
kind: Service
metadata:
name: static-server
spec:
type: ClusterIP
selector:
app: static-server
ports:
- protocol: TCP
port: 80
targetPort: 8080
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: static-server
---
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:
"consul.hashicorp.com/connect-inject": "true"
spec:
containers:
- name: static-server
image: hashicorp/http-echo:latest
args:
- -text="hello world"
- -listen=:8080
ports:
- containerPort: 8080
name: http
serviceAccountName: static-server
서비스가 서로 통신할 수 있도록 Service 의도를 정의하는 것이 필요합니다.
다음으로 두 번째 클러스터에 다음 구성으로 static-client를 배포하세요:
static-client.yaml
apiVersion: v1
kind: Service
metadata:
name: static-client
spec:
selector:
app: static-client
ports:
- port: 80
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: static-client
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: static-client
spec:
replicas: 1
selector:
matchLabels:
app: static-client
template:
metadata:
name: static-client
labels:
app: static-client
annotations:
"consul.hashicorp.com/connect-inject": "true"
"consul.hashicorp.com/connect-service-upstreams": "static-server:1234"
spec:
containers:
- name: static-client
image: curlimages/curl:latest
command: [ "/bin/sh", "-c", "--" ]
args: [ "while true; do sleep 30; done;" ]
serviceAccountName: static-client
두 서비스가 모두 실행 중이면 static-client에서 static-server에 연결해 보세요:
$ kubectl exec deploy/static-client -- curl --silent localhost:1234
"hello world"
성공적인 설치라면 위 curl 명령 출력에 hello world가 반환됩니다.