5분만에 읽는 도커 기본 – 도커 데몬, 오케스트레이션, 도커 스웜

2022.07.23

안녕하세요 클래스메소드의 수재입니다.
저번 글에서 정리했던 도커의 개요와 명령어에 이어서 내용을 정리해보았습니다.

도커 데몬

  • 도커는 Server-Client 아키텍쳐
    • 컨테이너와 이미지를 관리하는 도커 서버(=dockerd프로세스로 작동하며 이를 도커 데몬이라고 함)
    • 서버에 API를 입력할 수 있도록 CLI를 제공하는 도커 클라이언트

출처 : 도커 공식 페이지

  • dockerd 명령어로 다양한 옵션을 설정한 도커 실행 가능
    • 혹은 도커의 설정 파일을 수정해도 됨
    • Docker Desktop for Window을 이용하는 경우 docker desktop 에서 관리
    • -H옵션을 사용하면 Docker Remote API로 원격 통신 가능
      • WSL에서 Docker Desktop for Window을 이용하는 경우에는 다음 옵션을 활성화하면 내부에서 TCP 통신이 가능
    • --tlsverify 옵션으로 TLS 보안을 적용할 수 있음
      • dockerd --tlsverify \ --tlscacert={ca 경로} \ --tlscert={cert 경로} \ --tlskey={key 경로} \ -H localhost:2376 \ ~~
      • DOCKER_CERT_PATH , DOCKER_TLS_VERIFY등의 환경 변수를 설정하면 평소에 편하게 이용 가능
    • --storage-driver 옵션으로 도커의 스토리지 드라이버를 변경 가능
      • dockerd --storage-driver={OverlayFS, AUFS, Btrfs, Devicemapper, VFS, ZFS}
      • 변경 후의 드라이버가 이전 드라이버와 다른 경우 이전의 이미지와 컨테이너는 사용 할 수 없음
  • 스토리지 드라이버는 CoW 또는 RoW 방식을 사용
    • 덕분에 스냅샷 파일을 불변 상태로 유지할 수 있음
  • 데몬의 -D 옵션으로 디버그 모드를 활성화 할 수 있음
    • dockerd -D
    • 서비스로 구동했을 때는 로그 파일을 따로 찾아보자
  • 혹은 도커 서비스의 커맨드로도 확인 가능
    • 도커 데몬의 이벤트 실시간 스트림
      • docker events {--filter 'type=image/volume..'}
      • docker system events
    • 실행 중인 모든 컨테이너 자원 사용량을 실시간 스트림
      • docker stats
      • 한번만 보고 싶다면 --no-stream 옵션을 추가
    • 도커에서 사용하고 있는 이미지, 컨테이너, 로컬 볼륨에 관한 정보 출력
      • docker system df
  • CAdvisor, Prometheus, Node Exporter 등 3rd party 모니터링 도구를 이용하는 방법도 있음
  • 코드로 도커를 원격 조정하고 싶은 경우 Remote API를 래핑한 라이브러리를 이용하자

오케스트레이션

  • 여러 서버를 하나의 그룹으로 취급하는 클러스터를 관리하는 작업을 말함
    • 스케쥴링, 서비스 디스커버리, 로드 밸런싱, 고가용성, 배포 관리 등이 가능
    • 오케스트레이션 툴이 이런 기능들을 우선적으로 제공하며 툴에 따라 조금씩 기능의 차이가 있음
  • 도커 스웜, 아파치 메소스, 쿠버네티스(and EKS), ECS 등을 많이 사용

도커 스웜

  • 도커에서 제공하는 오케스트레이션 툴
  • 도커 클래식(컨테이너로서의 스웜)은 여러 대의 도커 서버에 접근하는 하나의 단일 접근점을 제공
    • docker run, ps등 일반적인 도커 명령어와 도커 API로 클러스터의 관리가 가능
    • 공식 문서에서도 레거시로 다루고 있으니 스웜 모드를 사용하자
  • 스웜 모드는 MSA를 다루기 위한 클러스터링 기능에 중점
    • 오토 스케일링, 로드 밸런싱 기능을 자체적으로 지원
    • 일반적으로 스웜 모드를 더 많이 사용
  • 각종 정보를 저장하고 동기화 하는 분산 코디네이터, 클러스터 내의 서버를 관리하고 제어하는 매니저, 각 서버를 제어하는 에이전트를 스웜 클래식은 별도로 실행해야 하지만 스웜 모드는 자체 내장
  • 매니저 노드와 워크 노드로 구성
    • 앞으로 다른 오케스트레이션 툴에서도 많이 사용되는 개념
    • 워커 노드를 매니저 노드에서 관리
      • 매니저 노드에서도 컨테이너가 생성될 수 있음
    • 매니저 노드는 1개 이상 있어야하지만 워커 노드는 없을 수도 있음
    • 매니저 노드를 다중화 하여 운영하는 것을 권장
      • 홀수 개의 매니저 노드 운용을 권장
  • docker swarm init명령어로 시작
    • 호스트의 IP가 여러 개인 경우 사용할 IP 주소를 지정해야함
    • docker swarm init --advertise-addr {ip address}
      • 출력되는 token 값은 새로운 노드를 클러스터에 추가하기 위한 비밀키
    • 기본적으로 2377 포트를 사용하며 노드 사이의 통신에 7946/tcp, 7946/udp 포트를 이용하고, 스웜이 사용하는 네트워크인 ingress 오버레이 네트워크에는 4789/tcp, 4789/udp 포트 사용
      • 따라서 이 포트를 각 호스트 머신에서 열어두어야 원활한 통신 가능
  • docker swarm join --token {출력 token 값} {통신 IP:PORT} 으로 워커 노드 추가
    • 주기적으로 토큰 값을 변경하는게 안전
    • docker swarm join-token --rotate {worker|manager}
  • 클러스터에 정상적으로 추가되었는지는 docker node ls로 확인
  • 클러스터에서 나가는건 해당 워커 노드에서 docker swarm leave
    • 매니저에서는 down 상태로 인식하기 때문에 실제로 관리 대상에서 제외하려면 docker node rm {worker node name}
    • 매니저 노드는 docker swarm leave --force
  • 워커 노드를 매니저 노드로 변경하려면 docker node promote {worker node name}
  • 매니저 노드를 워커 노드로 변경하려면 docker node demote {manager node name}

서비스

  • 스웜 모드에서 제어하는 단위는 컨테이너가 아닌 서비스
    • 같은 이미지에서 생성된 컨테이너 집합
    • 서비스 내에 컨테이너는 1개 이상 존재
    • 컨테이너들은 각 워커 노드와 매니저 노드에 할당되며 이 서비스 내의 컨테이너 배포 단위를 태스크(task)라고 함
  • 서비스에 설정된 레플리카 수만큼의 컨테이너가 스웜 클러스터 내에 유지됨
    • 운영 중 하나의 노드가 다운되면 해당 노드에서 실행되던 컨테이너는 다른 노드에서 실행
  • 서비스 생성은 docker service create [--name, --replicas 등등 옵션들] {image}
    • detached 모드로 실행되며 당연히 컨테이너 내부에 계속 실행되는 프로세스가 없으면 정지 > 장애로 판단해서 다시 생성 반복
  • 생성한 서비스의 숫자를 늘리려면 `docker service scale {service name=원하는 레플리카 수}
  • 모든 노드에 컨테이너를 반드시 하나씩 생성하는 글로벌 모드는 --mode global을 추가
    • docker service create --name study --mode global nginx
  • 노드 간에 변수 등을 넘기기 위해서 secret이나 config 사용
    • docker secret create {secret name} {value 혹은 value가 저장된 파일}
    • 생성된 secret은 컨테이너 내부의 /run/secrets/디렉터리에 마운트
      • docker service create ... --secret source={생성한 secret name},target={컨테이너 내부에 저장할 이름} -e {env name}="/run/secrets/target 값} ...
      • docker service create --secret source=test,target=mysql_pass -e MYSQL_ROOT_PASSWORD_FILE="/run/secrets/mysql_pass" ...
    • 경로나 값 등을 직접 기입하지 말고 호스트의 환경 변수 등을 이용하자
    • docker config create {config name} {value 혹은 value가 저장된 파일}
      • 입력된 값은 base64로 인코딩 됨
      • `docker service create ... --config source={생성한 config name},target=
  • 서비스의 업데이트는 docker service update --image {업데이트 대상 이미지} {service name}
    • 자체적으로 롤링 업데이트를 지원
    • 서비스를 생성할 때 업데이트 주기, 동시 업데이트 컨테이너 수, 실패 대응 등을 설정할 수 있음
      • docker service create --replicas 4 --update-delay 15s --update-parallelism 3 --update-failure-action ...
    • 롤백은 docker service rollback {service name}
  • 서비스 목록은 docker service ls
  • 서비스의 자세한 정보는 docker service ps {service name}
    • docker service inspect 혹은 docker inspect --type service등으로도 확인 가능
  • 서비스 삭제는 `docker service rm {service name}
    • 실행 중인지는 상관없이 바로 삭제
  • 장애 회복을 위해 다른 노드에 컨테이너가 실행된 후 노드가 정상 상태가 되더라도 실행중이던 컨테이너가 복구된 노드에 다시 할당되지 않음(rebalancing이 없음)
    • scale 명령어로 컨테이너 수를 줄이고 다시 늘려야함

서비스 네트워크

  • ingress 네트워크는 로드 밸런싱과 라우팅 메시에 사용

    기본적으로 모든 노드가 ingress 네트워크에 연결

    • 어떤 스웜 노드에 접근하더라도 서비스 내의 컨테이너에 접근할 수 있게 설정하는 라우팅 메시를 구성
    • 로드 밸런싱도 담당
      • 따라서 매니저 노드의 IP로 접근하더라도 다른 워커 노드의 컨테이너에 액세스 되는 경우도 있음
    • 오버레이 네트워크 드라이버를 사용
  • docker_gwbridge 네트워크는 오버레이 네트워크를 사용할 때 사용
    • 외부로 나가는 통신 및 오버레이 네트워크의 트래픽 종단점(VTEP) 역할
  • 네트워크도 생성 가능
    • docker network create --subnet 159.0.0.0/24 -d {overlay|bridge} {network name}
    • 클러스터에 속한 노드 하나에서만 실행해도 다른 노드에 자동 적용
    • docker run명령어로 스웜의 오버레이 네트워크를 사용하려면 --net {netowrk name} 옵션을 사용

서비스 디스커버리

  • 서비스의 컨테이너가 늘어나더라도 다른 서비스에서 해당 컨테이너를 인식할 수 있음
    • 정확히는 해당 컨테이너를 하나하나 알아야하는게 아니라 해당 서비스'만'알면 되기 때문
    • 각 서비스는 VIP를 가지며 내장 DNS 서버에서 어떠한 서비스 이름을 알아서 VIP로 변경

볼륨

  • 컨테이너에서 볼륨을 공유한 것과 똑같이 호스트의 디렉터리 혹은 볼륨을 공유할 수 있음
  • volume 타입은 다음과 같음
    • docker service create ... --mount type=volume,source={volume name},target={container target directory} ...
    • source를 지정하지 않으면 임의의 이름을 가진 볼륨이 생성됨
    • volume-nocopy옵션을 사용하면 컨테이너의 파일들이 볼륨에 복사되지 않게 할 수 있음
  • bind 타입은 호스트와 디렉터리를 공유할 때 사용
    • docker service create ... --mount type=bind,source={host target directory},target={container target directory} ...
  • 하지만 이렇게 볼륨을 공유하면 모든 노드가 서비스를 할당받을 수 있는 볼륨 데이터를 가지고 있어야하기 때문에 비효율적
    • 따라서 되도록이면 네트워크로 접근가능한 외부 스토리지를 이용하는게 바람직

노드 관리

  • 노드의 상태(status)는 변경 가능
    • docker node update --availability {active/drain/pause} {node name}
      • active는 컨테이너를 할당받을 수 있는 상태
      • drain은 새로운 컨테이너의 할당을 받지 않으며 실행 중이던 서비스의 컨테이너는 모두 중지되고 active 상태의 노드로 다시 할당
      • pause는 새로운 컨테이너의 할당을 다시 받지 않을 뿐 실행중인 컨테이너는 중지되지 않음
  • 노드에는 키:밸류 형태의 라벨을 추가할 수 있음
    • docker node update --label-add {key}={value} {node name} 로 라벨 추가 가능
  • 서비스를 생성할 때 조건(제약)을 설정할 수 있음(--contraint옵션)
    • docker service create --constraint 'node.labels.env == dev' ...
      • 라벨 조건
    • docker service create --constraint 'node.id == abd3123' ...
      • 노드 아이디 조건
    • docker service create --constraint 'node.hostname == {host name} ...
      • 호스트 네임(노드 이름) 조건
    • docker service create --constraint 'node.role == {manager|worker}' ...
      • 역할 조건
    • docker service create --constraint 'engine.labels.{key} == {value} ...
      • 엔진 라벨 조건
  • 여러 개의 조건도 설정 가능

마무리

이것으로 docker swarm 까지 대략적으로 정리해보았습니다.
오케스트레이션 툴에 대해서는 이전에 작성했었던 글을 참고해주세요.

도커에 대해 좀 더 상세하게 알고 싶으신 분은 collabnix/dockerlabs 깃허브를 살펴보시는 것을 추천합니다.

긴 글 읽어주셔서 감사합니다.
오탈자 및 내용 피드백은 언제나 환영합니다. must01940 지메일로 연락 주시면 감사합니다!


본 블로그 게시글을 보시고 문의 사항이 있으신 분들은
클래스메소드코리아 (info@classmethod.kr)로 연락 주시면 빠른 시일 내 담당자가 회신 드릴 수 있도록 하겠습니다 !