sudo systemctl set-default mult-user.target
- 일시적으로 xwindow로 전환
startx
sudo systemctl set-default graphical.target
- bash : start 해라
- ansible : started 를 보장해라
- ansible 의 실체는 ssh 이다
- AWS, GCP에서 제공하는 컨테이너 클러스터링 서비스는 EKS, GKE가 있다.
- 이들은 별도의 manager 용 VM을 제공해 주는 것이 아니라, 전체 관리용 VM(콘솔 VM)에 도커를 설치하여 사용한다.
- 노드(worker)는 완전 관리형 서비스로 제공된다.
- manager 에서 파일에 token join 명령어를 담아서, worker node 생성시 해당 파일을 붙여넣기 하고, firstboot-command 로 해당 파일을 실행시켜, worker node 가 manager 에 자동으로 Join 되게 할 수 있다
- replicas - 지정된 개수만큼 컨테이너를 동작시키며, 개수는 무조건 유지된다. scale 과 연계하여 확장 / 축소가 용이하다
- global : 지정된 Node 에 각 1 개씩 global 하게 배포한다
rapa@manager:~$ docker service create --name test1 --replicas 3 --constraint node.role!=manager -p 80:80 nginx
- node.role!=manager 는 manager node 가 아닌 node 들을 지정하는 것이다.
- 이는 node.role==worker 와 같은 의미다
rapa@manager:~$ docker container run -d -p 8888:80 --name test2 nginx
- Service로 배포한 컨테이너와 container run으로 배포한 컨테이너를 비교하면 Ports 부분이 일반 컨테이너는 8888->80 과 같이 Host 의 Port 에 종속적이지만, Service 로 배포한 컨테이너는 Host 의 Port 번호가 표시되있지 않으며 Host 의 Port 에 종속적이지 않다.
rapa@manager:~$ docker service inspect test1 --pretty
- inspect 할 때, pretty 옵션을 사용하면, 더 사용자 친화적으로 정보를 출력해준다.
- parallelism 은 task 한 번에 실행할 컨테이너 개수를 말한다
- on failure 는 업데이트 진행시 오류가 발생하면 실행하는 옵션이다. pause 는 오류가 발생하면 중단시킨다.
- continue 는 오류가 발생해도 업데이트를 계속 진행시킨다
- 롤링 업데이트 방식으로 업데이트
rapa@manager:~$ docker service update --image gnon5367/myweb:blue test1
- 이전 버전으로 되돌리기
rapa@manager:~$ docker service rollback test1
- gitlab 은 저장소를 모니터링 한다. 해당 저장소에 code 가 저장되어 commit 이 변경되면, gitlab 은 commit 변경을 감지하고, 자동으로 script 를 실행한다
- script 에는 새 이미지를 build 하여, 도커 저장소에 push 하게 설정한다
도커 저장소에서 image 를 pull 하는데, 이때, ansible 이 명령을 manager node 에게 전달해준다. manager node 에서는 해당 명령을 받고, worker node 에게 전달한다- gitlab 에서 manager node 에게 명령을 바로 전달하게 Pipe Line 을 만들수도 있다
git lab 과 jenkins 를 같이 사용할수도 있다
- 기존 명령에서 password를 지정하거나 변수를 선언했던 것처럼 하는것이 아니라 별도의 config 또는 secret 객체를 생성하고 이를 컨테이너에 적용하는 방식으로 운영하는 것
config
-> 레지스트리 설정파일, 변수 선언, index.html과 같은 보안성이 낮은 파일 자체
rapa@manager:~$ docker config create testconfig index.html
rapa@manager:~$ docker config ls
rapa@manager:~$ docker config inspect testconfig
- 데이터 값을 볼 수 있다.
rapa@manager:~$ echo "aGVsbG8gYWxsCg==" | base64 -d
[config 확인]
rapa@manager:~$ docker service create --name nginx1 --replicas 3 --constraint node.role==worker -p 8003:80 --config source=testconfig,target=/usr/share/nginx/html/index.html nginx
- http://211.183.3.X:8003 으로 웹접속을 시도하면 config 에 적용해 두었던 "HELLO ALL" 이 보여야 한다.
secret
-> DB 패스워드, SSH Key(Pubilc key), 인증서
- secret 사용해보기
rapa@manager:~$ echo "test1234" | docker secret create testsecret -
rapa@manager:~$ docker secret ls
- 데이터가 보이지 않는다.
rapa@manager:~$ docker secret inspect testsecret
- 데이터 값을 볼 수 없다
[secret 확인]
- secret 은 기본적으로 컨테이너의 /run/secrets 이라는 디렉터리 아래에 파일 형태로 보관된다. 또한 컨테이너내에 파일에서는 암호문이 아닌 평문으로 보관된다
rapa@manager:~$ docker service create --name sql --constraint node.role==worker --replicas 3 --secret source=testsecret,target=testsecret -e MYSQL_ROOT_PASSWORD_FILE="/run/secrets/testsecret" -e MYSQL_DATABASE=testdb mysql:5.7
rapa@worker1:~$ docker container ls CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 5c428b465a0f mysql:5.7 "docker-entrypoint.s…" 13 minutes ago Up 13 minutes 3306/tcp, 33060/tcp sql.3.n54caefnc631migodg95u0ser
rapa@worker1:~$ docker exec 5c428b465a0f ls /run/secrets -l total 4 -r--r--r-- 1 root root 9 Aug 25 01:58 testsecret
rapa@worker1:~$ docker exec 5c428b465a0f cat /run/secrets/testsecret test1234
rapa@manager:~$ docker service create --name test1 --mode global nginx
rapa@manager:~$ docker service create --name test2 -p 8001:80 --mode global nginx
rapa@manager:~$ docker container ls
- test1 상세 정보로 ip 확인
rapa@manager:~$ docker container inspect fe8317e89fa2
- test2 상세 정보로 ip 확인
rapa@manager:~$ docker container inspect 283c77076fb4
- 추가적으로 overlay 네트워크를 생성한다. overlay 드라이버를 이용한 네트워크는 전 클러스터 상에 동일한 네트워크 영역을 제공하고 터널을 통해 물리적 위치와 상관없이 통신된다.
rapa@manager:~$ docker network inspect ingress
- overlay 네트워크 생성
rapa@manager:~$ docker network create --subnet 20.20.20.0/24 -d overlay testoverlay
- 네트워크 리스트 확인
rapa@manager:~$ docker network ls
- 생성한 네트워크를 사용하여 서비스 배포
rapa@manager:~$ docker service create --name test3 -p 8002:80 --network testoverlay --mode global nginx
- 컨테이너 id 확인
rapa@manager:~$ docker container ls | grep test3
- test3 상세 정보로 ip 확인
rapa@manager:~$ docker container inspect 90c82198b533
"IPAddress": "10.0.0.31", "IPAddress": "20.20.20.6",
- 생성한 컨테이너의 상세 정보를 확인하면, testoverlay Network 와 ingress Network 에 연결되있는 것을 확인할 수 있다. 총 2 개의 Ip 주소를 가진다
- Swarm 환경에서 Service 배포시 -p 옵션을 사용하면, 무조건 Ingress Network 와 연결된다
- worker Node 를 확인하면, 이제 testoverlay Network 를 확인할 수 있다. Network 생성시 생성한 Network 를 이용해 Service 를 한 번 배포한 후에 Container 가 배포된 해당 worker Node 에서 Network 를 확인할 수 있다
- docker container run으로 생성한 컨테이너는 --network myoverlay를 하면(클러스터 네트워크에 연결)하는 것이 불가능하다
- 다음과 같이 overlay 네트워크를 생성할 때 --attachable을 부착하면 가능해 진다.
docker network create -d overlay --attachable myoverlay2
- 볼륨 마운트 (iSCSI)
docker container run ... -v testvoiume:/var/lib/mysql
- 바인딩 (NFS 사용)
docker cintainer run ... -v /tetsdir:/var/www/html
- 노드 자체(호스트)에 문제가 있을 경우 볼륨 접근 불가
- 스케일의 축소/확장 등으로 인하여 신규 컨테이너가 기존 볼륨과 연결되지 않는 문제
- 각 호스트 별로 별도의 볼륨을 사용하므로 데이터의 동기화가 되지 않아 각 볼륨 별로 별도의 데이터 베이스가 동작하는 문제
- 최종적으로 로컬 볼륨은 좋은 선택이 아니다. 외부에 있는 스토리지로 연결(사용)을 해야한다.
- 서비스 생성시 볼륨 생성을 동시에 진행할 수 있다.
- 단, 기존 컨테이너에서 -v 옵션을 이용하는 방법의 경우 volume, nfs 구분이 어려울 수 있으므로 서비스에서는 이를 명확히 구분해주어야 한다.
type=volume mount
- type 은 volume 으로 설정하고, Host에 vol1 볼륨을 생성하여 컨테이너의 /root 디렉터리와 Mount 시켜서 컨테이너를 생성
rapa@manager:~$ docker service create --name testvol1 --mount type=volume,source=vol1,target=/root --replicas 1 --constraint node.role==manager nginx
rapa@manager:~$ docker container ls CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES e39f9a76fb4d nginx:latest "/docker-entrypoint.…" 15 seconds ago Up 13 seconds 80/tcp testvol1.1.motsfrcqhz90tfb0rxez298ks
rapa@manager:~$ docker container exec e39f9a76fb4d df -h Filesystem Size Used Avail Use% Mounted on : : /dev/sda5 20G 14G 4.6G 75% /root <-- vol1 스토리지와 연결된다. :
- 컨테이너의 디스크 정보를 확인하자. 클러스터 환경이기에 공유되는 자원인 overlay 를 확인할 수 있다. 또한, Volume Mount 를 했으므로 Host 의 Volume 이 /dev/sda5 와 같은 디스크 형태로 /root 와 Mount 된 것을 확인할 수 있다
type=bind -> nfs
- type 을 bind 로 하여 디렉터리와 디렉터리가 연결
rapa@manager:~$ mkdir testvol3
rapa@manager:~$ docker service create --name testvol3 --mount type=bind,source=/home/rapa/testvol3,target=/root --replicas 1 --constraint node.role==manager nginx
- 디렉터리를 하나 만들고, Service 를 배포해주자
rapa@manager:~$ ls testvol3/ rapa@manager:~$ touch testvol3/test_host.txt
rapa@manager:~$ docker container ls | grep testvol3 71cd79204a3a nginx:latest "/docker-entrypoint.…" 3 minutes ago Up 3 minutes 80/tcp testvol3.1.m6qhg2108a375nioardf0ua5b
- 컨테이너의 /root 디렉터리 안을 살펴보면 파일을 확인할 수 있다
rapa@manager:~$ docker exec 71cd79204a3a ls /root test_from_host.txt
rapa@manager:~$ echo "hello" > testvol3/test_from_host.txt
rapa@manager:~$ docker exec 82fff4a0922d cat /root/test_from_host.txt hello
- Active는 노드가 컨테이너를 동작시키고 생성할 수 있는 준비가 된 상태
- drain - 컨테이너를 해당 노드에 배치시키지 않는다. 해당 노드에서 동작중인 모든 컨테이너는 중지
- pause - 컨테이너를 해당 노드에 배치시키지 않는다. 컨테이너가 일시중지된다.
- service 배포하기
rapa@manager:~$ docker service create --name test1 --replicas 3 --constraint node.role==worker -p 8001:80 nginx
- worker3 의 AVAILABILITY 를 drain 으로 변경
rapa@manager:~$ docker node update --availability drain worker3 worker3
- worker3 는 drain 상태이므로 컨테이너가 중지되고, worker1,2에 하나 더 신규 생성되어 Service 를 실행한다
rapa@manager:~$ docker node ls ID HOSTNAME STATUS AVAILABILITY MANAGER STATUS ENGINE VERSION a4mxykjw9ajjkqkx856utjg3t * manager Ready Active Leader 20.10.17 7r867xulr6u2335ih528n87z6 worker1 Ready Active 20.10.17 x9nd0vjcjqpuupp6fk115aifg worker2 Ready Active 20.10.17 ow1jqlptdinzg14o0agv4hy4a worker3 Ready Drain 20.10.17
rapa@manager:~$ docker service ps test1 ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS pt22h7t3t3ma test1.1 nginx:latest worker1 Running Running 2 minutes ago urhyx2pkaa3p test1.2 nginx:latest worker1 Running Running 44 seconds ago <- 신규생성 됨. worker3 에 배치되지 않음 63ayo6giztyx \_ test1.2 nginx:latest worker3 Shutdown Shutdown 47 seconds ago t0ryk5aurhgf test1.3 nginx:latest worker2 Running Running 2 minutes ago
- Scale 을 늘려서 컨테이너 늘리기
- drain 상태인 worker3 에는 컨테이너가 배치되지 않는다
rapa@manager:~$ docker service scale test1=4 <--- scale 을 3 에서 4로 늘림 test1 scaled to 4 overall progress: 4 out of 4 tasks 1/4: running 2/4: running 3/4: running 4/4: running verify: Service converged
- worker3 를 다시 Active 상태로 전환
rapa@manager:~$ docker node update --availability active worker3 worker3
- Active 상태 확인
rapa@manager:~$ docker node ls | grep worker3 ow1jqlptdinzg14o0agv4hy4a worker3 Ready Active 20.10.17
- Scale 을 1 로 줄였다가 다시 3 으로 늘리면, worker3 에도 컨테이너가 배치된다.
rapa@manager:~$ docker service scale test1=1 test1 scaled to 1 overall progress: 1 out of 1 tasks 1/1: running verify: Service converged
rapa@manager:~$ docker service scale test1=3 test1 scaled to 3 overall progress: 3 out of 3 tasks 1/3: running 2/3: running 3/3: running verify: Service converged
rapa@manager:~$ docker service ps test1 ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS pt22h7t3t3ma test1.1 nginx:latest worker1 Running Running 6 minutes ago wkn8rjhdnz0d test1.2 nginx:latest worker2 Running Running 10 seconds ago 63ayo6giztyx \_ test1.2 nginx:latest worker3 Shutdown Shutdown 5 minutes ago 6rdc8bwnt3dh test1.3 nginx:latest worker3 Running Running 11 seconds ago
- 1,2,3 에 각 1개의 컨테이너가 재 조정 , 배치된다.
- label은 기존의 node.role 과 비슷하게 Node 에 key:value 형식의 label 을 부착하고, 이를 기반으로 컨테이너를 배치하고자 할 때 활용한다.
- 노드를 구분하는 방법
node.role node.id node.hostname
role, id, hostname을 이용해 Node 를 구분할 수 있다.
- role 은 다수의 Node 를 한 번에 지정할 수 있지만, id 와 hostname 같은 경우에는 Node 하나 하나 따로 지정해야 한다.
worker1 - zone-a - company: abc worker2 - zone-b - company: abc worker3 - zone-c - company: X
- worker1 노드에 label 추가. --label-add
rapa@manager:~$ docker node update --label-add zone=a --label-add company=abc worker1 worker1- worker2 노드에 label 추가
rapa@manager:~$ docker node update --label-add zone=b --label-add company=abc worker2 worker2- worker3 노드
rapa@manager:~$ docker node update --label-add zone=c worker3 worker3- worker 3 zone 상세정보
rapa@manager:~$ docker node inspect worker3 --pretty | grep zone zone=c- zone c인 worker3에만 컨테이너 배포 하기
rapa@manager:~$ docker service create --name zone --mode global --constraint 'node.labels.zone == c' nginx cdlirzcyoa03qxa7k26efjzjs overall progress: 1 out of 1 tasks oqfoncccjqsh: running verify: Service converged- worker3 에만 컨테이너가 배포된다.
rapa@manager:~$ docker service ps zone | grep zone 7gfarybsdvbz zone.oqfoncccjqshle8jj67omuk9f nginx:latest worker3 Running Running 30 seconds ago
swarm mode
- 명령어를 사용하여 클러스터 환경에 컨테이너, 볼륨, 네트워크를 배포할 수 있다.
- 단, 위의 방법을 사용할 경우 서비스 환경을 조정해야 하는 경우에는 명령을 다시 처음부터 작성해야 하는 등의 불편함이 있다.
docker-compose
- 명령어 사용의 불편함을 해결하기 위하요 yml 형태로 환경을 구성하고 이를 도커가 명령으로 변환하여 서비스를 제공하는 기능
swarm mode + docker-compose = > docker stack
디렉터리 생성 후 yml 파일 생성
rapa@manager:~$ mkdir 0825 ; cd 0825 rapa@manager:~/0825$ touch web.ymloverlay 네트워크 생성
rapa@manager:~/0825$ docker network create --driver=overlay --attachable web kc53oh6c5x9uhbls7u8dffxus네트워크 생성 확인
rapa@manager:~/0825$ docker network ls NETWORK ID NAME DRIVER SCOPE cdb3ac03134d bridge bridge local 936fa8c3abdc docker_gwbridge bridge local 3ead376f089f host host local kc53oh6c5x9u web overlay swarmhaproxy 이미지 가져오기
rapa@manager:~/0825$ docker pull dockercloud/haproxyweb.yml 파일 구성
rapa@manager:~/0825$ vi web.yml rapa@manager:~/0825$ cat web.yml version: '3.7' services: nginx: image: nginx deploy: replicas: 3 placement: constraints: [node.role == worker] restart_policy: condition: on-failure max_attempts: 2 environment: SERVICE_PORTS: 80 networks: - web proxy: image: dockercloud/haproxy depends_on: - nginx volumes: - /var/run/docker.sock:/var/run/docker.sock ports: # -p option, attached to ingress network - "80:80" networks: # backend network -> nginx containers - web deploy: mode: global placement: constraints: [node.role==manager] networks: web: external: true컨테이너 생성
rapa@manager:~/0825$ docker stack deploy -c web.yml web Creating service web_nginx Creating service web_prox컨테이너 생성 확인
rapa@manager:~/0825$ docker stack ls NAME SERVICES ORCHESTRATOR web 2 Swarm
- 관리형 포테이너 설치
rapa@manager:~/0825$ docker container run -d --restart always -p 9000:9000 -v /var/run/docker.sock:/var/run/docker.sock --name portainer portainer/portainer
- HAPROXY -> manager에 배치
라벨 부착
- worker1 -> zone=seoul
- worker2 -> zone=seoul
- worker3 -> zone=busan
새로운 overlay network : myovlnet -> 서브넷 : 10.10.123.0/24
haproxy는 자신의 80번 포트를 호스트의 8001과 연결하고 해당 연결은 myovlnet을 통해 zone=seoul에 배포된, wordpress로 연결된다.
최종적으로 worker3에는 cadvisor가 연결된다. 항상 worker3만 동작해야한다. container run
[풀이]
- overlay 네트워크 생성
rapa@manager:~/0825$ docker network create --driver=overlay --subnet 10.10.123.0/24 --attachable myovlnet nqceqh1y3hznwzori53ox7ckl
- haproxy 이미지 가져오기
rapa@manager:~/0825$ docker pull dockercloud/haproxy
- worker1 노드에 label 추가. --label-add
rapa@manager:~$ docker node update --label-add zone=seoul worker1 worker1
- worker2 노드에 label 추가
rapa@manager:~$ docker node update --label-add zone=seoul worker2 worker2
- worker3 노드
rapa@manager:~$ docker node update --label-add zone=busan worker3 worker3
- yml 파일 구성
rapa@manager:~/0825$ cat web.yml version: '3.7' services: wordpress: image: wordpress deploy: replicas: 2 placement: constraints: [node.labels.zone == seoul] restart_policy: condition: on-failure max_attempts: 2 environment: SERVICE_PORTS: 80 networks: - myovlnet proxy: image: dockercloud/haproxy depends_on: - wordpress volumes: - /var/run/docker.sock:/var/run/docker.sock ports: # -p option, attached to ingress network - "8001:80" networks: # backend network -> nginx containers - myovlnet deploy: mode: global placement: constraints: [node.role==manager] networks: myovlnet: external: true
- 관리형 포테이너 설치
rapa@manager:~/0825$ docker container run -d --restart always -p 9000:9000 -v /var/run/docker.sock:/var/run/docker.sock --name portainer portainer/portainer