如何把一個(gè)Python應(yīng)用程序裝進(jìn)Docker
準(zhǔn)備
容器無(wú)處不在,但是如何在Docker容器中運(yùn)行Python應(yīng)用程序呢?這篇文章將告訴你怎么做!
如果您想知道,這些示例需要Python 3.x。
在深入討論容器之前,讓我們進(jìn)一步討論一下我們想要封裝的Python應(yīng)用程序。
這個(gè)應(yīng)用程序是一個(gè)web API,它從一個(gè)電影集合中返回一個(gè)隨機(jī)的電影。在我們的本地文件夾中,我們有3個(gè)文件:
- app.py # Python application
- movies.json # movie collection
- requirements.txt # where we specifiy our Python dependencies
app.py包含一個(gè)API端點(diǎn),它返回一個(gè)隨機(jī)的影片:
- import os
- import json
- from pathlib import Path
- from random import choice
- import cherrypy
- PORT = os.environ.get('PORT', 8888)
- FOLDER_PATH = Path(__file__).parent
- with open(FOLDER_PATH / "movies.json", "r") as f:
- MOVIES = json.loads(f.read())
- class Movie:
- @cherrypy.expose
- @cherrypy.tools.json_out()
- def index(self):
- return {"movie": choice(MOVIES)}
- cherrypy.quickstart(
- Movie(), config=cherrypy.config.update({
- 'server.socket_host': '0.0.0.0',
- 'server.socket_port': PORT,
- }))
requirement.txt,我們有我們的依賴包
- pip install -r requirements.txt
我們可以使用python app.py運(yùn)行我們的應(yīng)用程序。
運(yùn)行curl localhost:8888應(yīng)該返回一個(gè)隨機(jī)的影片,類似于:
- {
- "movie": {
- "Title": "Opal Dreams",
- "US_Gross": 14443,
- "Worldwide_Gross": 14443,
- "US_DVD_Sales": null,
- "Production_Budget": 9000000,
- "Release_Date": "Nov 22 2006",
- "MPAA_Rating": "PG",
- "Running_Time_min": null,
- "Distributor": "Strand",
- "Source": "Based on Book/Short Story",
- "Major_Genre": "Drama",
- "Creative_Type": "Contemporary Fiction",
- "Director": null,
- "Rotten_Tomatoes_Rating": null,
- "IMDB_Rating": 6.5,
- "IMDB_Votes": 468
- }
- }
如何容器化我們的程序
包含一個(gè)Python應(yīng)用程序意味著創(chuàng)建一個(gè)Docker鏡像,其中包含運(yùn)行它所需要的一切:源代碼、依賴項(xiàng)和配置。
容器化應(yīng)用程序的第一步是創(chuàng)建一個(gè)新的文本文件,名為Dockerfile:
- app.py
- movies.json
- requirements.txt
- Dockerfile
在Dockerfile(我們認(rèn)為是最小可行Dockerfile)中,我們需要指定三個(gè)步驟:
- 選擇我們想要使用的基本圖像
- 選擇我們想要在Docker圖像中復(fù)制的文件
- 安裝應(yīng)用程序的依賴項(xiàng)
Base image
要指定基本映像,我們使用FROM命令,后面跟著私有或公共映像。
在我們的例子中,我們將使用官方的Python Docker映像,該映像可在Docker hub上使用。
我們將選擇最新可用的基于Ubuntu的python3圖像。
- # 1. Base image
- FROM python:3.8.5-slim-buster
圖像名稱由兩個(gè)不同的部分組成:image:tag。在我們的例子中,圖像是python,標(biāo)簽是3.8.5-slim-buster。
這就是第一步所需要的一切。
復(fù)制應(yīng)用程序
要在Docker圖像中復(fù)制我們的應(yīng)用程序,我們將使用copy命令:
- # 2. Copy files
- COPY . /src
此命令將指定的文件(或文件夾)復(fù)制到Docker映像中。在我們的例子中,我們希望復(fù)制Docker映像中本地文件夾中/src路徑下的所有可用文件。
值得注意的是,COPY命令的第一部分是相對(duì)于構(gòu)建上下文的路徑,而不是相對(duì)于我們的本地機(jī)器的路徑。
安裝requirements.txt
最后一步是在Docker映像中安裝我們的依賴項(xiàng)。為了實(shí)現(xiàn)這一點(diǎn),我們將使用RUN命令運(yùn)行pip安裝:
- # 3. Install our deps
- RUN pip install -r /src/requirements.txt
需要注意的一件事是,requirements.txt的路徑與我們第一次運(yùn)行pip安裝時(shí)不同。
這背后的原因是復(fù)制的文件在映像內(nèi)的/src路徑下。
構(gòu)建并運(yùn)行Docker映像
- # 1. Base image
- FROM python:3.8.3-slim-buster
- # 2. Copy files
- COPY . /src
- # 3. Install our deps
- RUN pip install -r /src/requirements.txt
我們的Dockerfile現(xiàn)在已經(jīng)完成,我們可以使用它來(lái)構(gòu)建Docker映像。為此,我們需要使用docker構(gòu)建命令:
- docker build -t movie-recommender .
這個(gè)命令使用當(dāng)前文件夾作為構(gòu)建上下文構(gòu)建一個(gè)名為movie-recommender的Docker圖像。在最后指定我們想要使用的構(gòu)建上下文的路徑)。
現(xiàn)在我們可以使用docker run命令運(yùn)行剛剛構(gòu)建的圖像:
- docker run movie-recommender python /src/app.py
該命令將在基于電影推薦圖像的容器中執(zhí)行python /src/app.py。
但是,如果我們嘗試使用curl localhost:8888連接到我們的應(yīng)用程序,我們將會(huì)得到一個(gè)錯(cuò)誤。
這怎么可能?為什么我們不能連接到在容器內(nèi)運(yùn)行的應(yīng)用程序?
原因是我們沒(méi)有將應(yīng)用程序的端口公開(kāi)給本地機(jī)器。我們可以使用-p HostPort:ContainerPort標(biāo)志來(lái)實(shí)現(xiàn)這一點(diǎn)。
因此,讓我們嘗試再次運(yùn)行該命令,這一次指定我們希望在本地公開(kāi)端口8888:
- docker run -p 8888:8888 movie-recommender python /src/app.py
然后curl localhost:8888。
現(xiàn)在的效果非常好!我們剛剛包含了一個(gè)Python應(yīng)用程序!