NetMaker High Availibility 구성을 시작했다.
NetMaker 는 몇 가지 컴포넌트로 구성되어 있다.
NetMaker : NetMaker 네트워크의 백엔드 역할. VPN Host에 대한 control plane 및 여러 백엔드 api 제공
NetMaker-ui : NetMaker 대시보드로 웹 프론트엔드 역할을 함.
CoreDNS : VPN 네트워크 내부에서 사용하는 DNS 서버
Database : NetMaker의 데이터를 저장하는 역할. sqlite, rqlite, postgresql 세개중에 하나를 고를 수 있다.
Message Broker : NetMaker 서버에서 각 Host들에게 명령을 실시간 전파하는 용도. mosquitto나 emqx 둘 중에 하나를 선택 가능하다.
LoadBalancer : 기본 예제는 Caddy로 되어있지만 Nginx나 HAProxy 등 아무 리버스 프록시 서버를 사용해도 무관하다.
NetMaker를 HA로 구성하려면 저런 컴포넌트에 대해 Redundancy을 구성해야 하는데 그 중에서도 가장 중요한 것은 Database이고 그 다음으로 중요한 것은 LoadBalancer이다.
사실 이 외에는 이중화 구성하지 않아도 크게 무관하다. 레플리카 중 하나가 통째로 날아가더라도 결국 Message Broker나 NetMaker, CoreDNS의 데이터는 모두 Database에서 필요할 때 마다 가져오기 때문이다.
데이터베이스는 뭘 사용할까 고민하다가 rqlite를 사용해보기로 결정했다. 물론 PostgreSQL이 훨씬 역사도 오래되고 HA 구성에 대한 자료나 사례가 훨씬 많았는데, NetMaker에서 저장하는 데이터의 양 자체가 그리 크지 않고, rqlite 오픈소스 레포를 검토해보니 프로젝트 자체가 클러스터링 기능을 특화시키는 방향으로 꽤 오래 개발되어왔기 때문에 rqlite를 선택했다.
rqlite를 간단하게 설명하자면 분산 기능이 갖춰진 sqlite이다. RAFT 알고리즘으로 클러스터링을 하여 노드간 데이터 정합성을 동기화한다.
오늘 모각코에서는 rqlite를 이용해 클러스터링을 진행해보았다. 다음 공식 문서를 참고했다.
https://rqlite.io/docs/clustering/automatic-clustering/
공식 문서와 더불어 rqlite Docker Image 문서도 참조하여 컨테이너에서 사용하는 환경 변수들을 파악했다.
https://hub.docker.com/r/rqlite/rqlite
하여 만들어진 클러스터 예제는 다음과 같다.
version: '3'
services:
rqlite1:
image: rqlite/rqlite:latest
restart: always
ports:
- 4001:4001
environment:
- NODE_ID=1
- HTTP_ADDR=0.0.0.0:4001
- RAFT_ADDR=0.0.0.0:4002
- HTTP_ADV_ADDR=rqlite1:4001
- RAFT_ADV_ADDR=rqlite1:4002
networks:
- rqlite-net
command:
[
"-bootstrap-expect",
"3",
"-join",
"rqlite1:4002,rqlite2:4004,rqlite3:4006",
"-raft-log-level",
"INFO"
]
rqlite2:
image: rqlite/rqlite:latest
restart: always
ports:
- 4003:4003
environment:
- NODE_ID=2
- HTTP_ADDR=0.0.0.0:4003
- RAFT_ADDR=0.0.0.0:4004
- HTTP_ADV_ADDR=rqlite2:4003
- RAFT_ADV_ADDR=rqlite2:4004
networks:
- rqlite-net
command:
[
"-bootstrap-expect",
"3",
"-join",
"rqlite1:4002,rqlite2:4004,rqlite3:4006",
"-raft-log-level",
"INFO"
]
rqlite3:
image: rqlite/rqlite:latest
restart: always
ports:
- 4005:4005
environment:
- NODE_ID=3
- HTTP_ADDR=0.0.0.0:4005
- RAFT_ADDR=0.0.0.0:4006
- HTTP_ADV_ADDR=rqlite3:4005
- RAFT_ADV_ADDR=rqlite3:4006
networks:
- rqlite-net
command:
[
"-bootstrap-expect",
"3",
"-join",
"rqlite1:4002,rqlite2:4004,rqlite3:4006",
"-raft-log-level",
"INFO"
]
networks:
rqlite-net:
driver: bridge
노드 개수는 최소 정족수(Quorum)가 확보되면서도 1개의 장애를 허용하는 3대로 구성했다.