Notice
Recent Posts
Recent Comments
Link
«   2024/12   »
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30 31
Archives
Today
Total
관리 메뉴

nomad-programmer

[DevOps/Docker] Docker Compose를 사용한 여러 컨테이너의 구성 관리 본문

DevOps/Docker

[DevOps/Docker] Docker Compose를 사용한 여러 컨테이너의 구성 관리

scii 2020. 12. 5. 02:08

여러 컨테이너를 실행시킬 때 컨테이너마다 구성이나 시작/정지를 관리하자면 운용이 번잡해진다.

여러 컨테이너를 일괄적으로 관리할 수 있는 'Docker Compose' 의 구성 관리 파일인 'docker-compose.yml' 을 작성하는 방법에 대해 알아보자.

docker-compose.yml 파일의 개요

docker-compose는 'docker-compose.yml' 이라는 Compose 정의 파일에 시스템 안에서 가동하는 여러 서버들의 구성을 모아서 정의한다. 이 정의 파일은 YAML 형식으로 기술한다.

YAML

YAML은 구조화된 데이터를 표현하기 위한 데이터 포맷이다. YAML은 Python과 같이 들여쓰기로 데이터의 계층 구조를 나타낸다. 들여쓰기는 탭이 아닌 스페이스를 사용한다. 누가 써도 읽기 쉽기 때문에 설정 파일 등에 많이 이용된다.
YAML에서는 데이터의 맨 앞에 '-' 를 붙이면 배열을 나타낼 수 있다. '-' 다음에는 반드시 스페이스를 넣어야 한다. (배열의 나타낼 수 있는 또 다른 방식으로는 ['a', 'b', ...])

Compose 정의 파일에는 여러 컨테이너의 설정 내용을 모아서 하나의 파일에 기술한다. 확장자는 '.yaml' 이어도 상관없다. 이 Compose 정의 파일에는 관리하고 싶은 컨테이너의 서비스 (services:), 네트워크 (networks:), 볼륨 (volumes: ) 을 정의한다.

또한 Compose 정의 파일은 버전에 따라 기술할 수 있는 항목이 다르다는 것을 유념해야 한다.

버전을 지정할 때는 Compose 정의 파일의 맨 앞에 다음과 같이 정의한다.

version: '3.8'

버전을 명시적으로 지정하지 않았을 때는 '1.0' 으로 작동한다.

여러 개의 Compose 정의 파일이나 확장 서비스를 사용하는 경우는 각 파일에서 동일한 버전을 사용해야 하므로 주의해야 한다.

현재 지정할 수 있는 Compose 정의 파일의 버전과 DockerEngine의 버전과의 관계는 아래의 링크를 통해 볼 수 있다.

docs.docker.com/compose/compose-file/

 

Compose file version 3 reference

 

docs.docker.com

다음의 예는 webserver 라는 서비스와 redis 라는 이름의 서비스를 만들고 들여쓰기를 하여 각각의 컨테이너의 상세 정보를 설정하고 있다. 

# docker-compose file format version
version: '3.8'

# service
services:
  webserver:
    image: ubuntu
    ports:
      - '80:80'
    networks:
      - webnet

  redis:
    image: redis
    networks:
      - webnet

# network
networks:
  webnet:

# volume
volumes:
  data-volume:

이미지 지정 (image)

Docker 컨테이너의 바탕이 되는 베이스 이미지를 지정하려면 image 를 사용한다. image 에는 이미지의 이름 또는 이미지 ID 중 하나를 지정한다.

위의 예에서는 webserver라는 이름의 이미지의 베이스 이미지를 'ubuntu'로 지정하고 있다. 베이스 이미지로 로컬 환경에 있으면 그것을 사용하고, 로컬 환경에 없으면 Docker Hub로부터 자동으로 다운로드한다.

이미지 태그를 지정하지 않은 경우 최신 버전(latest)이 다운로드 된다.

제품 환경에서 사용할 때는 태그를 지정하여 버전을 고정시켜 두는 것이 안전하다.

공식 이미지뿐만 아니라 Docker Hub에 공개되어 있는 이미지는 모두 지정할 수 있다. 다음의 예는 Docker Hub의 test라는 사용자가 작성한 'dockersample' 의 버전 1.0 이미지를 베이스 이미지로 지정하고 있다.

// 이미지의 태그를 지정한 경우
services:
  webserver:
    image: test/dockersample:1.0

이미지 빌드 (build)

이미지의 작성을 Dockerfile에 기술하고 그것을 자동으로 빌드하여 베이스 이미지로 지정할 때는 build를 지정한다. build에는 Dockerfile의 파일 경로를 지정한다.

예를 들면 sample이라는 디렉토리 안에 docker-compose.yml과 Dockerfile을 다음과 같이 배치한다.

sample
    docker-compose.yml
    Dockerfile

build에는 docker-compose.yml이 있는 디렉토리를 현재 디렉토리로 했을 때의 Dockerfile의 위치를 지정한다.

// build 지정

version: '3.3'

services:
  webserver:
    # . 은 현재 디렉토리를 지칭한다.
    build: .

그 다음 Dockerfile을 준비한다. 작동 확인을 위해 FROM 명령으로 ubuntu의 베이스 이미지를 지정했다.

FROM ubuntu:latest

이 상태에서 다음과 같은 docker-compose 명령을 실행하면 docker-compose.yml 파일 안에서 지정한 Dockerfile이 자동으로 빌드되어 컨테이너가 생성된다.

// 컨테이너 생성
$ docker-compose up --build

Creating network "sample1_default" with the default driver
Building webserver
Step 1/1 : FROM ubuntu:latest
latest: Pulling from library/ubuntu
...

임의의 이름으로 된 Dockerfile을 빌드할 때는 'dockerfile'을 지정한다. 이 때 Dockerfile이 있는 디렉토리의 경로나 Git 저장소의 URL을 'context'로 지정한다.

다음의 예에서는 '/data' 에 저장되어 있는 'Dockerfile-alternate' 라는 이름의 Dockerfile을 빌드하고 있다. 또한 파일 경로는 상대 경로로도 지정할 수 있다.

// Dockerfile과 컨텍스트 지정

services:
  webserver:
    build:
      context: /data
      dockerfile: Dockerfile-alternate

또한 Docker 이미지를 빌드할 때에 인수를 args로 지정할 수 있다. 다음의 예에서는 projectno=1, user=scii 라는 값을 빌드 시의 변수로 전달하고 있다. bool 연산자 (true/false/yes/no) 를 사용하는 경우는 따옴표로 둘러싸야 한다. 또한 변수의 값은 Docker Compose 를 실행하는 머신 위에서만 유효하다.

// 빌드 시의 인수 지정

services:
  webserver:
    build:
      args:
        projectno: 1
        user: scii

컨테이너 안에서 작동하는 명령 지정 (command / entrypoint)

컨테이너에서 작동하는 명령은 command로 지정한다. 다음은 베이스 이미지에서 지정되어 있을 때는 그 명령을 덮어쓴다.

// 컨테이너 안에서 작동하는 명령 지정

command: /bin/bash

또한 entrypoint를 덮어쓸 수도 있다. entrypoint는 다음과 같이 나열할 수 있다.

// entrypoint 지정

entrypoint:
  - php
  - -d
  - memory_limit=-1

컨테이너 간 연결 (links)

다른 컨테이너에 대한 링크 기능을 사용하여 연결하고 싶을 때는 links 를 사용하여 연결할 컨테이너명을 설정한다. 

예를 들어 logserver라는 이름의 컨테이너와 링크시키고 싶을 때는 다음과 같이 지정한다. 또한 컨테이너명과는 별도로 앨리어스명을 붙이고 싶을 때는 '서비스명:앨리어스명' 으로 지정한다.

// 링크 지정

links:
  - logserver
  - logserver:log01

또한 서비스 간의 의존관계는 depends_on 을 사용하여 지정할 수 있다. 

depends_on 은 서비스를 시작하는 순서도 지정할 수 있다.

컨테이너 간 통신 (ports / expose)

컨테이너가 공개하는 포트는 ports로 지정한다. '호스트 머신의 포트 번호:컨테이너의 포트 번호' 를 지정하거나, 컨테이너의 포트 번호만 지정한다. 또한 컨테이너의 포트 번호만 지정한 경우는 호스트 머신의 포트는 랜덤한 값으로 설정된다.

YAML은 xx:yy 형식을 시간으로 해석하므로 포트 번호를 설정할 때는 반드시 다음의 예와 같이 겹따옴표로 둘러싸서 문자열로 정의해야 한다.

// 공개 포트 지정

ports:
  - "3000"
  - "8000:8000"
  - "50522:22"
  - "127.0.0.1:8001:80001"

호스트 머신에 대한 포트를 공개하지 않고 링크 기능을 사용하여 연결하는 컨테이너에게만 포트를 공개할 때는 expose를 지정한다.

로그 서버와 같이 호스트 머신에서 직접 액세스하고 않고 웹 애플리케이션 서버 기능을 갖고 있는 컨테이너를 경유해서만 액세스하고 싶은 경우 등에 사용한다.

// 컨테이너 내부에만 공개하는 포트 지정

expose:
  - "3000"
  - "8000"

서비스의 의존관계 정의 (depends_on)

여러 서비스의 의존관계를 정의할 때는 depends_on 을 지정한다. 예를 들어 webserver 컨테이너를 시작하기 전에 db 컨테이너와 redis 컨테이너를 시작하고 싶을 때는 다음과 같이 정의한다. depends_on 을 사용하여 webserver 컨테이너가 db 컨테이너와 redis 컨테이너에 각각 의존하고 있다는 것을 정의한다.

// 의존관계 지정

services:
  webserver:
    build: .
    depends_on:
      - db
      - redis
    
  redis:
    image: redis
    
  db:
    image: postgre

여기서 주의할 점은 depends_on 은 컨테이너의 시작 순서만 제어할 뿐 컨테이너상의 애플리케이션이 이용 가능해 질 때까지 기다리고 제어를 하지 않는다는 점이다. 즉, 의존관계에 있는 데이터베이스 서비스의 준비가 끝날 때까지 기다리는 것은 아니기 때문에 애플레케이션 측에서 이에 대한 대책을 세울 필요가 있다.


컨테이너 환경변수 지정 (envrionment / env_file)

컨테이너 안의 환경변수를 지정할 때는 environment 를 지정한다. YAML 배열 형식 또는 해시 형식 중 하나로 변수를 지정한다.

// 환경변수 지정

# 배열 형식으로 지정
environment:
  - FOO=bar
  - UNAME=scii
  
# 해시 형식으로 지정
environment:
  FOO=bar
  UNAME=scii

설정하고 싶은 환경변수의 수가 많을 때는 다른 파일에서 환경변수를 정의하고 그 파일을 읽어 들일 수도 있다. 

환경변수 파일을 읽어 들을 때는 env_file 을 지정한다.

다음과 같이 docker-compose.yml과 동일한 디렉토리에 envfile 이라는 이름의 파일을 작성한다.

sample
    docker-compose.yml
    envfile

이것을 docker-compose.yml 파일에서 읽어 들이려면 다음과 같이 지정한다.

// 환경변수 파일 읽어 들이기

env_file: envfile

또한 환경변수를 정의한 파일은 여러 개를 읽어 들일 수도 있다. 파일의 지정은 다음과 같은 YAML 배열 형식으로 지정한다. 파일의 경로 지정은 상대 경로든 절대 경로든 상관 없다.

다음의 예에서는 현재 디렉토리의 envfile1과 현재 디렉토리 아래의 app 디렉토리 안에 있는 envfile2와 /tmp에 있는 envfile3, 이 세 개의 환경변수 파일을 읽어 들이고 있다.

// 여러 개의 환경변수 파일 읽어 들이기

env_file:
  - ./envfile1
  - ./app/envfile2
  - /tmp/envfile3

 

애플리케이션 안에서 사용하는 API 키와 같은 비밀정보의 관리는 컨테이너 오케스트레이션 툴의 기능을 사용하는 것이 좋다.

컨테이너 정보 설정 (container_name / labels)

Docker Compose 로 생성되는 컨테이너에 이름을 붙일 때는 container_name 을 지정한다. 

예를 들어 webserver라는 이름으로 정의한 컨테이너에 web-container 라는 이름을 붙일 때는 다음과 같이 docker-compose.yml 을 작성한다. 

단, Docker 컨테이너명은 고유해야하므로 사용자정의 이름을 지정하면 여러 컨테이너로 스케일할 수 없어진다.
// 컨테이너명 지정

container_name: web-container

컨테이너에 라벨을 붙일 때는 labels를 지정한다. 

다음과 같이 여러 개의 라벨을 붙일 때는 YAML 배열 또는 해시 형식 중 하나로 변수를 지정한다.

// 컨테이너 라벨 설정

# 배열 형식으로 지정
labels:
  - "com.example.description=Accounting webapp"
  - "com.example.department=Finance"
  
# 해시 형식으로 지정
labels:
  com.example.description: "Accounting webapp"
  com.example.department: "Finance"

설정한 라벨을 확인할 때는 docker-compose config 명령을 사용한다.


컨테이너 데이터 관리 (volumes / volumes_from)

컨테이너에 볼륨을 마운트할 때는 volumes를 지정한다. 다음의 예에서는 /var/lib/mysql 을 마운트하고 있다. 호스트 측에서 마운트할 경로를 지정하려면 '호스트의 디렉토리 경로:컨테이너의 디렉토리 경로' 를 지정한다.

// 볼륨 지정

volumes:
  - /var/lib/mysql
  - cache/:/tmp/cache

또한 다음과 같이 볼륨 지정 뒤에 ro를 지정하면 볼륨을 읽기 전용으로 마운트할 수 있다. 설정 파일이 저장된 볼륨 등과 같이 쓰기를 금지하고 싶은 경우에 지정해야 한다.

// 읽기 전용 볼륨 지정

volumes:
  - ~/configs:/etc/configs/:ro

다른 컨테이너로부터 모든 볼륨을 마운트할 때는 volumes_from 에 컨테이너명을 지정한다.

예를 들어 log라는 이름의 컨테이너로 마운트할 때는 다음과 같이 설정한다.

// 볼륨 마운트 지정

volumes_from:
  - log
Comments