용찬호. 「 시작하세요! 도커/쿠버네티스」. 위키북스 를 읽으며, 학습한 내용을 정리하는 글입니다.
→ 본문의 내용은 모두 책의 내용에 대한 직/간접적 인용임을 밝힙니다.
Q. 하나의 호스트 머신에서 도커 엔진을 구동하다가 CPU, 메모리, 디스크 용량과 같은 자원이 부족하다면?
→ 여러 대의 서버를 클러스터로 만들어 자원을 병렬적으로 확장하는 방법!
→ 이 문제를 해결하는 대표적인 오픈소스 솔루션이,
도커에서 공식 제공하는 도커 스웜(docker swarm)과 스웜 모드(swarm mode)이다!
[ 도커 스웜의 두 가지 종류 ]
1. 도커 버전 1.6부터 사용 가능한 컨테이너로서의 스웜
→ 이하에서 스웜 클래식
이라고 함!
2. 도커 버전 1.12 이후부터 사용 가능한 도커 스웜 모드(Swarm Mode)
→ 이하에서 스웜 모드
라고 함!
[ 스웜 클래식과 스웜 모드의 차이 ]
< 목적 >
스웜 클래식
은 여러 대의 도커 서버를 하나의 지점에서 사용하도록 단일 접근점을 제공스웜 모드
는 마이크로서비스 아키텍처의 컨테이너를 다루기 위한 클러스터링 기능에 초점!스웜 클래식
은 docker run, docker ps 등 일반적인 도커 명령어와 도커 API로 클러스터의 서버를 제어, 관리할 수 있는 기능 제공스웜 모드
는 같은 컨테이너를 동시에 여러 개 생성해 필요에 따라 컨테이너 수를 유동적으로 조절할 수 있고, 컨테이너로의 연결을 분산하는 로드밸런싱 기능을 자체 제공!스웜 모드가 서비스 확장성, 안정성 등 여러 측면에서 스웜 클래식보다 뛰어나므로 일반적으로 스웜 모드를 더 많이 사용!
cf. 스웜 클래식은, 각종 정보를 저장하고 동기화하는 분산 코디네이터, 클러스터 내의 서버를 관리 및 제어하는 매니저, 각 서버를 제어하는 에이전트 등이 모두 별도로 실행되어야 함!
스웜 모드는, 이런 클러스터링을 위한 도구가 도커 엔진 자체에 내장!
docker info | grep Swarm
Swarm : inactive
→ 지금까지의 도커 엔진 사용은 모두 단일 도커 서버에서 이루어진 것이므로, 현재 Swarm 모드는 비활성이다.
스웜 모드는 매니저 노드와 워커(Worker) 노드로 구성된다.
매니저 노드는 1개 이상 있어야 하지만, 워커 노드는 없을 수도 있음.
스웜 매니저는 홀수 개로 구성하는 것을 권장
[ Example ]
swarm-manager 192.168.0.100
swarm-worker1 192.168.0.101
swarm-worker2 192.168.0.102
--advertise-addr
에는 다른 도커 서버가 매니저 노드에 접근하기 위한 IP 주소 (즉, 매니저 노드의 IP 주소)를 입력!docker swarm init --advertise-addr ${SWARM_MANAGER_ADDR}
[ P. S ]
docker swarm join \
--token ${매니저_노드에서_확인한_TOKEN} \
${매니저_노드_IP}:2377
[ 매니저 노드 추가 ]
docker swarm join-token manager
위 명령어로 확인!
[ 워커 노드 추가 ]
docker swarm join-token worker
[ 워커 노드 삭제 ]
해당 워커 노드에서 아래 입력
docker swarm leave
→ leave 명령어로 스웜 모드를 해제하면, 매니저 모드는 해당 워커 노드의 상태를 Down을 인지할 뿐, 자동으로 워커 노드를 삭제하지 않음!
→ 매니저 노드에서 docker node rm
명령어를 사용해 해당 워커 노드를 지워준다.
[ 3.3.3.1 스웜 모드 서비스 개념 ]
ex) ubuntu:14.04 이미지로 서비스 생성 → 컨테이너 수 3개로 설정
[ 3.3.3.2 서비스 생성 ]
서비스를 제어하는 도커 명령어는 전부 매니저 노드에서만 사용 가능!
docker service create \
ubuntu:14.04 \
/bin/sh -c "while true; do echo hello world; sleep 1; done"
→ -d 옵션으 사용해 동작 가능한 이미지로, 서비스 생성
docker service ls
→ 서비스 목록 확인!
[ nginx 웹 서버 서비스 생성하기 ]
docker service create --name myweb \
--replicas 2 \
-p 80:80 \
nginx
docker service scale myweb=4
→ 이렇게 하면, 3개 중 하나의 노드(swarm-worker2)에 2개의 컨테이너가 할당된다.
→ 실제로는 각 노드의 80번 포트로 들어온 요청을 4개 컨테이너 중 1개로 리다이렉트하기에, 문제가 없음!
[ global 서비스 생성하기 ]
복제 모드(replicated)
와, 글로벌(global)
모드로 나뉜다. 복제 모드
는 레플리카 셋의 수를 정의해 그만큼의 컨테이너를 생성하는 모드docker service create --name global_web
[ 3.3.3.4 서비스 롤링 업데이트 ]
docker service create --name myweb2 \
--replicas 3 \
nginx:1.10
docker service update \
--image nginx:1.11 \
myweb2
docker service create \
--replicas 4 \
--name myweb3 \
--update-delay 10s \
--update parallelism 2 \
nginx:1.10
[ 3.3.3.5 서비스 컨테이너에 설정 정보 전달하기 : config, secret ]
secret
은 비밀번호나 SSH 키, 인증서 키와 같이 보안에 민감한 데이터를 전송하기 위해, config
는 nginx나 레지스트리 설정 파일과 같이 암호화할 필요가 없는 설정값들에 쓰인다.[ secret 사용하기 ]
echo 1q2w3e4r | docker secret create my_mysql_password -
docker secret ls
→ 생성된 secret을 docker secret inspect my_mysql_password
로 조회해도 실제 값 확인은 불가!
→ 매니저 노드에 암호화된 상태로 저장되는 값으로, 서비스 컨테이너가 삭제될 경우 함께 삭제된다.
docker service create \
--name mysql \
--replicas 1 \
--secret source=my_mysql_password, target=mysql_root_password \
--secret source=my_mysql_password, target=mysql_password \
...
...
mysql:5.7
--secret
옵션을 통해 컨테이너로 공유된 값은 기본적으로 컨테이너 내부의 /run/secrets
디렉터리에 마운트된다.[ config 사용하기 ]
docker config create registry-config config.yml
→ config는 입력된 값을 base64로 인코딩한 뒤 저장하여, base64로 디코딩하면 원래 값을 확인 가능!
docker service dreate --name yml_registry -p 5000:5000 \
--config source=registry-config,target=/etc/docker/registry/config.yml \
registry:2.6
[ 3.3.3.6 도커 스웜 네트워크 ]
→ 스웜 모드가 자체 지원하는 네트워크 드라이버를 통해 사용 가능!
[ ingress 네트워크 ]
[ 오버레이 네트워크 ]
컨테이너 내부에서 ifconfig
실행 결과
docker exec ${CONTAINER_ID} ifconfig
컨테이너마다 eth0, eth1, lo가 할당됐고, eth0이 ingress 네트워크와 연결된 네트워크 카드이다.
swarm-manager
에서 생성된 컨테이너와 swarm-worker1
에서 생성된 컨테이너는 IP 주소가 차례로 할당됨!
ingress 네트워크는 오버레이 네트워크 드라이버를 사용함.
이는 여러 개의 도커 데몬을 하나의 네트워크 풀로 만드는 네트워크 가상화 기술의 하나로, 이를 통해 여러 도커 데몬에 존재하는 컨테이너가 통신 가능!
즉, 여러 스웜 노드에 할당된 컨테이너는 오버레이 네트워크의 서브넷에 해당하는 IP 대역을 할당받고, 이를 통해 통신한다.
[ docker_gwbridge 네트워크 ]
[ 3.3.3.6 서비스 디스커버리 ]
ex) 2개의 컨테이너 레플리카를 갖는 B 서비스가 있고, A 서비스는 이 B 서비스의 컨테이너를 사용하는 경우
→ 스웜 모드에서는 B
라는 이름으로 서비스 B 컨테이너에 모두 접근!
→ 컨테이너의 IP 주소, 새롭게 생성된 사실 등을 몰라도, B
이름만 알면 된다.
서비스 이름은 어떻게 각 컨테이너의 IP로 변환되는가?
server
)은 서비스의 VIP(Virtual IP)를 가진다. server
호스트 이름으로 접근하면 실제로는 VIP로 요청을 전송server
서비스의 컨테이너의 IP로 포워딩된다. [ 3.3.4.1 노드 AVAILABILITY 변경하기 ]
docker node update \
--availability ${AVAILABILITY} \
${HOSTNAME}
[ Active ]
[ Drain ]
[ Pause ]
도커 컴포즈는 컨테이너를 이용한 서비스의 개발과 CI를 위해 여러 개의 컨테이너를 하나의 프로젝트로서 다룰 수 있는 작업 환경을 제공
[ 4.3.1.1 docker-compose.yml 작성과 활용 ]
docker-compose.yml
파일을 읽어, 로컬의 도커 엔진에게 컨테이너 생성을 요청[ 4.3.1.2 도커 컴포즈의 프로젝트, 서비스, 컨테이너 ]
[프로젝트 이름]_[서비스 이름]_[서비스 내에서 컨테이너의 번호]
docker-compose scale
명령어로 ubuntu_mysql_2, ubuntu_mysql_3 을 생성할 수 있음!docker-compose -p
옵션에 프로젝트의 이름을 사용해, 제어할 프로젝트의 이름을 명시할 수 있다. [ 4.3.2.1 YAML 파일 작성 ]
[ 주요 정의 ]
< 서비스 정의 >
image
: 서비스의 컨테이너를 생성할 때 쓰일 이미지의 이름을 설정links
: docker run --link와 동일, 다른 서비스에 서비스명만으로 접근할 수 있도록 설정command
: 컨테이너가 실행될 때 수행할 명령어를 설정, Dockerfile의 RUN과 같은 배열 형태로도 사용이 가능!depends_on
: 특정 컨테이너에 대한 의존관계를 나타내며, 이 항목에 명시된 컨테이너가 먼저 생성되고 실행된다. links
도 depends_on
과 같이 컨테이너의 생성 순서와 실행 순서를 정의하지만, depends_on
은 서비스 이름으로만 접근 가능하다는 차이!ports
: docker run 명령어의 -p와 같으며, 서비스의 컨테이너를 개방할 포트를 설정. docker-compose scale
명령어로 서비스의 컨테이너의 수를 늘릴 수는 없다.extends
: 다른 YAML 파일이나 현재 YAML 파일에서 서비스 속성을 상속받게 설정< 네트워크 정의 >
driver
: 도커 컴포즈는 생성된 컨테이너를 위해 기본적으로 브리지 타입의 네트워크를 생성한다. ipam
: IPAM(IP Address Manager)를 위해 사용할 수 있는 옵션으로서 subnet, ip 범위 등을 설정external
: YAML 파일을 통해 프로젝트 생성할 때마다 네트워크를 생성하는 것이 아닌, 기존의 네트워크를 사용하도록 설정external
의 값을 true로 설정합니다.services:
web:
image: alicek106/composetest:web
networks:
- alicek106_network
networks:
alicek106_network:
external: true
< 볼륨 정의 >
driver
: 볼륨을 생성할 때 사용될 드라이버를 설정합니다. 어떠한 설정도 하지 않으면 local로 설정되며, 사용하는 드라이버에 따라 변경해야 함. volumes:
driver: flocker
driver_opts:
opt: "1"
opt2 : 2
external
: 도커 컴포즈는 YAML 파일에서 volume, volume-from 옵션 등을 사용하면 프로젝트마다 볼륨을 생성external
옵션을 설정하면 볼륨을 프로젝트 생성 시마다 생성하지 않고, 기존 볼륨을 사용하도록 설정< YAML 파일 검증하기 >
docker-compose config
명령어 사용![ 4.3.2.2 도커 컴포즈 네트워크 ]
[ 4.3.2.3 도커 스웜 모드와 함께 사용하기 ]
docker stack
으로 제어해야 한다. docker stack deploy -c docker-compose.yml mystack
// 스택을 생성
--attachable
옵션이 설정되지 않기 때문에 일반 컨테이너는 이 네트워크를 사용할 수 없음