본문 바로가기
Service Mesh/Consul

Consul 가용 영역 우선순위 라우팅(locality-aware routing)

by wlsdn3004 2024. 2. 7.
728x90
반응형

 

일반적으로 Consul은 서비스 간 통신할 때 아래와 같이 동작한다.

위 방식은 사용 가능한 모든 서비스에 트래픽을 분산시킬 수 있기 때문에 대부분의 환경에서는 문제가 되지 않는다.

그러나 어떤 상황에서는 서비스 간 호출 대기 시간을 줄이거나, 가용 영역 간 데이터 전송 비용을 줄이기 위해 트래픽이 동일한 가용 영역 내에 유지되도록 하고 싶을 수 있다. 

 

이 문제를 해결하기 위해 Consul 1.17 버전에서는 locality-aware routing에 대한 기능을 도입했다.

 

locality-aware routing 기능을 적용하면 아래와 같이 동작하게 된다.

서비스 호출 시 트래픽을 같은 영역 내에 유지함으로써 서비스 간 대시 시간을 줄여 서비스 성능을 향상하고, 트래픽 비용을 절감할 수 있다.

 

같은 영역 내 서비스에서 장애가 발생할 경우 아래와 같이 Service Mesh는 자동으로 인접 영역의 정상 서비스로 장애조치 되어 데이터 센터 내 가용성을 보장한다.

 

본 글에서는 위 시나리오 기반 구성하는 실습을 다룬다.

 

Information Panel

참고

해당 기능은 Consul Enterprise에서 사용할 수 있다.

구성 환경

  • Amazon EKS 클러스터 v1.27.7
  • Consul v1.17-ent
  • Consul Enterprise license
  • Consul Helm Chart 버전 1.3.1
  • Helm Cli v3.8.2

 

1. Consul 구성


Consul Helm repo를 등록한다.

$ helm repo add hashicorp https://helm.releases.hashicorp.com
$ helm repo update

 

Consul 라이센스를 적용한다.

# license.yaml
apiVersion: v1
data:
  key: {license key base64 incoding}
kind: Secret
metadata:
  name: license
  namespace: consul

 

위 라이센스 파일을 적용한다.

$ kubectl apply -f license.yaml

 

Consul의 Helm Chart values 파일을 작성한다.

# consul-values.yaml
global:
  datacenter: dc2
  peering:
    enabled: true 
  enterpriseLicense:
    secretName: license
    secretKey: key
  adminPartitions:
    enabled: true
    name: "default"
  enableConsulNamespaces: true
  image: hashicorp/consul-enterprise:1.17.1-ent
  metrics:
    enabled: true
    enableAgentMetrics: true
    agentMetricsRetentionTime: '1m'
  tls:
    httpsOnly: false
    enabled: true
    enableAutoEncrypt: true
    verify: false
  acls:
    manageSystemACLs: true
  gossipEncryption:
    autoGenerate: true
server:
  replicas: 1
  exposeGossipAndRPCPorts: true
dns:
  enableRedirection: true
  enabled: true
connectInject:
  enabled: true
  consulNamespaces:
    mirroringK8S: true
controller:
  enabled: true
ingressGateways:
  enabled: true
  defaults:
    replicas: 1
terminatingGateways:
  enabled: true
  defaults:
    replicas: 1
meshGateway:
  enabled: true
  replicas: 1

 

위에서 작성한 "consul-values.yaml" 파일로 Consul을 설치한다.

$ helm upgrade -i -n consul consul -f consul-values.yaml hashicorp/consul --version 1.3.1 --create-namespace

 

proxydefaults 파일을 작성한다.

# proxydefaults.yaml
apiVersion: consul.hashicorp.com/v1alpha1
kind: ProxyDefaults
metadata:
  name: global
spec:
  meshGateway:
    mode: local

 

proxydefaults를 적용한다.

$ kubectl apply -f proxydefaults.yaml

 

static-client 서비스를 배포를 위해 yaml파일을 작성한다.

# static-client.yaml
apiVersion: consul.hashicorp.com/v1alpha1
kind: ServiceDefaults
metadata:
  name: static-client
spec:
  protocol: 'http'
---
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'
    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 서비스를 배포한다.

$ kubectl apply -f static-client.yaml

 

배포된 static-client Pod가 배포된 노드를 확인한다.

$ kubectl get po static-client-7bbffb9f6d-lt6f4  -o wide 
NAME                             READY   STATUS    RESTARTS   AGE    IP           NODE                                            NOMINATED NODE   READINESS GATES
static-client-7bbffb9f6d-lt6f4   2/2     Running   0          3h6m   10.10.2.64   ip-10-10-2-16.ap-northeast-2.compute.internal   <none>           <none>

 

AWS의 각 노드의 zone을 확인한다.

  • 해당 글에서 static-client 서비스는 "ap-northeast-2b"에 위치해 있다.
$ kubectl get nodes -o jsonpath='{range .items[*]}[node name] {.metadata.name}{"\t"} [region] {.metadata.labels.topology\.kubernetes\.io/region}{"\t"} [zone] {.metadata.labels.topology\.kubernetes\.io/zone}{"\n"}{end}'
[node name] ip-10-10-1-121.ap-northeast-2.compute.internal       [region] ap-northeast-2         [zone] ap-northeast-2a
[node name] ip-10-10-2-16.ap-northeast-2.compute.internal        [region] ap-northeast-2         [zone] ap-northeast-2b
[node name] ip-10-10-3-89.ap-northeast-2.compute.internal        [region] ap-northeast-2         [zone] ap-northeast-2c

 

각 노드에 Pod를 분산하여 배포하기 위해 아래와 같이 static-server를 배포한다.

# static-server.yaml
apiVersion: consul.hashicorp.com/v1alpha1
kind: ServiceDefaults
metadata:
  name: static-server
spec:
  protocol: 'http'
---
apiVersion: v1
kind: Service
metadata:
  name: static-server
spec:
  selector:
    app: static-server
  ports:
    - protocol: TCP
      port: 8080
      targetPort: 8080
---
apiVersion: v1
kind: ServiceAccount
metadata:
  name: static-server
---
apiVersion: v1
kind: Pod
metadata:
  name: static-server1
  labels:
    app: static-server
  annotations:
    consul.hashicorp.com/connect-inject: "true"
spec:
  containers:
    - name: static-server
      image: hashicorp/http-echo:latest
      args:
        - -text="i'm server1"
        - -listen=:8080
      ports:
        - containerPort: 8080
          name: http
  serviceAccountName: static-server
  nodeName: ip-10-10-3-89.ap-northeast-2.compute.internal
---
apiVersion: v1
kind: Pod
metadata:
  name: static-server2
  labels:
    app: static-server
  annotations:
    consul.hashicorp.com/connect-inject: "true"
spec:
  containers:
    - name: static-server
      image: hashicorp/http-echo:latest
      args:
        - -text="i'm server2"
        - -listen=:8080
      ports:
        - containerPort: 8080
          name: http
  serviceAccountName: static-server
  nodeName: ip-10-10-2-16.ap-northeast-2.compute.internal
---
apiVersion: v1
kind: Pod
metadata:
  name: static-server3
  labels:
    app: static-server
  annotations:
    consul.hashicorp.com/connect-inject: "true"
spec:
  containers:
    - name: static-server
      image: hashicorp/http-echo:latest
      args:
        - -text="i'm server3"
        - -listen=:8080
      ports:
        - containerPort: 8080
          name: http
  serviceAccountName: static-server
  nodeName: ip-10-10-1-121.ap-northeast-2.compute.internal

 

세 개의 static-server Pod가 배포된 노드를 확인한다.
  • static-client Pod와 같은 위치에 있는 Pod는 static-server2이다.
$ kubectl get po -o wide static-server1 static-server2 static-server3
NAME             READY   STATUS    RESTARTS   AGE   IP            NODE                                             NOMINATED NODE   READINESS GATES
static-server1   2/2     Running   0          27s   10.10.3.228   ip-10-10-3-89.ap-northeast-2.compute.internal    <none>           <none>
static-server2   2/2     Running   0          27s   10.10.2.41    ip-10-10-2-16.ap-northeast-2.compute.internal    <none>           <none>
static-server3   2/2     Running   0          27s   10.10.1.19    ip-10-10-1-121.ap-northeast-2.compute.internal   <none>           <none>

 

서비스 간 트래픽 허용을 위해 serviceintention을 설정한다.

# intentions.yaml
apiVersion: consul.hashicorp.com/v1alpha1
kind: ServiceIntentions
metadata:
  name: static-server-intention
spec:
  destination:
    name: static-server
  sources:
   - name: "*"
     action: deny
   - name: static-client
     action: allow

 

static-client 서비스에 접근하여 static-server로 호출한다.

$ kubectl exec -it deploy/static-client -c static-client -- /bin/sh

 

아직 locality-aware routing 기능을 적용하지 않았기 때문에  static-server 서비스에 대해 분산된 응답을 받는 걸 확인할 수 있다.

 

 

2. locality-aware routing 적용 및 테스트


locality-aware routing기능 적용을 위해 아래와 같이 proxydefaults 파일을 작성한다.

# proxydefaults.yaml
apiVersion: consul.hashicorp.com/v1alpha1
kind: ProxyDefaults
metadata:
  name: global
spec:
  meshGateway:
    mode: local
# 아래 추가    
  prioritizeByLocality:
    mode: failover

 

작성한 proxydefaults 파일을 적용한다.

$ kubectl apply -f proxydefaults.yaml

 

static-client 서비스에 접근하여 static-server로 호출한다.

$ kubectl exec -it deploy/static-client -c static-client -- /bin/sh

 

같은 zone(ap-northeast-2b)에 있는 static-server2 Pod를 호출하는 걸 확인할 수 있다.

 
같은 zone에 있는 static-server2 Pod를 삭제한 뒤 다시 호출하여 확인해 보자.
$ kubectl delete po static-server2

 

static-server2 Pod가 삭제된 후 static-server1, static-server3로 트래픽을 분산시키는 걸 확인할 수 있다.

 

반응형

댓글