[엉박사] 2.3 Docker

impala·2023년 1월 12일
0
post-thumbnail

2.3 Docker

앞에서 언급한 것처럼 이번 프로젝트에서는 한 인스턴스 안에 두개의 서버를 올려야 했기 때문에 환경을 구분하기 위해 도커를 사용했다.

2.3.1 Docker

Docker란 컨테이너 기반 오픈소스 가상화 플랫폼으로 각 프로세스를 격리된 공간(컨테이너)으로 나누어 관리할 수 있도록 도와주는 툴이다. 도커의 역할은 가상머신과 비슷하지만 구현 방법에 있어서 가상머신처럼 OS를 가상화하지 않고 프로세스를 격리하는 방법을 통해 더 가볍게 가상화를 구현하였다.

도커를 사용하기 위해 알아야 하는 가장 중요한 개념은 컨테이너이미지이다.

  • 이미지 : 도커 이미지란 쉽게 말해 컨테이너를 찍어내는 틀로 컨테이너의 환경과 구성정보에 대한 내용이 담겨져있는 파일이다. Dockerfile을 빌드하여 만들거나 Docker Hub에서 이미지파일을 받을 수 있다.
  • 컨테이너 : 도커 이미지를 통해 생성된 실제 인스턴스로 프로세스를 독립된 환경에서 실행하기 위해 실제로 마련된 공간이다.

즉, 컨테이너 안에서 nginx나 django등의 어플리케이션을 실행하기 위해서는 아래의 순서를 따라 컨테이너를 실행하면 된다.

  1. Dockerfile을 통해 이미지파일을 만들거나 Docker Hub에서 이미지파일을 받아온다
  2. 명령어를 통해 이미지파일로부터 컨테이너를 생성, 실행한다

도커환경을 구축하면서 자주 사용되었던 명령어들은 다음과 같다.

# 도커 명령어 구조
$ docker    <대상>      <명령어>
            container   run, start, exec, ps, stop, rm ...
            image       ls, rm, pull, push ...
            network     ls, create, rm ...
            volume      ls, create, rm ...

# 컨테이너 생성
$ docker container create <옵션> --name=<컨테이너 이름> <이미지 이름> <명령어>

# 컨테이너 생성 후 실행
$ docker container run <옵션> --name=<컨테이너 이름> <이미지 이름> <명령어>

# 옵션
# -it : 컨테이너 안에서 터미널 실행 가능
# -p : 포트 포워딩(host port : container port)
# -v : 호스트의 저장공간과 컨테이너 안의 디렉토리를 바인딩(host path: container path)
# -d : 백그라운드에서 컨테이너 실행

# 컨테이너 실행
$ docker container start <컨테이너 이름>

# 컨테이너 접속
$ docker container exec -it <컨테이너 이름> /bin/bash

# 컨테이너 정지
$ docker container stop <컨테이너 이름>

# 컨테이너 삭제
$ docker container rm <컨테이너 이름>

# 실행중인 컨테이너 조회
$ docker container ps

# 전체 컨테이너 조회
$ docker container ps -a

# 이미지파일 조회
$ docker image ls

# 이미지파일 삭제
$ docker image rm <이미지 이름>

# 도커허브에서 이미지파일 받아오기
$ docker image pull <이미지이름>

# 도커허브에 이미지파일 업로드
$ docker image push <도커 레포지토리>/<이미지이름>

이번 프로젝트에서 API서버는 직접 커스터마이징한 이미지파일을, 웹서버는 도커허브에서 제공하는 기본 Nginx 이미지파일을 통해 컨테이너를 생성하여 서버를 구축하였다.

API서버의 컨테이너를 커스터마이징한 이유는 자연어처리 모델을 사용하기 위해서는 python3.8 버전이 설치된 환경에서 Mecab이라는 단어사전을 지정된 위치에 설치해야했는데, 로컬에서도 같은 환경에서 테스트를 하기 위해서 이를 이미지파일로 만들어 관리하는 것이 더 편하다고 생각되었기 때문이다. 컨테이너를 커스터마이징한 구체적인 과정은 다음과 같다.

  1. python3.8버전이 설치된 이미지파일을 도커허브에서 내려받아 컨테이너를 만든다.
    $ docker pull python:3.8-buster
    $ docker run -dit --name=python3.8_linux python:3.8-buster
  2. 컨테이너에 접속해 API서버환경을 구축한다(Mecab설치, django 및 DRF설치)
    $ docker exec -it python3.8_linux /bin/bash         (컨테이너 외부)
    # pip install django djangorestframework            (컨테이너 내부)
  3. 컨테이너를 종료하고 이미지파일로 빌드한다
    $ docker commit python3.8_linux iimpala/dr_eung

이후 환경변수 설정 및 docker-compose툴 사용을 위해 Dockerfile로 다시 이미지파일을 빌드하였다.

# Dockerfile
FROM iimpala/dr_eung

ENV DJANGO_SECRET_KEY "**********"

WORKDIR /srv/docker-server

ADD . /srv/docker-server

EXPOSE 8000
$ docker build <Dockerfile명> <Dockerfile경로>

Dockerfile이란 도커 이미지를 만들기 위해 필요한 문서로, 컨테이너를 구성하는 방법을 적은 파일이다. Dockerfile에 사용되는 주요 명령어는 아래와 같다.

명령어설명
FROMbase image를 지정
ADD파일이나 폴더 추가
RUN이미지를 빌드할 때 실행할 명령
CMD컨테이너를 실행할 때 실행할 명령
ENV환경변수 정의
VOLUME컨테이너의 외부에 데이터를 저장할 경로를 설정
EXPOSE통신에 사용할 포트를 설정
WORKDIR명령어를 실행하는 디렉토리를 설정

2.3.2 docker-compose

docker-compose는 여러개의 도커 컨테이너를 쉽게 관리하기 위한 툴이다. docker-compose를 사용하면 여러 컨테이너의 실행순서나 옵션, 명령어등을 매번 치지 않고도 손쉽게 매번 동일하게 실행시킬 수 있다.

docker-compose는 컨테이너를 실행시키는 데 필요한 정보를 docker-compose.yml이라는 문서에 작성해두고 docker-compose의 명령을 통해 문서에 적힌 내용을 실행시킨다. 다음은 이번 프로젝트에 사용된 docker-compose.yml파일의 내용이다.

version: "3"

services:
        # 서비스 이름
        nginx:
                image: nginx:latest             # 이미지파일(docker hub)
                container_name: nginx_release   # 컨테이너 이름
                ports:                          # 포트포워딩 정보
                        - "80:80"
                        - "443:443"
                restart: always
                volumes:                        # 볼륨 마운트 정보
                        - ./frontend:/frontend
                        - ./static/:/data/static/
                        - ./nginx:/etc/nginx/conf.d
                        - ./data/certbot/conf:/etc/letsencrypt
                        - ./data/certbot/www:/var/www/certbot
                depends_on:                     # 먼저 실행할 컨테이너 설정
                        - django
                
                # 컨테이너 실행 후 컨테이너 안에서 실행할 명령어
                command: "/bin/sh -c 'while :; do sleep 6h & wait $${!}; nginx -s reload; done & nginx -g \"daemon off;\"'"

        certbot:
                image: certbot/certbot
                restart: unless-stopped
                volumes:
                        - ./data/certbot/conf:/etc/letsencrypt
                        - ./data/certbot/www:/var/www/certbot
                entrypoint: "/bin/sh -c 'trap exit TERM; while :; do certbot renew; sleep 12h & wait $${!}; done;'"

        django:
                build:                              # 이미지파일(Dockerfile)
                        context: ./docker-server    # Dockerfile 경로
                        dockerfile: Dockerfile      # Dockerfile 이름
                container_name: django_release
                restart: always
                command: bash -c "
                        python manage.py makemigrations
                        && python manage.py migrate
                        && gunicorn config.wsgi:application --bind 0.0.0.0:8000
                        "
                volumes:
                        - ./docker-server:/srv/docker-server
                expose:                             # 컨테이너 간 통신에 사용할 포트
                        - "8000"
                

docker-compose.yml에 적힌 작업은 아래의 명령어로 실행하고 종료한다.

# docker-compose 작업 실행
$ docker-compose up

# docker-compose 작업 종료
$ docker-compose down

소스코드를 서버에 올린 후에도 수정이 잦아서 서버를 내렸다가 다시 켤 일이 많았는데 도커와 도커 컴포즈를 활용하여 간단한 docker-compose up/down 명령어만으로 손쉽게 서버를 관리할 수 있었다.

0개의 댓글