Docker + Python使用 Docker 创建容器化 Python 应用程序(入门指南)
Posted Xavier Jiezou
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Docker + Python使用 Docker 创建容器化 Python 应用程序(入门指南)相关的知识,希望对你有一定的参考价值。
文章目录
概述
本文讲解如何使用 Docker 创建容器化 Python 应用程序,你将学到如下知识:
- 创建一个 Python 应用程序示例
- 创建一个新的 Dockfile,其中包含构建 Python 镜像所需的指令
- 构建一个镜像,并将新构建的镜像作为一个容器运行
- 设置卷和网络
- 使用 Compose 编排容器
- 使用容器进行开发
- 使用 GitHub Actions 为你的应用程序配置 CI/CD 管道
- 应用程序的云部署
安装
Docker 官方安装指南:https://docs.docker.com/engine/install/
构建
预备知识
阅读 Get started Part 1 中的介绍和设置,以了解 Docker 的 基本概念。
启用 BuildKit
构建镜像前,先在机器上启动 BuildKit。BuildKit 允许你高效地构建 Docker 镜像。
在 Docker Desktop 上,所有用户默认都启动了 BuildKit。如果你安装了 Docker Desktop,你不必手动启用 BuildKit。如果你在 Linux 上运行 Docker,你可以通过修改环境编辑或 BuildKit 默认设置来启用它。
要在运行 docker build
命令时设置 BuildKit 环境变量,请运行:
DOCKER_BUILDKIT=1 docker build .
要默认启用 Dokcer BuildKit,请将 /etc/docker/daemon.json
功能中的守护程序配置设置为 true
,然后重启启动守护程序。如果 daemon.json
文件不存在,就新建一个,然后将以下内容添加到文件中:
{
"features": {"buildkit": true}
}
最后,重启 Docker 守护程序。
概述
现在我们对容器和 Docker 平台有了很好的了解,让我们来看看如何如何构建我们的第一个镜像。镜像包含运行应用程序所需的一切:代码或二进制文件、运行时、依赖项和所需的其它文件系统对象。
要完成本教程,你需要以下内容:
- Python 3.8 或更新版本(Download Python)
- 能在本地运行的 Docker(Downlaod Docker)
- IDE 或 文本编辑器(Visual Studio Code)
示例应用程序
让我们使用 Flask 框架创建一个简单的 Python 应用程序作为我们的教程示例。在本地计算机创建一个名为 python-docker
的目录,并按照以下步骤创建一个简单的 web 服务器:
cd /path/to/python-docker
pip3 install Flask
pip3 freeze > requirements.txt
touch app.py
现在,让我们添加一些代码来处理简单的 web 请求。在你喜欢的 IDE 中打开这个工作目录,并在 app.py
文件中键入以下代码:
from flask import Flask
app = Flask(__name__)
@app.route('/')
def hello_world():
return 'Hello, Docker!'
测试应用程序
启动应用程序并确保它能正常运行。打开终端并导航到你创建的工作目录。
python3 -m flask run
为确保应用程序能够正常运行,打开一个新浏览器并导航到 http://localhost:5000
。
切换回服务器运行终端,你应该会在服务器日志中看到以下请求。你机器上的数据和时间戳是不同的。
127.0.0.1 - - [22/Sep/2020 11:07:41] "GET / HTTP/1.1" 200 -
为 Python 创建一个 Dockerfile
现在,我们的应用程序已经能够正常运行,让我们看看如何创建一个 Dockerfile。
Dockerfile 是一个文本文档,包含组装 Docker 镜像的指令。当我们告知 Docker 通过执行 docker build
命令来构建我们的镜像时,Docker 会读取这些指令并执行他们,最终创建一个 Docker 镜像。
让我们了解一下为应用程序创建 Dockerfile 的过程。在项目的根目录下,创建一个名为 Dockerfile
的文件,并在文本编辑器中打开该文件。
如何命名你的 Dockerfile?
Dockerfile 使用的默认文件名是
Dockerfile
(不带文件拓展名)。使用默认名称运行您运行docker build
命令,而不必指定额外的命令参数。
有些项目可能需要不同的 Dockerfile 用于特定目的。一个常见的约定是将这些文件命名为Dockerfile.<something>
或<something>.Dockerfile
。这样的 Dockerfiles 可以通过docker build
命令上的--file
(或-f
速记)选项使用。请参阅docker build
指南中的 “指定一个 Dockerfile” 部分,以了解--file
选项。
我们建议对项目的主 Dockerfile 使用默认值(Dockerfile
),本指南中的大多数示例都将使用该文件。
要添加到 Dockerfile 中的第一行是 # syntax
解析指令。虽然是可选的,但该指令指示 Docker builder 在解析 Dockerfile 时使用什么语法,并允许启用 BuildKit 的较旧版本的 Docker 在启动 build 之前升级解析器。解析指令必须出现在 Dockerfile 中的任何其它注释,空格或 Dockerfile 指令之前,并且应该是 Dockerfile 中的第一行。
# syntax=docker/dockerfile:1
我们推荐使用 docker/dockerfile:1
,它始终指向版本1语法的最新版本。构建之前,BuildKit 会自动地检查语法更新,确保你使用的是最新的版本。
接下来,我们需要在 Dockerfile 中添加一行代码,告诉 Docker 我们想为应用程序使用什么基础的镜像。
# syntax=docker/dockerfile:1
FROM python:3.8-slim-buster
Docker 镜像可以从其它镜像继承。因此,我们将使用 Python 官方镜像,而不是使用我们自己的基础镜像,该镜像已经具有运行 Python 应用程序所需的所有工具和包。
注意
要了解创建自己基本镜像的更多信息,请参见 创建基本镜像
为了在运行其余命令时更容易,让我们创建一个工作目录。这指示 Docker 将此路径用作后续所有命令的默认位置。这样做以后,我们不必键入完整的文件路径,而是可以使用基于工作目录的相对路径。
WORKDIR /app
通常,下载下来用 Python 编写的项目只有,首先要做的就是安装 pip
包。这可以确保应用程序安装了其所有依赖项。
在我们运行 pip3 install
之前,我们需要将 requirements.txt
文件放到镜像中。我们将使用 COPY
命令来执行此操作。COPY
命令接受两个参数。第一个参数告诉 Docker 要将哪些文件复制到镜像中。第二个参数告诉 Docker 要将该文件复制到何处。我们将把 requirements.txt
文件复制到我们的工作目录 /app
中。
COPY requirements.txt requirements.txt
一旦镜像中有了 requirements.txt
文件,我们就可以使用 RUN
命令来执行 pip3 install
命令。这与我们在本地机器上运行 pip3 install
的工作原理完全相同,但这次模块被安装到镜像中。
RUN pip3 install -r requirements.txt
现在,我们有了一个基于 Python 3.8 版本的镜像,并且已经安装好了依赖项。下一步就是将源代码添加到镜像中。我们将像上面的 requirements.txt
文件一样使用 COPY
命令。
COPY . .
COPY
命令获取当前目录中的所有文件,并将他们复制到镜像中。现在,我们要做的就是告诉 Docker,当我们的镜像在容器中执行时,我们要运行什么命令。我们使用 CMD
命令来做这个。注意,我们需要通过指定 --host=0.0.0.0
使应用程序在外部可见(即从容器外部可见)。
CMD [ "python3", "-m" , "flask", "run", "--host=0.0.0.0"]
以下是完整的 Dockerfile 文件:
# syntax=docker/dockerfile:1
FROM python:3.8-slim-buster
WORKDIR /app
COPY requirements.txt requirements.txt
RUN pip3 install -r requirements.txt
COPY . .
CMD [ "python3", "-m" , "flask", "run", "--host=0.0.0.0"]
目录结构
简单回顾一下,我们在本机中创建了一个名为 python-docker
的目录,并使用 Flask 框架创建了一个简单的 Python 应用程序。我们使用 requirements.txt
文件收集我们的依赖包,并创建了一个包含构建镜像命令的 Dockerfile 文件。Python 应用程序的目录结构如下所示:
python-docker
|____ app.py
|____ requirements.txt
|____ Dockerfile
构建一个镜像
现在我们已经创建了 Dockerfile,让我们来构建镜像。为此,我们使用 docker build
命令。docker build
命令使用 Dockerfile 和 context 构建镜像。构建用的 context 是位于指定路径或 URL 中的一组文件。Docker 构建过程中可以访问 context 中的任何文件。
构建命令可以选择 --tag
标签。该 tag
用于设置镜像的名称和格式为 name:tag
的可选标签。我们暂时就不用 tag 了,有助于简化工作。如果未设置 tag
参数,Docker 默认使用 latest
作为 tag
的值。
让我们构建我们的第一个 Docker 镜像。
docker build --tag python-docker .
[+] Building 25.3s (16/16) FINISHED
=> [internal] load build definition from Dockerfile 0.0s
=> => transferring dockerfile: 262B 0.0s
=> [internal] load .dockerignore 0.0s
=> => transferring context: 2B 0.0s
=> resolve image config for docker.io/docker/dockerfile:1 5.4s
=> [auth] docker/dockerfile:pull token for registry-1.docker.io 0.0s
=> docker-image://docker.io/docker/dockerfile:1@sha256:9e2c9eca7367393aecc68795c671f93466818395a2693498debe831fd67f5e89 2.2s
=> => resolve docker.io/docker/dockerfile:1@sha256:9e2c9eca7367393aecc68795c671f93466818395a2693498debe831fd67f5e89 0.0s
=> => sha256:9e2c9eca7367393aecc68795c671f93466818395a2693498debe831fd67f5e89 2.00kB / 2.00kB 0.0s
=> => sha256:cb8d6fa06268f199b41ccc0c2718caca915f74c640f3cd044af8e205e8d616cf 528B / 528B 0.0s
=> => sha256:b1e2fdbfa8cb359e5e566c70344df94749db2e6419e06ac542ed14a348c3ce81 1.21kB / 1.21kB 0.0s
=> => sha256:8d9a8cad598f6c5e97bcb90aab70cd2e868d3dc0d514fa9b60468bf72bf32338 9.67MB / 9.67MB 2.0s
=> => extracting sha256:8d9a8cad598f6c5e97bcb90aab70cd2e868d3dc0d514fa9b60468bf72bf32338 0.1s
=> [internal] load .dockerignore 0.0s
=> [internal] load build definition from Dockerfile 0.0s
=> [internal] load metadata for docker.io/library/python:3.8-slim-buster 4.1s
=> [auth] library/python:pull token for registry-1.docker.io 0.0s
=> [1/5] FROM docker.io/library/python:3.8-slim-buster@sha256:8e04987ebe19f6ec73575287f0caf836da0d3c14a8a68392352236af8b98b3fb 4.9s
=> => resolve docker.io/library/python:3.8-slim-buster@sha256:8e04987ebe19f6ec73575287f0caf836da0d3c14a8a68392352236af8b98b3fb 0.0s
=> => sha256:8e04987ebe19f6ec73575287f0caf836da0d3c14a8a68392352236af8b98b3fb 1.86kB / 1.86kB 0.0s
=> => sha256:ab3056266306eb0abf54a5d51f76d7018bd6c210d526cfa0a3b2a8a91aa8f8c1 1.37kB / 1.37kB 0.0s
=> => sha256:319f36747aed383d5a329b87812f818dd51dac6d3c20d40f817d02e6d7526522 7.92kB / 7.92kB 0.0s
=> => sha256:07aded7c29c6011dfdf02fc98e087c941d3c2661c4e73d134c6491e25231d16c 27.15MB / 27.15MB 3.0s
=> => sha256:1242903d2b2348c44f7d30c366f0f9f034913c7353d1eaf1967f39233f343772 2.77MB / 2.77MB 2.4s
=> => sha256:6feb96d3e4f934a8bf382bcb86902040578493fb0939239bd0aa2c9e2ae90a25 10.73MB / 10.73MB 3.2s
=> => sha256:36bf03acdc5060e3181ffab2b339aad6bc2d98b03f932d13450f87653a401c35 233B / 233B 2.9s
=> => sha256:366f5e2f70434bee85845903597a45030c395be3c3b0f59b4a8616b6f973f981 2.64MB / 2.64MB 3.9s
=> => extracting sha256:07aded7c29c6011dfdf02fc98e087c941d3c2661c4e73d134c6491e25231d16c 0.8s
=> => extracting sha256:1242903d2b2348c44f7d30c366f0f9f034913c7353d1eaf1967f39233f343772 0.1s
=> => extracting sha256:6feb96d3e4f934a8bf382bcb86902040578493fb0939239bd0aa2c9e2ae90a25 0.3s
=> => extracting sha256:36bf03acdc5060e3181ffab2b339aad6bc2d98b03f932d13450f87653a401c35 0.0s
=> => extracting sha256:366f5e2f70434bee85845903597a45030c395be3c3b0f59b4a8616b6f973f981 0.2s
=> [internal] load build context 0.0s
=> => transferring context: 455B 0.0s
=> [2/5] WORKDIR /app 0.3s
=> [3/5] COPY requirements.txt requirements.txt 0.0s
=> [4/5] RUN pip3 install -r requirements.txt 8.0s
=> [5/5] COPY . . 0.0s
=> exporting to image 0.1s
=> => exporting layers 0.1s
=> => writing image sha256:811f21deadc2fa57587e353d637a43543c39f40c46a375cfd4e3fe3897fe4eb2 0.0s
=> => naming to docker.io/library/python-docker
查看本地镜像
我们有两种查看本地机器上的镜像列表的方式。一种是使用 CLI,另一种是使用 Docker Desktop。由于我们目前正在终端中工作,让我们看看用 CLI 列出的镜像。
只需运行 docker images
命令即可简单地列出镜像。
docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
python-docker latest 8cae92a8fbd6 3 minutes ago 123MB
python 3.8-slim-buster be5d294735c6 9 days ago 113MB
你应该看到至少列出了两个镜像。其中一个是基础 3.8-slim-buster
镜像,另一个是我们刚才构建的 python-docker:latest
镜像。
标记镜像
如前所述,镜像名称由斜杠分割的名称组件组合而成。名称组件可以包含小写字母、数字和分隔符。分隔符定义为句号、一个或多个下划线、一个或多个破折号。名称组件不能以分隔符开始或结束
镜像由清单和层列表组成。除了指向这些工件组合的“tag”之外,不要太担心清单和层。一个经镜像可以有多个 tag。让我们为构建的镜像创建第二个 tag,并查看它的层。
要为上面创建的镜像构建新 tag,请运行以下命令:
docker tag python-docker:latest python-docker:v1.0.0
·docker tag` 命令为镜像创建一个新 tag,而不是创建一个新镜像。新 tag 和 旧 tag 指向相同的镜像,新 tag 只是引用镜像的另一种方式。
现在,运行 docker images
命令查看本地镜像列表。
docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
python-docker latest 8cae92a8fbd6 4 minutes ago 123MB
python-docker v1.0.0 8cae92a8fbd6 4 minutes ago 123MB
python 3.8-slim-buster be5d294735c6 9 days ago 113MB
你可以看到,我们有两个以 python-docker
开头的镜像。我们知道它们是相同的镜像,因为如果你看一下 IMAGE ID
列,你可以看到这两个镜像的值是相同的。
让我们删除刚才创建的 tag。为此,我们要使用 rmi
命令,rmi
命令代表删除镜像。
docker rmi python-docker:v1.0.0
Untagged: python-docker:v1.0.0
注意,Docker 的响应告诉我们镜像并没有被删除,只是未标记。你可以运行 docker images
命令进行检查。
docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
python-docker latest 8cae92a8fbd6 6 minutes ago 123MB
python 3.8-slim-buster be5d294735c6 9 days ago 113MB
标记为 :v1.0.0
的镜像已经被删除,但我们的机器上仍有标记为 :latest
的镜像。
总结
在本模块中,我们介绍了如何设置示例 Python 应用程序,我们将在本教程的其余部分中使用该应用程序。我们还创建了一个 Dockerfile,用于构建 Docker 镜像。然后,我们学习了给镜像加标签和删除镜像。在下一个模块中,我们将了解如何将镜像作为容器运行。
运行
预备知识
阅读构建模块以了解如何构建一个 Python 镜像。
概述
前一个模块中,我们创建了示例应用程序,然后创建了一个用于生成镜像的 Dockerfile。我们使用 docker 命令 docker build 来创建映像。既然我们已经有了一个镜像,可以运行该镜像,看看应用程序是否能够正常运行。
容器是一个正常的操作系统进程,但这个进程是隔离的,因为它有自己的文件系统、自己的网络和自己独立于主机的独立进程树。
要在容器中运行镜像,我们可以可以使用 docker run
命令。docker run
命令需要一个参数,即镜像的名称。让我们启动镜像并确保它能正常运行。在终端运行以下命令。
docker run python-docker
运行此命令后,你会注意到没有返回到命令提示符。这是因为我们的应用程序是一个在循环中运行的 REST 服务器,持续等待传入的请求,而不会将控制权返回给操作系统,直到我们停止容器。
让我们打开一个新的终端,然后使用 curl
命令向服务器发起一个 GET
请求。
curl localhost:5000
curl: (7) Failed to connect to localhost port 5000: Connection refused
如你所见,我们的 curl
命令失败了,因为到服务器的连接被拒绝了。这意味着,我们无法链接到端口5000的主机。这是意料之中的,因为我们的容器是独立运行的,其中包括网络。让我们停止容器,并在本地网络上发布端口5000后重新启动。
要停止容器,请按 ctrl-c。这将返回到终端提示符。
要发布容器的端口,我们将在 docker run
命令上使用 --publish
参数(简称 -p
)。--publish
命令的格式是 [host port]:[container port]
。因此,如果我们想将容器内的端口5000公开给容器外的端口3000,我们将把 3000:5000
传递给 --publish
参数。
在容器中运行 flask 应用程序时,我们没有指定端口,默认值是5000。如果我们希望之前对端口5000的请求生效,我们可以将主机的端口5000映射到容器的端口5000:
docker run --publish 5000:5000 python-docker
现在,让我们按照上面一样重新运行 curl 命令。记得打开一个新的终端。
curl localhost:5000
Hello, Docker!
成功了!我们能够在端口5000上连接到容器中运行的应用程序。切换回运行容器的终端,您应该看到控制台记录了 GET 请求。
[04/Oct/2021 07:22:28] "GET / HTTP/1.1" 200 -
按 ctrl-c 停止容器。
以分离模式运行
到目前为止,这很好,但是我们的样例应用程序是一个 Web 服务器,我们不需要连接到容器。Docker 可以以分离模式或在后台运行容器。为此,我们可以使用 --detach
或缩写为 -d
。Docker 会像以前一样启动您的容器,但这次将从容器“分离”并返回到终端提示符。
docker run -d -p 5000:5000 python-docker
6505e11551b2f34e7ac16071a30df26b905205d7c0f8961baa1e4427c21beb74
列出容器
因为我们是在后台运行容器的,我们如何知道容器是否在运行,或者其他什么容器在我们的机器上运行?我们可以运行 docker ps
命令。就像在查看 Linux 机器上的进程列表一样,我们可以运行 ps
命令。本着同样设计理念,我们可以运行 docker ps
命令,该命令显示机器上运行的容器列表。
docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
6505e11551b2 python-docker "python3 -m flask ru…" 5 minutes ago Up 5 minutes 0.0.0.0:5000->5000/tcp, :::5000->5000/tcp serene_gauss
docker ps
命令提供了一系列关于正在运行的容器的信息。我们可以看到容器 ID、容器内运行的镜像、用于启动容器的命令、创建容器的时间、状态、公开的端口以及容器的名称。
您可能想知道我们的容器名称来自哪里。由于我们在启动容器时没有提供容器的名称,Docker 生成了一个随机名称。我们将在一分钟内解决这个问题,但首先我们需要停止容器。要停止容器,请运行 docker stop
命令,该命令将停止容器。您需要传递容器的名称,或者您可以使用容器 ID。
docker stop wonderful_kalam
wonderful_kalam
现在,重新运行 docker ps
命令,查看正在运行的容器列表。
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
停止、启动和命名容器
您可以启动、停止和重新启动 Docker 容器。当我们停止一个容器时,它不是被删除,而是状态被更改为已停止,容器内的进程也将停止。当我们在前一个模块中运行 docker ps
命令时,默认输出只显示正在运行的容器。
当我们传递 --all
或 -a
参数时,我们会看到机器上的所有容器,而不管它们的启动或停止状态如何。
docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
ce02b3179f0f python-docker "python3 -m flask ru…" 16 minutes ago Exited (0) 5 minutes ago wonderful_kalam
ec45285c456d python-docker "python3 -m flask ru…" 28 minutes ago Exited (0) 20 minutes ago agitated_moser
fb7a41809e5d python-docker "python3 -m flask ru…" 37 minutes ago Exited (0) 36 minutes ago goofy_khayyam
您现在应该看到列出了几个容器。这些是我们开始和停止但没有被移走的容器。
让我们重新启动刚刚停止的容器。找到我们刚刚停止的容器的名称,并在 restart 命令中替换下面容器的名称。
docker restart wonderful_kalam
wonderful_kalam
现在使用 docker ps
命令再次列出所有容器。
docker ps --all
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
ce02b3179f0f python-docker "python3 -m flask ru…" 19 minutes ago Up 8 seconds 0.0.0.0:5000->5000/tcp wonderful_kalam
ec45285c456d python-docker "python3 -m flask ru…" 31 minutes ago Exited (0) 23 minutes ago agitated_moser
fb7a41809e5d python-docker "python3 -m flask ru…" 40 minutes ago Exited (0) 39 minutes ago goofy_khayyam
注意,我们刚刚重启的容器是在分离模式下启动的,并且公开了端口5000。另外,观察容器的状态为“Up X seconds”。当您重新启动容器时,它将以与最初启动时相同的参数或命令启动。
现在,让我们停止并移除所有容器,看看如何修复随机命名问题。停止我们刚才启动的容器。找到正在运行的容器的名称,并将下面命令中的名称替换为系统上的容器名称。
docker stop wonderful_kalam
wonderful_kalam
现在,我们所有的容器都停止了,让我们把它们移除吧。移除容器时,该容器将不再运行,也不会处于停止状态,但容器内的进程已停止,容器的元数据已被删除。
docker ps --all
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
ce02b3179f0f python-docker "python3 -m flask ru…" 19 minutes ago Up 8 seconds 0.0.0.0:5000->5000/tcp wonderful_kalam
ec45285c456d python-docker "python3 -m flask ru…" 31 minutes ago Exited (0) 23 minutes ago agitated_moser
fb7a41809e5d python-docker "python3 -m flask ru…" 40 minutes ago Exited (0) 39 minutes ago goofy_khayyam
要删除容器,只需运行 docker rm
命令传递容器名称。您可以使用单个命令将多个容器名称传递给该命令。同样,将下面命令中的容器名称替换为系统中的容器名称。
docker rm wonderful_kalam agitated_moser goofy_khayyam
wonderful_kalam
agitated_moser
goofy_khayyam
再次运行 docker ps --all
命令以查看是否已删除所有容器。
现在,让我们讨论一下随机命名问题。标准做法是命名容器,原因很简单,即更容易识别容器中运行的内容以及与之关联的应用程序或服务。
要命名容器,只需将 --name
参数传递给 docker run
命令。
docker run -d -p 5000:5000 --name rest-server python-docker
1aa5d46418a68705c81782a58456a4ccdb56a309cb5e6bd399478d01eaa5cdda
docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
1aa5d46418a6 python-docker "python3 -m flask ru…" 3 seconds ago Up 3 seconds 0.0.0.0:5000->5000/tcp rest-server
太好了!现在,我们可以根据名称轻松识别容器。
总结
在本模块中,我们了解了如何运行容器、发布端口和在分离模式下运行容器。我们还介绍了通过启动、停止和重新启动容器来管理容器。我们还研究了为容器命名,以便它们更容易识别。在下一个模块中,我们将学习如何在容器中运行数据库并将其连接到应用程序。
开发
预备知识
阅读运行模块以了解如何将镜像作为容器运行。
简介
在本模块中,我们将介绍如何为在前面模块中构建的应用程序设置本地开发环境。我们将使用 Docker 构建我们的镜像,Docker Compose 使一切变得更加简单。
在容器中运行数据库
首先,我们将了解如何在容器中运行数据库,以及如何使用卷和网络来持久化数据并允许应用程序与数据库通信。然后,我们将把所有内容合并到一个 Compose 文件中,该文件允许我们使用一个命令设置和运行本地开发环境。最后,我们将研究如何将调试器连接到在容器中运行的应用程序。
我们不需要下载 mysql、安装、配置 MySQL 数据库,然后将其作为服务运行,而可以使用 Docker 官方 MySQL 映像并在容器中运行它。
在容器中运行MySQL之前,我们将创建两个卷,Docker可以管理这些卷来存储持久数据和配置。让我们使用 Docker 提供的托管卷功能,而不是使用绑定装载。您可以在我们的文档中阅读有关使用卷的所有内容。
现在让我们创建卷。我们将为数据和 MySQL 的配置各创建一个。
docker volume create mysql
docker volume create mysql_config
现在,我们将创建一个网络,应用程序和数据库将使用该网络相互通信。该网络称为用户定义的网桥网络,它为我们提供了一个很好的 DNS 查询服务,我们可以在创建连接字符串时使用该服务。
docker network create mysqlnet
现在我们可以在容器中运行 MySQL,并连接到上面创建的卷和网络。Docker 从 Hub 拉取映像并在本地运行它。在以下命令中,选项 -v
用于启动具有卷的容器。要了解更多信息,请参见 Docker卷。
docker run --rm -d -v mysql:/var/lib/mysql \\
-v mysql_config:/etc/mysql -p 3306:3306 \\
--network mysqlnet \\
--name mysqldb \\
-e MYSQL_ROOT_PASSWORD=p@ssw0rd1 \\
mysql
现在,让我们确保 MySQL 数据库正在运行,并且可以连接到它。使用以下命令连接到容器内正在运行的 MySQL 数据库,然后输入“p@ssw0rd1”当提示输入密码时:
docker exec -ti mysqldb mysql -u root -p
Enter password:
Welcome to the MySQL monitor. Commands end with ; or \\g.
Your MySQL connection id is 8
Server version: 8.0.23 MySQL Community Server - GPL
Copyright (c) 2000, 2021, Oracle and/or its affiliates.
Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.
Type 'help;' or '\\h' for help. Type '\\c' to clear the current input statement.
mysql>
将应用程序连接到数据库
在上面的命令中,我们通过将“MySQL”命令传递给 mysqldb
容器来登录 MySQL 数据库。按 CTRL-D 退出 MySQL 交互终端。
接下来,我们将更新在构建模块中创建的示例应用程序。要查看 Python 应用程序的目录结构,请参见 Python 应用程序目录结构。
好的,现在我们有了一个正在运行的 MySQL,让我们更新 app.py
以使用 MySQL 作为数据存储。我们还要向服务器添加一些路由。一个用于获取记录,另一个用于插入记录。
import mysql.connector
import json
from flask import Flask
app = Flask(__name__)
@app.route('/')
def hello_world():
return 'Hello, Docker!'
@app.route('/widgets')
def get_widgets() :
mydb = mysql.connector.connect(
host="mysqldb",
user="root",
password="p@ssw0rd1",
database="inventory"
)
cursor = mydb.cursor()
cursor.execute("SELECT * FROM widgets")
row_headers=[x[0] for x in cursor.description] #this will extract row headers
results = cursor.fetchall()
json_data=[]
for result in results:
json_data.append(dict(zip(row_headers,result)))
cursor.close()
return json.dumps(json_data)
@app.route('/initdb')
def db_init():
mydb = mysql.connector.connect(
host="mysqldb",
user="root",
password="p@ssw0rd1"
)
cursor = mydb.cursor()
cursor.execute("DROP DATABASE IF EXISTS inventory")
cursor.execute("CREATE DATABASE inventory")
cursor.close()
mydb = mysql.connector.connect(
host="mysqldb",
user="root",
password="p@ssw0rd1",
database="inventory"
)
cursor = mydb.cursor()
cursor.execute("DROP TABLE IF EXISTS widgets")
cursor.execute("CREATE TABLE widgets (name VARCHAR(255), description VARCHAR(255))")
cursor.close()
return 'init database'
if __name__ == "__main__":
app.run(host ='0.0.0.0')
我们添加了 MySQL 模块,并更新了连接到数据库服务器的代码,创
以上是关于Docker + Python使用 Docker 创建容器化 Python 应用程序(入门指南)的主要内容,如果未能解决你的问题,请参考以下文章
使用Docker Python SDK登录注册表(docker-py)
Docker:如何在 Centos 6.8 docker 文件中设置和使用 python 2.7