Docker swarm에 대하여3 - 8.24

양승현·2022년 8월 24일
2

docker

목록 보기
6/12

sudo sed -i 's/kr.archive.ubuntu.com/mirror.kakao.com/g' /etc/apt/sources.list

sudo apt update
우분투 레포지토리 변경 -> 다운로드 속도향상

Docker swarm

  • swarm - 클러스터의 의미처럼 여러 대의 서버를 네트워크로 묶어 마치 하나의 서버처럼 작동한다는 뜻에서 한 무리라는 의미의 스웜을 사용

[도커 스웜 가상 머신 환경]

                                      CPU  RAM  NIC (VMnet10)
 manager(private-registry)       2       4      211.183.3.100            
 worker1                            2       2            101
 worker2                            2       2            102
 worker3                            2       2            103
  1. 가상머신 생성 (manager, worker1 ~ worker3)
  2. 각 노드 IP 주소 및 호스트이름 변경하기
rapa@manager:~$ hostnamectl set-hostname 이름
rapa@manager:~$ sudo vi /etc/netplan/01-network-manager-all.yaml 
rapa@manager:~$ sudo netplan apply
  1. 모든 노드의 /etc/hosts 에 아래의 추가한다.
211.183.3.100   manager
211.183.3.101   worker1
211.183.3.102   worker2
211.183.3.103   worekr3
  1. ping manager -c 3 ; ping worker1 -c 3 ; ping worker2 -c 3 ; ping worker3 -c 3

API 사용하기

mkdir 0824; cd 0824
touch ctn.py
    1. sudo apt install -y pip
    1. pip install docker
    1. 파일 작성 (ctn.py)
rapa@manager:~/0824$ chmod +x ctn.py 
rapa@manager:~/0824$ cat ctn.py 

3.1.

rapa@worker1:~/0824$ cat ctn.py 
#!/usr/bin/python3

import docker
client = docker.from_env()

print(client.containers.run("alpine", ["echo", "hello", "all"]))

3.2 nginx 컨테이너 생성

rapa@worker1:~/0824$ cat ctn1.py 
#!/usr/bin/python3

import docker
client = docker.from_env()

test = client.containers.run("nginx", detach=True)
print(test.id)

3.3 for 문으로 컨테이너 리스트 출력

rapa@worker1:~/0824$ cat ctn2.py 
#!/usr/bin/python3

import docker
client = docker.from_env()

for ctn in client.containers.list():
    print(ctn.id)

3.4 for 문으로 컨테이너 이미지 출력

rapa@worker1:~/0824$ cat ctn2.py 
#!/usr/bin/python3

import docker
client = docker.from_env()

for img in client.images.list():
    print(img.id) 

swarm 시작 전 확인 사항

    1. 각 노드에서 /etc/hosts 파일을 열고 아래의 내용이 추가되어 있는지 여부를 확인하세요
211.183.3.100   manager		
211.183.3.101   worker1	
211.183.3.102   worker2	
211.183.3.103   worker3
    1. 모든 노드에서 동작중인 컨테이너 중지 -> 삭제
    1. 모든 노드에서 시간을 확인하여 동일한 시간인지 여부 확인

  • cluster 환경에서는 자원을 pool에 담아 하나의 자원(computing, network,storage)으로 활용될 수 있다.
    기능적으로 두가지 기능이 호스트에 부여된다.
  • manager (master@k8s)
-> controller의 역할을 수행
-> manager는 worker의 기능을 포함한다.
-> 일반적로 매니저는 컨테이너 배포에서 제외시키고 주로 컨트롤, 관리, 모니터링 역할에 주력해야 한다.
  • worker (node@k8s)
-> 컨트롤로 부터 명령을 전달받고 이를 수행하는 역할
  • manager, worker는 처음 클러스터 생성시 자동으로 node.role이 각 노드에 부여된다.
  • 또는 추가적으로 label을 각 노드에 부여하여 컨테이너 배포시 활용할 수 있다.

K8S와 docker의 차이

  • 쿠버네티스의 master는 worker의 기능을 수행하지 않는다.

MSA (Micro service Architecture)

  • 고도화를 위해 다수의 컨테이너나 VM을 이용하여 개발을 진행 할 수 있다. 개발 속도를 향상 시키고 모듈 형식으로 기능을 구분하여 개발하므로 문제 발생시 해당 컨테이너나 코드, VM만 확인하면 되므로 관리가 용이하다.
  • 또한 수평적 확장에도 유용하다.
  • 각 기능 개발에서 언어를 지정하지 않으므로 필요한 언어를 선택하여 개발하면 된다.
  • 각 기능별 데이터는 api 를 통해 주고 받으면 된다.

클러스터 환경 구현하기

매니저 역할을 수행할 노드에서 토큰을 발행하고 워커는 해당 토큰을 이용하여 매니저에 조인한다

AVAILABILITY

-> Active 는 컨테이너 생성이 가능한 상태

drain

-> 동작중인 모든 컨테이너가 종료되고 새로운 컨테이너를 생성할 수도 없는 상태

pause

-> 새로운 컨테이너를 생성할 수는 없다. 하지만 , drain 과는 달리 기존 컨테이너가 종료되지는 않는다. 유지보수를 위해 해당 모드를 drain 또는 pause 로 변경한다.

docker swarm join-token worker | manager

0 처음 매니저가 토큰을 발행하면 manager 용, worker 용 토큰이 발행된다.

  • 워커 외에 추가로 manager 를 두고 싶다면 별도의 노드에서는 manager 용 토큰으로 스웜 클러스터에 join 한다.
 manager1(leader), manager2 , worker1, worker2
  • 만약 manager 가 한개인 상태에서 해당 매니저가 다운된다면 전체 클러스터를 관리할 수 없으므로 실제 환경에서는 최소한 2대의 매니저를 두어야 한다.

만약 현재 상태에서 worker1(worker) 을 manager 로 변경하고 싶다면??

  • 상태 확인
rapa@manager:~/0824$ docker node inspect manager --format "{{.Spec.Role}}"
manager 
rapa@manager:~/0824$ docker node inspect worker1 --format "{{.Spec.Role}}"
worker
rapa@manager:~/0824$ docker node inspect worker2 --format "{{.Spec.Role}}"
worker
  • manager로 상태 승격
rapa@manager:~/0824$ docker node promote worker1
Node worker1 promoted to a manager in the swarm.
rapa@manager:~/0824$ docker node inspect worker1 --format "{{.Spec.Role}}"
manager
  • worker로 상태 다운
rapa@manager:~/0824$ docker node demote worker1
Manager worker1 demoted in the swarm.
rapa@manager:~/0824$ docker node inspect worker1 --format "{{.Spec.Role}}"
worker

도커 스웜 모드 초기화

  • 도커 스웜 모드 의 노드가 매니저 노드에 접근하기 위한 IP 입력
rapa@manager:~$ docker swarm init --advertise-addr ens32
  • 토큰 발행
rapa@manager:~$ docker swarm join-token worker

도커 스웜 모드 작업자 노드 연결

  • 발행된 토큰으로 worker 연결
docker swarm join-token worker | manager
  • 연결 확인
rapa@manager:~$ docker node ls
ID                            HOSTNAME   STATUS    AVAILABILITY   MANAGER STATUS   ENGINE VERSION
qetnw53j04x0r93phk11qjrim *   manager    Ready     Active         Leader           20.10.17
q0ykem8jc4bmmg1bv2akm6xs5     worker1    Ready     Active                          20.10.17
mp287ff2flki2r0tr0siuwxad     worker2    Ready     Active                          20.10.17
oqfoncccjqshle8jj67omuk9f     worker3    Ready     Active                          20.10.17

각 노드에서 클러스터 벗어나기

  • 워커에서 docker swarm leave, manager에서는 docker node rm worker1
  • leave 하게 되면 status가 Down 상태가 된다
rapa@worker1:~$ docker swarm leave
rapa@worker2:~$ docker swarm leave
rapa@worker3:~$ docker swarm leave
  • rm 하게 되면 연결이 해제 된다
rapa@manager:~/0824$ docker node rm manager

단일노드에서는 컨테이너 단위의 배포

  • compose, swarm 에서 서비스(다수개의 컨테이너 가능) 단위로 배포
rapa@manager:~/0824$ docker service create --name web --constraint node.role==worker --replicas 3 -p 80:80 nginx

  • docker service ls - 클러스터에 동작중인 서비스의 목록확인, 동작컨테인개수/요청컨테이너개수
  • docker service ps web - 각 컨테이너가 어떤 노드에서 동작중인가?
  • Service 목록을 확인
rapa@manager:~/0824$ docker service ls
ID             NAME      MODE         REPLICAS   IMAGE          PORTS
p9sh2zh06n2z   web       replicated   3/3        nginx:latest   *:80->80/tcp
  • 생성된 Service가 정상적으로 가동하는지 확인
rapa@manager:~/0824$ docker service ps web
ID             NAME      IMAGE          NODE      DESIRED STATE   CURRENT STATE            ERROR     PORTS
hgkvwgdlwi10   web.1     nginx:latest   worker1   Running         Running 13 minutes ago             
k9reh2dbx874   web.2     nginx:latest   worker2   Running         Running 13 minutes ago             
gg674blo0ep3   web.3     nginx:latest   worker3   Running         Running 13 minutes ago       
  • 생성한 서비스의 레플리카 수를 1개로 스케일 아웃
rapa@manager:~/0824$ docker service scale web=1
레플리카 수를 1개로 조정해도 100,101,102,103 전부 nginx에 접속이 가능하다 그 이유는 overlay 때문이다.
  • 생성한 서비스의 레플리카 수를 4개로 스케일 아웃
rapa@manager:~/0824$ docker service scale web=4
ID             NAME      IMAGE          NODE      DESIRED STATE   CURRENT STATE            ERROR     PORTS
hgkvwgdlwi10   web.1     nginx:latest   worker1   Running         Running 24 minutes ago             
ttfqgrsrewxl   web.2     nginx:latest   worker3   Running         Running 53 seconds ago             
m4gezuumdto7   web.3     nginx:latest   worker3   Running         Running 53 seconds ago             
sxdgs3x8fgfl   web.4     nginx:latest   worker2   Running         Running 44 seconds ago 
  • 각 worker에서 docker container ls (manager에서는 확인 불가)
rapa@worker1:~$ docker container ls
CONTAINER ID   IMAGE          COMMAND                  CREATED          STATUS          PORTS     NAMES
b7c3b2f15c90   b692a91e4e15   "/docker-entrypoint.…"   25 minutes ago   Up 25 minutes   80/tcp    web.1.hgkvwgdlwi109it9aok10570m
rapa@worker2:~$ docker container ls
CONTAINER ID   IMAGE          COMMAND                  CREATED              STATUS              PORTS     NAMES
7c471132510a   nginx:latest   "/docker-entrypoint.…"   About a minute ago   Up About a minute   80/tcp    web.4.sxdgs3x8fgflmagu0phwl5x39
rapa@worker3:~$ docker container ls
CONTAINER ID   IMAGE          COMMAND                  CREATED              STATUS              PORTS     NAMES
ff42e8c3b8c1   nginx:latest   "/docker-entrypoint.…"   About a minute ago   Up About a minute   80/tcp    web.3.m4gezuumdto78un39bzno11r5
684dc8689e14   nginx:latest   "/docker-entrypoint.…"   About a minute ago   Up About a minute   80/tcp    web.2.ttfqgrsrewxlpohfqm1bshnps

컨테이너가 생성되지 않는 이유

    1. 이미지가 다운되지 않은 상태에서 생성하려고 할때
    1. 이미지 다운로드를 위한 인증정보가 없을 경우
-> 자원 사용의 불균형이 발생할 수 있다. 즉, 한대의 노드에서 여러 컨테이너가 동작하고 몇 노드에서는 컨테이너 생성이 되지 않는 문제

각 노드에 저장소 접근을 위한 인증 정보가 config.json에

    1. manager 에서 로그인을 하고 config.json 정보를 일일이 각 노드의 config.json 에 붙여넣기한다.
    1. manager 에서 로그인을 하고 config.json 정보를 docker serivce create 시 넘겨준다.
      --with-registry-auth
    • 내가 가지고 있는 명령전달을 보낼 때 인증정보도 같이 보내겠다.

인증 정보 확인

rapa@worker1:~$ cat ~/.docker/config.json
{
	"auths": {
		"https://index.docker.io/v1/": {
			"auth": "토큰"
		}
	}

동작중인 서비스 삭제하기

  • 동작중인 모든 서비스 컨테이너 삭제
rapa@manager:~/0824$ docker service rm web

replicas

rapa@manager:~/0824$ docker service create --name web --constraint node.role!=manager --replicas 3 -p 80:80 nginx
  • --replicas 3 - 항상 최솟값을 3으로 유지해야한다.

★ swarm의 모드

  • swarm은 2가지 모드가 있다.
    도커 스웜(스웜 클래식) VS 스웜 모드

도커 스웜 클래식

  • zookeeper, etcd와 같은 별도의 분산 코디네이터를 두고 이를 통해 노드, 컨테이너들의 정보를 관리한다.
  • 또한 컨테이너의 정보를 확인하기 위하여 각 노드에 agent를 두고 이를 통해 통신하게 된다.

스웜 모드

  • manager 자체에 분산 코디네이터가 내장되어 있어 추가 설치 패키지등이 없다.
  • 일반적으로 이야기하는 스웜 클러스터는 스웜 모드를 지칭한다.

업데이트 방식

롤링 업데이트

  • 동작중인 컨테이너를 새로운 컨테이너로 업데이트 할 수 있다.
  • 컨테이너 내부의 내용을 바꾸는 것이 아니라, 기존 컨테이너는 중지되고 새로운 컨테이너로 대체되는 것이다.
  • 홀드 스탠바이

도커 허브 저장소 만들기

rapa@manager:~/0824$ mkdir blue green
rapa@manager:~/0824$ touch blue/Dockerfile green/Dockerfile
rapa@manager:~/0824$ touch blue/index.html green/index.html
rapa@manager:~/0824$ echo "<h2>BLUE yang PAGE</h2>" > blue/index.html 
rapa@manager:~/0824$ echo "<h2>GREEN yang PAGE</h2>" > green/index.html
rapa@manager:~/0824$ cat blue/Dockerfile  > green/Dockerfile 
rapa@manager:~/0824$ cat blue/Dockerfile 
FROM httpd
ADD index.html /usr/local/apache2/htdocs/index.html
CMD httpd -D FOREGROUND
rapa@manager:~/0824$ cat green/Dockerfile 
FROM httpd
ADD index.html /usr/local/apache2/htdocs/index.html
CMD httpd -D FOREGROUND

도커 허브 저장소에 저장

  • blue 이미지
rapa@manager:~/0824/blue$ docker build -t blue .
rapa@manager:~/0824/blue$ docker image tag blue gnon5367/myweb:blue
rapa@manager:~/0824/blue$ docker push gnon5367/myweb:blue
  • green 이미지
위와 동일

  • 도커 허브에 저장된 blue 이미지를 사용해 서비스 배포
rapa@manager:~/0824$ docker service create --name web --replicas 6 --update-delay 3s --update-parallelism 3 --constraint node.role==worker -p 80:80 gnon5367/myweb:blue

롤링 업데이트 방식으로 green으로 업데이트 하기

    1. task(작업) 에 동시에 3개의 컨테이너를 업데이트하고 3초를 쉬고 난뒤 다음 테스트를 진행한다.
rapa@manager:~/0824$ docker service update --image gnon5367/myweb:green web

  • 업데이트를 하게 되면 기존에 동작하고 있던 컨테이너는 down 상태가 되고 새로운 이미지로 생성한 컨테이너 외부에 서비스를 제공하게 된다.
  • 기존 컨테이너의 내용을 업데이트 하는

업데이트 이전 상태로 되돌리기

rapa@manager:~/0824$ docker service rollback web

config/secret

  • compose 파일이나 Dockerfile 에서 변수 지정(-e MYSQL_DATABASE, -e MYSQL_ROOT_PASSWORD) 을 한 적이 있다.
  • 해당 내용은 민감한 정보를 포함하고 있음에도 이미지에서 해당 내용을 직접 볼 수 있다는 단점이 있다.
  • 모든 사용자별로 별도의 환경변수, index.html, DB 패스워드를 다르게 하고싶다면 그때마다 별도의이미지를 만들어야 하는 불편함이 있다.
  • 이 경우 사용자별로 별도의 config, secret 을 사용하면 추가 이미지를 생성하는 작업 없이 패스워드나 변수 전달이 가능해 진다.
변수, 파일 -> config
password, key -> secret 
  • Docker Secret을 사용하면 아래와 같은 민감한 데이터를 안전하게 관리할 수 있다.
echo "test123" | docker secret create mysql_password -
v8mg82wh48r6ckznyw2zre6ab
  • Secret를 이용해 service 배포하기
  • Docker Secret은 메모리에 저장되어 있는 정보이기 때문에 컨테이너 내에서 특정 경로에 마운트가 불가능하고 /run/secrets 디렉토리에서 참조할 수 있다.
rapa@manager:~/0824$  docker service create --name sql --secret source=mysql_password,target=mysql_root_password --secret source=mysql_password,target=mysql_password -e MYSQL_ROOT_PASSWORD_FILE="/run/secrets/mysql_root_password" -e MYSQL_PASSWORD_FILE="/run/secrets/mysql_password" -e MYSQL_DATABASE="testdb" mysql:5.7
  • 생성된 Docker Secret을 확인
rapa@manager:~/0824$ docker secret ls

  • service 확인
rapa@manager:~/0824$ docker service ls

rapa@manager:~/0824$ docker container ls --all
CONTAINER ID   IMAGE          COMMAND                  CREATED          STATUS          PORTS                 NAMES
6e0e39cb90b1   mysql:5.7      "docker-entrypoint.s…"   47 minutes ago   Up 47 minutes   3306/tcp, 33060/tcp   sql.1.1b402fhwb65wxu7jurjt1e0pv
rapa@manager:~/0824$ docker container exec 6e0e39cb90b1 ls /run/secrets/
mysql_password
mysql_root_password
rapa@manager:~/0824$ docker container exec 6e0e39cb90b1 cat /run/secrets/mysql_password
test123
rapa@manager:~/0824$ docker container exec 6e0e39cb90b1 cat /run/secrets/mysql_root_password
test123
rapa@manager:~/0824$ curl -L http://www.naver.com > index.html
rapa@manager:~/0824$ docker config create webconfig index.html 

[config 사용하기]

rapa@manager:~/0824$ echo "hello world" > index.html 
rapa@manager:~/0824$ docker config create webcfg index.html 
rapa@manager:~/0824$ docker config inspect webcfg
[
    {
        "ID": "nny59ujcvm76wpnjf2859pbm7",
        "Version": {
            "Index": 2526
        },
        "CreatedAt": "2022-08-24T08:06:40.829867581Z",
        "UpdatedAt": "2022-08-24T08:06:40.829867581Z",
        "Spec": {
            "Name": "webcfg",
            "Labels": {},
            "Data": "aGVsbG8gd29ybGQK"
        }
    }
]
rapa@manager:~/0824$ docker service create --replicas 1 --constraint node.role==manager --name webcfg -p 8888:80 --config source=webcfg,target=/usr/share/nginx/html/index.html nginx

클러스터에서 네트워크

  • docker_gwbridge brdge local
-> 각 호스트에서만 영향을 미친다.
-> 스웜에서 오버레이 네트워크 사용.
-> 외부로 나가는 통신 및 오버레이 네트워크 트래픽의 종단 점 역할
  • ingress overlay swarm
-> 클러스터 전체에 하나의 네트워크로 동작한다.
-> 로드밸런싱과 라우팅 메시에 사용되며 서비스 내의 컨테이너에 대한 접근을 라운드 로빈 방식으로 분산하는 로드밸런싱을 담당한다.
  • 스웜모드로 생선된 모든 서비스의 컨테이너가 외부로 노출되기 위해서는 무조건 ingress 네트워크를 사용해야 하는 것은 아니다.
  • docker run -p를 사용해 외부에 노출했던 것처럼 특정 포트를 사용하도록 설정 할 수도 있다.
  • 다음은 ingress 를 사용하지 않고 호스트의 8888 포트를 직접 컨테이너의 80 포트에 연결하는 방식이다.
  • 아래처럼 인그레스를 사용하지 않고도 외부랑 통신할 수 있다.
rapa@manager:~/0824$ docker service create --publish mode=host,target=80,published=8080,protocol=tcp --name web nginx

사용자 정의 네트워크 - 전 클러스터에 걸쳐있는 오버레이 네트워크 생성하기

  • 네트워크 생성
rapa@manager:~/0824$ docker network create --subnet 192.168.123.0/24 -d overlay myoverlay
  • 네트워크 목록 확인
rapa@manager:~/0824$ docker network ls
NETWORK ID     NAME              DRIVER    SCOPE
06tivcjjndjp   myoverlay         overlay   swarm
  • overlay nerwork를 이용한 service 생성
    rapa@manager:~/0824$ docker service create --name ovctn --network myoverlay --replicas 1 --constraint node.role==manager ubuntu:18.04

0개의 댓글