프로젝트 소개


안녕하세요 이번 프로젝트는 42서울에서 docker에 대해 배우고 활용해보는 프로젝트입니다. docker에 대해서는 다른 글에서 다루었으니 참고하시면 좋을 것 같습니다.

프로젝트는 다음과 같이 진행됩니다.

세 개의 컨테이너를 띄우고 각 컨테이너 안에 NGINX, WordPress, MariaDB를 돌려놓습니다. 그 후 각 컨테이너를 docker network로 연결하고, NGINX와 제 컴퓨터를 연결하여 특정 포트로 들어가면 wordpress 화면을 받아올 수 있도록 합니다.



프로젝트 진행


그러면 어떻게 컨테이너끼리 연결되어 하나의 서비스가 구성되었는지, 각 컨테이너는 어떻게 설정되어있는지 확인해보면서 프로젝트가 완성되었는지 확인해보겠습니다.

Docker-compose 구성

이렇게 멀티 컨테이너 환경에서 중요한 것은 역시 docker compose이겠습니다. docker compose 파일에서 각 컨테이너들이 어떻게 만들어질지 정할 수 있고, 어떻게 연결될지 정할 수 있기때문입니다.

제 docker compose 파일은 아래와 같이 구성되어있습니다.

version: '3.8'

volumes:
  wp:
    driver: local
    driver_opts:
      type: none
      o: bind
      device: /home/jukim2/data/wordpress
  db:
    driver: local
    driver_opts:
      type: none
      o: bind
      device: /home/jukim2/data/mariaDB
    
networks:
  inception:

services:
  nginx:
    image: nginx
    build: srcs/nginx
    ports: 
      - "443:443"
    volumes:
      - "wp:/var/www/html"
    networks:
      - inception
    depends_on:
      - wordpress

  wordpress:
    image: wordpress
    build: srcs/wordpress
    expose:
      - 9000
    volumes:
      - "wp:/var/www/html"
    networks:
      - inception
    env_file:
      - .env
    depends_on:
      - mariadb

  mariadb:
    image: mariadb
    build: srcs/mariaDB
    volumes:
      - "db:/var/lib/mysql"
    expose:
      - 3306
    env_file:
      - .env
    networks:
      - inception

Volume

먼저 맨 위의 volume파트 중 wp를 살펴보곘습니다.

volumes:
  wp:
    driver: local
    driver_opts:
      type: none
      o: bind
      device: /home/jukim2/data/wordpress

docker compose Volume 글을 참고하면 docker compose 파일에서 volume을 어떻게 설정해야하는지 대략적으로 알 수 있습니다.

wp는 volume의 이름이고 이 volume에는 driver를 명시해주어야 합니다. volume driver는 컨테이너의 데이터를 어떻게 보관하고 공유할지 구성합니다.

local은 호스트의 파일 시스템에 데이터를 저장하는 방식을 의미합니다. 이외에 efs같은 옵션은 AWS의 EFS를 이용하여 데이터를 저장하고 nfs는 네트워크 파일 시스템을 이용하여 데이터를 저장합니다.

driver_opts는 드라이버의 옵션을 설정합니다. 지금 제가 하고자 하는 것은 제 로컬 디렉토리를 컨테이너에 마운트시키고 싶은 것이므로 bind 옵션을 주고, 디렉토리 경로를 적어줍니다. type같은 경우 특별한 파일 시스템을 사용할 때 ext4, xfs 등을 적어주게 됩니다.

Network

다음으로 네트워크에 대해 알아보겠습니다. 우선 docker network는 여러 종류의 network driver를 사용할 수 있습니다. 대표적인 예시로는 bridge, host, overlay등이 있는데 bridge가 디폴트 드라이버입니다.

bridge 드라이버는 같은 호스트 안의 다른 컨테이너끼리 통신해야하는 상황에서 사용합니다. 그러므로 저는 bridge 드라이버를 사용하겠습니다.

컨테이너를 생성하게되면 기본적으로 default bridge network에 컨테이너가 연결되게 됩니다. 그런데 이런 default network에 연결되는 것보다는 제가 필요로하는 컨테이너들끼리만 연결된 user-defined bridge network가 있는 것이 좋을 것입니다. 그걸 위해 docker compsoe 파일에 아래와 같이 네트워크를 명시해줄 수 있습니다.

networks:
  inception:

이런 user-defined network의 장점은 다른 컨테이너에 그 컨테이너의 이름으로 접근가능하다는 것입니다. 그래서 db, nginx 이런 이름으로 통신이 가능해지는 것이죠

Service

마지막으로 서비스 부분의 nginx를 잠깐만 보겠습니다. nginx컨테이너 같은 경우 image로 nginx를 사용하고 이 image는 srcs/nginx에 있는 docker file로 빌드한다고 설정해놓았습니다.

ports같은 경우 Host의 443 포트와 컨테이너의 443 포트를 연결하겠다는 의미이며 volume는 wp volume을 컨테이너의 /var/www/html에 마운팅하겠다는 의미가 됩니다.

network는 inception network를 사용할 것이며 wordpress service가 만들어진 후 만들어진다는 의미로 depend_on에 wordpress를 적어놓았습니다.

services:
  nginx:
    image: nginx
    build: srcs/nginx
    ports: 
      - "443:443"
    volumes:
      - "wp:/var/www/html"
    networks:
      - inception
    depends_on:
      - wordpress

이런 모든 과정을 통해 docker compose파일로 원하는 세개의 컨테이너로 구성된 서비스를 만들 수 있습니다. 이제 중요한 것은 각 container들이 어떻게 만들어지느냐겠죠. 그것은 각 이미지를 만드는 docker file에 달려있습니다.

대표적인 예시로 Nginx docker file만 살펴보도록 하겠습니다.

NGINX docker file


위에서 본 nginx service를 위한 image인 nginx를 만드는 docker file은 아래와 같이 구성되어있습니다.

debian을 바탕으로 nginx를 설치하고, https를 위한 작업들을 해준 뒤 nginx configuration 파일을 적용해주게 됩니다.

nginx.conf 파일에 443포트를 듣는다는 설정값이 있으므로 host의 443포트로 https 요청을 날리게 되면 docker-compose의 포트 포워딩을 통해 nginx 컨테이너의 443포트로 전달되어 nginx가 듣게되는 것이죠.

FROM debian:bullseye

RUN apt-get update && \
    apt-get upgrade && \
    apt-get install -y nginx && \
    apt-get install -y openssl && \
    mkdir -p /etc/nginx/ssl && \
    openssl req -new -x509 -newkey rsa:2048 -nodes -keyout server.key -out server.crt -days 365 -subj "/C=KR/ST=Seoul/L=Seoul/O=My Company/OU=IT/CN=localhost" && \
    mv server.key /etc/nginx/ssl && \
    mv server.crt /etc/nginx/ssl
    
COPY nginx.conf /etc/nginx/nginx.conf

CMD ["nginx", "-g", "daemon off;"]

마무리

이렇게 docker에 관한 지식을 기반으로 세 개의 컨테이너를 통해 서비스를 만들어 보는 과정을 진행해보았습니다.

docker를 사용하는 법은 알았지만 이런 식으로 사용을 해보니 새로웠고, docker 자체가 한 컨테이너에 하나의 app만 실행하는 것을 권장하기에 이러한 구성 방식을 연습해보는 것도 좋겠다고 생각했습니다.

멀티 컨테이너 환경을 다뤄야하는 분이 계시다면 참고해주시면 좋겠습니다.