Docker에 Flask 웹 서버 호스팅하기

d4v1d·2022년 2월 18일
0

Docker & Kubernetes

목록 보기
2/8
post-thumbnail
post-custom-banner

TL;DR

Flask로 구현한 API 서버 app.py를 도커 컨테이너에 띄워 실행시키고, 로컬에서 해당 API서버로 접근하는 방법을 정리했습니다.

  • flask app을 실행할 때 호스트 IP를 "0.0.0.0" 으로 명시해야 합니다. 이는 동일한 네트워크 상에서 localhost가 아닌 서버의 IP로 접속을 가능하게 해줍니다.
    app.run(host='0.0.0.0', port=...)
  • docker run 을 실행할 때 -p 옵션을 통해 포트 포워딩을 할 수 있습니다. -p 1234:8888은 호스트 기기의 1234번 포트를 도커 컨테이너의 8888번 포트와 연결한다는 의미입니다.
  • 도커 컨테이너 내에서의 localhost는 컨테이너 내에서만 접근 가능한 로컬호스트로, 호스트 기기의 localhost와는 원칙적으로 구분되어 있습니다!

시작

로컬에 웹 서버를 호스팅하고 접근하는 것은 어렵지 않습니다.
python flask를 이용해 아주 간단한 웹 API 서버를 만들고 실행해봅시다!

# app.py
from flask import Flask

app = Flask(__name__)
host_addr = "0.0.0.0"
host_port = 5000

@app.route('/')
def hello():
    return "try /ping!"

@app.route('/ping')
def ping():
    return {'response': 'pong'}


if __name__ == "__main__":
    app.run(debug=True,
            host=host_addr,
            port=host_port)

로컬 환경에서 위의 app.py를 실행하면 서버 호스팅이 시작됩니다.

서버 호스팅 시작

이 상태에서 웹 브라우저에서 http://localhost:5000 접근하면 다음 결과를 얻을 수 있습니다.

http://localhost:5000


http://localhost:5000/ping

이제 이 API서버를 도커 컨테이너 위에서 실행하려는데...

Docker에 띄우려면 고려할 게 한 두 가지가 아니다.

Docker 이미지

우선, Docker container를 어떤 환경으로 세팅할 것인지를 정해야합니다. 처음엔 도커 컨테이너에서 jupyter를 사용해야하나 싶어서 jupyter/minimal-notebook을 기반으로 컨테이너를 실행시켰습니다.

docker pull jupyter/minimal-notebook
docker run -p 8888:8888 jupyter/minimal-notebook

실행 후 다음과 같은 메시지를 확인할 수 있습니다.

http://127.0.0.1:8888/lab?token=... 주소를 복사하여 웹 브라우저에서 접속하면 JupyterLab 환경이 설치되어 있는 것을 확인할 수 있습니다.

그런데 생각해보니, 컨테이너 내에서 jupyter를 사용할 이유가 전혀 없어서 다른 도커 이미지를 사용하기로 했습니다.

docker pull python3.10.2-slim # 현재 사용중인 python 버전

Dockerfile

이제 본격적으로 컨테이너를 구동하기 위해 Dockerfile을 작성합시다. Dockerfile은 특정 이미지를 베이스로 하여 컨테이너를 생성할 때 미리 명시한 동작들을 수행할 수 있도록 새로운 이미지를 만드는 파일입니다.

FROM python:3.10.2-slim

ADD . /app
WORKDIR /app
RUN pip install flask
ENTRYPOINT python app.py

비교적 간단하게 작성한 Dockerfile입니다. 한 줄씩 살펴보면,

  • FROM <이미지 이름>:<버전> 어떤 이미지를 기반으로 만들 것인지를 가장 위에 작성합니다. FROM python:3.10.2-slim
  • ADD <로컬 파일 이름/목록> <컨테이너 내에 저장할 위치> 로컬 디렉토리의 파일을 컨테이너의 특정 위치에 추가합니다. ADD . /appdocker run 을 실행하는 디렉토리 내의 모든 파일을, 컨테이너 내부의 /app 위치에 추가한다는 의미입니다. 컨테이너를 생성할 때 로컬 파일을 같이 띄우고 싶을 때 유용합니다.
  • WORKDIR <작업 디렉토리> 컨테이너 내에서 작업할 디렉토리로 이동합니다.
  • RUN <스크립트 명령어> 컨테이너를 생성할 때 실행할 명령어입니다. &&\와 줄바꿈을 통해 여러 개의 명령을 하나의 RUN 커맨드로 묶을 수 있습니다.
  • ENTRYPOINT <스크립트 명령어> 컨테이너를 시작할 때 실행할 명령어입니다. RUN은 컨테이너가 최초로 생성될 때만 실행되지만, ENTRYPOINT는 컨테이너를 시작할 때마다 실행됩니다.

Docker 이미지 빌드

Dockerfile을 만들었으면 이를 이용해 도커 이미지를 빌드합니다.

docker build <Dockerfile이 위치한 디렉토리> -t <이미지 이름>:<태그>

태그를 명시하지 않으면 알아서 :latest (최신 버전) 태그를 붙입니다.

docker build . -t flask-image

Docker 컨테이너 실행

이제 도커를 실행할 차례입니다!

docker run -d -p 8888:5000 <이미지>

-d 현재 터미널에 도커 터미널을 띄우지 않고 백그라운드로 컨테이너를 실행합니다.
-p <호스트 포트>:<컨테이너 포트> 포트 포워딩 옵션입니다. 위의 app.py는 5000번 포트로 서버를 열어두는데, 이를 컨테이너 환경에서 실행하기 때문에 컨테이너의 5000번 포트를 연결해야 컨테이너 내의 flask 서버에 접근할 수 있습니다.

Docker 컨테이너 실행 결과. Dockerfile 내의 ENTRYPOINT 덕분에 컨테이너 실행과 동시에 flask 서버가 구동되는 것을 확인할 수 있다.

웹 브라우저에서 flask 서버 접근

마무리

Docker의 포트 바인딩때문에 몇 시간을 구글링하면서 끙끙댔습니다. 이 문제를 해결하면서 호스트 포트와 컨테이너 포트, 그리고 서버 프로그램에서 사용하는 포트를 어떻게 연결해야 하는지 감을 잡았습니다.
상황에 따라 필요한 이미지를 찾아 pull하고, 적절한 Dockerfile을 작성하여 컨테이너를 생성하는 방법을 배웠습니다.

profile
데이터 엔지니어/백엔드 개발자 d4v1d의 개발 일지🐯
post-custom-banner

0개의 댓글