Computer >> 컴퓨터 >  >> 소프트웨어 >> 가상 머신

Docker Engine 스웜 모드 완벽 입문: 클러스터링 튜토리얼

'스웜(Swarm)'은 펑크 록 밴드 이름처럼 들리지만, 사실 Docker의 오케스트레이션 기능을 크게 발전시킨 완전히 새로운 메커니즘입니다. 간단히 설명하자면, 예전 버전의 Docker를 사용할 때는 클러스터를 구성하기 위해 Swarm을 별도로 수동 설치해야 했습니다. 하지만 버전 1.12부터는 Docker 엔진에 네이티브 스웜 기능이 기본 탑재되어, 복잡한 설정 없이도 매끄럽게 클러스터를 구축할 수 있게 되었습니다. 바로 이 변화가 이 글의 출발점입니다.

이 튜토리얼에서는 Docker가 오케스트레이션 분야에서 어떤 일을 할 수 있는지 맛보기로 소개합니다. 물론 이 글 하나에 모든 내용을 담을 수는 없지만, 클러스터링 여정을 시작하기에는 충분한 내용을 담고 있습니다. 그럼 함께 시작해 보겠습니다.

기술 개요

Docker 공식 문서에 이미 아주 상세하고 유용한 설명이 잘 정리되어 있으므로, 여기서는 기술에 대한 간략한 개요만 짚고 넘어가겠습니다. Docker가 있고, 이제 단일 서버가 아닌 여러 대의 서버를 Docker 호스트로 사용하면서 동시에 하나의 논리적 개체로 묶고 싶다고 가정해 봅시다. 이것이 바로 클러스터링입니다.

우선 노드 하나짜리 클러스터부터 살펴봅시다. 호스트에서 스웜을 초기화하면 해당 호스트는 클러스터의 매니저(manager)가 됩니다. 기술적으로 말하면 노드 하나로 구성된 컨센서스 그룹이 만들어지는 것이며, 그 수학적 기반은 Raft 알고리즘입니다. 매니저는 작업(task) 스케줄링을 담당하며, 워커(worker) 노드가 스웜에 참여하면 작업이 해당 노드들에 위임됩니다. 이 과정은 Node API가 관리하는데, API라는 단어가 늘 마음에 들지는 않지만 여기서는 어쩔 수 없이 사용해야겠습니다.

이 구현의 두 번째 축은 Service API입니다. Service API를 통해 매니저 노드는 스웜에 속한 모든 노드 위에 분산 서비스를 생성할 수 있습니다. 서비스는 복제(replicated) 방식으로 운영될 수 있는데, 이 경우 로드 밸런싱 메커니즘을 통해 클러스터 전체에 인스턴스가 분산 배치됩니다. 또는 글로벌(global) 방식으로 운영할 수도 있는데, 이 경우 모든 노드마다 서비스 인스턴스가 하나씩 실행됩니다.

실제로는 훨씬 더 많은 요소들이 작동하지만, 시작하기에는 이 정도면 충분합니다. 이제 직접 실습으로 넘어가 봅시다. 실습 대상 플랫폼은 CentOS 7.2인데, 이 글을 작성하던 시점 기준 저장소에는 Docker 1.10만 제공되었기 때문에 스웜을 사용하려면 프레임워크를 수동으로 업그레이드해야 했습니다(별도 튜토리얼에서 다룰 예정입니다). 이후에는 새 노드를 클러스터에 추가하는 후속 가이드와, Fedora를 활용한 비대칭 구성 실험도 준비되어 있습니다. 지금은 올바른 환경이 갖춰져 있다고 가정하고, 클러스터 서비스를 실제로 구동해 보겠습니다.

이미지 및 서비스 설정

여기서는 로드 밸런싱된 Apache 서비스를 구성해 보겠습니다. 여러 인스턴스가 하나의 IP 주소를 통해 콘텐츠를 서빙하는, 아주 표준적인 시나리오입니다. 이는 클러스터 구성을 선택하는 전형적인 이유, 즉 가용성, 이중화, 수평 확장, 성능을 잘 보여줍니다. 물론 네트워킹과 스토리지도 반드시 고려해야 하지만, 이는 본 가이드의 범위를 벗어나므로 다음 기회로 미루겠습니다.

Dockerfile 템플릿은 공식 저장소의 httpd 항목에서 확인할 수 있습니다. 최소한의 설정만으로도 시작할 수 있습니다. 이미지를 내려받는 방법이나 직접 생성하는 방법 등 자세한 내용은 이 튜토리얼 앞부분에서 링크한 Docker 입문 가이드를 참고하시기 바랍니다.

docker build -t my-apache2 .
Sending build context to Docker daemon 2.048 kB
Step 1 : FROM httpd:2.4
Trying to pull repository docker.io/library/httpd ...
2.4: Pulling from docker.io/library/httpd

8ad8b3f87b37: Pull complete
c95e1f92326d: Pull complete
96e8046a7a4e: Pull complete
00a0d292c371: Pull complete
3f7586acab34: Pull complete
Digest: sha256:3ad4d7c4f1815bd1c16788a57f81b413...a915e50a0d3a4
Status: Downloaded newer image for docker.io/httpd:2.4
 ---> fe3336dd034d
Step 2 : COPY ../public-html/ /usr/local/apache2/htdocs/
...

본격적으로 진행하기 전에 먼저 단일 인스턴스를 실행하여, 컨테이너가 오류 없이 생성되고 웹 서버에 접속할 수 있는지 확인해야 합니다. 이것이 확인되면 분산 서비스를 생성합니다.

docker run -dit --name my-running-app my-apache2

IP 주소를 확인하고 브라우저로 접속해 결과를 살펴보세요.

스웜 초기화 및 설정

다음 단계는 스웜을 구동하는 것입니다. 아래 명령이 가장 기본적인 형태이며, Docker 블로그의 예제와도 매우 유사합니다.

docker service create --name frontend --replicas 5 -p 80:80/tcp my-apache2:latest

무엇을 하는 명령일까요? 'frontend'라는 이름의 서비스를 컨테이너 인스턴스 5개로 생성하고, 호스트의 80번 포트와 컨테이너의 80번 포트를 바인딩하며, 방금 만든 Apache 이미지를 사용하도록 지정한 것입니다. 그런데 이 명령을 실행하면 다음과 같은 오류가 발생합니다.

docker service create --name frontend --replicas 5 -p 80:80/tcp my-apache2:latest
Error response from daemon: This node is not a swarm manager. Use "docker swarm init" or "docker swarm join" to connect this node to swarm and try again.

이 오류는 현재 호스트(노드)가 아직 스웜 매니저로 설정되지 않았다는 의미입니다. 새 스웜을 초기화하거나 기존 스웜에 참여해야 합니다. 아직 스웜이 없으므로 초기화를 진행해 보겠습니다.

docker swarm init
Swarm initialized: current node (dm58mmsczqemiikazbfyfwqpd) is now a manager.

To add a worker to this swarm, run the following command:

docker swarm join \
--token SWMTKN-1-4ofd46a2nfyvrqwu8w5oeetukrbylyznxla
9srf9vxkxysj4p8-eu5d68pu5f1ci66s7w4wjps1u \
10.0.2.15:2377

To add a manager to this swarm, run 'docker swarm join-token manager' and follow the instructions.

출력 내용은 비교적 직관적입니다. 스웜이 생성되었으며, 새 노드는 올바른 토큰을 사용해야 스웜에 참여할 수 있습니다. 방화벽 규칙이 필요한 경우를 대비해 IP 주소와 포트도 함께 안내됩니다. 매니저 노드를 추가할 수도 있습니다. 이제 서비스 생성 명령을 다시 실행해 보겠습니다.

docker service create --name frontend --replicas 5 -p 80:80/tcp my-apache2:latest
6lrx1vhxsar2i50is8arh4ud1

연결 테스트

이제 서비스가 실제로 작동하는지 확인해 봅시다. 개념적으로는 Vagrant와 coreOS로 실습했던 내용과 거의 같습니다. 결국 같은 아이디어의 다른 구현일 뿐입니다. 먼저 docker ps 명령이 올바른 출력을 보여주는지 확인하세요. 생성된 서비스의 여러 복제본이 보여야 합니다.

docker ps
CONTAINER ID        IMAGE               COMMAND              CREATED              STATUS              
NAMES
cda532f67d55        my-apache2:latest   "httpd-foreground" 
2 minutes ago       Up 2 minutes        80/tcp               frontend.1.2sobjfchdyucschtu2xw6ms9a
75fe6e0aa77b        my-apache2:latest   "httpd-foreground" 
2 minutes ago       Up 2 minutes        80/tcp               frontend.4.ag77qtdeby9fyvif5v6c4zcpc
3ce824d3151f        my-apache2:latest   "httpd-foreground" 
2 minutes ago       Up 2 minutes        80/tcp               frontend.2.b6fqg6sf4hkeqs86ps4zjyq65
eda01569181d        my-apache2:latest   "httpd-foreground" 
2 minutes ago       Up 2 minutes        80/tcp               frontend.5.0rmei3zeeh8usagg7fn3olsp4
497ef904e381        my-apache2:latest   "httpd-foreground" 
2 minutes ago       Up 2 minutes        80/tcp               frontend.3.7m83qsilli5dk8rncw3u10g5a

기본값이 아닌 다른 포트로도 테스트해 보았는데 역시 잘 작동했습니다. 서버에 접속하고 응답을 받는 방식은 매우 유연합니다. localhost를 사용하거나, 올바른 포트와 함께 Docker 인터페이스 IP 주소를 사용할 수 있습니다. 아래 예제는 1080번 포트를 사용한 경우입니다.

지금까지의 과정은 아주 기초적인 첫걸음에 불과합니다. 진짜 도전 과제는 최적화되고 확장 가능한 서비스를 설계하는 것이며, 이를 위해서는 적절한 기술적 사용 사례가 필요합니다. 또한 docker info 및 docker service (inspect|ps) 명령을 활용하면 클러스터의 동작 상태를 더 깊이 파악할 수 있습니다.

발생 가능한 문제들

Docker와 스웜을 다루다 보면 사소한(또는 그렇지 않은) 문제에 부딪힐 수 있습니다. 예를 들어 SELinux가 부적절한 작업을 시도했다며 불평할 수 있습니다. 하지만 오류나 경고가 작업을 크게 방해하지는 않을 것입니다.

'service'는 docker 명령이 아니다

복제 서비스를 시작하는 필수 명령을 실행했을 때 docker: 'service' is not a docker command라는 오류가 나타날 수 있습니다. 이는 설치된 Docker 버전이 올바르지 않다는 의미입니다(-v 옵션으로 확인 가능). 해결 방법은 후속 튜토리얼에서 다루겠습니다.

docker service create --name frontend --replicas 5 -p 80:80/tcp my-apache2:latest
docker: 'service' is not a docker command.

Docker 태그가 인식되지 않는 문제

아래와 같은 오류를 볼 수도 있습니다.

docker service create -name frontend -replicas 5 -p 80:80/tcp my-apache2:latest
Error response from daemon: rpc error: code = 3 desc = ContainerSpec: "-name" is not a valid repository/tag

이 문제에 대한 논의 스레드가 여럿 존재합니다. 원인은 의외로 단순할 수 있습니다. 브라우저에서 명령을 복사해 붙여넣으면 하이픈(-)이 올바르게 파싱되지 않을 때가 있습니다. 정말 그만큼 간단한 문제입니다.

더 읽을 거리

이 주제에 대해 말할 것이 많습니다. Docker 1.12 이전의 독립형(standalone) Swarm 구현과 현재 Docker 엔진의 스웜 모드 모두 관련 자료가 풍부합니다. 게을러하지 마시고 아래 자료들을 읽어보시기를 권합니다.

Docker Swarm 개요 (독립형 Swarm 설치용)

프로덕션용 Swarm 클러스터 구축 (독립형 구성)

Docker Swarm 설치 및 생성 (독립형 구성)

Docker 엔진 스웜 개요 (버전 1.12)

스웜 모드 시작하기 (버전 1.12)

결론

여기까지입니다. 지금 단계에서는 거창한 내용은 아니지만, 이 글이 도움이 될 것이라 믿습니다. 핵심 개념 몇 가지를 다루었고, 스웜 모드의 작동 방식과 역할을 개괄적으로 살펴보았으며, 직접 웹 서버 이미지를 내려받아 생성한 뒤 여러 클러스터형 인스턴스를 성공적으로 구동했습니다. 현재는 단일 노드에서 진행했지만, 앞으로 확장해 나갈 계획입니다. 또한 흔히 발생하는 몇 가지 문제도 함께 다루었습니다.

이 가이드가 재미있었다면 좋겠습니다. 이전에 작성한 Docker 관련 글들과 함께 읽으신다면 이미지, 네트워킹 스택, 스토리지, 그리고 이제 클러스터까지 다루는 방법을 폭넓게 이해하실 수 있을 것입니다. 이제 막 워밍업이 시작된 단계입니다. 즐겁게 읽어주시고, 곧 새로운 Docker 튜토리얼로 다시 찾아오겠습니다. 저도 참을 수[원문 표현] 없이 벌써부터 신이 나네요.

그럼, 즐거운 클러스터링 되세요.