개발자로 후회없는 삶 살기

도커 PART.도커 기반 서비스 개발 본문

[Infra]/[도커]

도커 PART.도커 기반 서비스 개발

몽이장쥰 2023. 1. 29. 21:36

서론

앞에서 도커의 기본이 되는 내용은 전부 배웠습니다. 이것으로 어떻게 도커 기반으로 서비스 개발을 하는지 알아보겠습니다.

 

본론

만들어볼 서비스는 다음과 같이 몽고 db 데이터를 플라스크로 웹에 출력하는 것입니다. 차이점은 이 모든 것을 도커 이미지로 불러와 컨테이너로 실행한다는 것입니다. 원래 같으면 서비스할 코드를 작성하고 톰캣같은 서버를 실제로 다운받고 로컬에서 flask 작성하고 몽고 DB 서버 띄어서 진행하겠지만 이번에는 이미지 외에는 물리적으로 다운 받는게 없습니다.

 

> 브릿지로 서브넷을 만들고 서브넷 안에 db 서버와 프로그램을 실행할 것입니다. 몽고 db 이미지를 통해서 서버를 실행시키고 플라스크 웹 서비스를 만들어서 배포할 것입니다. 도커 기반 어플리케이션이므로 플라스크도 컨테이너로 띄워야합니다. 그러니 플라스크 코드를 도커 파일로 이미지로 만들어서 플라스크 컨테이너를 띄우고 하나의 서브넷으로 통신을 해보고 로컬에서 플라스크를 접근해보도록 할 것입니다.

 

> 이때 플라스크가 몽고 db에 접속을 해야합니다. 접속하기 위해 db 컨테이너의 ip를 알아야하는데 그걸 하드코딩하면 db 컨테이너의 정보가 바뀔 때마다 플라스크 이미지를 매번 만들어야합니다. 그것을 도커 파일에서 환경변수로 어떻게 처리하는지가 중요 포인트입니다.

 

- 도커 컨테이너 기반 어플리케이션 개발 워크플로

 

1. 개발할 플라스크 웹 어플리케이션 코드를 작성

몽고 db는 진짜 그냥 활용만 할 것이니 원래 있는 이미지 실행하면 되는데 앱은 우리만의 고유한 앱이니 따로 코드를 작성해야할 것이다! 몽고 db에 접속할 때 connection string을 적어야하는데 하드 코딩을 안하기 위해 환경변수를 줘야한다.이 부분을 도커 파일에서 작성을 해야 어플리케이션을 도커 이미지로 만들 수 있습니다.

 

2. 우리가 만든 어플을 도커 파일로 만들어서 이미지로 만듬

우리가 만든 프로그램을 도커 안에 집어 넣은 다음에 도커 이미지로 만들어야합니다. 어플을 만들 때 app이라는 폴더를 만들고 프로그램을 집어 넣습니다. 도커 파일을 작성할 때 명령어(참고 1)를 알아야합니다.

 

FROM python # 파이썬 이미지 기반(이미지이다. latest가 생략된 것이다.) = app이 돌아기기 위한 기반 설치

RUN pip install flask pymongo # app이 돌아기기 위한 라이브러리들 설치
COPY app /app

ENV USERNAME admin
ENV PASSWORD password
ENV SERVER mongodb
EXPOSE 5000

WORKDIR /app
CMD ["python", "app.py"]

그 파일을 도커 이미지로 만들 것이기 때문에 같은 폴더 계층에 dockerfile을 만듭니다. 도커 파일은 생성될 컨테이너의 구성 요소를 작성하는 것입니다. chroot를 공부할 때와 같은 개념으로 컨테이너 환경에 서비스가 동작하기 위한 lib를 전부 설치해야 합니다.

 

1) 다운 받기 위해 RUN 명령어에 적습니다. pip 등을 많이 쓰겠지요? 왜냐면 서비스가 동작하기 위한 라이브러리를 다운 받을 것이기 때문입니다.

 

2) COPY를 보면 도커에서 항상 왼쪽은 로컬이고 오른쪽이 도커 내부입니다. 8080:80에서 8080은 내 로컬호스트이고 80이 컨테이너였습니다. 로컬에 있는 app 폴더를 컨테이너 안쪽에 루트(/) 밑에 app이라는 폴더를 만들고 복사합니다. 내가 개발한 프로그램을 컨테이너에 짚어 넣는 것으로 (작성한 코드를 직접 명시해 주어야합니다.) 실행시킬 컨테이너가 몽고 DB처럼 실제로 서비스를 할 컨테이너이니 서비스 코드를 작성하고 컨테이너 내부에 넣어줍니다.

 

3) 환경변수를 env로 주고 > expose는 플라스크가 5000번 포트에서 실행이 되는데 도커는 고립된 환경이라서 외부에 노출시키기 위한 명령어입니다. 도커의 -p 옵션과 똑같은 건데 이런 게 다 이미지로 만들 때 필요합니다.

 

4) workdir은 "나"를 도커 내부에서 이 프로그램이 실행되는 위치인 /app으로 옮기라는 얘기입니다. 그래야 앱을 실행할 때 경로가 알맞게 됩니다.

 

5) 이동 후 CMD에 있는 명령을 수행하게 됩니다. 이미지가 처음 컨테이너로 실행 되어서 올라오면(docker run 하면) 바로 그때 이 cmd가 실행됩니다. = 도커 파일을 이미지로 만들어서 컨테이너로 올리면 app.py file이 실행이 되는 것과 같은 것입니다.

 

-> 결론 : 이미지가 컨테이너로 올라왔을 때 RUN 실행되기 위한 준비를 하는 것을 script로 작성해 놓은 것이 도커 파일이고 가상환경을 만들고 목적을 위해 다양한 라이브러리를 다운 받는 것과 같은 것입니다.

 

=> 어플리케이션이 복잡해질 경우

FROM ubuntu:14.04

RUN apt-get update &&\
  apt-get -qq -y install git curl build-essential apache2 php5 libapache2-mod-php5 rcs

WORKDIR /tmp
RUN \
  curl -L -O https://github.com/wkpark/moniwiki/archive/v1.2.5p1.tar.gz &&\
  tar xf /tmp/v1.2.5p1.tar.gz &&\
  mv moniwiki-1.2.5p1 /var/www/html/moniwiki &&\
  chown -R www-data:www-data /var/www/html/moniwiki &&\
  chmod 777 /var/www/html/moniwiki/data/ /var/www/html/moniwiki/ &&\
  chmod +x /var/www/html/moniwiki/secure.sh &&\
  /var/www/html/moniwiki/secure.sh

RUN a2enmod rewrite

ENV APACHE_RUN_USER www-data
ENV APACHE_RUN_GROUP www-data
ENV APACHE_LOG_DIR /var/log/apache2

EXPOSE 80
CMD bash -c "source /etc/apache2/envvars && /usr/sbin/apache2 -D FOREGROUND"

어플리케이션이 복잡해질 경우 dir가 존재하기에 도커 파일을 이미지로 만들고 도커 컨테이너 띄울 때 library들을 실행하기 위해 내부로 들어가는 과정이 선행되어야 합니다. apt-get update를 한 후 바로 WORKDIR을 바꿔서 안으로 들어가서 설치하기도 하고

 

requirements.txt를 .(컨테이너)로 복사하기도 합니다.

 

3. 도커 파일을 이미지로 만들기

docker build로 해도 되는데 그러면 3개의 이미지를 전부 다 커맨드로 실행해야 합니다. 따라서 컴포즈를 이용하여 이미지로 만듭니다. 도커 컴포즈를 먼저 만들고 도커 컴포즈를 이용하여 도커 파일을 도커 이미지로 만들고 컨테이너를 실행할 것입니다.

 

 

아까 app 바깥에 도커 파일이 있어야한다고 했는데 도커 컴포스는 앱과 도커파일을 폴더로 감싸고 그 밖에 만듭니다. 

 

version: "3.7"

services:
  mongodb:
    image: mongo
    networks:
      - mongo_net
    ports:
      - 27017:27017
    environment:
      - MONGO_INITDB_ROOT_USERNAME=admin
      - MONGO_INITDB_ROOT_PASSWORD=password
    volumes:
      - /home/hsb/mongodb:/data/db # 몽고 db 컨테이너의 데이터는 /data/db안에 있다.
    

  mongo-express:
    image: mongo-express
    networks:
      - mongo_net
    ports:
      - 8081:8081
    environment:
      - ME_CONFIG_MONGODB_ADMINUSERNAME=admin
      - ME_CONFIG_MONGODB_ADMINPASSWORD=password
      - ME_CONFIG_MONGODB_SERVER=mongodb
    depends_on:
      - mongodb
  
  mongo_flask:
    build:
      context: ./docker_app_flask
      dockerfile: Dockerfile
    image: mongo_flask:1.0
    container_name: mongo_flask
    hostname: myservice
    environment:
      - MONGO_USERNAME=admin
      - MONGO_PASSWORD=password
      - MONGO_SERVER=mongodb
    ports:
      - 8050:5000
    networks:
      - mongo_net
    depends_on:
      - mongodb
    

networks:
  mongo_net:
    driver: bridge

이번에 도커 컴포즈에는 플라스크 앱 파일도 한 번에 실행을 해야합니다. 아까는 오피셜 몽고 db 이미지를 컴포즈로 불러오는 방법을 실험해 본 것이고 이번에는 어플리케이션을 만들 것이고 그것을 컨테이너로 구성할 것이기 때문입니다.

 

플라스크 앱 파일은 몽고 DB처럼 도커 이미지를 가져오는게 아니고 우리가 만든 앱 파일을 도커파일로 만들었고 그 파일을 이미지로 build한 후 몽고 DB 이미지들과 함께 실행하도록 해야합니다. context는 루트 경로로 만들겠다는 것으로 .yml과 같은 층에 있는 프로젝트 전체 폴더로 지정합니다.

 

> dockerfile은 Dockerfile을 루트 경로에서 찾아서 이미지로 만들겠다는 것입니다. image에는 우리가 만든 이미지가 생성될 이름을 적습니다. mongo-express의 경우 image: 만 있어서 도커 허브에서 이미지를 다운받아서 컨테이너로 실행하는 것이고 build: 하고 image: 를 하면 build한 이미지를 image: 에 있는 이름으로 만들게 됩니다.

> containe_name은 --name입니다.

 

 

volumes:
      - /home/hsb/mongodb:/data/db # 몽고 db 컨테이너의 데이터는 /data/db안에 있다.

이번에는 몽고 db의 데이터를 볼륨에 저장하였습니다.

 

5. 도커 컴포즈로 컨테이너 올리기

이런 상태에서 docker-compose build를 하면 build 섹션만 실행되어 mongo_flask만 빌드됩니다. 

 

※ 알게된 점

여기서 알게된 점이 컨테이너 기반 어플리케이션은 모든 컨테이너를 한 번에 올려야하는 것이 아니라 따로 따로 올려서 있어야하는 컨테이너들이 모두 모이면 비로소 어플리케이션이 된다는 것입니다. 왜냐면 몽고 db는 이미 컨테이너로 되어있으니 flask만 따로 build 했습니다.

 

이제 접속을 하려면 docker-compose up -d라고 하면 d 옵션으로 docker-compose에 작성된 모든 것들이 컨테이너로 한 번에 올라갑니다.

 

> 우리가 만든 컨테이너 기반 어플리케이션이 정상적으로 실행이 되는 것을 알 수 있습니다. 다운받은 파일이 하나도 없이 이미지만 컨테이너로 실행했는데 원래 flask를 사용할 때와 똑같이 할 수 있습니다!

 

 

 

결론

이번에 wsl로 윈도우에서 도커와 리눅스를 사용하고 vscode로 플라스크까지 사용해 보니 도커 기반 어플리케이션 개발 워크플로를 제대로 알 수 있었습니다.

 

참고

명령어

'[Infra] > [도커]' 카테고리의 다른 글

도커 PART.docker-compose  (0) 2023.01.29
도커 PART.도커 life cycle  (0) 2023.01.26
도커 PART.iptables  (0) 2022.05.28
루트 파일 시스템 RART.환경변수  (0) 2022.05.10
루트 파일 시스템 PART.chroot  (0) 2022.04.07
Comments