ZetCode

Python Docker

最后修改于 2024 年 1 月 29 日

Python Docker 教程展示了如何为 Python 应用程序使用 Docker。

Docker

Docker 是一个供开发人员和系统管理员使用容器构建、运行和共享应用程序的平台。Docker 促进了应用程序的可移植性和可伸缩性。Docker 提供应用程序隔离,从而消除了许多由库和环境差异引起的问题。它有助于自动化开发和部署。通过预定义的社区镜像,开发人员可以节省时间并改善他们的整体体验。

一个 Docker 镜像 是一个只读模板,其中包含创建 Docker 容器的说明。一个 Docker 容器 是镜像的一个可运行实例。

Docker 镜像存储在仓库中。Docker Hub 是官方 Docker 仓库。Docker Engine 是底层的客户端-服务器技术,它使用 Docker 的组件和服务来构建和运行容器。

一个 Dockerfile 是一个特殊的文件,其中包含构建 Docker 镜像所需的指令。

$ sudo docker --version
Docker version 19.03.12, build 48a66213fe

这是我们使用的 Docker 版本。

Python Docker hello 示例

在下面的示例中,我们将创建一个非常简单的 Docker 镜像并运行它。当我们运行镜像时,将执行一个简单的 Python 文件。

hello.py
#!/usr/bin/python

import sys

print("hello there!")
print(sys.version)

这是将在容器内执行的简单文件。

Dockerfile
FROM python:3.8
COPY hello.py /tmp/
CMD ["python", "/tmp/hello.py"]

这些是构建 Docker 镜像的指令。

FROM python:3.8

我们的镜像基于社区的 python:3.8 镜像。

COPY hello.py /tmp/

COPY 指令将 hello.py 文件复制到镜像的 tmp 目录中。

CMD ["python", "/tmp/hello.py"]

CMD 指令启动 Python 程序。

$ sudo docker build -t hello .

我们构建镜像并将其命名为 hello

$ sudo docker images
REPOSITORY             TAG             IMAGE ID            CREATED             SIZE
hello                  latest          60251c18f538        5 minutes ago       882MB
firstimage             latest          319917db1025        5 hours ago         111MB
python                 slim            38cd21c9e1a8        5 days ago          113MB
python                 3.8             79cc46abd78d        5 days ago          882MB
python                 latest          79cc46abd78d        5 days ago          882MB

我们使用 docker images 命令列出可用的镜像。

$ sudo docker run hello
hello there!
3.8.5 (default, Aug  5 2020, 08:22:02) 
[GCC 8.3.0]

我们运行 hello 镜像。

Python Docker 交互模式

我们可以通过使用 -it 选项以交互模式运行镜像。-it 指示 Docker 分配一个连接到容器 stdin 的伪 TTY;在容器中创建一个交互式 bash shell。

$ sudo docker run -it python3.8:slim bash
root@98ece0c01946:/#

我们运行镜像并在容器内获取 bash shell。

root@98ece0c01946:/# python -c "import os; print(os.system('ls -l'))"

total 68
drwxr-xr-x   1 root root 4096 Aug  4 16:25 bin
drwxr-xr-x   2 root root 4096 Jul 10 21:04 boot
drwxr-xr-x   5 root root  360 Aug 19 13:40 dev
drwxr-xr-x   1 root root 4096 Aug 19 13:39 etc
drwxr-xr-x   2 root root 4096 Jul 10 21:04 home
drwxr-xr-x   1 root root 4096 Aug  4 16:25 lib
drwxr-xr-x   2 root root 4096 Aug  3 07:00 lib64
drwxr-xr-x   2 root root 4096 Aug  3 07:00 media
drwxr-xr-x   2 root root 4096 Aug  3 07:00 mnt
drwxr-xr-x   2 root root 4096 Aug  3 07:00 opt
dr-xr-xr-x 345 root root    0 Aug 19 13:40 proc
drwx------   1 root root 4096 Aug  4 16:18 root
drwxr-xr-x   3 root root 4096 Aug  3 07:00 run
drwxr-xr-x   2 root root 4096 Aug  3 07:00 sbin
drwxr-xr-x   2 root root 4096 Aug  3 07:00 srv
dr-xr-xr-x  13 root root    0 Aug 19 13:40 sys
drwxrwxrwt   1 root root 4096 Aug 11 20:37 tmp
drwxr-xr-x   1 root root 4096 Aug  3 07:00 usr
drwxr-xr-x   1 root root 4096 Aug  3 07:00 var
0

我们可以运行 Python 代码。

root@98ece0c01946:/# python -c "import sys; print(sys.version)"
3.8.5 (default, Aug  4 2020, 16:24:08) 
[GCC 8.3.0]

在我们的例子中,我们预装了 Python 3.8.5。

Python Docker get 请求

在下一个示例中,我们将构建一个检索 HTML 页面的镜像。我们使用 requests 库,该库必须安装在镜像中。

get_req.py
#!/usr/bin/python

import requests as req

resp = req.get("http://webcode.me")

print(resp.text)

代码示例通过发出 GET 请求来重试一个简单的网页。

Dockerfile
FROM python:slim
RUN pip install requests
COPY get_req.py /tmp/
CMD ["python", "/tmp/get_req.py"]

这是 Dockerfile

FROM python:slim

在此示例中,我们使用社区的 python:slim 镜像,该镜像占用的空间要小得多。

RUN pip install requests

使用 RUN 指令,我们执行 pip管理器并安装 requests 模块。

COPY get_req.py /tmp/

COPY 指令将 get_req.py 文件从我们的主机复制到容器的 /tmp/ 目录。如果目录不存在,则会创建该目录。

CMD ["python", "/tmp/get_req.py"]

CMD 指令在容器启动时运行程序。

$ sudo docker build -t pygetreq .

我们构建镜像并称之为 pygetreq

$ sudo docker images | grep pygetreq
pygetreq           latest          0d3c5953ff60        23 seconds ago      121MB

此镜像仅需要 121MB。

$ sudo docker run pygetreq
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>My html page</title>
</head>
<body>

    <p>
        Today is a beautiful day. We go swimming and fishing.
    </p>
    
    <p>
            Hello there. How are you?
    </p>
    
</body>
</html>

Python Docker Flask

在下一个示例中,我们将在 Docker 容器中运行一个简单的 Flask 应用程序。

app.py
#!/usr/bin/python

from flask import Flask

app = Flask(__name__)

@app.route('/')
def hello():
    return 'Hello there!'

这是一个带有单个主路由的简单 Flask 应用程序。

Dockerfile
FROM python:slim

COPY app.py /app/
WORKDIR /app
RUN pip install flask
RUN export FLASK_APP=app.py

EXPOSE 5000
CMD ["/usr/local/bin/flask", "run", "--host", "0.0.0.0"]

这是 Dockerfile。

FROM python:slim

我们的镜像基于 python-slim 镜像。

COPY app.py /app/
WORKDIR /app

我们将一个文件复制到镜像中的一个目录,并设置工作目录。如果目录尚不存在,则会创建它。

RUN pip install flask

使用 RUN 指令,我们安装 Flask。

RUN export FLASK_APP=app.py

我们将 FLASK_APP 环境变量设置为 app.py 应用程序文件。

EXPOSE 5000

我们暴露端口。

CMD ["/usr/local/bin/flask", "run", "--host", "0.0.0.0"]

使用 CMD 指令,我们设置了容器启动时运行的默认命令。我们将主机 IP 设置为 0.0.0.0,以便应用程序可以在容器外部访问。

$ sudo docker build -t flasksimple .

我们构建镜像。

$ docker run -p 5000:5000 flasksimple

我们运行镜像。容器的 5000 端口映射到我们计算机的 5000 端口。

$ curl localhost:5000/
Hello there!

使用 curl 工具,我们向应用程序生成一个 GET 请求。

Python Docker MariaDB

在以下示例中,我们将创建一个基于 mariadb 镜像的容器。

schema.sql
USE testdb;
DROP TABLE IF EXISTS cities;
CREATE TABLE cities(id INT PRIMARY KEY AUTO_INCREMENT, name VARCHAR(255), population INT);
INSERT INTO cities(name, population) VALUES('Bratislava', 432000);
INSERT INTO cities(name, population) VALUES('Budapest', 1759000);
INSERT INTO cities(name, population) VALUES('Prague', 1280000);
INSERT INTO cities(name, population) VALUES('Warsaw', 1748000);
INSERT INTO cities(name, population) VALUES('Los Angeles', 3971000);
INSERT INTO cities(name, population) VALUES('New York', 8550000);
INSERT INTO cities(name, population) VALUES('Edinburgh', 464000);
INSERT INTO cities(name, population) VALUES('Berlin', 3671000);

这是 cities 表的 SQL 代码。

Dockerfile
FROM mariadb

RUN apt-get update && apt-get install -y \
    python3.8 \
    python3-pip

RUN pip3 install pymysql

ADD schema.sql /docker-entrypoint-initdb.d

ENV MYSQL_USER=user7
ENV MYSQL_PASSWORD=7user
ENV MYSQL_DATABASE=testdb
ENV MYSQL_ROOT_PASSWORD=s$cret

EXPOSE 3306

我们的镜像源自 mariadb 镜像。

RUN apt-get update && apt-get install -y \
    python3.8 \
    python3-pip

在镜像上,我们安装 Python 和 pip。

RUN pip3 install pymysql

我们安装 pymysql 驱动程序。

ADD schema.sql /docker-entrypoint-initdb.d

/docker-entrypoint-initdb.d 目录下的 SQL 脚本在容器初始化时运行。我们使用 ADD 指令复制 schema 文件。

ENV MYSQL_USER=user7
ENV MYSQL_PASSWORD=7user
ENV MYSQL_DATABASE=testdb
ENV MYSQL_ROOT_PASSWORD=s$cret

通过环境变量,我们创建一个新用户、一个新数据库,并为 root 用户设置密码。

EXPOSE 3306

EXPOSE 指令通知 Docker 容器在运行时监听指定的网络端口。

app.py
#!/usr/bin/python

import pymysql

con = pymysql.connect(host='localhost', user='user7',
            password='7user', database='testdb', port=3306)

try:
    with con.cursor() as cur:

        cur.execute('SELECT * FROM cities')

        rows = cur.fetchall()

        for row in rows:
            print(f'{row[0]}, {row[1]}, {row[2]}')

finally:

    con.close()

该示例连接到正在容器内运行的 MariaDB testdb 数据库。它显示了 cities 表中的所有行。

$ sudo docker build -t pymaria-simple .
Sending build context to Docker daemon  4.608kB
Step 1/9 : FROM mariadb
    ---> b95867b52886
Step 2/9 : RUN apt-get update && apt-get install -y     python3.8     python3-pip
    ---> Using cache
    ---> 9370769248ed
Step 3/9 : RUN pip3 install pymysql
    ---> Using cache
    ---> 108146aaa2d8
...    

我们构建镜像。

$ sudo docker run -p 3306:3306 pymaria-simple

我们从自定义的 pymaria-simple 镜像运行容器。使用 -p 选项,我们将容器的 3306 端口发布到主机的 3306 端口。

$ ./app.py 
1, Bratislava, 432000
2, Budapest, 1759000
3, Prague, 1280000
4, Warsaw, 1748000
5, Los Angeles, 3971000
6, New York, 8550000
7, Edinburgh, 464000
8, Berlin, 3671000

容器启动后,我们运行 app.py 程序,该程序显示城市。

来源

Python Docker SDK

在本文中,我们使用 Python 和 Docker 进行了实践。

作者

我叫 Jan Bodnar,我是一名热情的程序员,拥有丰富的编程经验。我从 2007 年开始撰写编程文章。到目前为止,我已撰写了 1400 多篇文章和 8 本电子书。我在教授编程方面拥有十多年的经验。

列出所有 Python 教程