[Docker 이해하기] 7. 여러 컨테이너의 운용 관리

Titu·2021년 9월 12일
1

Docker

목록 보기
6/6
post-custom-banner

Docker에서 작동하는 웹 애플리케이션을, 제품 환경에서 운용할 때는 애플리케이션 서버, 로그 서버, 프록시 서버 등과 같이 여러 개의 컨테이너들을 연계하여 작동시킨다.

이 장에서는 여러 개의 컨테이너를 운용 관리하는 법을 살펴보기로 한다.

7.1 여러 컨테이너 관리의 개요

웹 시스템의 실행 환경은 웹 서버, 프록시 서버 등과 같이 역할이 다른 여러 개의 서버를 연계하여 작동시키는 것이 일반적이다.

웹 3계층 시스템 아키텍처

웹 3계층 아키텍처는 웹 애플리케이션의 대표적인 인프라 아키텍처 중 하나로, 웹 시스템의 서버들을 역할별로 프론트 서버, 애플리케이션 서버, 데이터베이스 서버 3개로 나누는 것을 의미한다.
대부분의 웹 시스템은 웹 3계층 아키텍처 구성을 취하고 있다. 논리적인 분할이므로 부하가 적은 시스템에서는 동일한 노드 상에서 실행하는 것도 가능하며, 클라우드 시스템 등에서 실행시킬 때는 부하에 따른 오토스케일 기능을 사용하는 것이 좋다.

프론트 서버

클라이언트의 웹 브라우저가 보낸 HTTP 요청을 받아, HTTP 응답을 반환하는 서버 기능을 가진다. 이 서버 기능은 웹 프론트 서버 또는 웹 서버라고 한다.

  • 웹 서버의 기능은 미들웨어로 구축하는 경우도 있으며, 제품군은 오픈소스인 Nginx, 마이크로소프트의 IIS 등이 있다.
  • 요청의 처리가 주요 업무이므로 부하가 높은 경우는 스케일러블하게 처리 대수를 늘리고, 로드밸런서와 같은 기기를 사용하여 부하분산을 한다.

애플리케이션 서버

애플리케이션 서버는 업무 처리를 실행하는 서버다.

  • 결제 처리, 수주 처리 등 애플리케이션의 비즈니스 로직을 실행하는 프로그램의 실행 환경이 된다.
  • 애플레케이션 서버 기능도 프론트 서버 기능처럼 미들웨어로 구축하는 경우가 있다.

데이터베이스 서버

데이터베이스 서버는 영구 데이터를 관리하기 위한 서버이다.

  • 애플리케이션의 처리 실행에서 발생하는 영구 데이터는 RDBMS나 NoSQL 기능을 갖고 있는 미들웨어에서 관리된다.
    • 관계형 데이터베이스인 RDBMS(Relational Database Management System)의 제품군으로는 오픈소스인 MySQL, PostgreSQL과 오라클의 Oracle database 등이 있다.
    • NoSQL은 RDBMS와는 다른 새로운 방식을 총칭하는 것이며, 병렬분산처리나 유연한 스키마 설정이 특징이다. 주요 방식으로는 KVS(key-value store)나 document database등이 있다. 대량의 데이터 축적이나 병렬처리가 특기이기 때문에 많은 사용자의 액세스를 처리할 필요가 있는 온라인 시스템 등에서 널리 이용되고 있다. 제품군으로는 오픈소스인 Redis, MongoDB가 있다.
  • 영구 데이터는 높은 가용성이 요구되기 때문에 클러스터링과 같은 기술로 다중화하는 경우가 많다. 또한 만일의 장애에 대비하여 데이터의 백업이나 원격지 보관 등과 같은 대책도 필요하다.
  • 데이터베이스를 조작하는 처리는 부하가 걸리는 경우도 있으므로 시스템 전체의 병목 부분이 되는 경우가 있다. 그래서 운용 상황에 따라 OS나 미들웨어의 파라미터 설정의 변경과 같은 퍼포먼스 튜닝이 필요하다.

컨테이너에서 영구데이터를 다룰 때 주의점

Docker 컨테이너는 웹 프론트 서버와 같이 트래픽의 증감 등에 맞춰 필요할 때 실행하고 필요 없어지면 파기시키는 일회성 운용에 적합하다. 한편 데이터베이스에는 영구적으로 관리해야하는 중요한 정보가 저장되어 있기 때문에, 쉽게 생성하고 삭제할 수 있는 컨테이너에 영구 데이터를 저장하는 것은 적합하지 않을 수 있다. 따라서, 어떤 시스템을 컨테이너에서 운용하는 것이 적절한지 고민해볼 필요가 있다.

Docker Compose

웹 시스템에서는 여러 개의 Docker 컨테이너가 협력하며 작동한다. Docker Compose는 여러 컨테이너를 모아서 관리하기 위한 툴이다. Docker Compose는 'docker-compose.yml'라는 파일에 컨테이너의 구성 정보를 정의함으로써 동일 호스트 상의 여러 컨테이너를 일괄적으로 관리할 수 있다.

  • Compose 정의 파일은 웹 애플리케이션의 의존관계(데이터베이스, 큐, 캐시, 애플리케이션 등)를 모아서 설정할 수 있으며, 이 정의 파일을 바탕으로 docker-compose 명령을 실행하면 여러 개의 컨테이너를 모아서 시작하거나 정지할 수 있다.
  • 또한, 컨테이너의 구성 정보를 YAML 형식의 파일로 관리할 수 있으므로 CI/CD 프로세스에 있어서 자동 테스트를 할 때의 환경 구축에도 그대로 이용할 수 있다.

7.2 웹 애플리케이션을 로컬에서 움직여 보자

Compose 구성 파일의 작성

# 샘플 애플리케이션 클론
$ git clone https://github.com/asashiho/dockertext2
$ cd dockertext2/chap07/

# Compose 정의 파일 확인
$ cat docker-compose.yml
version: '3.3'
services:
  # WebServer config
  webserver:
    build: .		#현재 디렉토리에 이미지 빌드
    ports:
     - "80:80"		#외부에 80번 포트공개
    depends_on:
     - redis		#redis 서비스에 의존

  # Redis config
  redis:
    image: redis:4.0

여러 Docker 컨테이너 시작

# 샘플 애플리케이션의 컨테이너 시작
$ docker-compose up

# (다른 터미널에서 실행) 가동중인 컨테이너 확인
$ docker-compose ps

http://localhost:80 에 접속하면 샘플 애플리케이션이 정상적으로 시작된걸 확인할 수 있다.

여러 Docker 컨테이너 정지

# 컨테이너 정지
$ docker-compose stop

# 리소스 삭제
$ docker-compose down

7.3 Docker Compose를 사용한 여러 컨테이너의 구성 관리

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

# Compose 정의 파일의 예

# 버전을 지정
version: "3"

# 서비스 정의 
services:
  webserver:
    image: ubuntu
    ports:
      - "80:80"
    networks:
      - webnet
  
  redis:
    image: redis
    networks:
      - webnet

# 네트워크 정의
networks:
  webnet:
  
# 데이터 볼륨 정의
volumes:
  data-volume:

이미지 지정

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

  • 베이스 이미지는 로컬 환경에 있으면 그것을 사용하고, 없으면 Docker Hub에서 자동으로 다운로드 된다.
  • 이미지의 태그를 지정하지 않은 경우는 최신 버전(latest)이 다운로드 된다.
# 이미지의 태그를 지정하지 않는 경우
services:
webserver:
  image: ubuntu
  
# 이미지의 태그를 지정한 경우
services:
webserver:
  image: asashiho/dockersample:1.0

이미지 빌드(build)

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

# build 지정
services:
  webserver:
    build: . # docker-compose.yml이 있는 디렉토리를 현재 디렉토리로 했을 때의 Dockerfile의 위치를 지정한다.
# 임의의 이름으로 된 Dockerfile 빌드 시
services:
  webserver:
    build:
      context: /data
      dockerfile: Dockerfile-alternate
# Docker 이미지 빌드시 인수 지정
services:
  webserver:
    build:
      args:
        projectno: 1
        user: asa
# docker-compose.yml 안에서 지정한 Dockerfile이 자동으로 빌드되어 컨테이너가 생성
$ docker-compose up --build

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

# 링크 지정
links:
  - logserver
  - logserver:log01		# 서비스명:앨리어스명으로 지정할 수도 있다.

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

컨테이너가 공개하는 포트는 ports로 지정한다.

  • 'host 머신의 포트 번호:컨테이너의 포트 번호'로 지정하거나, '컨테이너의 포트 번호'로 지정한다. 후자의 경우에 host 머신의 포트는 랜덤한 값으로 설정된다.
# 공개 포트 지정
ports:
  - "3000"
  - "8000:8000"
  - "49100:22"
  - "127.0.0.1:8001:8001"

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

  • 로그서버와 같이 호스트 머신에서 직접 액세스하지 않고 웹 애플리케이션 서버 기능을 갖고 있는 컨테이너를 경유해서만 액세스하고 싶은 경우 등에 사용한다.
# 컨테이너 내부에만 공개하는 포트 지정
expose:
  - "3000"
  - "8000"

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

여러 서비스의 의존관계를 정의할 때는 depends_on을 지정한다.

# 의존관계 지정
services:
  webserver:
    build: .
    depends_on:
      - db
      - redis
  redis:
    image: redis
  db:
    image: postgress

webserver 컨테이너를 시작하기 전에 db 컨테이너와 redis 컨테이너를 시작하고 싶을 때는 위와 같이 정의한다. 단, depends_on은 컨테이너의 시작 순서만 제어할 뿐 컨테이너상의 애플리케이션이 이용 가능해질 때까지 기다리고 제어하지는 않으므로 주의해야 한다.

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

컨테이너 안의 환경변수를 지정할 때는 environment를 지정한다.

# 환경변수 지정

# 배열 형식으로 지정
environment:
  - HOGE=fuga
  - FOO
  
# 해시 형식으로 지정
environment:
  HOGE: fuga
  FOO:

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

# 환경변수 파일 읽어들이기
env_file: envfile

# 여러 개의 환경변수 파일 읽어 들이기
env_file:
  - ./envfile1
  - ./app/envfile2
  - /tmp/envfile3

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

Docker Compose로 생성되는 컨테이너에 이름을 붙일 때는 container_name을 지정한다. 단, Docker 컨테이너명은 고유해야하므로 커스텀명을 지정하면 여러 컨테이너로 스케일할 수 없어진다.

# 컨테이너명 지정
container_name: web-container

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

# 컨테이너 라벨 설정

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

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

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

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

# 볼륨 지정
volumes:
  - /var/lib/mysql
  - cache/:/tmp/cache

# 읽기 전용 볼륨 지정
volumes:
  - ~/configs:/etc/configs/:ro
  
# 볼륨 마운트 지정
volumes_from:
  - log		#log라는 컨테이너로 마운트할 때

7.4 Docker Compose를 사용한 여러 컨테이너의 운용

Docker compose의 버전 확인

Docker Compose는 Docker for Mac 또는 Docker for Windows에 미리 설치되어 있으며, docker-compose --version을 통해 버전을 확인할 수 있다.

여러 컨테이너 생성(up)

  • docker-compose up [옵션] [서비스명]
    • -d 옵션을 지정하면 백그라운드에서 실행한다.
    • --no-deps 옵션을 지정하면 링크 서비스를 시작하지 않는다
    • --build 옵션을 지정하면 이미지를 빌드한다.
    • --no-build 옵션을 지정하면 이미지를 빌드하지 않는다.
    • -t, --timeout 옵션을 지정하면 컨테이너의 타임아웃을 초로 지정(기본 10초)한다.
    • --scale [서비스명=수] 를 지정하면 서비스 수를 지정한다.
# 여러 컨테이너의 일괄 생성 및 시작
$ docker-compose up

# 여러 컨테이너를 백그라운드로 시작
$ docker-compose up -d

# Docker 이미지 빌드
$ docker-compose up --build

# 컨테이너 개수 지정
$ docker-compose up --scale server_a=10 --scale server_b=20

여러 컨테이너 확인(ps/logs)

  • docker-compose ps : 컨테이너 목록 확인
  • docker-compose logs : 컨테이너 로그 확인
# 여러 컨테이너의 상태 확인
$ docker-compose ps
NAME                 COMMAND                  SERVICE             STATUS              PORTS
chap07_redis_1       "docker-entrypoint.s…"   redis               running             6379/tcp
chap07_webserver_1   "python /opt/imagevi…"   webserver           running             0.0.0.0:80->80/tcp, :::80->80/tcp

# 컨테이너 ID 확인
$ docker-compose ps -q
05f714da81b84f598e2b0ef745b8a154435247f72da5aca2095897d077df2131
e671cb389faf0f26a0417beb6b9686ccbdb5c5a46e12755a19d60eb494d369ef

# Docker 명령을 사용한 컨테이너 확인
$ docker container ls
CONTAINER ID   IMAGE              COMMAND                  CREATED              STATUS              PORTS
                NAMES
e671cb389faf   chap07_webserver   "python /opt/imagevi…"   About a minute ago   Up About a minute   0.0.0.0:80->80/tcp, :::80->80/tcp   chap07_webserver_1
05f714da81b8   redis:4.0          "docker-entrypoint.s…"   About a minute ago   Up About a minute   6379/tcp
                chap07_redis_1

# Docker 명령을 사용한 로그 확인
$ docker-compose logs

컨테이너에서 명령 실행(run)

  • docker-compose run [컨테이너명][명령] : Docker Compose로 시작한 컨테이너에서 임의의 명령을 실행하고 싶을 때
# 컨테이너에서 명령 실행
$ docker-compose run redis /bin/bash
root@aa4b78e287fc:/data#

여러 컨테이너에서 시작/정지/재시작(start/stop/restart)

Docker Compose를 사용하면 여러 개의 서비스를 일괄적으로 시작, 정지, 재시작 할 수 있다.

$ docker-compose start

$ docker-compose stop

$ docker-compose restart

# 특정 컨테이너 재시작
$ docker-compose restart redis
```shell

### 여러 컨테이너 일시 정지/재개(pause/unpause)
Docker Compose를 사용하면 여러 개의 서비스를 일괄적으로 일시정지, 재개할 수 있다.
```shell
$ docker-compose pause

$ docker-compose unpause

서비스의 구성 확인(port/config)

  • docker-compose port [옵션] [서비스명]
    • -protocol=proto 옵션을 통해 프로토콜을 지정할 수 있다.
    • --index=index 옵션을 통해 컨테이너의 인덱스 수를 지정할 수 있다.
# 공개 포트 확인
$ docker-compose port webserver 80
0.0.0.0:80
  • docker-compose config: Compose의 구성 확인

여러 컨테이너 강제 정지/삭제(kill/rm)

  • docker-compose kill: 실행중인 컨테이너를 강제로 정지
    • 이 명령을 사용하면 컨테이너에 시그널을 송신할 수 있다. 시그널은 프로세스 간의 연락을 주고받기 위한 장치로 Linux 커널에 내장되어 있으며, 실행 중인 프로세스의 처리를 멈추고 다른 프로세스를 처리하고 싶은 경우나 프로세스를 강제 종료시키고 싶을 때 사용한다.
    • 옵션을 지정하지 않고 실행하면 SIGKILL이 전송된다. SIGKILL은 프로세스를 강제로 종료시키는 것이다.
# 컨테이너에 시그널 송신
$ docker-compose kill -s SIGINT
  • docker-compose rm: 생성한 여러 컨테이너를 삭제
    • -f옵션을 지정하면 삭제 확인 메시지를 표시하지 않고 강제로 삭제한다
# 여러 컨테이너 일괄 삭제
$ docker-compose rm

여러 리소스의 일괄 삭제(down)

실행중인 컨테이너를 정지시키고, Docker 이미지, 네트워크, 데이터 볼륨을 일괄적으로 삭제하는 명령이다.

  • docker-compose down [옵션]
    • --rmi all 옵션을 지정하면 모든 이미지를 삭제한다.
    • --rmi local 옵션을 지정하면 커스텀 태그가 없는 이미지만 삭제한다.
    • -v, --volumes 옵션을 지정하면 Compose 정의 파일의 데이터 볼륨을 삭제한다.
# 여러 이미지 삭제
$ docker-compose down --rmi all

본문은 'Asa Shijo, <완벽한 IT 인프라 구축을 위한 Docker>, 정보문화사(2020)' 를 참고하여 정리한 글입니다.

[참고: 완벽한 IT 인프라 구축을 위한 Docker]

profile
This is titu
post-custom-banner

0개의 댓글