먼저 클러스터 개념을 소개하기전에 라즈베리파이 컴퓨터에 대해서 알아보겠습니다.
라즈베리파이 재단에서 만든 초소형/초저가의 컴퓨터를 라즈베리파이라고 하는데요,
2012년 3월에 첫 버전을 출시하여, 현재 버전 4까지 이어져오고 있습니다.
가격이 저렴한 만큼 성능이 제한적이라서, 개인 실험용이나 임베디드 리눅스 개발보드로 사용되고 있습니다. (IoT 프로젝트할때, 많이 쓰는 편!)
출처: https://www.devicemart.co.kr/goods/view?no=12234534
인간들은 라즈베리파이를 진짜 프로덕션에서 쓸 수 없을까? 성능을 어떻게 끌어올려볼까? 이런 호기심이 생기기 시작합니다.
사람들은 이 작고 가벼운 성능의 라즈베리파이를 괴롭혀보기로 합니다.
다수의 라즈베리파이를 병렬로 묶어서 사용해보자. 즉, 클러스터를 만들어보기로 합니다...
처음에는 3대
조금만 더 ...
인간의 욕심은 끝이 없죠
결국 144노드를 클러스터링한 상용 모듈까지 나오게 됩니다..
심지어 버지니아 공대에서는 SeeMore라는 256노드의 창작품까지 만들었습니다.
seeMore at SXSW from Sam Blanchard on Vimeo.
출처: https://magpi.raspberrypi.com/articles/seemore
하지만 이렇게 클러스터링한다고 해서 성능이 무작정 좋아지는건 아닙니다.
4대의 클러스터와 라즈베리파이 한대의 Run-time과 Speed Up 비교를 보면 라즈베리파이 한대가 오히려 성능이 더 좋게 나옵니다.
이유는 클러스터링된 노드간 통신에 사용하는 이더넷 속도(10/100Mbps)의 한계인 것으로 보입니다.
출처: https://magpi.raspberrypi.com/articles/benchmarking-raspberry-pi-cluster
정리하자면, 컴퓨터의 클러스터라는 개념은 다수의 노드(컴퓨터)를 묶어서, 병렬처리가 가능하게 하여 성능을 올려주는 기술을 말합니다.
도커에도 클러스터를 위한 도커 스웜이라는 기술이 있습니다.
도커 스웜은 노드들의 집합에 서비스형태로 도커컨테이너를 배포하고 관리할 수 있게 하는 기술입니다.
쉽게 말해서, 클러스터용 컨테이너 서비스 관리 툴이라고 보면 됩니다.
RAM 8GB 서버로 도커를 운영하고 있는데, 가용램을 넘어서, 더이상 서비스를 올릴 수가 없다면 어떻게 해야할까요?
RAM 8GB 짜리 서버가 한대 더 있다고, 가정해봅시다. 그러면 이 한대를 더 추가해서 운영할 것 입니다. 그런데, 이 두대를 하나의 자원으로 쓰고 싶다고 가정해봅시다.
마치 RAM 16GB의 서버 한대처럼 동작하도록 말이죠. 이럴때 필요한게 병렬확장인 클러스터입니다.
하지만 이런 병렬처리 컴퓨팅을 개인이 만드는 것은 쉽지 않습니다. 하지만 다행하게도 그걸 도와주는 툴이 존재하죠! 바로 도커 스웜 입니다.
스웜모드가 아닌 도커와의 차이는 서비스 개념 입니다.
도커에서는 컨테이너가 단위었다면, 스웜에서는 서비스가 단위입니다.
서비스는 한개의 컨테이너 또는 다수의 컨테이너가 조합될 수 있는 단위입니다.
이 포스팅에서는 도커 스웜의 기초를 다지기 위해서, 클러스터 사용없이, 단일 노드 스웜 모드를 사용하도록 하겠습니다.
아래 명령어로 스웜 모드 초기화를 진행해봅시다.
docker swarm init
싱글노드로 사용하기 위한 준비는 끝났습니다! 엄청 간단하죠?
도커 스웜에서는 서비스를 배포하기 위해서 docker-compose 형식의 파일을 사용합니다.
하지만 도커 컴포즈와는 다르게 deploy라는 옵션이 있고, docker stack에서는 제한되는 옵션들이 있습니다.
build
cgroup_parent
container_name
devices
tmpfs
external_links
links
network_mode
restart
security_opt
userns_mode
도커스택에서 사용하는 기본적인 옵션들에 대해서 알아보겠습니다.
version: "3.9"
services:
mysql:
image: mysql:5.7
environment:
- MYSQL_ROOT_PASSWORD=rootpw
deploy:
replicas: 1
adminer:
image: adminer
ports:
- "8080:8080"
deploy:
replicas: 1
limits: 최대 리소스 성능 제한
reservations: 점유할 리소스 예약
version: "3.9"
services:
redis:
image: redis:alpine
deploy:
resources:
limits:
cpus: '0.50'
memory: 50M
reservations:
cpus: '0.25'
memory: 20M
이 옵션은 컨테이너가 어떻게 다시 켜질 것인지에 대한 옵션입니다.
condition: none, on-failure, any (default: any)
delay: 재시작 시도 시간 간격 (default: 5s)
max_attempts: 재시작 시도 횟수 (default: never give up)
window: 재시작 성공시, 서비스를 다시 실행하는데 걸리는 시간 (default: decide immediately)
version: "3.9"
services:
redis:
image: redis:alpine
deploy:
restart_policy:
condition: on-failure
delay: 5s
max_attempts: 3
window: 10s
parallelism: 한 번에 업데이트할 컨테이너 수입니다.
delay: 컨테이너 그룹 업데이트 사이에 대기하는 시간입니다.
failure_action: 업데이트에 실패한 경우 수행할 작업. 중 하나 continue, rollback또는 pause
(기본값 : pause)
monitor: 실패 모니터링을 위한 각 작업 업데이트 후의 기간 (ns|us|ms|s|m|h)(기본값 5초)
(참고 : 0으로 설정하면 기본값 5초가 사용됩니다.)
max_failure_ratio: 업데이트 중 허용되는 실패율입니다.
order: 업데이트 중 작업 순서입니다. 하나는 stop-first(이전 작업은 새로운 하나를 시작하기 전에 정지)
또는 start-first(새 작업이 먼저 시작되고 실행중인 작업 간략하게 중복)
(기본값 stop-first) (참고 : compose V3.4 이상에서 지원.)
version: "3.9"
services:
redis:
image: redis:alpine
deploy:
restart_policy:
condition: on-failure
delay: 5s
max_attempts: 3
window: 120s
vote:
image: dockersamples/examplevotingapp_vote:before
depends_on:
- redis
deploy:
replicas: 2
update_config:
parallelism: 2
delay: 10s
order: stop-first
스웜모드가 활성화되면 아래와 같은 명령어를 실행할 수 있습니다.
docker service create
로 컴포즈 파일없이 즉시 서비스를 올릴 수 있다.
예제
docker service create --name registry --publish published=5000,target=5000 registry:2
docker service ls
로 실행중인 서비스들을 확인할 수 있다.
docker stack 명령어는 -c
or --compose-file
옵션으로 컴포즈파일을 지정해주어야 한다.
예제에 사용할 yaml파일은 아래와 같다.
version: "3.9"
services:
mysql:
image: mysql:5.7
environment:
- MYSQL_ROOT_PASSWORD=rootpw
deploy:
replicas: 1
adminer:
image: adminer
ports:
- "8080:8080"
deploy:
replicas: 1
docker stack deploy --compose-file <compose 파일경로> <stack 이름>
예제는 아래와 같다.
docker stack deploy --compose-file docker-compose.yml stackdemo
or
docker stack deploy -c docker-compose.yml stackdemo
docker stack services stackdemo
로 실행중인 서비스를 확인할 수 있다.
docker stack rm stackdemo
로 스택을 없앨 수 있다.
var http = require('http');
var os = require('os');
http.createServer(function (req, res) {
res.writeHead(200, {'Content-Type': 'text/html'});
res.end(`<h1>I'm ${os.hostname()}</h1>`);
console.log(os.hostname())
}).listen(8080);
FROM node
RUN mkdir -p /usr/src/app
COPY index.js /usr/src/app
EXPOSE 8080
CMD [ "node", "/usr/src/app/index" ]
docker-compose.yaml
version: '3.9'
services:
node:
image: api-example
ports:
- 8080
environment:
- SERVICE_PORTS=8080
deploy:
replicas: 5
update_config:
parallelism: 5
delay: 10s
restart_policy:
condition: on-failure
max_attempts: 3
window: 120s
networks:
- web
proxy:
image: dockercloud/haproxy
depends_on:
- node
environment:
- BALANCE=leastconn
volumes:
- /var/run/docker.sock:/var/run/docker.sock
ports:
- 80:80
networks:
- web
deploy:
placement:
constraints: [ node.role == manager ]
networks:
web:
driver: overlay
위의 세개파일을 만들어 놓고, 순서대로 설정해보자
일단 도커파일로 이미지를 만든다.
docker build -t api-example .
다음으로 스택을 배포 할 수 있도록 도커스웜 초기화 명령어인
docker swarm init
을 실행해보자
도커 스웜 init이 제대로 실행되었다면,
docker stack deploy --compose-file=docker-compose.yaml study
으로 서비스를 실행시켜보자
docker ps
로 확인해보면 5개의 컨테이너와 하나의 haproxy 서버가 올라가 있는것을 확인할 수 있다.
docker service ls
로 조금 더 정리된 화면을 확인할 수 있다.
docker service logs -f study_node
로 로그를 확인해보자.