发布于 2026-01-06 0 阅读
0

将 Python 应用 Docker 化 wemake-django-template

将 Python 应用容器化

wemake-django-template

概述

相关 xkcd

Python 是最流行的编程语言之一,应用范围非常广泛,从构建后端到创建神经网络都能胜任。然而,正如上文所述,在不同项目之间保持 Python 环境的一致性可能非常麻烦。

这时 Docker 就派上了用场。Docker 支持应用程序容器化,这意味着您可以运行服务和应用程序的独立实例。此外,Docker 还允许您使用 Docker Compose 将应用程序和服务连接起来,这使得构建 Python 应用程序变得非常便捷。

请注意,本文中引用的所有代码均来自此GitHub 代码库。这是一个正在运行的应用程序,虽然该版本中的代码尚未达到生产就绪状态,但仍然可以通过 Docker 运行所有功能。

什么是 Docker?

Docker到底是什么?我前面已经简单介绍过了,正如前面提到的,它是一款可以将应用程序和服务容器化的软件。它的优势在于,你无需安装和使用多个Python版本,也无需管理多个虚拟环境,Docker可以为每个应用程序分别构建独立的隔离环境。

这意味着我们不需要python -m venv venv每次构建新项目时都运行,只要我们设置好DockerFile一个docker-compose.yml文件即可。

图片、容器和排版

好了,既然这件事已经解决了,我们需要快速复习一些词汇。

首先是 Docker 镜像。Docker 镜像本质上是应用程序的一个不可变的“快照”。它包含在新的容器中启动应用程序的指令,并且可以与其他镜像一起构建。这种不可变性非常重要,因为它允许我们拥有同一应用程序的多个版本,而不会出现镜像版本冲突的情况。

其次是 Docker 容器。Docker 容器是基于我们镜像运行的应用程序实例。它类似于前面提到的“快照”的复制品,无法共享。但是,我们可以根据需要启动任意数量的特定镜像的 Docker 容器,这对于数据库和类似服务来说非常方便!

安装 Docker

如果您还没有安装Docker Desktop ,则需要先进行安装。如果您已经安装了 Docker Desktop 并且知道如何操作,则可以跳到下一节

我还会简要介绍一下您可以使用 Docker CLI 运行的一些命令。

  docker image ls
Enter fullscreen mode Exit fullscreen mode

docker image ls列出您计算机上当前所有可用的图像。

  docker container ls
Enter fullscreen mode Exit fullscreen mode

docker container ls列出所有当前已启动/正在运行的容器。

  docker container ls -a
Enter fullscreen mode Exit fullscreen mode

docker container ls -a列出所有容器,无论它们是否已启动或处于活动状态。该-a标志是以下情况的缩写:--all

  docker container rm <first 3 symbols of the container ID or container name> [...other containers you want to remove]
Enter fullscreen mode Exit fullscreen mode

docker container rm移除列出的容器。请注意,您需要提供容器 ID 的前三位字符或容器名称,并且移除容器之前该容器不能正在运行。

  docker [COMMAND] --help
Enter fullscreen mode Exit fullscreen mode

帮助标志非常有用,可以与任何命令一起使用。它会列出所有选项,并提供命令的使用说明。

设置 Docker 环境

也就是说,要设置 Docker 环境,我们需要一些东西。

  1. 我们需要为我们的应用程序创建一个 Docker 镜像。
  2. 我们需要以某种方式协调我们的应用程序使用的所有数据库。

关于第一点,这就是 `.a` 文件的作用Dockerfile。`.a`Dockerfile文件定义了设置和运行应用程序所需的命令行参数。简单来说,它是一个指定设置和运行应用程序所需的最基本信息的文件。

以下是一个示例Dockerfile

FROM python:3.8

WORKDIR /src

COPY ./requirements.txt .

RUN pip install -r requirements.txt

COPY . .

EXPOSE 5000

CMD ["flask", "run", "--host", "0.0.0.0"]
Enter fullscreen mode Exit fullscreen mode

Dockerfile 中包含什么内容

简单概括一下所有内容:

第一行指定我们的应用程序镜像基于 Python 3.8 镜像。

  • 既然我们可以利用其他图像来构建自己的图像,我们就充分利用了这一点。
  • 更多镜像可以在DockerHub中找到。
  • 我们用冒号后跟标签来指定所需的标签/版本,所以这里python:3.8指定的是Python 3.8标签

第二行代码设置了容器的工作目录。这一点很重要,因为我们的应用程序文件将存放在这个目录中。

第三行代码将requirements.txt文件复制到我们的工作目录中。我们可以一次性复制所有内容,但实际上我们不这样做是有重要原因的,接下来会解释。

第四行会运行我们列出的命令。所以这里它会根据requirements.txt文件安装我们的 Python 包。

  • 我们单独执行此操作,因为 Docker 会缓存我们可能需要的任何外部软件包,具体取决于requirements.txt(或package.jsonNPM)的更改。
  • 如果我们不这样做,Docker 每次都会卸载缓存的软件包,浪费大量原本可以节省的时间。

第五行代码将应用程序目录中的剩余文件复制到工作目录中。如果需要,我们也可以将其添加到不同的子目录中,如下所示:

COPY . ./my-subdirectory
Enter fullscreen mode Exit fullscreen mode

第六行定义了一个端口,供我们访问容器。这里是端口 5000。

最后一行指定了容器启动时要执行的默认命令。请注意,命令的每个部分都位于一个数组中。

  • 请注意,这种字符串数组是首选方法,并且每个命令片段都必须用双引号 (") 括起来,因为它会被解析为 JSON 数组。

Docker Compose

太好了,那数据库呢?当然,我们可以在本地运行数据库,但由于 Docker 也提供了数据库镜像,我们实际上可以运行任意数量的容器来运行我们的数据库。

但这里有个大问题,我们不想手动创建和启动应用程序依赖的每一个服务。如果只有一个数据库,那当然没问题,但如果我们有两个不同的数据库,而且还有一个应用程序/服务需要自己的数据库呢?

这就docker-compose派上用场了(随着规模扩大,Kubernetes 也派上用场了,但这又是另一个话题了)。与其手动启动和创建应用程序所依赖的服务的容器,不如使用一个docker-compose.yml配置文件来自动化大部分操作。

请点击以下链接查看示例docker-compose.yml文件

遗憾的是,本文无法提供完整的 Docker Compose 文件创建指南,但我会概述各个部分。

所以文件中包含以下内容(可能有一些注释):

version: '3.5' # Docker compose version
services:
  app:
    build:
      context: .
    # Binding the current working directory to the new container
    volumes:
      - .:/
    # The working directory in the app Dockerfile
    working_dir: ''
    command: ''
    links:
      - app-redis
    # ENV configuration
    env_file: .env
    # Additional app secrets
    environment:
      APP_TOKEN: /run/secrets/app_token
    secrets:
      - app_token
    ports:
      - '5000:5000'
  app-redis:
    image: redis:5
    ports:
      - '6379:6379'
# App secret registration
secrets:
  app_token:
    file: app_token.txt
Enter fullscreen mode Exit fullscreen mode

总体而言,compose 文件包含三个主要部分:

  • 我们想要的 Docker Compose 版本
    • 指定 Docker Compose 版本非常重要,因为某些属性在其他版本中不可用,更多信息请参阅Docker Compose v3 文档。
  • 注册服务
  • 注册容器密钥

在服务注册部分,我们有以下内容:

  • 配置我们的 Python 应用容器
    • 将我们的容器连接到另一个服务(Redis)
    • 绑定我们的工作目录,以便我们可以实时更新容器。
    • 添加 .env 文件
    • 添加我们的应用程序秘密
    • 暴露端口并启动命令
  • 配置 Redis 容器
    • 添加要从中构建容器的镜像
    • 暴露端口

请注意,该links属性的作用是明确表明该app-redis服务是我们 Python 应用的依赖项。这意味着我们在 Flask 应用中访问数据库的方式与通常情况不同,但我们稍后会详细介绍。

我们的 Python 应用程序需要更新

现在我们已经启动了docker-compose.yml文件,但我们不能像之前那样访问 Redis 实例了。因此,localhost我们不能再像以前那样让 Python 应用程序访问 Redis 实例,而是需要更新它,使其使用服务名称,如下所示:

# Fetch.py
# Std lib imports
import os
import json
from pathlib import Path

## Lib Imports
import redis
import requests
from dotenv import load_dotenv

# Global Module Var
isDocker = os.getenv('IS_DOCKER')

cacheHost = 'app-redis'
# ...Extra code
red_cache = redis.Redis(host = cacheHost, port = 6379)
# ...Rest of the module's implementation
Enter fullscreen mode Exit fullscreen mode

非常快捷方便,这样我们就可以docker-compose up在我们的应用程序目录中运行并启动 Flask 应用程序。

结论

所以我们总结了如何快速将 Python 应用 Docker 化。这包括以下步骤:

  1. 创建 Dockerfile 时:
    • 我们开发这款应用所依据的图片
    • 我们正在复制的内容
    • 我们想要运行的任何终端命令
    • 启动命令
    • 一个要暴露的端口
  2. 创建docker-compose.yml包含以下内容的文件:
    • Docker Compose 的版本
    • 将要创建和运行的服务列表
    • 上述服务需要明确说明它们之间是否相互关联。
    • 此外,我们的 Python 应用程序所连接的服务还进行了额外的 .env 和密钥设置。
    • 我们想在应用程序中隐藏的任何秘密

最终生成的应用程序的依赖项由 Docker而非本地机器提供。这使得开发环境每次都能保持一致的性能和配置。

文章来源:https://dev.to/wilsonj806/dockerizing-a-python-app-2ee