bxm's IT Story

Docker (#Final. 노드 Availability-Active/Drain/Pause Mode, 도커 컴포즈) 본문

가상화/Docker

Docker (#Final. 노드 Availability-Active/Drain/Pause Mode, 도커 컴포즈)

bxmsta9ram 2021. 10. 1. 16:53

## 도커 Swarm mode 노드 다루기 ##

## 1) 노드 AVAILABILITY 변경하기 (Active/Drain) ★★★★★ 매우중요!!!!

docker node ls

특정 노드에서 유지보수 작업을 수행할 때 해당 노드에 컨테이너를 할당하지 않게 하고 싶을 때가 있다.
이를 위해 특정 노드의 AVAILABILITY를 설정함으로써, 컨테이너의 할당 가능 여부를 변경할 수 있다.


1) Active

노드가 컨테이너를 할당받을 수 있음을 의미한다.
Active 상태가 아닌 노드를 Active 상태로 변경하려면 다음과 같이 수행하면 된다.
docker node update --availability active worker2


2) Drain

// Manager, Worker1, Worker2가 있는데 만약에 내일 Worker2가 컴퓨터가 이상해서 하드디스크를 내일 갈아야한다...!
그럼 Worker2에 레플리카가 들어서면 안되고 스웜모드에서 제외시켜야 한다!!

노드를 Drain 상태로 설정하면, 스웜 매니저의 스케줄러는 컨테이너를 해당 노드에 할당하지 않는다.

Manager]

docker node update --availability drain worker2
docker node ls

// Worker2에 있던 레플리카들은 Manager와 Worker1으로 이전된다. 그리고 다시 Worker2가 원상복구가 된다고
하더라도, 이전되었던 레플리카들은 Worker2로 다시 돌아가지 않는다.
또한, "docker swarm leave로 나가는것과 똑같지 않느냐?" 할 수도 있는데 그것과는 엄연히 다르다!! 다 깨져버림.

docker service ls
docker service ps server

Drain 모드로 바뀐 worker2의 레플리카는 죽고 새로 하나가 자동으로 생성된다.
노드를 Drain 상태로 변경하면 해당 노드에서 실행 중이던 서비스의 컨테이너는 전부 중지되고 Active 상태의 노드로 재할당된다.


또한, Drain 상태의 노드를 Active 상태로 다시 변경한다고 해서 서비스의 컨테이너가 다시 분사되어 할달되지는
않으므로 docker service scale 명령어를 사용해 컨테이너의 균형을 재조정해야 한다.


3) Pause

서비스의 컨테이너를 더는 할당받지 않는다는 점에서 Drain과 같지만 실행 중인 컨테이너가 중지되지는 않는다는
점에서 다르다.

docker node update --availability pause worker2
docker node ls


docker service scale server=5
// Scale로 조정을 하면, Swarm 알고리즘에 의해서 레플리카가 자동으로 분산되는데 Manager와 Worker1이 Worker2 보다 메모리도 더 크고, 용량도 더 크기 때문에 그곳에 더 많은 레플리카를 할당하고 싶다!!!
이럴때는 Worker2를 Pause 모드로 놔두고, 스케일을 높이면 두 곳에 추가로 할당이 가능하다.


하지만 위의 방법은 그리 권장하는 방법은 아니다.

## 2) 노드 라벨 추가 - 실무에서 더 많이 쓰임.

노드에 라벨을 추가하는 것은 노드를 분류하는 것과 같다.

라벨은 '키-값' 형태를 가지고 있으며, 특정 노드에 라벨을 추가하면 서비스를 할당할 때 컨테이너를 생성할 노드의
그룹을 선택하는 것이 가능하다.

이를테면, 위의 'Pause'에서 다뤘던 예시에서 Worker2가 Manager와 Worker1보다 하드웨어 사양이 딸린다면,
Manager와 Worker1에 노드 라벨을 부여하여 Worker2에 레플리카가 생성되지 않도록 할 수 있다.


다른 방법으로는 위의 Pause를 통한 방법을 통해, 특정 노드를 'Pause' 상태로 만든 후 scale을 조정하는 방법도 있다.
예를 들어, swarm-worker1는 SSD 라벨을, swram-worker2는 HDD 스토리지를 사용하고 있어 STORAGE=SSD 라는
라벨을 설정했다고 가정하자.
서비스가 하드웨어 종속적이기 때문에, SSD를 사용하는 노드에서 수행한다면 서비스를 생성할 때 라벨을
STORAGE=SSD로 설정해서 swram-worker1노드에만 컨테이너를 할당할 수 있다.

Manager]

docker node update --label-add storage=ssd worker1 // 라벨을 붙이는 명령어 (Update로 붙여야한다.)
docker node inspect --pretty worker1 // 라벨이 붙은 것을 확인!!


## 서비스 제약 설정

[-- constraint] 옵션을 추가해서 서비스의 컨테이너가 할당될 노드의 종류를 선택할 수 있다.
① node.labes 제약 조건
: 다음 명령어는 storage 키의 값이 ssd로 설정된 노드에 서비스의 컨테이너를 할당한다.
docker service create --name label_test --constraint 'node.labels.storage==ssd' --replicas=5 ubuntu:14.04 ping docker.com

docker service ps label_test

// docker.com에다가 ping을 날리는 ping test 컨테이너를 만들자.   워커 1에만 5개가 만들어진 것을 볼 수 있다.

// 관리자가 컨테이너를 만들고자 하는 곳에 이렇게 인위적으로 만들 수 있다 !!!


② node.id 제약 조건
: node.id 조건에 노드의 ID를 명시해서 서비스의 컨테이너를 할당할 노드를 선택한다.
docker node ls | grep worker1



// 이렇게 ID를 통해서 특정 노드에 배치할 떄에는 아이디를 긁어서 명령어를 기입하면 된다.
docker service create --name label_test2 --constraint 'node.id==bge0qqoa6qrzgpkkhfopkrbc8' --replicas=5 ubuntu:14.04 ping docker.com

docker service ps label_test2


③ node.hostname과 node.role 제약 조건 ★★★★★ 이걸 제일 많이 쓴다.
: 스웜 클러스터에 등록된 호스트 이름 및 역할로 제한 조건을 설정할 수도 있다.
docker service create --name label_test3 --constraint 'node.hostname==worker1' ubuntu:14.04 ping docker.com
docker service ps label_test3



docker service create --name label_test4 --constraint 'node.role!=manager' --replicas 2 ubuntu:14.04 ping docker.com






 

 



 

## 도커 컴포즈 ##

여러 개의 컨테이너가 하나의 어플리케이션으로 동작할 때 이를 테스트하려면 각 컨테이너를 하나씩 생성해야 한다.
예컨대, 웹 어플리케이션을 테스트하려면 웹 서버와 DB컨테이너를 생성해야 한다.
docker run --name mysql -d moon682/composetest:mysql mysqld

DB 컨테이너 생성


docker run -d -p 80:80 --link mysql:db --name web moon682/composetest:web apachectl -DFOREGROUND


## 80번 포트를 쓰고 있는 컨테이너 전부 삭제후 다시 해보자. 어차피 이전꺼는 안 쓸 것이므로!!


매번 run 명령어를 이용한 CLI로 컨테이너를 생성하기보다는 여러 개의 컨테이너를 하나의 서비스로 정의해 컨테이너 묶음으로 관리할 수 있다면 좀 더 편리할 것이다.
이를 위해 도커 컴포즈(Docker Compose) 는 컨테이너를 이용한 서비스의 개발을 위해 여러 개의 컨테이너를 하나의 프로잭트로서 다룰 수 있는 작업 환경을 제공한다.

도커 컴포즈는 여러 개의 컨테이너 옵션과 환경을 저의한 파일을 읽어 컨테이너를 순차적으로 생성하는 방식을 취한다.

## 1) 도커 컴퍼즈 설치 및 구축

yum -y install epel-release && yum -y install docker-compose 1.29.2

아래의 깃헙에서 다운받는 방식과 이 방식과 똑같은 것이다. 


// curl : wget과 비슷한 역할을 하며, url이 있는 프로그램을 다운로드 받는데에 사용된다.
curl -L "https://github.com/docker/compose/releases/download/1.29.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose



// 구버전도 설치 - 공백이 없기 때문에 "" 를 없애자!!
curl -L https://github.com/docker/compose/releases/download/1.11.0/docker-compose-'uname -s'-'uname -m' > /usr/local/bin/docker-compose

호환성을 위해서 구버전도 그냥 설치해보았다.


// 접근 가능하게 하기 위해서 허가권을 주기.
chmod +x /usr/local/bin/docker-compose // 접근 가능하게 하기 위해서 허가권 주기

// 심볼릭 링크 만들기
ln -s /usr/local/bin/docker-compose /usr/bin/docker-compose


## 도커를 구동시켜보자. 아까 컨테이너 2개를 만들었는데 그것을 자동으로 만들게끔 해보자.
mkdir /temp
cd /temp
vi ./docker-compose.yml

version: '3.0'
services:
web:
image: moon682/composetest:web // 2칸 들여쓰기
ports:
- "80:80" // 1칸 들여쓰기
links:
- mysql:db
command: apachectl -DFOREGROUND
mysql:
image: moon682/composetest:mysql
command: mysqld


Swarm 안에 Service 안에 2개의 컨테이너를 넣었고, 각 컨테이너의 이미지도 들어가있다.

## 이렇게 하면 컨테이너 2개가 샥샥 만들어진다!!


docker-compose -v




## 이제 양쪽 다 컴퍼즈 한 것을 가져오기. (그리고 Swarm이 동작하는 상태에서 해야한다!! 'docker node ls' 모두
Active가 되어야 한다!!) 그리고 꼭 /temp 여기에서 해야한다!! 여기서 컴포즈를 해줬기 때문에!!
docker-compose up -d


## 아파치 접속해보기

Host PC]

http://192.168.1.100

// 이렇게 자동으로도 생성하는 방법을 배웠다!!



## 2) 도커 컴포즈의 프로젝트, 서비스 컨테이너

// YAML 파일로도 '도커 컴포즈' 구축이 가능하다.

YAML 파일에서 들여쓰기 할 때 탭(TAB)은 도커 컴퍼즈가 인식하지 못하므로, 2개의 공백을 사용해 하위 항목을

구분해야 한다.

Version YAML 파일 포맷의 버전을 나타낸다.
Service 생성될 때 컨테이너들을 묶어놓은 단위이다. 서비스 항목 아래에는 각 컨테이너에 적용될 생성 옵션을
지정한다.
Web, Mysql 생성될 서비스의 이름이다. 이 항목 아래에 컨테이너가 생성될 때 필요한 옵션을 지정할 수 있다.

 

// 파일이 저장된 현재 디렉토리(/temp)에서

docker-compose up -d

 

위 예제에서 쓰인 이미지는 도커 컴포즈 테스트용 이미지로, 서버의 /main.php 경로를 통해 간단한 로그인 페이지를

사용할 수 있다.

docker-compose ps


예제 YAML 파일에서 Web 서비스와 Mysql 서비스를 정의하였고, 서비스별로 컨테이너가 1개씩 생성됐으며

각 컨테이너의 이름은 temp_web1, temp_mysql_1 이었다.

 

도커 컴포즈는 컨테이너를 프로젝트 및 서비스 단위로 구분하므로 컨테이너의 이름은 일반적으로 다음과 같다.

[프로젝트 이름]_[서비스 이름]_[서비스 내의 컨테이너의 번호]

도커 컴포즈는 docker-compose.yml 파일이 위치한 디렉토리 이름을 프로젝트 이름으로 사용한다.

 

[docker-compose scale] 명령어로, temp_mysql_2를 생성할 수 있다.

 

docker-compose scale mysql=2

docker ps

mysql 서비스의 컨테이너가 늘어난 것을 알 수 있다.

 

 

## 도커 컴포즈 삭제 (방법.1 - 프로젝트 명이 없는 도커 컴포즈 삭제)

생성된 프로젝트는 [docker-compose down] 명령어로 삭제할 수 있다. <프로젝트 명이 없는 것만 삭제된다!!>

프로젝트 명이 있는 것은 [docker-compose -p 프로젝트명 down] 명령을 사용해서만 삭제가 가능하다!!!!! 휴..

다날아가는줄 알았네 ㅎㅎ...

docker-compose down

docker-compose ps

// 정확히 말하면 프로젝트 명이 없는 도커 컴포즈만 삭제가 된다!!!


## 도커 컴포즈 삭제 (방법.2 - 프로젝트 명이 있는 도커 컴포즈 삭제)

 

프로젝트 명을 명시하지 않을 경우, 도커 컴포즈는 yml 파일이 있는 위치명을 프로젝트명으로 사용한다. 그러나, [-p

옵션에 프로젝트 이름을 사용할 수 있다. 

즉, -p 옵션을 사용하면 하나의 yml 파일로 서로 이름이 다른 여러개의 프로젝트를 생성할 수 있다.

 

// 다음 2번째 삭제 방법을 알아보기 위해서 프로젝트 명을 주어 도커 컴포즈를 다시 살려보자. 이렇게 프로젝트명을

   다르게도 만들 수 있다!!

docker-compose -p myproject1 up -d

docker-compose -p myproject2 up -d         // 80번 포트를 2개 쓴다고 에러가 떨어진다!!

 

docker-compose -p myproject1 ps

 

// 프로젝트 명이 있는 도커 컴포즈 삭제하기!!

docker-compose -p myproject1 down

docker ps

도커 컴포즈가 삭제되었다!!



 

## 도커 컴포즈의 활용 ##

1. 도커 컴포즈를 사용하려면, 컨테이너 설정을 저장해 놓은 YAML 파일로 변환하는 것이 도커 컴포즈 사용법의

   대부분이다.

 

YAML 파일은 크게 버전 서비스 볼륨 네트워크 정의의 4가지 항목으로 구성된다. 이 가운데 가장 많이 사용하는 것이

'서비스 정의' 이며, 볼륨 정의와 네트워크 정의는 서비스로 생성된 컨테이너에 선택적으로 사용된다.

 

각 항목의 하위 항목을 정의하려면, 2개의 공백(스페이스O / TabX_인식 못함)으로 들여쓰기해서 상위 항목과 구분한다.

 

도커 컴포즈는 기본적으로 현재 또는 상위 디렉토리에서 yml 파일을 찾아서 컨테이너를 생성한다. 

그러나, docker-compose 명령어의 [-f] 옵션을 사용하면 yml 파일의 위치와 이름을 지정할 수 있다.

docker-compose -f /home/sunny/my_compose_file.yml up -d

 

 

## yml 파일 문법 사용법

ⓐ 버전 정의 도커 컴포즈 버전 1.10에서 사용할 수 있는 Version 3을 기준으로 실습해보자. 버전 항목은 일반적으로
YAML 파일의 맨 윗 부분에 명시한다.

version: '3.0'
ⓑ 서비스 정의 서비스는 도커 컴포즈로 생성할 컨테이너 옵션을 정의한다. 이 항목에 쓰인 각 서비스는 컨테이너로
구현되며, 하나의 프로젝트로써 도커 컴포즈에 의해 관리된다.
services:
  my_container_1:
    image: ...
  my_container_2:
    image: ...

  - image : 서비스의 컨테이너를 생성할 때 쓰일 이미지의 이름을 설정한다.
- links :   docker run 명령어의 --link와 같으며, 다른 서비스에 서비스명만으로 접근할 수 있도록 설정한다.
environment : docker run 명령어의 --env, -e 옵션과 동일하다. 서비스 컨테이너 내부에서 사용할
                      환경변수를 지정하며, 딕셔너리나 배열 형태로 사용한다.

                      services:
                        web:
                          environment:
                            - MYSQL_ROOT_PASSWORD = mypassword
                            - MYSQL_DATABASE_NAME = mydb  또는
 
                          environment:
                            MYSQL_ROOT_PASSWORD: mypassword
                            MYSQL_DATABASE_NAME: mydb        이 두개는 같은 말이다!!
command : 컨테이너가 실행될 때 수행할 명령어를 설정하며, docker run 명령어의 마지막에 붙는
                   커맨드와 같다. Dockerfile의 RUN과 같은 배열 형태로도 사용할 수 있다.
                   service:
                     web:
                       image: moon682/composetest:web
                       command: apachectl -DFOREGROUND     또는

                     web:
                       image: moon682/composetest:web
                       command: [apachectl -DFOREGROUND]            
- depends_on : 특정 컨테이너에 대한 의존 관계를 나타내며, 이 항목에 명시된 컨테이너가 먼저 생성된다.
                     다음 예제에서는 web 보다 mysql 컨테이너가 먼저 생성된다.

                     services:
                       web:
                         image: moon682/composetest:web
                         depends_on
                           - mysql
                       mysql:
                         image : moon682/composetest:mysql

// Web하고 Mysql 컨테이너가 있는데, 최 우선적으로 Mysql(DB)를 먼저 생성하고 Web을 생성하라는 뜻!!
   depends_on 
     - mysql             << 때문에 mysql에 의존하는 상태라서 DB를 먼저 생성하라는 뜻이다!!


특정 서비스의 컨테이너만 생성하되, 의존성이 없는 컨테이너를 생성하려면 [--no-deps] 옵션을 사용한다.
docker-compose up --no-deps web
- ports: docker run 명령어의 -p와 같으며, 서비스의 컨테이너를 개방할 포트를 설정한다. 그러나, 단일
           호스트 환경에서 80:80 과 같이 호스트의 특정 포트를 서비스의 컨테이너에 연결하면

           docker-compose scale 명령어로 서비스의 컨테이너의 수를 늘릴 수 없는 단점이 있다.

           services:
             web:
               image: moon682/composetest:web
                 ports:
                   - "8080"                     // 왼쪽 포트는 무작위고, 8080은 컨테이너의 포트이다.
                   - "8081-8085"              //              "             , 8081~8085는 컨테이너의 포트이다.
                   - "80:80"                     // 
- build : 해당 항목에 정의된 도커 파일에서 이미지를 빌드해서 서비스의 컨테이너를 생성한다.
            services:
              web:
                build: ./composetest                            // 도커 파일명
                image: moon682/composetest:web         // 도커 파일명으로 만드는 이미지 명

 

## 과제1. ##

위 예시를 참고로 아파치 웹 서버를 사용하는 컨테이너를 도커 파일로 이미지 빌드와 동시에 컨테이너를 생성하는 yml

파일을 작성하여 실행해 보세요. 포트 넘버는 80:80을 사용.

 

1) composetest(이름 상관X)라는 도커 파일을 만들고, (이미지를 만드는게 목적)

vi test.html

<h1> Welcome to Edu </h1>

 

vi ./composetest

FROM ubuntu:14.04
MAINTAINER moon682
LABEL "purpose"="practice"
RUN apt-get update && apt-get install apache2 -y                          // 이렇게 && 연산을 써야 Layer가 줄어든다 !!
ADD test.html /var/www/html
RUN ["/bin/bash", "-c", "echo hello >> test2.html"]
CMD apachectl -DFOREGROUND
EXPOSE 80  // 포트번호는 어차피 yml 파일에서 해줄 것이므로 필요 없다.

 

2) yml 파일로 도커 파일을 불러와야 한다.

vi ./docker-compose2.yml

version: '3.0'
services:
  web:
    build: ./composetest
    image: moon682/composetest:web
    ports:
      - "80:80"
    command: apachectl -DFOREGROUND


 

3) 접속해보기

docker-compose -f docker-compose2.yml up -d

 

docker images

docker ps

 

 

Host PC]

http://192.168.1.100

아차피는 접근이 된다!!

 

http://192.168.1.100/test2.html

음 ...? 안된다...? T 말로는 test.html이 복사가 안되서 그런다고 한다...! 이건 책에도 없는 즉석고안이라서 찾아봐야 할 것 같다!!
책에도 없는 거라서 한번 찾아봐야 될 것 같다. composetest 말고, Dockerfile로 나중에 만들어보자.



 

## 네트워크 정의 ##

- driver : 도커 컴포즈는 생성된 컨테이너를 위해 기본적으로 브리지 타입의 네트워크를 생성한다.

그러나 YAML 파일의 driver 항목을 정의해서 서비스의 컨테이너가 다른 네트워크를 사용하도록 할 수 있다.

특정 드라이버에 필요한 옵션은 하위 항목인 driver_ops로 전달한다.

version: '3.0'
services:
  myservice:
    image: ubuntu:14.04                                    // 아파치가 설치되어 있지 않아서 아래에 에러가 난다!!
    image: moon682/composetest:web               // 아파치가 설치되어 있는 이미지로 해보자!!
    ports:
      - "80:80"
    command: apachectl -DFOREGROUND             // 만약 ubuntu가 아니라 nginx 라면 아파치는 필요 없음.
    networks:
      - my_network
networks:
  my_network:
    driver: overlay
    driver_opts:
      subnet: "255.255.255.0"
      IPAddress: "192.168.10.2"                             // 10.0.0.2 했다가 자꾸 10.0.1.2 , 10.0.2.2 만들때마다 바뀌어서 바꿈!

 

## 과제 2. 위 내용으로 YAML 파일을 작성, 컴포즈하여 웹 서버에 접속 ##

// 이전에 사용하던 docker-compose2.yml을 삭제 후 기존의 docker-compose에서 편집

vi docker-compose.yml

 

docker-compose up -d

빌드 성공~

 

// IP 확인

docker exec cd5c3c08dee6 ifconfig

docker ps -a

docker inspect cd5c3c08dee6 | grep IPAddr           // inspect ID만 해도 나오긴 하는데 너무 많아서 찾기 힘듦 ㅋㅋ

// 정리... 10 네트워크 대역으로 설정을 했는데 3번째 자리가 자꾸 올라간다 ^^... 1가지 방법을 더해보자.


마지막!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

## 도커 네트워크를 전부 삭제해보자.

docker network prune

vi docker-compose.yml

 

docker-compose up -d

docker network ls

docker network inspect temp_mynetwork | grep IPAddr

 

// 그렇다면 아까처럼 컨테이너를 확인해보자.

docker ps

docker inspect  | grep IPAddr

컨테이너에서는 10.0.0.0 대역을 순차 할당한다.


## 추가적으로 배울 옵션(설정)들 ##

// ipam

vi docker-compose.yml

- ipam IPAM(IP Address Manager)를 위해 사용할 수 있는 옵션으로 subnet, ip 범위 등을 설정할 수 있다.
driver 항목에는 IPAM을 지원하는 드라이버의 이름을 입력한다.


version: '3.0'
services:
  my_new_service2:
    image: moon682/composetest:web
    ports:
      - "80:80"
    command: apachectl -DFOREGROUND
    networks:
      - ipam
networks:
  ipam:
    driver: mydriver
    config
      subnet: 172.20.0.0/16
      ip_range: 172.20.5.0/24
      gateway: 172.20.5.1

 

ipam을 깔아야 한단다 ^^... 그냥 이런게 있구나... 라고 알아두기


// external

 

docker network create moon682_network

 

vi docker-compose.yml

- external YAML 파일을 통해 프로젝트를 생성할 때마다 네트워크를 생성하는 것이 아닌, 기존의 네트워크를 사용하도록
설정한다.

version: '3.0'
services:
  my_new_service3:
    image: moon682/composetest:web
    ports:
      - "80:80"
    command: apachectl -DFOREGROUND
    networks:
      - moon682_network
networks:
  moon682_network:
    external: "true"

 

docker-compose up -d

이렇게 하면 아까처럼 계속 새로운 네트워크가 생성되는게 아니라, 이렇게 기존의 것을 가져다가 쓸 수 있다!!!!! ㅎㅎㅎㅎ


ⓒ 볼륨 정의 - driver: 볼륨을 생성할 때 사용될 드라이버를 설정한다.  어떠한 설정도 하지 않으면 local로 설정되며              사용하는 드라이버에 따라 변경해야 한다.

version: '3.0'
services:
.....
volumes:
  driver: flocker
    driveropts:
      opt: "1"
      opt: 2
- external: 도커 컴포즈는 YAML 파일에서 volumes-from 옵션 등을 사용하면 프로젝트 마다 볼륨을 
             생성한다.  이때 external 옵션을 설정하면 프로젝트를 생성할 때 마다 볼륨을 생성하지 않고                 기존 볼륨을 사용하도록 설정한다.  다음은 myvolume 이라는 볼륨을 web 서비스 컨테이너에               마운트한다.

version: '3.0'
services:
  web:
    image: moon682/composetest:web
    volumes:
      - myvol:/var/www/html
volumes:
  myvol:
    external: "true"

 

docker-compose up -d