본 글은 Flask 앱을 Docker 환경에서 실행하는 예시다. Docker 환경 구축을 중심으로 설명하며, Flask에 대해 자세히 다루지 않는다.
이미지와 컨테이너
- Dockerfile: 도커 환경 생성에 필요한 설정을 작성한다.
- 이미지: 라이브러리 등 필요한 설정이 완료된 템플릿. 한 번 빌드하면 수정할 수 없으며, 읽기만 가능하다.
- 컨테이너: 이미지를 실행해 만든 환경. 실제 코드가 실행되는 환경으로, 읽기/쓰기가 가능하다.
본 글에서는 Dockerfile을 이용해 이미지를 빌드한다. 빌드한 이미지로부터 컨테이너를 만들고 Flask 앱을 실행한다.
파일 구성
본 프로젝트 구조는 다음과 같다.
/root
|-- Dockerfile
|-- app.py
|-- requirements.txt
|-- static
|-- templates
|-- *.html
| ...
Dockerfile
Dockerfile은 이미지 빌드에 필요한 명령어를 작성한다.
FROM python:3.10-slim
COPY . /app
WORKDIR /app
RUN pip install --upgrade pip
RUN pip install -r requirements.txt
EXPOSE 5000
CMD ["python", "app.py"]
- FROM: docker-hub의 python:3.10-slim에서 도커 이미지를 가져온다. Python 3.10이 설치되어 있는 이미지를 가져와 이 위에 필요한 정보를 추가로 설정한다.
- COPY: 현재 디렉토리(.) 파일을 도커 이미지의 /app에 복사한다.
- WORKDIR: 도커 명령어를 /app 경로에서 실행한다.
- RUN: 빌드에 필요한 명령어를 작성한다.
- EXPOSE: 도커를 노출할 포트를 설정한다.
- CMD: 컨테이너를 시작할 때, 기본으로 실행할 명령어를 작성한다.
요악하면,
- Python 3.10이 설치된 도커 이미지 생성
- 로컬 파일을 도커 내 /app으로 복사
- /app을 기본 경로로 설정
- pip로 라이브러리 설치
- 포트를 5000으로 설정
- 이미지를 시작할 때 "python app.py"를 실행
requirements.txt
flask==3.1.0
numpy==1.26.3
pillow==10.2.0
...
Flask 앱 실행에 필요한 라이브러리를 작성한다.
app.py
from flask import Flask, render_template, request
app = Flask(__name__)
@app.route("/")
def index():
return render_template("index.html")
# 생략...
if __name__ == "__main__":
app.run(host="0.0.0.0", port=5000, debug=True)
Flask의 host는 "0.0.0.0"으로 작성한다. Flask는 도커 컨테이너 안에서 실행된다. host를 설정하지 않으면 컨테이너 외부에서 접근할 수 없다. 따라서 host를 0.0.0.0으로 설정해야 컨테이너 외부에서 접속할 수 있다.
Flask 앱 실행
docker build -t flask-app:0.1 .
- build: 이미지를 빌드
- -t: tag. <이미지명>:<태그(버전)>을 입력하는 옵션
- .: 현재 폴더. Dockerfile 위치
flask-app이라는 이름으로 이미지를 생성한다. 버전은 0.1로 기록한다. 마지막에 .이 있다. Dockerfile이 현재 폴더에 위치한다는 표시다. 명령어를 실행하면 Dockerfile에 작성한 대로 라이브러리를 설치하고 이미지를 완성한다.
docker image ls -a
- image ls: 도커 이미지 목록을 출력
- -a: all. (초기 이미지까지) 모두 출력
REPOSITORY TAG IMAGE ID CREATED SIZE
flask-app 0.1 823226be2ade 4 minutes ago 14.9GB
ls 명령어를 통해 이미지가 잘 생성되었는지 확인한다. 예상한 대로 flask-app이 0.1 버전으로 생성되었다. -a 옵션을 사용하지 않으면 실행된 적 없는 이미지는 출력되지 않는다. 따라서 반드시 -a 옵션을 사용한다.
docker run -p 8080:5000 --name test flask-app:0.1
- run: 컨테이너 생성 및 실행
- -p: port. <host 포트>:<container 포트>로 작성
- --name: 컨테이너 이름을 지정 (예시: test)
- flask-app:0.1: 이미지 이름 (예시)
test라는 이름의 컨테이너를 실행한다. 컨테이너가 없다면 flask-app:0.1로부터 새로운 컨테이너를 생성한다. host 포트는 외부에서 접속하는 포트, container 포트는 내부에서 접속하는 포트다.
Flask 앱에서 container 포트는 app.py에서 설정한 포트가 된다. Dockerfile도 같은 포트를 사용해 컨테이너 내부에서 Flask 앱에 접속하도록 한다. 이 경우 5000이다. host 포트는 우리가 브라우저에서 접속할 때 사용하는 포트다. 위 예시는 8080이므로 "127.0.0.1:8080"으로 접속한다.
정리하면, (8080):[Host] → (5000):[Docker → Flask]로 접속한다.
전체 코드: github:denev6/deep-learning-codes/ML-Ops/app