메뉴

문서정보

목차

Consule에 대해서 간단히 살펴봤으니, 클러스터를 구성해보려 한다.

테스트 환경

노드 이름은 consul01, consul02, consul03 으로 했다. 노드 구성은 아래와 같다.

 Consul cluster 구성

각 노드의 /etc/hosts 파일을 아래와 같이 수정했다.
# cat /etc/hosts
127.0.0.1	localhost.localdomain	localhost
127.0.1.1	consul01	
::1		localhost6.localdomain6	localhost6

192.168.122.150 consul01.joinc.co.kr consul01
192.168.122.151 consul02.joinc.co.kr consul02
192.168.122.152 consul03.joinc.co.kr consul03

consul 애플리케이션을 위한 consul 유저와 작업디렉토리를 만든다.
# adduser consul
# mkdir /var/lib/consul
# chown consul.consul /var/lib/consul

consul 설치

Download Consul페이지에서 운영체제별로 다운로드 할 수 있다. 압축을 풀면 consul 단일 파일이 나온다. 이 파일을 /usr/bin/local에 복사했다. 2019년 9월 15일 현재 최신버전은 1.6.0이다.
# consul version
Consul v1.6.0
Protocol 2 spoken by default, understands 2 to 3 (agent will automatically use protocol >2 when speaking to compatible agents)

Consul 아키텍처

아래는 높은 수준에서의 consul 아키텍처다. 핵심 키워드만 간단히 살펴보자.

 consul 아키텍처

GOSSIP : Gossip Protocol - wikipedia문서를 참고하면 된다. 느슨하게 연결된 분산 네트워크에서 정보를 전파하는 프로토콜이다. 사람으로 구성된 어떤 집단에서 누군가에 대한 험담이 퍼지는 매커니즘과 크게 다르지 않다. 특정인이 자기가 좋아하는 동료에게 정보를 전달하면, 그 동료는 다시 자신의 주변 동료에게 정보를 전달 할 것이다. 일정 시간이 지나면 회사안에 모든 직원들이 왜 특정 직원이 이직을 했는지 알게 될 것이다. 여기에 걸리는 시간은 직원 수에 대한 로그함수다. 컴퓨터 노드가 정보를 전파하는 것도 동일한 방식이다. Gossip는 분산된 네트워크에 참여하고 있는 노드들간의 정보전파를 위해서 주로 사용한다. 노드들간에 주고 받는 정보가 항상 옳다라고 가정 할 수는 없기 때문에, 올바른 정보를 가려내는 것이 매우 중요하다. 서로를 신뢰하지 않는 노드들의 네트워크인 블럭체인, 토렌트등에서 중요하게 사용하는 프로토콜이다.

Consul는 LAN과 WAN 두개의 Gossip 프로토콜을 사용한다. 분산 시스템에서는 장애를 감지하는게 중요한데, 하나의 서버에서 장애를 감지하도록 하지 않고 분산된 노드들이 장애감지를 수행한다. 이로써 더 높은 신뢰도를 가지는 장애감지 시스템을 구성 할 수 있다.

Consul server는 하나 이상의 리더와 (최소)두 개 이상의 팔로워(Follower)로 구성된다. 리더 서버가 실패한다면, 리더 선출(elect)알고리즘을 통해서 팔로워 중 하나가 리더가 된다. 과반이상을 넘는 서버가 실패하기 전에는 서비스를 계속 할 수 있는 견고한 서비스를 만들 수 있다. 리더와 팔로워는 모든 정보를 공유한다. 리더가 죽더라도 일관성 있는 정보를 유지 할 수 있다.

Consule 은 WAN Gossip을 이용한 멀티 데이터센터(Multi Datacenter)를 지원한다. 각 데이터 센터는 WAN Gossip 프로토콜을 통해서 느슨하게 연결되며, 하나의 데이터센터에 문제가 생기더라도 전체 Consul의 가용성에 문제가 생기지 않도록 할 수 있다.

consul 포트

consul이 사용하는 포트는 아래와 같다.
사용 기본포트
DNS: The DNS Server(TCP and UDP) 8600
HTTP: HTTP API (TCP only) 8500
HTTPS: HTTs API 8501
gRPC: gRPC API 8502
LAN Serf: The Serf LAN port (TCP and UDP) 8301
Wan Serf : The Serf WAN port (TCP and UDP) 8302
Server: Server RPC address (TCP only) 8300
Sidecar Proxy Min 21000
Sidecar Proxy Max 21255
8600은 DNS 서비스를 위해서 사용한다. Service Discovery 목적으로 주로 사용한다.

Serf는 HashCorp의 "Decentralized Cluster Membership, Failure Detection, and Orchestration" 라이브러리다. gossip protocol을 이용해서 메시지를 클러스터에 브로드캐스트해서 메시지를 주고 받는 것으로 멤버쉽을 유지한다. 자세한 내용은 Gossip Protocol - Serf by HashiCorp문서를 참고하자.

consul 노드 설정

consul 설정파일 /etc/consul.d/config.json을 만든다.
{
    "bootstrap_expect": 3,
    "client_addr": "0.0.0.0",
    "bind_addr": "192.168.122.150",
    "datacenter": "KE-DC",
    "data_dir": "/var/lib/consul",
    "domain": "consul",
    "enable_script_checks": true,
    "dns_config": {
        "enable_truncate": true,
        "only_passing": true
    },
    "enable_syslog": true,
    "encrypt": "op+bPRe2ZDynNu2m7V8o1BdFp0L1swlvxzDqOiRWwP0=",
    "leave_on_terminate": true,
    "log_level": "INFO",
    "rejoin_after_leave": true,
    "retry_join": [
        "consul01",
        "consul02",
        "consul03"
    ],
    "server": true,
    "start_join": [
        "consul01",
        "consul02",
        "consul03"
    ],
    "ui": true
}
datacenter는 consule Agent가 실행될 데이터센터의 이름을 설정한다. 클러스터 단위라고 생각하면 된다. datacenter는 같은 LAN에 있어야 한다.

start_joinretry_join에 클러스터에 참여할 node 목록을 설정한다. encrypt는 해당 클러스터에 참여할 노드들이 공통으로 가져야 할 암호화 키로 사용한다. consul keyjen명령으로 만들 수 있다. 이 값은 모든 노드들이 동일하게 가지고 있어야 한다. 결과적으로 bind_addr만 다르게 해서 consul02, consul03에 복사하면 된다.

/etc/systemd/system/consul.service파일을 만든다.
[Unit]
Description=Consul Service Discovery Agent
Documentation=https://www.consul.io/
After=network-online.target
Wants=network-online.target

[Service]
Type=simple
User=consul
Group=consul
ExecStart=/usr/local/bin/consul agent \
        -node=consul01 \
        -config-dir=/etc/consul.d

ExecReload=/bin/kill -HUP $MAINPID
KillSignal=SIGINT
TimeoutStopSec=5
Restart=on-failure
SyslogIdentifier=consul

[Install]
WantedBy=multi-user.target
-node=consul01만 수정해서 consul02, consul03에 복사하면 된다.

설정이 끝났으면 consule01, 02, 03에서 consul을 실행한다.
# systemctl daemon-reload
# systemctl start consul

consul 멤버 확인

consul members 명령으로 멤버들을 확인 할 수 있다.
root@consul01:/var/lib/consul/serf# consul members
Node      Address               Status  Type    Build  Protocol  DC     Segment
consul01  192.168.122.150:8301  alive   server  1.6.0  2         ke-dc  <all>
consul02  192.168.122.151:8301  alive   server  1.6.0  2         ke-dc  <all>
consul03  192.168.122.152:8301  alive   server  1.6.0  2         ke-dc  <all>

HTTP API를 이용해서 리더(leader)노드를 확인해보자.
# curl localhost:8500/v1/status/leader
"192.168.122.150:8300"

K/V 읽고쓰기

consul kv put과 get을 이용해서 데이터를 읽고 쓰는 테스트를 해봤다.
# consul kv put redis/config/connections 5
Success! Data written to: redis/config/connections

# consul kv get redis/config/connections
5
recurse 플래그를 이용해서 하위 디렉토리의 모든 키를 조회할 수 있다.
# consul kv get -recurse redis/config
redis/config/connections:5
redis/config/cpu:128
redis/config/memory:512

Watch

Watch는 관심있는 데이터(노드의 목록, KV pair, 헬스체크 등)의 업데이트를 모니터링 하기 위해서 사용하는 방법이다. 업데이트가 감지되면 외부 핸들러를 호출 한다. 실행 파일과 HTTP 엔드포인트를 핸들러로 사용 할 수 있다. 예를들어 헬스체크의 상태가 변할 경우(애플리케이션이 내려가거나 새로 올라왔을 때) 이 내용을 외부 시스템에 알릴 수 있다.

핸들러

watch 설정을 이용해서 모니터링할 데이터를 설정할 수 있다. 모니터링할 데이터가 변경되면 설정한 핸들러가 호출된다. 핸들러는 외부 프로그램 혹은 HTTP 엔드포인트를 호출할 수 있으며, 변경된 정보를 JSON 형식으로 전송 한다.

외부 명령 실행

핸들러는 표준입력(stdin)으로 JSON 정보를 읽어서 처리한다. 처리 결과는 표준출력(stdout)으로 기록된다. 아래는 핸들러 설정예제다.
{
  "type": "key",
  "key": "foo/bar/baz",
  "handler_type": "script",
  "args": ["/usr/bin/my-service-handler.sh", "-redis"]
}

HTTP endpoint

업데이트가 발생 할 때 HTTP 요청을 보낼 수 있다. JSON 정보는 요청 페이로드(body)로 전송된다. HTTP X-Consul-Index 헤더에 Consul 색인정보가 설정된다.
{
  "type": "key",
  "key": "foo/bar/baz",
  "handler_type": "http",
  "http_handler_config": {
    "path":"https://localhost:8000/watch",
    "method": "POST",
    "header": {"x-foo":["bar", "baz"]},
    "timeout": "10s",
    "tls_skip_verify": false
  }
}

Watch Types

Consul은 7가지의 watch 타입을 제공한다.

KV Watch Test

consul watch 명령을 이용해서 watch를 수행 할 수 있다. "redis/config/connections"에 대해서 watch를 해보자.
# consul watch -type=key -key=redis/config/connections ./my-key-handler.sh 
my-key-handler.sh의 내용은 아래와 같다. 딱 테스트만 할 수 있는 간단한 프로그램이다.
#!/bin/bash
while read line
do
    echo $line >> dump.txt
done
consul put을 이용해서 redis/config/connections의 값을 7로 설정하면, my-key-handler.sh가 실행되는 걸 확인 할 수 있다.
# consul watch -type=key -key=redis/config/connections ./my-key-handler.sh 
{"Key":"redis/config/connections","CreateIndex":1191,"ModifyIndex":2826,"LockIndex":0,"Flags":0,"Value":"Nw==","Session":""}
Value는 base64 인코딩된 값이다. 디코딩하면 7이다.

정리

원래는 Watch 애플리케이션까지 개발해보려고 했는데, 내용이 너무 길어질 것 같아서 분리하기로 했다. 그래서 Watch는 소개 정도만 하고 실제 응용은 별도 문서에서 테스트해보려 한다. 만들 프로그램은 "아주 간단한 분산커널"이다.