Gom3rye
Docker Swarm 본문
- nginx 설정 파일 만들기
vi nginx.conf
upstream web-alb{ # 실제로 요청을 보내는 곳
server pyfla_app1:5000;
server pyfla_app2:5000; # ip대신 서비스 이름(컨테이너 이름) 적어줘도 된다. -> 도커나 쿠버내티스는 내부 dns를 가지고 있어서
server pyfla_app3:5000;
server { # 여기로 요청이 오면 web-alb로 가라
location / {
proxy_pass <http://web-alb>;
}
}
요청을 보내는 쪽에서는 내가 보낸 요청이 어디로 가는 지는 몰라도 된다. Just 로드밸런서에게 요청 주고 그 요청을 로드밸런서가 분배해서 보내는 것
Load Balancer
- L4: IP와 Port로 분류할 수 있다.
- L7: URL로도 분류할 수 있다.
Web Server (요청이 오면 뭘 불러드리는 것만)
→ 무조건 포트 2개만 연다. http:80 https:443
- apache2
- nginx
WAS server (Web Application Server)
→ 8080
- apache tomcat
Proxy Server
→ 내가 직접 요청하는 게 아니라 누군가에게 대신 요청해서 받아오는 것
자바스크립트
→ 동일한 도메인에만 데이터를 요청할 수 있다. (애플리케이션이 쪼개지면 요청 못 함)
- ajax ————>
- fetch api ————> axios library
- web socket
- web push (SSE)
⇒ 해결책
- 서버가 풀어주는 것 CORS (너는 와도 돼.)
- 서버를 가진 사람만 풀어줄 수 있다.
- proxy를 사용해서 자바스크립트는 proxy에게 요청만 해서 proxy는 server로 가서 데이터를 받아온다. → 프록시 패턴
노드는 자바스크립트로 작성을 하면 내부는 c++로 작동한다.
nginx에는 도커 파일과 설정 파일을 만든 것
파이썬 앱에서 0.0.0.0 해준 부분에 private cloud를 쓰고 있으면 private ip를 작성해라.
가상환경 만들고 pip freeze로 requirements.txt 내보내는 게 낫다.
항상 Docker file의 첫 번째는 FROM → 너 뭐할건데
- 도커 안에서의 포트는 1개만 존재해야 한다. (따라서 총 가질 수 있는 포트는 6만 5천개 정도밖에 없음)
- 도커는 하나의 gateway를 가지고 그 안에서 여러 개의 docker-compose로 생성한 네트워크를 가지고 있다 → 이 때 compose로 생성한 네트워크는 ~~_default로 생성되고 이 네트워크는 vlan의 역할만 해주고 진짜 포트포워딩은 gateway에서 시작된다. ex 172.17.0.1(가상의 NIC) → 172.18.0.1/16(docker-compose network) → 172.18.0.2(service)
- 여기서 172.18.0.1 안에 포트 80이 있다면 172.19.0.1 (다른 네트워크) 에서는 포트 80번 못 쓴다.
환경 변수
환경 변수를 다루는 방법
- docker-compose 파일에 직접 입력
- shell 환경 변수로 등록
- 환경 변수 파일로 구성
- Dockerfile에 환경 변수를 직접 삽입
1. docker-compose 파일에 직접 입력
- MySQL에는 MySQL_ROOT_PASSWORD 라는 변수 값이 반드시 필요하다.
- service 안에 environment라는 속성에 변수이름:값의 형태를 사용한다.
~/docker/compose$ vi docker-compose.yml
version: "3.8"
services:
mysql:
image: mysql:8
restart: unless-stopped
ports:
- 3306:3306
environment:
MYSQL_ROOT_PASSWORD: 비밀번호
2. Shell 환경 변수 활용
- 환경 변수 등록
export MYSQL_ROOT_PASSWORD=password
version: "3.8"
services:
mysql:
image: mysql:8
restart: unless-stopped
ports:
- 3306:3306
environment:
MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD}
- 실제 내용 확인: docker-compose convert (안되면 docker compose config)
3. 환경 변수 파일로 생성
배포용 Compose 파일에 환경변수를 하나하나 다 적어 넣거나 매번 쉘에서 변수로 직접 선언하는 방법은 다소 비효율적이다. (매번 타이핑을 해야하니까)
- 필요한 환경 변수 항목들만 골라내어 별도의 파일로 구성해둔다면 환경 변수 관리를 보다 효율적으로 할 수 있다.
- Docker Compose에서 환경 변수 정보들을 떼어 별도의 파일로 구성할 때 가장 간편한 방법은 Compose 파일이 위치한 동일한 경로에 .env 파일을 따로 구성하는 것이다.
- .env 파일을 이용하는 방식은 간편하기는 하지만 Docker Compose에서 docker compose up 명령을 수행할 때에만 활용이 가능하다.
- env 파일 문법
- 각 줄마다 변수명=값 의 형태로 입력
- 주석 처리는 #문자를 이용
- 비어 있는 줄은 무시
- 따옴표 처리는 불필요한데 입력된 따옴표는 위치에 따라 변수명이나 값의 일부로 간주
실습
- 이전에 만든 환경변수 삭제
unset MYSQL_ROOT_PASSWORD
- .env 파일 생성하고 작성
MYSQL_ROOT_PASSWORD=비밀번호
# 확인
echo ${MYSQL_ROOT_PASSWORD}
- 확인
docker-compose convert
실행 시 파일 지정하기
- 경우에 따라서 여러 개의 환경변수 파일로 나누는 일이 필요할 수 있는데 개발 환경(dev)과 운영 환경(prod)에 따라 주입해야 할 값이 다른 경우에는 각각의 환경에 맞는 별도의 env_file을 구성한 뒤 배포할 때 --env-file 파일경로 플래그로 불러올 파일을 직접 지정할 수 있다.
- 환경변수 파일 생성
- cat ./config/.env.dev 파일에 MYSQL_ROOT_PASSWORD=password_dev
- ./config/.env.prod 파일에 MYSQL_ROOT_PASSWORD=password_prod
적용
docker-compose --env-file ./config/.env.dev config
3-1. 서비스 별로 다른 환경 변수 파일 사용하기
- 각 서비스의 env_file 속성에 환경 변수 파일의 경로를 배열로 나열한다.
services:
mysql:
env_file:
- a.env
- b.env
4. Dockerfile에 환경 변수를 직접 삽입
- 환경변수를 yaml이나 별도의 외부 파일에 담아두지 않고자 하는 경우 Dockerfile에 ARG 또는 ENV를 이용하여 환경 변수를 직접 삽입한 뒤 이미지를 빌드해서 사용한다.
실습
FROM mysql:8
ENV MYSQL_ROOT_PASSWORD password
우선 순위
- compose 파일에 직접 입력한 값
- 쉘 환경 변수로 등록한 값
- 환경 변수 파일로 입력한 값 (.env)
- Dockerfile을 이용해서 삽입한 값
한계점
- Docker Compose 에서의 환경 변수 관리 방법에는 단점이 하나 있는데 모든 정보가 평문으로 저장된다는 것으로 중요한 정보가 평문 상태로 호스트에 남아있도록 하는 것은 보안 측면에서 결코 바람직하지 않다.
- 운영 환경에서 이를 보완하기 위한 방법
- 외부에 노출되지 않는 private registry를 구축한 뒤 보안 정보가 포함된 전용 이미지를 빌드하면 운영하는 방법을 고려
- 이 경우에는 보안 정보가 이미지의 특정 레이어에 남아있게 되므로 이미지와 레지스트리 관리에 신중해야 한다.
- kubernetes나 docker-swarm 등 컨테이너 오케스트레이션 도구에서는 이러한 보안 정보를 조금 더 안전히 다룰 수 있는 secret을 제공하며 AWS, Azure 같은 클라우드 서비스 제공자들이 지원하는 컨테이너 인스턴스들 역시 환경 변수를 설정할 때 이러한 시크릿 기능을 제공한다.
- 더욱 강화된 형태의 보안이 필요하면 HashiCorp Vault 같은 솔루션을 사용한다.
Docker Swarm
여러 도커 호스트를 클러스터로 묶어주는 컨테이너 오케스트레이션 도구
- 컨테이너 오케스트레이션 도구 없이는 도커 호스트 여러 대를 사용하는 확장성 있는 애플리케이션을 만들기가 매우 어렵다.
- 어느 도커 호스트에 어떤 컨테이너를 배치해야 하는지 서로 다른 호스트에 위치한 컨테이너 간의 통신은 어떻게 제어하는지 등의 조율을 직접 하는 것은 매우 어렵다.
- 오케스트레이션 도구를 도입하면 이러한 조율에 수고를 절감할 뿐 아니라 호스트가 여러 대로 나뉘어 있다는 점을 신경쓰지 않고 클러스터를 투명하게 다룰 수 있다는 이점이 있다.
- 구분
- compose
- 여러 컨테이너로 구성된 도커 애플리케이션을 관리한다.
- 단일 호스트에 사용하고 명령어는 docker-compose
- swarm
- 클러스터 구축 및 관리
- 주로 멀티 호스트에 사용하고 명령어는 docker swarm
- service
- 스웜에서 클러스터 안의 서비스(하나 이상의 컨테이너 작업)를 관리
- 명령어는 docker service
- stack
- 스웜에서 여러 개의 서비스를 합한 전체 애플리케이션을 관리
- 명령어는 docker stack
- compose
여러 대의 도커 호스트로 스웜 클러스터 구성
- 윈도우/Mac OS용 도커를 사용한다면 호스트가 1대 뿐이라서 여러 대의 호스트를 갖출려면 클라우드 서비스 등을 이용한다.
- Docker Machines를 사용하면 여러 대의 도커 호스트를 만들 수 있지만 도커 머신즈를 사용하려면 mac OS는 virtualbox 드라이버를 윈도우에서는 hyperv 드라이버를 설치해야 한다.
- virtual box와 같은 가상화 소프트웨어를 이용한다.
- Docker in Docker 라는 기능을 사용하면 도커 컨테이너 안에 도커 호스트를 실행할 수 있다.
Docker Swarm의 주요 기능
- 역할이 분리된 설계
- 도커 스웜에서 노드의 역할은 크게 보면 3가지이다.
- Manager Node
- Leader Node
- Worker Node
- 클러스터에 연결된 서버의 역할은 단일 관리자 환경이라면 Manager Node(Leader Node)와 Worker Node로 분리하여 각 역할에 따른 전문적 관리를 수행하지만 다중 매니저 모드로 구성하게 되면 그 중 하나를 리더 매니저 모드로 구성하여 나머지 매니저 노드와 작업자 노드를 관리한다.
- Manager Node는 클러스터의 관리 역할로 컨테이너 스케쥴링 서비스 및 상태 유지 등을 제공하고 작업자 노드는 컨테이너를 실행하는 역할을 수행한다.
- 쿠버네티스와 비교하면 쿠버네티스의 매니저 노드인 마스터 노드는 기본적으로 작업자 노드의 전체적인 관리만 수행하고 서비스 컨테이너는 수행하지 않지만 도커 스웜의 매니저 모드는 작업자 노드의 역할인 서비스 컨테이너도 수행할 수 있다. ( 쿠버네티스에서 관리자 모드로 되어 버리면 컨테이너 실행 같은 건 아예 못한다. But, 도커 스웜에서는 아무 상관이 없다. )
- 관리 역할을 수행하는 노드의 부하를 고려해서 각 역할은 분리해 사용하는 것을 권장하는데 매니저 노드에 서비스 컨테이너를 수행하지 않도록 역할 분리를 수행하는 방법은 도커 서비스를 생성할 때 --constraint node.role != manager 옵션을 사용하면 된다.
- 도커 스웜에서 노드의 역할은 크게 보면 3가지이다.
- 도커 엔진과 통합된 다중 서버 클러스터 환경: 도커 엔진에 포함된 도커 스웜 모드를 통해 별도의 오케스트레이션 도구를 설치하지 않아도 컨테이너 애플리케이션 서비스를 배포하고 관리할 수 있다.
- 서비스 확장과 원하는 상태 조정
- 도커 스웜 모드에서 서비스 생성 시 안정적인 서비스를 위해 Replicas Option(중복)된 서비스를 배포할 수 있고 초기 구성 후 스웜 관리자를 통해 애플리케이션 가용성에 영향을 주지 않고 서비스 확장 및 축소를 선택할 수 있다. (몇 개로 늘이고 몇 개로 줄이냐만 선택하면 된다.)
- 배포된 서비스는 매니저 노드를 통해서 지속적으로 모니터링 가능하다.
- 사용자가 요청한 상태와 다르게 서비스 장애가 생길 경우 장애가 발생한 서비스를 대체할 새로운 복제본을 자동으로 생성해서 사용자 요구를 지속적으로 처리하게 되는데 이를 요구 상태 관리라고 한다. (원래 대부분의 오케스트레이션 도구는 이것을 할 목적으로 나오는 것)
- 서비스 스케쥴링
- 스케쥴링 기능은 우리가 구성한 도커 스웜 모드 클러스터 내의 노드에 작업 단위의 서비스 컨테이너를 배포하는 작업
- 도커 클래식 스웜 엔진의 노드 선택 전략은 swarm manage --strategy (option) 방식을 통해 선택
- 모든 작업자 노드에 균등하게 할당하는 spread 전략
- 작업자 노드의 자원 사용량을 고려하여 할당하는 binpack 전략
- 임의의 노드에 할당하는 random 전략
- 도커 스웜 모드는 단일 옵션으로 고가용성 분산 알고리즘(HA Spread Algorithm)을 사용하는데 생성되는 서비스의 복제본을 분산 배포하기 위해서 현재 복제본이 가장 적은 작업자 노드 중에서 이미 스케쥴링된 다른 서비스 컨테이너 수가 가장 적은 작업자 노드를 우선 선택
- Load Balancing
- 도커 스웜 모드를 초기화(docker swarm init 명령)하면 자동으로 생성되는 네트워크 드라이버 중 하나가 Ingress Network
- 인그레스 네트워크는 서비스의 노드 간 load balancing과 외부에 서비스를 노출하기 위해 사용되는 overlay network(네트워크 위에 올라가는 네트워크)
- 도커 스웜 모드는 서비스 컨테이너에 PublishedPort(--publish <published port>:<container port>옵션)를 자동으로 할당(30000~32767)하거나 수동으로 노출할 포트를 구성할 수 있고 서비스 컨테이너가 포트를 오픈하면 동시에 모든 노드에서 동일한 포트가 오픈되기 때문에 클러스터에 합류되어 있는 어떤 노드에 요청을 전달해도 실행 중인 서비스 컨테이너에 자동으로 전달되는데 모든 노드가 스웜 모드의 routing mesh에 참여하기 때문이다.
- 작업자 노드 1의 nginx 웹 서비스 컨테이너가 실행 중이라고 가정하고 작업자 노드 2에서 노출된 포트로 접속해도 작업자 노드 1의 nginx 웹 서비스에 접속이 가능한데 이를 수행해주는 것이 인그레스 네트워크에서 로드밸런싱을 해주기 때문이다.
- 서비스 검색
- 도커 스웜 모드는 서비스 검색을 위해 자체 DNS 서버를 통한 서비스 검색 기능을 제공한다.
- 도커 스웜 모드 매니저 노드는 클러스터에 합류된 모든 노드의 서비스에 고유한 DNS 이름을 할당하고 할당된 DNS 이름은 도커 스웜 모드에 내장된 DNS 서버를 통해 스웜 모드에서 실행 중인 모든 컨테이너를 조회할 수 있게 되는데 이것을 service discovery 라고 한다.
- Rolling Update
- 도커 스웜 모드 매니저 노드를 통해 현재 실행 중인 서비스 컨테이너의 업데이트를 노드 단위로 점진적으로 적용할 수 있는 Rolling Update를 수행할 수 있다.
- 각 작업자 노드에서 실행 중인 서비스 컨테이너를 노드 단위의 지연적 업데이트를 수행하는 것
- 새 버전 서비스 컨테이너를 하나씩 늘려가고 이전 버전 서비스 컨테이너를 하나씩 줄여가는 방식
- 업데이트가 실패할 경우 다양한 기능을 통해 재시도 및 업데이트 중지 등을 수행할 수도 있고 잘못된 업데이트를 취소하기 위해 rollback 기능도 제공한다.
- 클러스터 구축
- 기본 구성
- swarm-manager(192.168.56.100)
- swarm-worker1(192.168.56.101)
- swarm-worker2(192.168.56.102)
- Nat Network 생성
- IPv4 접두사: 192.168.56.0/24
- DHCP 활성화는 체크 해제(해제하지 않으면 IP가 자동 할당)
- 기본 가상 머신에 NAT Network 적용
- 가상 머신을 선택하고 설정을 누른 후 네트워크 탭을 선택하고 [다음에 연결됨] 항목에서 Nat Network를 선택하고 [이름] 란에서 이전에 생성한 NatNetwork를 선택
- Ubuntu에서 IP 설정하는 방법
- 네트워크 인터페이스 확인: ip link show
- lo(루프백) 가 하나 보이고 enp로 시작하는 인터페이스 확인(enp0s8)
- netplan 설정 파일 편집(파일명은 의미가 없음)
sudo vi /etc/netplan/00-installer-config.yaml network: version: 2 renderer: networkd ethernets: enp0s8: dhcp4: no addresses: [192.168.56.100/24] gateway4: 192.168.56.1 nameservers: addresses: [8.8.8.8, 1.1.1.1]
- netplan 변경 내용 적용: sudo netplan apply
- 확인: ip addr show
- 리부팅 했을 때 설정한 IP가 아닌 다른 IP가 있다면 NAT Network 만들 때 dhcp 설정을 해제했는지 확인
- 네트워크 인터페이스 확인: ip link show
- hostname 변경
- 이름 변경: sudo hostnamectl set-hostname swarm-manager
- 이름 확인: cat /etc/hostname
- 실제 적용은 재부팅 되어야 한다.
- hostname과 IP 연결: sudo vi /etc/hosts
- 127.0.0.1 localhost
- 127.0.1.1 swarm-manager
- 192.168.56.100 swarm-manager
- 192.168.56.101 swarm-worker1
- 192.168.56.102 swarm-worker2
- 기본 구성
- 외부 접속이 가능하도록 SSH 설정
- NatNetwork에서 포트포워딩을 수행: 가상 머신의 22번 포트와 설정
- 접속이 안되는 경우
- ssh 서비스가 설치되어서 구동 중인지 확인
systemctl status ssh sudo apt update sudo apt install openssh-server sudo systemctl start ssh sudo systemctl enable ssh
- 방화벽이 구동 중이고 22번 포트를 열어주지 않아서
systemctl status ftw sudo ufw status sudo ufw allow 22
- 도커 설치
# 패키지 목록 업데이트 `sudo apt-get update` `sudo apt-get install ca-certificates curl` `sudo install -m 0755 -d /etc/apt/keyrings` `sudo curl -fsSL <https://download.docker.com/linux/ubuntu/gpg> -o /etc/apt/keyrings/docker.asc` `sudo chmod a+r /etc/apt/keyrings/docker.asc` # 데비안 계열의 Docker repository 추가 (도커 레포지토리를 레포지토리 목록에 추가) `echo \\\\ "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] <https://download.docker.com/linux/ubuntu> \\\\ $(. /etc/os-release && echo "${UBUNTU_CODENAME:-$VERSION_CODENAME}") stable" | \\\\ sudo tee /etc/apt/sources.list.d/docker.list > /dev/null sudo apt-get update` # 패키지 목록 업데이트 `sudo apt update` # 저장소 확인 `apt-cache policy docker-ce` # 도커 클라이언트와 엔진 설치 `sudo apt-get install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin` # 도커 설치 확인 `sudo docker version` # 서비스 시작 `sudo service docker start` # 현재 로그인 한 유저에게 docker 명령 실행 권한 부여 `sudo usermod -aG docker $(whoami) sudo chmod 666 /var/run/docker.sock sudo service docker restart`
Docker Swarm Cluster 구축
- manager 노드로 사용할 컴퓨터에서 초기화
docker swarm init [옵션]
docker 1.24 버전 이상이 설치된 경우만 가능
# 현재 스웜 모드 상태를 조회
docker info | grep Swarm
# 스웜 모드가 아니면 Swarm: inactive 가 출력
# 초기화
docker swarm init --advertise-addr IP주소(192.168.56.100)
# 초기화가 수행되고 나면 docker swarm join 이라는 문구와 키 그리고 IP:@2377 이라는 내용이 출력된다.
# worker node 가 접속할 때 사용할 key
# 네트워크 확인
sudo netstat -nlp | grep dockerd
→ 2377, 작업자 노드와는 7946/tcp와 7946/udp를 이용해서 통신하고 인그레스 오버레이 네트워크는 4789/tcp 와 4789/udp 를 사용한다.
⇒ 이 포트들을 방화벽에서 사용할 수 있도록 해제해 줘야 한다.
sudo ufw allow 2377/tcp
sudo ufw allow 2377/udp
sudo ufw allow 4789/udp
sudo ufw allow 4789/tcp
sudo ufw allow 7946/tcp
sudo ufw allow 7946/u
- worker node 에서 작업
- docker swarm join --token manager에서 받아온 토큰
- 토큰 값 확인 (manager node에서 수행)
- docker swarm join-token worker
- manager 추가를 위한 토큰 발행
- docker swarm join-token manager
- 연결 확인 (manager node에서 수행)
- docker node ls
Swarm initialized: current node (ygz9pik85s5up4vfohwa3ew08) is now a manager.
To add a worker to this swarm, run the following command:
docker swarm join --token SWMTKN-1-221jv9c4idlgocc4zojh4yf65mi3ufv1pofl1ux88rubm7y2yz-1x34or2no8zwxaorlvaepzxak 192.168.56.100:2377
To add a manager to this swarm, run 'docker swarm join-token manager' and follow the instructions.
- swarm 정보 확인
- docker info
- network 확인
- docker network ls
- Ingress와 bridge가 추가되었을 것
- docker_gwbridge 가 마스터와 워커를 연결해주는 것
- ingress: 내부를 외부로 노출시켜주는 것
- Ingress와 bridge가 추가되었을 것
- docker network ls
- bridge: 기본 도커 네트워크 (로컬 호스트 내 컨테이너 간 통신용)
- docker_gwbridge: Swarm 클러스터 노드 간 네트워크 연결용
- ingress: 외부 트래픽을 클러스터 서비스로 전달하는 라우팅용
'현대 오토에버 클라우드 스쿨' 카테고리의 다른 글
Kubernetes (0) | 2025.06.27 |
---|---|
Docker Swarm (1) | 2025.06.26 |
Load Balancer (0) | 2025.06.25 |
도커 네트워크와 docker-compose를 이용한 2개의 컨테이너 연동 (1) | 2025.06.24 |
Docker compose (0) | 2025.06.23 |