Flask ๋ฐ Docker ์์๐ณ๐
๋์ ๋ฐ ๋ชฉํ
๋ณธ๊ณ ๋ ์ด๋ณด์ ๊ฐ๋ฐ์๋ฅผ ๋์์ผ๋ก docker์flask๋ฅผ ์ฌ์ฉํ๋ ์๋ด์๋ฅผ ์ฐพ๊ณ ์๋ค.๊ทธ๋ฌ๋ ๊ฐ์ด๋ฐ
๊ฐ๋ฐ์๋ ๋ ์ฝ๊ฐ์ ์ง์์ ์์งํ ์ ์๋ค.๋๋ ๋ ๋ด๊ฐ ์ด ํ๋ก์ ํธ์์ ์ง๋ฉดํ ๋ฌธ์ ๋ฅผ ์ง์ ํ๋ ค๊ณ ๋ ธ๋ ฅํ ๊ฒ์ด๋ค.
๋ณธ๊ณ ๋ ๊ฐ๋จํ flask ํ๋ก๊ทธ๋จ์ ๊ฐ๋ฐํ์ฌ ์ด ํ๋ก๊ทธ๋จ์ ์ฐ๊ฒฐํ๊ณ ์ฝ๋๋ฅผ GitHub๋ก ์ ์กํ๋ ๋ฐ ๋ชฉ์ ์ ๋๊ณ ์๋ค.
์ ๊ฒฐ ์กฐ๊ฑด
๋ณธ๋ฌธ๊ณผ ํ์ ์ฝ๋๋ฅผ ํจ๊ณผ์ ์ผ๋ก ๋ฐ๋ฅด๊ธฐ ์ํด์๋ ๋ค์๊ณผ ๊ฐ์ ์ ๊ฒฐ ์กฐ๊ฑด์ด ํ์ํฉ๋๋ค.
์ด๊ธฐ ์ค์
์ด๋ฌํ ๋ช ๋ น์ ๋๋ถ๋ถ์ Unix ์์คํ ์์ ์คํ๋ฉ๋๋ค.์ฐธ๊ณ : Windows ๊ตฌํ์ ๋ค๋ฅผ ์ ์์ต๋๋ค.
mkdir flask_starter_app && cd flask_starter_app
python3 -m venv venv
source venv/bin/activate
pip install flask flask-bootstrap jikanpy
pip freeze > requirements.txt
์ฐ๋ฆฌ๋ ์ฐ๋ฆฌ์ ํ๋ก์ ํธ๋ฅผ ์ํด ๋ฉ์ธ ํ๋ผ์คํฌ ๋ชจ๋์ ์ค์นํ๊ณ ์๋ค.Flask Bootstrap์ Bootstrap์ ์์ฉ ํ๋ก๊ทธ๋จ์ ํตํฉํ์ฌ ์คํ์ผ๋งํ๋ ๋ฐ ๋์์ ์ค ๊ฒ์
๋๋ค.Jikanpy๋ ์ค์นํ์ต๋๋ค. Jikan Api์python ํจํค์ง์ ๋๋ค. ๋น๊ณต์์ ์ธ MyAnimeList Api์ ๋๋ค.
๋ชจ๋ ๊ฒ์ด ์ฑ๊ณต์ ์ผ๋ก ์ค์น๋๊ธฐ๋ฅผ ๋ฐ๋๋๋ค.๋๋ ์์ ์ฝ๋ ๋ณด๊ธฐ
์บ๋ณด๋ผ 1 / flask starter ์์ฉ ํ๋ก๊ทธ๋จ
docker๋ฅผ ์ด์ฉํ ๊ฐ๋จํ ํ๋ผ์คํฌ ์ ๋ฌธ ํ๋ก๊ทธ๋จ
flask starter ์์ฉ ํ๋ก๊ทธ๋จ
๊ฐ๋จํ ํ๋ผ์คํฌ ์
๋ฌธ ํ๋ก๊ทธ๋จ, docker๋ฅผ ์ด์ฉํ์ฌ jikanpy์ผ๋ก ๊ณ์ ์ ๋๋ฉ์ด์
์ ์
(myanimelist ๋น๊ณต์api).
๋ฌธ์ฅ.
์์ฑ์ ๋งํฌ
Docker ๋น ๋ฅธ ์์
ํธํ๋๋ ๋ฒ์ ์ Python๊ณผ Node๋ฅผ ์ฌ์ฉํ์ฌ ํ๋ก๊ทธ๋จ์ ์คํํ ์ ์๋๋ก Docker๋ฅผ ์ฌ์ฉํ๋ ๊ฒ์ ๊ถ์ฅํฉ๋๋ค.
์์ฉ ํ๋ก๊ทธ๋จ์์ Dockerfile์ ์ฌ์ฉํ์ฌ ์์ํ ์ ์์ต๋๋ค.
์์ฉ ํ๋ก๊ทธ๋จ์ ๊ฐ๋ฐ ๋ฒ์ ์ ๊ตฌ์ถํ๋คdocker build -t flask-starter-app .
To run the app
docker run --name=flask-app -p 5001:5000 -t -i flask-starter-app
If everything went well, the app should be running on localhost:5001
๋ค ์ปจํ ์ด๋์์.
Docker refers to open source containerization platform.
Containers are standardized executable components that combine application source code with OS-level dependencies and libraries. We can create containers without docker, however it provides a consistent, simpler and safer way to build containers. One of the major reasons for the meteoric growth of the use of containers from software development to software delivery and even testing, is the ease of use and reproducibility of the entire workflow.
Previously developers used Virtual Machines in the cloud or self-hosted servers to run their applications and workloads.
However, going from development to production was sometimes plagued with failures due differences in Operating systems or
at times dependencies. Containers allow us to essentially take the code, file structure, dependencies etc. and package them and deploy them to a server and have them run as expected with minimal changes.
์ฉ์ด
Here we'll run through some tools and terminology in reference to Docker:
DockerFile
Docker containers start out as single text file containing all the relevant instructions on how build an image.
A Dockerfile automates the process of creating an image, contains a series of CLI instructions for the Docker engine to assemble the image.
Docker ์ด๋ฏธ์ง
Docker images hold all application source code, libraries and dependencies to run an application. It is very possible to build a docker image from scratch but developers leverage common repositories to pull down pre-built images for common software and tools.
Docker images are made up of layers and each time a container is built from an image. a new layer is added becoming the latest version of the image. You can use a single to run multiple live containers.
๋ถ๋ ์ผํฐ
This is a public repository of Docker images, containing over 100,000 container images. It holds containers of software from commercial vendors, open-source projects and even individual developers.
Docker ๋ฐ๋ชฌ
Refers the service that runs in your system powering the creation of Docker images and containers.The daemon receives commands from client and executes them.
Docker ๋ ์ง์คํธ๋ฆฌ
This is an open-source scalable storage and distribution system for docker images. Using git( a version control system) the registry track image versions in repositories using tags for identification.
๊ฑด์คํฉ์๋ค!
๋ณ.
Flask prides itself in being micro framework therefore it only comes with
simple configuration out of the box. However. it allows for a wide range of custom configuration options. This gives you
the freedom to start simple, add extensions for variety utilities as you grow.
์ฐ๋ฆฌ ๋ญ ์ง๊ณ ์์ด?
Today we'll be building a simple web app to display the current seasonal anime from MyAnimeList. If you follow me on you'll know am a massive manga and anime fan. MyAnimeList is defacto platform for information, reviews and rankings thus it was the optimal choice. However, it doesn't have an API or sdk to access their content. Normally we would have to scrape the site, luckily the awesome community created Jikan Api as well jikanpy which is python wrapper for the API.
๋น๋ฐ๋ฒํธ ์ด๋ ์์ด์?
Now hopefully you carried out the steps above in Prerequisites section. Ensure your virtual environment is activated. Inside our flask-starter-app
directory create run.py
file.
# run.py
from app import app
if __name__ == '__main__':
app.run()
์ด ํ์ผ์ ์ ํฌ ํ๋ก๊ทธ๋จ์ ์ฌ์ฉ๋ฉ๋๋ค.์ฐ์ , ์ฐ๋ฆฌ๋ app ๋๋ ํฐ๋ฆฌ์์ ์ฐ๋ฆฌ์ app ์ค๋ก๋ฅผ ๊ฐ์ ธ์๋๋ฐ, ์ด ๋๋ ํฐ๋ฆฌ๋ ์์ง ์กด์ฌํ์ง ์๋๋ค.์ฐ๋ฆฌ๊ฐ ๊ทธ๊ฒ์ ์ฐฝ์กฐํฉ์๋ค.์์ฉ ํ๋ก๊ทธ๋จ ๋๋ ํ ๋ฆฌ๋ฅผ ๋ง๋ค๊ณ ์ฌ๊ธฐ์ ๋ง๋ค๋ ค๋ฉด ๋ค์๊ณผ ๊ฐ์ด ํ์ญ์์ค.
__init__.py
ํ์ผ models.py
ํ์ผ views.py
ํ์ผ anime_requests.py
ํ์ผ python-projects $ tree flask_starter_app
flask_starter_app
โโโ app
โ โโโ __init__.py
โ โโโ anime_request.py
โ โโโ models.py
โ โโโ views.py
โ โโโ templates
โ โโโ index.html
โโโ requirements.txt
โโโ run.py
โโโ venv
2 directories, 7 files
__init__.py
ํ์ผ์ ๋ค์ ์ฝ๋๋ฅผ ์ถ๊ฐํฉ๋๋ค.# app/__init__.py
from flask import Flask
from flask_bootstrap import Bootstrap
bootstrap = Bootstrap()
app = Flask(__name__)
bootstrap.init_app(app)
from . import views
์์ ๋ ํ์ ๊ฐ ๋ชจ๋์์ Flask ๋ฐ Bootstrap ํด๋์ค๋ฅผ ๊ฐ์ ธ์ต๋๋ค.๊ทธ๋ฐ ๋ค์ Bootstrap ํด๋์ค๋ฅผ ์ธ์คํด์คํํ๊ณ Bootstrap ๋ณ์๋ฅผ ํ ๋นํฉ๋๋ค.app ๋ณ์๋ Flask ํด๋์ค์ ์ค๋ก๋ฅผ ํฌํจํ๊ณ ์ ํฌ app๋ฅผ ์ธ์ฉํ๋ ์ฒซ ๋ฒ์งธ ๋งค๊ฐ ๋ณ์๋ก ์ด๋ฆ์ ์ ๋ฌํฉ๋๋ค.๊ทธ๋ฆฌ๊ณ ์ฐ๋ฆฌ๋ init_app()
๋ฐฉ๋ฒ์ ๋งค๊ฐ ๋ณ์๋ก purapp๋ฅผ ์ ๋ฌํ์ฌ ์๋ด๋ฅผ ์ด๊ธฐํํฉ๋๋ค.๋ง์ง๋ง์ผ๋ก ํ์ฌ ๋๋ ํฐ๋ฆฌ์์ ๋ณด๊ธฐ ํ์ผ์ ๊ฐ์ ธ์ต๋๋ค.
์์ ์ ์์ํ๋ค
models.py
ํ์ผad์์ ๋ค์ ์ฝ๋๋ฅผ ์
๋ ฅํฉ๋๋ค.# app/models.py
from dataclasses import dataclass
@dataclass
class Anime:
"""
class to model anime data
"""
mal_id: int
url: str
title: str
image_url: str
synopsis: str
type: str
airing_start: str
episodes: int
members: int
์ด ํ์ผ์ Api์ ๋ฐ์ดํฐ๋ฅผ ์ ์ฅํ๋ ์ ๋๋ฉ์ด์
ํด๋์ค๋ฅผ ๋ง๋๋ ๋ชจ๋ ๋ชจ๋ธ์ ์ ์ฅํฉ๋๋ค.์ฐ๋ฆฌ๋ dataclasses ๋ชจ๋์์ ๋ฐ์ดํฐ ํด๋์ค ์ฅ์๊ธฐ๋ฅผ ๊ฐ์ ธ์ต๋๋ค.์ด๊ฒ์ ์ฐ๋ฆฌ๋ก ํ์ฌ๊ธ ๊ฐ์ข
ํน์ํ ๋ฐฉ๋ฒ์ ์ฌ์ฉํ ์ ์๊ฒ ํ๊ณ , ์ฐ๋ฆฌ์ ์ฝ๋๋ฅผ ๊ฐ๋จํ๊ณ ๊ฐ๊ฒฐํ๊ฒ ์ ์งํ ๊ฒ์ด๋ค.decorator๋ฅผ ํด๋์ค์ ์ถ๊ฐํ ๋ค์ Api์์ ๋ฐ์ดํฐ์ ๊ตฌ์กฐ๋ฅผ ๊ณ์ ์ ์ํฉ๋๋ค.์์ธํ ๋ด์ฉ์ docs์ ์ฐธ์กฐํ์ญ์์ค.๋ถํ
anime_request.py
ํ์ผ์ ๋ค์์ ์ถ๊ฐํฉ๋๋ค.# app/anime_request.py
from jikanpy import Jikan
from .models import Anime
jikan = Jikan()
# function to get seasonal anime
def get_season_anime():
"""
function to get the top anime from My anime list
:return: list of anime
"""
season_anime_request = jikan.season()
season_anime = []
if season_anime_request['anime']:
response = season_anime_request['anime']
for anime in response:
mal_id = anime.get('mal_id')
url = anime.get('url')
title = anime.get('title')
image_url = anime.get('image_url')
synopsis = anime.get('synopsis')
type = anime.get('type')
airing_start = anime.get('airing_start')
episodes = anime.get('episodes')
members = anime.get('members')
new_anime = Anime(mal_id, url, title, image_url, synopsis, type, airing_start, episodes, members)
season_anime.append(new_anime)
return season_anime
์ ์ฝ๋์์ Jikanpy ๋ชจ๋์์ Jikan ํด๋์ค๋ฅผ ๊ฐ์ ธ์์ต๋๋ค. ์ด๋ก์จ Jikan Api๋ฅผ ์์ฒญํ๊ธฐ ์ํด ๋ค์ํ ๋ฐฉ๋ฒ์ ์ ๊ทผํ ์ ์์ต๋๋ค.์ฐ๋ฆฌ๋ ๋ํ models
ํ์ผ์์ ์ฐ๋ฆฌ์ ์ ๋๋ฉ์ด์
์ข
๋ฅ๋ฅผ ๊ฐ์ ธ์๋ค.์ฐ๋ฆฌ๋ ๋ณ์ jikan์ ๋ง๋ค๊ณ , ๊ทธ ๋ณ์์ jikan ํด๋์ค๋ฅผ ๋ถ๋ฐฐํ๋ ์ค๋ก๋ฅผ ๋ง๋ญ๋๋ค.์ด์
get_season_anime
ํจ์๋ฅผ ์ ์ํ์ฌ Jikan Api์ ์์ฒญํ์ฌ ๋ชฉ๋ก์ ์ถ๊ฐํฉ๋๋ค.์ฐ๋ฆฌ๋ ๋ณ์ season_anime_request
์ ๋ง๋ค์๋๋ฐ, ์ด ๋ณ์๋ Jikan๋ฅ์์ season
๋ฐฉ๋ฒ์ ํธ์ถํฉ๋๋ค.์ด๊ฒ์ ๋ ๊ฐ์ง ํ๋ผ๋ฏธํฐ๋ฅผ ๋ฐ์๋ค์ธ๋ค. ์ฐ๋์ ๊ณ์ ์ด๋ค. ์ฐ๋, ์ฌ์ง์ด ๊ณ์ ์์ ํน์ ํ ๋ฐ์ดํฐ๋ฅผ ๊ฒ์ํ๋ ค๋ฉด ๋งค์ฐ ํธ๋ฆฌํ๋ค.์ฐ๋ฆฌ์ ์์์ ์ฐ๋ฆฌ๋ ์ด๋ฒ ์์ฆ์ ์ ๋๋ฉ์ด์
์ ์ป๊ธฐ ์ํด ์ง์ ํ์ง ์์๋ค.๊ทธ๋ฆฌ๊ณ ๋ฐ์ดํฐ๋ฅผ ์ ์ฅํ๊ธฐ ์ํด ๋น ๋ชฉ๋ก์ ์ ์ํฉ๋๋ค.season ๋ฐฉ๋ฒ์ ๊ฐ์ข ํค ๊ฐ์ด ๋ง๋ ์ฌ์ ์ ๋๋๋ ค์ค๋๋ค.์ฐ๋ฆฌ๊ฐ ํ์๋ก ํ๋ ๋ฐ์ดํฐ๋
anime
ํค์ ๊ฐ์ด๋ค.์ด๊ฒ์ ์ฌ์ ๋ชฉ๋ก์ด๋ค.์ฐ๋ฆฌ๊ฐ ์ํ๋ ํค๊ฐ ์กด์ฌํ๋์ง ํ์ธํ๊ธฐ ์ํดif๋ฌธ์ฅ์ ์ถ๊ฐํ ๋ค์ ์ด ๊ฐ์ ๋ฐ๋ณตํฉ๋๋ค.์ฐ๋ฆฌ๋ ์๋ต์ ๋ฐ์ดํฐ๋ฅผ ์ธ์ฉํ๊ธฐ ์ํด ์ ๋นํ ๋ณ์๋ฅผ ๋ง๋ญ๋๋ค.Anime ํด๋์ค์ ์ธ์คํด์ค์ธ
new_anime
๋ณ์๋ฅผ ๋ง๋ค์์ต๋๋ค.์ฐ๋ฆฌ๋ ํด๋์ค๋ฅผ ๋น ๋ชฉ๋ก์ ์ถ๊ฐํ๊ณ , ๋ง์ง๋ง์ผ๋ก ํด๋์ค ๋ชฉ๋ก์ ๋๋๋ ค์ค๋๋ค.๋ฉฐ์น ํ๊ฒฝ
views.py
ํ์ผ์ ๋ค์ ์ฝ๋๋ฅผ ์ถ๊ฐํฉ๋๋ค.from flask import render_template
from .anime_request import get_season_anime
from . import app
@app.route('/', methods=['GET', 'POST'])
def index():
"""
root page view that returns the index page and its data
:return: index template
"""
season_anime = get_season_anime()
return render_template('index.html', season_anime=season_anime)
์ด ํ์ผ์ flask ์ ํ๋ฆฌ์ผ์ด์
์ ์ฌ์ฉ๋ฉ๋๋ค.ํ์ฌ, ์ฐ๋ฆฌ๋ ํ๋๋ฟ์
๋๋ค. ๋ง์๋๋ก ๋ ๋ง์ด ์ถ๊ฐํ์ธ์.์ฐ๋ฆฌ๋ ์ฐ์ render_template
์ ๊ฐ์ ธ์ต๋๋ค. ์ด๊ฒ์ ๋ธ๋ผ์ฐ์ ์์ html ํ์ด์ง๋ฅผ ๋ณด์ฌ์ฃผ๊ณ ํ์ํ ๋ชจ๋ ๋งค๊ฐ ๋ณ์๋ฅผ ์ ๋ฌํฉ๋๋ค.์ ๋๋ฉ์ด์
์์ฒญ ํ์ผ์์ get_season_anime
ํจ์๋ฅผ ๊ฐ์ ธ์์ต๋๋ค.๋ํ __init__.py
ํ์ผ์์ ํ๋ก๊ทธ๋จ์ ๊ฐ์ ธ์ต๋๋ค. ์ด๊ฒ์ ๊ณต๊ฐ ๋ฃจํธ ๋ฐฉ๋ฒ์ @app
์ฅ์๊ธฐ๋ฅผ ์ฌ์ฉํ ์ ์๋๋ก ํฉ๋๋ค.์ด๊ฒ์ ๋งค๊ฐ ๋ณ์๋ก ์ ๋ฌ๋๋ ๋ฃจํธ์ ๋ฃจํธ๊ฐ ํ์ฉํ๋ ๋ฐฉ๋ฒ์ผ๋ก ๋ฑ๋ก๋ฉ๋๋ค.์ฐ๋ฆฌ๋
index
ํจ์๋ฅผ ์ ์ํ๋๋ฐ, ์ฌ์ฉ์๊ฐ ๋ฃจํธ๋ฅผ ์ด๋ฉด ์ด ํจ์๋ฅผ ํธ์ถํฉ๋๋ค.ํจ์์์ ์ ๋๋ฉ์ด์
ํด๋์ค์ ์ค๋ก ๋ชฉ๋ก์ ์ ์ฅํ๋ ๋ณ์๋ฅผ ์ ์ํ์ต๋๋ค.์ฐ๋ฆฌ๋ ์ต์ข
์ ์ผ๋ก render_template
ํจ์๋ฅผ ํธ์ถํ์ฌ ์์ธ์ ์ ๋ฌํ๋ค.ํ
ํ๋ฆฟ ํด๋์ html ํ์ผ๊ณผ ํ
ํ๋ฆฟ์ ๊ณ์ ์ ๋๋ฉ์ด์
๋ณ์์
๋๋ค.๋ค์ ๋ด์ฉ์ ์์ธ์ ์ถ๊ฐํฉ๋๋ค.ํ ํ๋ฆฟ ํด๋์ html ํ์ผ:
<!--app/templates/index.html -->
{% extends 'bootstrap/base.html' %}
{% block navbar %}
<div class="navbar navbar-inverse" role="navigation">
<div class="container-fluid">
<div class="navbar-header">
<button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse">
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand" href="/"> Anime Watchlist </a>
</div>
<div class="navbar-collapse collapse">
<ul class="nav navbar-nav">
<li><a href="/">Home</a></li>
</ul>
</div>
</div>
</div>
{% endblock %}
{% block content %}
{% for anime in season_anime %}
<div class="card-group col-xs-12 col-sm-4 col-md-2 col-lg-2">
<div class="card">
<img src="{{ anime.image_url }}" alt="{{ anime.title }} poster" class="img-responsive"
style="max-height: 30rem">
<li class="text-left ">
<a href="/anime/{{anime.mal_id}}">
{{ anime.title|truncate(30)}}</a>
<p> Episodes : {{ anime.episodes }}</p>
<p> date started airing: {{ anime.airing_start | truncate(13) }}</p>
</li>
</div>
</div>
{% endfor %}
{% endblock %}
Flask๋ jinja ํ
ํ๋ฆฟ ์์ง์ ์ฌ์ฉํฉ๋๋ค.์ด๊ฒ์ ์ฐ๋ฆฌ๋ก ํ์ฌ๊ธ ์ผ๋ จ์ ๊ณ ๊ธ ๊ธฐ๋ฅ์ ์ฌ์ฉํ ์ ์๊ฒ ํ๋ค.์ฐ๋ฆฌ์ ์์์ ์ฐ๋ฆฌ๋ ๋ชจ๋ ์๋ด ์คํ์ผ์ ํฌํจํ๋ ๊ธฐ๋ณธ html ํ์ผ์ ํ์ฅํ๋๋ฐ ์ด๊ฒ์ ๋ชจ๋ ํ์ด์ง์ ์ ์ฉ๋๋ ๊ธฐ๋ณธ ๊ตฌ์กฐ๋ฅผ ํ์ฉํ๋ค.์ฐ๋ฆฌ๋ ๋ํ ํน์ํ {% %}
์ ์ฌ์ฉํ์ฌ ํน์ํ ๋ด๋น๊ฒ์ด์
๋ธ๋ก์ ์ ์ํ๋ค.์ผ๋ฐ์ ์ธ ๊ฒฝ์ฐ, ์ด๊ฒ์ ์์ ์ ํ์ผ์ ์ค์ ๋์ด ๊ฐ์ ธ์จ ๊ฒ์ด์ง๋ง, ์ฌ๊ธฐ์๋ ๊ทธ๊ฒ์ ์ฌ๊ธฐ์ ๋์ ๊ฒ์ด๋ค.์ฐ๋ฆฌ๋ ๋ณด๊ธฐ ํ์ผ์์ ์ ๋ฌ๋ ์ ๋๋ฉ์ด์ ํ๋ผ๋ฏธํฐ๋ฅผ ์ํํ๋ ๋ด์ฉ ๋ธ๋ก์ ์ ์ํ๋ค.๋ชจ๋ ๊ฐ์ ๋ํด ์ฐ๋ฆฌ๋ ์ ๋ชฉ, ์ด๋ฏธ์ง, ๋๋ผ๋ง ํ์, ๋ฐฉ์ก ์์ ๋ ์ง๊ฐ ์๋ ์นด๋๋ฅผ ๋ณด์ฌ ์ค๋ค.
ํฐ๋ฏธ๋์ ์ด๊ณ
python run.py
์ ์คํํ์ญ์์ค. ์์ฉ ํ๋ก๊ทธ๋จ์ ๋ค์๊ณผ ์ ์ฌํ๊ฒ ๋ณด์ผ ๊ฒ์
๋๋ค.๋ชจ๋ ๊ฒ์ ๊ธฐ๋กํ๋ค
ํ์ฌ ์ฐ๋ฆฌ๋ ๊ธฐ๋ฅ์ด ์๋น๋flask ์์ฉ ํ๋ก๊ทธ๋จ์ ๊ฐ์ง๊ณ ์์ผ๋ฉฐ, ์ด๋ฅผ dockerize๋ก ์งํํ ์ ์๋ค.์์ฉ ํ๋ก๊ทธ๋จ(flask starter ์์ฉ ํ๋ก๊ทธ๋จ)์ ๋ฃจํธ ๋๋ ํ ๋ฆฌ์
Dockerfile
์ ์์ฑํฉ๋๋ค.๋ค์ ๊ตฌ์ฑ์ ์ถ๊ฐํฉ๋๋ค.
#Dockerfile
FROM python:3.9.7
MAINTAINER Ken Mwaura "[email protected]"
COPY ./requirements.txt /app/requirements.txt
RUN pip install -r requirements.txt
COPY . /app
WORKDIR app
ENV FLASK_APP=run.py
ENV FLASK_ENV=development
EXPOSE 5001:5000
CMD ["flask", "run", "--host", "0.0.0.0"]
์ฒซ ๋ฒ์งธ ์ค์์ ๊ตฌ์ถํ ๊ธฐ๋ณธ ์ด๋ฏธ์ง๋ฅผ ์ค์ ํฉ๋๋ค. ์์์์python 3.9.7 ์ด๋ฏธ์ง๋ฅผ ์ฌ์ฉํ์ฌ ๊ฐ๋ฐ์ ๋ฐ์ํฉ๋๋คํ๊ฒฝDocker์ ๋ํ ๋ช ๊ฐ์ง ์ค๋ช ์ ์ดํด๋ณด๊ฒ ์ต๋๋ค.
FLASK_APP
์ ์คํ์ผ๋ก ์ค์ ํฉ๋๋ค.py ํ์ผ.์คํํ ํ์ผ์
๋๋ค.FLASK_ENV
์ development๋ก ์ค์ ํฉ๋๋ค.์ด๊ฒ์ flask๊ฐ ๊ฐ๋ฐ ๋ชจ๋๋ก ํ๋ก๊ทธ๋จ์ ์คํํ๋ ๊ฒ์ ์๋ ค ์ค๋๋ค.์ด๋ฏธ์ง๋ฅผ ํ๋ฆฝํ๋ค
Dockerfile์ ์ ๊ณตํ์ผ๋, ๊ตฌ์ถ์ด ์ ํํ์ง ํ์ธํด ๋ด ์๋ค
docker build -t flask-starter-app .
์ปจํ ์ด๋ ์คํ
๊ตฌ์ถ์ด ์๋ฃ๋๋ฉด ์ฉ๊ธฐ๋ฅผ ์คํํฉ๋๋ค
docker run --name=flask-app -p 5001:5000 -t -i flask-starter-app
localhost:5001์ผ๋ก ์ด๋ํ๋ฉด ๋ค์๊ณผ ๊ฐ์ ์ ํ๋ฆฌ์ผ์ด์
์ด ์คํ๋ฉ๋๋ค.์ง์ผ๋ณดํ ์๋ฃ
์ฌ๋ฐ๋ฅธ ํฌํธ๋ฅผ ์ฌ์ฉํด์ผ ํฉ๋๋ค.Flask๋ ๊ธฐ๋ณธ์ ์ผ๋ก ํฌํธ 5000์์ ์คํ๋ฉ๋๋ค. (Django์ ๊ฐ์ 8000์ด๋ Apache์ ๊ฐ์ 80์ด ์๋๋๋ค.)
์์ธํ ๋ด์ฉ์ Binding Docker Ports์ ์ฐธ์กฐํ์ญ์์ค.
๋๋ ๋ค๊ฐ ์ด ๋ฌธ์ฅ์ ์ข์ํ๊ณ ๊ณ๋ฐ์ ๋ฐ์ ๋์ฑ ํ์ฅํ๊ธฐ๋ฅผ ๋ฐ๋๋ค.๊ณ์ ์ธ์ฝ๋ฉ!๋ฐ์ด๋ ๋ฐ์ ๋๊ธ ๋จ๊ฒจ์ฃผ์๋ ๊ฑธ ํ์ํฉ๋๋ค.
ํธ์ํฐ์ ์ฐ๋ฝ:.
Reference
์ด ๋ฌธ์ ์ ๊ดํ์ฌ(Flask ๋ฐ Docker ์์๐ณ๐), ์ฐ๋ฆฌ๋ ์ด๊ณณ์์ ๋ ๋ง์ ์๋ฃ๋ฅผ ๋ฐ๊ฒฌํ๊ณ ๋งํฌ๋ฅผ ํด๋ฆญํ์ฌ ๋ณด์๋ค https://dev.to/ken_mwaura1/getting-started-with-flask-and-docker-3ie8ํ ์คํธ๋ฅผ ์์ ๋กญ๊ฒ ๊ณต์ ํ๊ฑฐ๋ ๋ณต์ฌํ ์ ์์ต๋๋ค.ํ์ง๋ง ์ด ๋ฌธ์์ URL์ ์ฐธ์กฐ URL๋ก ๋จ๊ฒจ ๋์ญ์์ค.
์ฐ์ํ ๊ฐ๋ฐ์ ์ฝํ ์ธ ๋ฐ๊ฒฌ์ ์ ๋ (Collection and Share based on the CC Protocol.)
์ข์ ์นํ์ด์ง ์ฆ๊ฒจ์ฐพ๊ธฐ
๊ฐ๋ฐ์ ์ฐ์ ์ฌ์ดํธ ์์ง
๊ฐ๋ฐ์๊ฐ ์์์ผ ํ ํ์ ์ฌ์ดํธ 100์ ์ถ์ฒ ์ฐ๋ฆฌ๋ ๋น์ ์ ์ํด 100๊ฐ์ ์์ฃผ ์ฌ์ฉํ๋ ๊ฐ๋ฐ์ ํ์ต ์ฌ์ดํธ๋ฅผ ์ ๋ฆฌํ์ต๋๋ค