Docker 컨테이너를 통한 Flask 앱과 nginx 연결을 실습해보겠습니다.
지난번에 올린 포스팅 Django + nginx와 같은 방법으로 실습을 진행합니다. Flask 컨테이너와 nginx 컨테이너를 각각 실행시켜 연결하는 방법 외에 docker-compose를 사용해서 실행하는 방법까지 진행해보겠습니다.
1. Flask 설치 및 api 생성
먼저 django와 마찬가지로 flask 라이브러리를 설치합니다. 파이썬 가상환경을 설치, 실행하고 해당 가상환경 안에서 flask를 설치하겠습니다.
저는 도커 실습을 위해 만들어놓은 가상환경에서 진행하도록 하겠습니다.
> cd django-docker
> source bin/activate
> which python
/Users/choi/Workspace/django-docker/bin/python
> which pip
/Users/choi/Workspace/django-docker/bin/pip
> pip install flask
Collecting flask
Obtaining dependency information for flask from https://files.pythonhosted.org/packages/61/80/ffe1da13ad9300f87c93af113edd0638c75138c42a0994becfacac078c06/flask-3.0.3-py3-none-any.whl.metadata
Downloading flask-3.0.3-py3-none-any.whl.metadata (3.2 kB)
Collecting Werkzeug>=3.0.0 (from flask)
Obtaining dependency information for Werkzeug>=3.0.0 from https://files.pythonhosted.org/packages/9d/6e/e792999e816d19d7fcbfa94c730936750036d65656a76a5a688b57a656c4/werkzeug-3.0.3-py3-none-any.whl.metadata
Downloading werkzeug-3.0.3-py3-none-any.whl.metadata (3.7 kB)
Collecting Jinja2>=3.1.2 (from flask)
Obtaining dependency information for Jinja2>=3.1.2 from https://files.pythonhosted.org/packages/31/80/3a54838c3fb461f6fec263ebf3a3a41771bd05190238de3486aae8540c36/jinja2-3.1.4-py3-none-any.whl.metadata
Downloading jinja2-3.1.4-py3-none-any.whl.metadata (2.6 kB)
Collecting itsdangerous>=2.1.2 (from flask)
Obtaining dependency information for itsdangerous>=2.1.2 from https://files.pythonhosted.org/packages/04/96/92447566d16df59b2a776c0fb82dbc4d9e07cd95062562af01e408583fc4/itsdangerous-2.2.0-py3-none-any.whl.metadata
Downloading itsdangerous-2.2.0-py3-none-any.whl.metadata (1.9 kB)
Collecting click>=8.1.3 (from flask)
Obtaining dependency information for click>=8.1.3 from https://files.pythonhosted.org/packages/00/2e/d53fa4befbf2cfa713304affc7ca780ce4fc1fd8710527771b58311a3229/click-8.1.7-py3-none-any.whl.metadata
Using cached click-8.1.7-py3-none-any.whl.metadata (3.0 kB)
Collecting blinker>=1.6.2 (from flask)
Obtaining dependency information for blinker>=1.6.2 from https://files.pythonhosted.org/packages/bb/2a/10164ed1f31196a2f7f3799368a821765c62851ead0e630ab52b8e14b4d0/blinker-1.8.2-py3-none-any.whl.metadata
Downloading blinker-1.8.2-py3-none-any.whl.metadata (1.6 kB)
Collecting MarkupSafe>=2.0 (from Jinja2>=3.1.2->flask)
Obtaining dependency information for MarkupSafe>=2.0 from https://files.pythonhosted.org/packages/11/e7/291e55127bb2ae67c64d66cef01432b5933859dfb7d6949daa721b89d0b3/MarkupSafe-2.1.5-cp311-cp311-macosx_10_9_universal2.whl.metadata
Downloading MarkupSafe-2.1.5-cp311-cp311-macosx_10_9_universal2.whl.metadata (3.0 kB)
Downloading flask-3.0.3-py3-none-any.whl (101 kB)
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 101.7/101.7 kB 5.3 MB/s eta 0:00:00
Downloading blinker-1.8.2-py3-none-any.whl (9.5 kB)
Using cached click-8.1.7-py3-none-any.whl (97 kB)
Downloading itsdangerous-2.2.0-py3-none-any.whl (16 kB)
Downloading jinja2-3.1.4-py3-none-any.whl (133 kB)
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 133.3/133.3 kB 6.3 MB/s eta 0:00:00
Downloading werkzeug-3.0.3-py3-none-any.whl (227 kB)
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 227.3/227.3 kB 6.9 MB/s eta 0:00:00
Downloading MarkupSafe-2.1.5-cp311-cp311-macosx_10_9_universal2.whl (18 kB)
Installing collected packages: MarkupSafe, itsdangerous, click, blinker, Werkzeug, Jinja2, flask
Successfully installed Jinja2-3.1.4 MarkupSafe-2.1.5 Werkzeug-3.0.3 blinker-1.8.2 click-8.1.7 flask-3.0.3 itsdangerous-2.2.0
[notice] A new release of pip is available: 23.2.1 -> 24.0
[notice] To update, run: pip install --upgrade pip
flask를 설치했으니 실행시켜보겠습니다.
flask를 실행하기 위해서는 endpoint를 정의하는 파이썬 코드를 작성해야합니다. 간단한 api를 작성해보겠습니다.
from flask import Flask
app = Flask(__name__)
@app.route('/')
def root():
return 'hello world'
if __name__ == '__main__':
app.run(host='0.0.0.0', port='8081')
0.0.0.0:8081 주소의 /(루트) 로 접근하는 클라이언트에게 hello world라는 문자열을 반환하는 간단한 코드입니다.
> python main.py
* Serving Flask app 'main'
* Debug mode: off
WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead.
* Running on all addresses (0.0.0.0)
* Running on http://127.0.0.1:8081
* Running on http://192.168.45.58:8081
Press CTRL+C to quit
python 명령어로 위에서 생성한 main.py 파일을 실행시키면 서버가 정상적으로 작동하게 됩니다.
웹브라우저로 요청을 보내보겠습니다.
localhost의 8081 포트로 접속하면 위에서 반환한 'hello world'가 웹브라우저에 나타나게 됩니다.
그리고 파일을 실행시킨 터미널에서는 아래와 같은 api 로그를 확인할 수 있습니다.
127.0.0.1 - - [03/Jun/2024 21:29:56] "GET / HTTP/1.1" 200 -
2. Flask 컨테이너 실행
위에서 만들었던 flask 앱을 도커 컨테이너 형태로 실행시키겠습니다.
우선 더 다양한 테스트를 위해 간단한 api endpoint를 추가하겠습니다.
from flask import Flask
app = Flask(__name__)
users = {
"kim": '30',
"park": '20',
"choi": '25'
}
@app.route('/')
def root():
return 'hello world'
@app.route('/items', methods=['GET'])
def get_all():
return users
@app.route('/items/<name>', methods=['GET'])
def get(name):
return users.get(name, "유저 없음")
if __name__ == '__main__':
app.run(host='0.0.0.0', port='18081')
nginx와 연결해서 테스트할 flask는 두개의 endpoint를 추가했습니다. users라는 딕셔너리를 추가해서 클라이언트에서 확인할 수 있는 api를 만들었습니다. 로컬과 차이점을 두며 테스트하기 위해 포트번호도 8081에서 18081로 변경했습니다.
이제 Dockerfile을 생성하겠습니다.
FROM python:3.11.7
WORKDIR /usr/src/app
COPY . .
RUN python -m pip install --upgrade pip
RUN pip install -r requirements.txt
WORKDIR ./myapp
CMD gunicorn --bind 0.0.0.0:18081 main:app
EXPOSE 18081
로컬에서 실행하는 것과 차이를 두기 위해 연결을 위한 포트는 18081번으로 변경했습니다.
requirement.txt를 생성하고 Dockerfile을 통해 flask 이미지를 빌드하겠습니다.
> pip freeze > requirements.txt
> docker image build . -t flask
[+] Building 8.4s (11/11) FINISHED docker:desktop-linux
=> [internal] load .dockerignore 0.0s
=> => transferring context: 2B 0.0s
=> [internal] load build definition from Dockerfile 0.0s
=> => transferring dockerfile: 241B 0.0s
=> [internal] load metadata for docker.io/library/python:3.11.7 0.8s
=> [1/6] FROM docker.io/library/python:3.11.7@sha256:63bec515ae23ef6b4563d29e547e81c15d80bf41eff5969cb43d034d333b63b8 0.0s
=> [internal] load build context 0.0s
=> => transferring context: 421B 0.0s
=> CACHED [2/6] WORKDIR /usr/src/app 0.0s
=> [3/6] COPY . . 0.0s
=> [4/6] RUN python -m pip install --upgrade pip 2.1s
=> [5/6] RUN pip install -r requirements.txt 4.9s
=> [6/6] WORKDIR ./myapp 0.0s
=> exporting to image 0.5s
=> => exporting layers 0.5s
=> => writing image sha256:58d41850072a4dc21c9108a161175a52dc98bc8f8a5884d872fe84277745ba56 0.0s
=> => naming to docker.io/library/flask 0.0s
> docker image ls
flask latest 58d41850072a 25 seconds ago 1.17GB
flask 이미지가 생성되었습니다. 이제 nginx와 연결해보도록 하겠습니다.
3. nginx 컨테이너 실행
여기서부터는 지난 포스팅의 django와 같습니다. nginx 설정파일을 생성해주고 설정파일 안에서 flask와 연결해주면 됩니다.
upstream myweb {
server flask:18081;
}
server {
listen 81;
server_name localhost;
location / {
proxy_pass http://myweb;
}
}
nginx 포트를 81번으로 설정하고 upstream은 위에서 flask의 포트를 18081로 변경했으니, 거기에 맞춰 설정 파일을 수정해줍니다.
> docker build . -t nginx
=> [internal] load build definition from Dockerfile 0.0s
=> => transferring dockerfile: 207B 0.0s
=> [internal] load .dockerignore 0.0s
=> => transferring context: 2B 0.0s
=> [internal] load metadata for docker.io/library/nginx:1.25.3 2.9s
=> [auth] library/nginx:pull token for registry-1.docker.io 0.0s
=> [1/3] FROM docker.io/library/nginx:1.25.3@sha256:c7a6ad68be85142c7fe1089e48faa1e7c7166a194caa9180ddea66345876b9d2 0.0s
=> [internal] load build context 0.0s
=> => transferring context: 232B 0.0s
=> CACHED [2/3] RUN rm /etc/nginx/conf.d/default.conf 0.0s
=> [3/3] COPY default.conf /etc/nginx/conf.d/ 0.0s
=> exporting to image 0.0s
=> => exporting layers 0.0s
=> => writing image sha256:f5321ebc877fc6d3c66eaee632a53ee021e4601d3dfb9b4c9746e66dce097e3c 0.0s
=> => naming to docker.io/library/nginx 0.0s
flask와 nginx의 이미지를 모두 생성했습니다. 이제 flask와 nginx를 컨테이너를 실행하면서 연결해주겠습니다.
4. Flask + nginx 연결 및 접속 테스트
두 컨테이너를 연결하기 전에 먼저 네트워크를 생성하겠습니다.
> docker network create flaskapp
80bac38df911a086b9557ae2b7da8f9616a052eaa97f9b29fc83b0ad7b422958
생성된 네트워크를 통해 컨테이너를 실행시키고 묶어줍니다.
> docker container run -d --name flask --network flaskapp flask
9ce7aae75e1fcc3462a85f8091dfeebc30802f19d16027b696d97ec5816a5ce6
> docker container run -d --name nginx --network flaskapp -p 81:81 nginx
916392fe3b02f2bc21a3574b3f97098a7fefccedc74f19d217400da3f033c3f4
docker container ps 명령어로 실행중임을 확인한 후 브라우저를 통해 접속해보겠습니다.
변경한 flask의 코드도 적용된 것을 볼 수 있습니다.
이제 마지막으로 docker-compose를 통해 컨테이너를 실행시켜보겠습니다.
version: "3"
services:
flask:
build: ./docker
networks:
- flaskapp
restart: always
nginx:
build: ./front
networks:
- flaskapp
ports:
- "81:81"
depends_on:
- flask
restart: always
networks:
flaskapp:
기존에 실행중이던 컨테이너와 이미지를 모두 삭제하고 docker-compose를 실행시키겠습니다.
> docker compose up -d --build
✔ Network api_flaskapp Created 0.0s
✔ Container api-flask-1 Started 0.2s
✔ Container api-nginx-1 Started
정상적으로 실행된 것을 확인할 수 있습니다. 브라우저로 접속해보면 아까와 똑같은 결과가 반환됩니다.
compose up으로 생성된 이미지와 컨테이너는 compose down 명령어로 종료할 수 있습니다.
> docker compose down
[+] Running 3/3
✔ Container api-nginx-1 Removed 0.1s
✔ Container api-flask-1 Removed 10.1s
✔ Network api_flaskapp Removed 0.1s
'프로그래밍' 카테고리의 다른 글
[kubernetes] ubuntu 20.04에 python3.11 버전 설치 및 kubespray로 쿠버네티스 설치하기 (2) | 2024.06.11 |
---|---|
[kubernetes] 쿠버네티스 환경 구축 (0) | 2024.06.11 |
[docker] 도커 컨테이너 연결을 통한 프로젝트 구성(feat. nginx, django, postgresql) (0) | 2024.05.25 |
[docker] 도커 기초 명령어 (0) | 2024.05.19 |
[mongoDB] mongo shell을 이용해서 collection 여러개 삭제하기 (0) | 2024.04.24 |