» Python:使用Flask构建REST API » 3. 部署 » 3.3 Docker和Docker Compose

Docker 和 Docker Compose

Docker 允许开发人员将他们的应用程序与所有依赖项一起打包到一个称为容器的单个单元中。这确保了在不同环境(如开发、测试和生产环境)之间的一致性,从而缓解了“它在我的机器上能跑”的问题。

安装 Docker:https://docs.docker.com/engine/install/

Dockerfile

Dockerfile 是一个包含构建 Docker 镜像指令的文本文件。它定义了创建 Docker 镜像所需的步骤,作为将来启动 Docker 容器的蓝图。

添加 Dockerfile

# Use Alpine Linux with Python 3 as base image
FROM python:3.9.18-alpine3.19

# Set the working directory in the container
WORKDIR /app

# Copy the dependencies file to the working directory
COPY requirements.txt .

# Install dependencies
RUN pip install --no-cache-dir -r requirements.txt
RUN pip install gunicorn

# Copy the current directory contents into the container at /app
COPY books/ /app/books
COPY main.py /app

# Expose port 8000
EXPOSE 5000

# Command to run the Flask application with Gunicorn
CMD ["gunicorn", "-w", "2", "-b", "0.0.0.0:5000", "main:app"]

Alpine Linux 是一个轻量级的安全的 Linux 发行版,特别适用于容器化环境、嵌入式系统和资源受限环境。这些环境下效率和安全性至关重要。

构建你的 docker 镜像:

docker build . -t lrbooks-py:latest

注意
如果遇到权限问题,使用 sudo docker ...

执行 docker images 来检查镜像:

docker images

结果:

REPOSITORY                 TAG       IMAGE ID       CREATED         SIZE
lrbooks-py                 latest    741a7999d19f   9 seconds ago   74.1MB
...

Docker Compose

Docker Compose 是一个用于定义和运行多容器的 Docker 工具。它允许你使用 YAML 文件配置应用程序的服务、网络和卷,然后使用单个命令启动所有运行所需的容器,包括应用程序的依赖中间件和服务。

注意

安装 Docker Compose 最方便最推荐的方式是安装 Docker 桌面版。Docker 桌面版包含了 Docker 引擎,Docker CLI 和 Docker Compose。

按需安装 Compose:https://docs.docker.com/compose/install/

添加 compose/docker-compose.yml:

services:
  lr-rest-books:
    image: lrbooks-py:latest
    ports:
      - 5000:5000
    volumes:
      - ./config.yml:/app/config.yml
    depends_on:
      mysql:
        condition: service_healthy
      redis:
        condition: service_started
      mongo:
        condition: service_started
  redis:
    image: docker.io/bitnami/redis:7.0
    environment:
      - REDIS_PASSWORD=${REDIS_PASSWORD}
    ports:
      - 6379:6379
  mysql:
    image: docker.io/bitnami/mysql:5.7.43
    environment:
      - MYSQL_DATABASE=lr_book
      - MYSQL_USER=test_user
      - MYSQL_PASSWORD=${MYSQL_PASSWORD}
      - MYSQL_ROOT_PASSWORD=${MYSQL_ROOT_PASSWORD}
    ports:
      - 3306:3306
    healthcheck:
      test: ["CMD", "mysqladmin", "ping", "-h", "localhost"]
      timeout: 20s
      retries: 10
    volumes:
      - ~/lr-mysql-data:/bitnami/mysql/data
  mongo:
    image: bitnami/mongodb:latest
    environment:
      - ALLOW_EMPTY_PASSWORD=yes
    ports:
      - 27017:27017
    volumes:
      - ~/lr-mongodb-data:/bitnami/mongodb

添加专用于 Compose 的配置文件,compose/config.yml:

app:
  port: 5000
  page_size: 5
  token_secret: "I_Love_LiteRank"
  token_hours: 24
db:
  file_name: "test.db"
  host: mysql
  port: 3306
  user: "test_user"
  password: "test_pass"
  database: "lr_book"
  mongo_uri: "mongodb://mongo:27017"
  mongo_db_name: "lr_book"
cache:
  host: redis 
  port: 6379
  password: "test_pass"
  db: 0

添加 compose/.env 用于设置环境变量:

REDIS_PASSWORD=test_pass
MYSQL_PASSWORD=test_pass
MYSQL_ROOT_PASSWORD=test_root_pass

Caution: .env files should be ignored in .gitignore.

更改 .gitignore:

 lrFlaskEnv/
 test.db
+.env

执行:

cd compose
docker compose up

你应该看到类似下方内容:

[+] Running 4/4
 ✔ Container compose-mongo-1          Created                                                                                                                                                                                          0.0s 
 ✔ Container compose-redis-1          Created                                                                                                                                                                                          0.0s 
 ✔ Container compose-mysql-1          Recreated                                                                                                                                                                                        0.1s 
 ✔ Container compose-lr-rest-books-1  Recreated                                                                                                                                                                                        0.0s 
Attaching to lr-rest-books-1, mongo-1, mysql-1, redis-1
redis-1          | redis 13:24:52.38 
redis-1          | redis 13:24:52.39 Welcome to the Bitnami redis container
...

mongo-1          | mongodb 13:24:52.60 INFO  ==> 
mongo-1          | mongodb 13:24:52.60 INFO  ==> Welcome to the Bitnami mongodb container
mongo-1          | mongodb 13:24:52.61 INFO  ==> ** Starting MongoDB setup **
...
mysql-1          | mysql 13:24:52.61 
mysql-1          | mysql 13:24:52.62 Welcome to the Bitnami mysql container
mysql-1          | mysql 13:24:52.63 INFO  ==> ** Starting MySQL setup **
...

你不再需要手动安装那些数据库。它们都被 docker compose 搞定了。

如果你发一些请求到 5000 端口的 api 服务器,你将看到如下日志:

lr-rest-books-1  | [2024-03-08 15:46:08 +0000] [8] [DEBUG] GET /books
lr-rest-books-1  | [2024-03-08 15:46:09 +0000] [8] [DEBUG] GET /books
lr-rest-books-1  | [2024-03-08 15:46:10 +0000] [8] [DEBUG] GET /books
lr-rest-books-1  | [2024-03-08 15:46:11 +0000] [8] [DEBUG] GET /books

如果你想跳过 docker 镜像构建步骤,可以调整 compose/docker-compose.yml

@@ -1,6 +1,8 @@
 services:
   lr-rest-books:
-    image: lrbooks-py:latest
+    build:
+      context: ../
+      dockerfile: Dockerfile
     ports:
       - 5000:5000
     volumes:

再次运行:

docker compose up

Compose 插件会自动按需构建你的镜像。

[+] Building 2.8s (13/13) FINISHED                                                                                                                                                                                     docker:desktop-linux
 => [lr-rest-books internal] load build definition from Dockerfile                                                                                                                                                                     0.0s
 => => transferring dockerfile: 633B                                                                                                                                                                                                   0.0s
 => [lr-rest-books internal] load metadata for docker.io/library/python:3.9.18-alpine3.19                                                                                                                                              2.7s
 => [lr-rest-books auth] library/python:pull token for registry-1.docker.io                                                                                                                                                            0.0s
 => [lr-rest-books internal] load .dockerignore                                                                                                                                                                                        0.0s
 => => transferring context: 89B                                                                                                                                                                                                       0.0s
 => [lr-rest-books 1/7] FROM docker.io/library/python:3.9.18-alpine3.19@sha256:ce83ae657ad10635ea43ecd5efb6ca50bec62183148e37fba075e18a8a34868f                                                                                        0.0s
 => [lr-rest-books internal] load build context                                                                                                                                                                                        0.0s
 => => transferring context: 2.37kB                                                                                                                                                                                                    0.0s
 => CACHED [lr-rest-books 2/7] WORKDIR /app                                                                                                                                                                                            0.0s
 => CACHED [lr-rest-books 3/7] COPY requirements.txt .                                                                                                                                                                                 0.0s
 => CACHED [lr-rest-books 4/7] RUN pip install --no-cache-dir -r requirements.txt                                                                                                                                                      0.0s
 => CACHED [lr-rest-books 5/7] RUN pip install gunicorn                                                                                                                                                                                0.0s
 => CACHED [lr-rest-books 6/7] COPY books/ /app/books                                                                                                                                                                                  0.0s
 => CACHED [lr-rest-books 7/7] COPY main.py /app                                                                                                                                                                                       0.0s
 => [lr-rest-books] exporting to image                                                                                                                                                                                                 0.0s
 => => exporting layers                                                                                                                                                                                                                0.0s
 => => writing image sha256:4fb63b26ccd7a5803055ec9898b324a6a78c0b0f5ae5ca8f516cbcdde5b921f3                                                                                                                                           0.0s
 => => naming to docker.io/library/compose-lr-rest-books         
...

现在,你可以用 curl 再次测试那些端点。它们应该表现得超预期的顺滑。

Kubernetes

如果你的云原生方案想更进一步的话,请尝试 Kubernetes

它也被称为 K8s,是一个用于自动化部署、扩展和管理容器化应用程序的开源系统。

创建一个如下的部署 yaml:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: lr-books-deployment
spec:
  replicas: 3
  selector:
    matchLabels:
      app: lr-books
  template:
    metadata:
      labels:
        app: lr-books
    spec:
      containers:
      - name: lr-books-api
        image: lrbooks:latest
        ports:
        - containerPort: 5000

然后执行如下命令使其生效:

kubectl apply -f lr-books-deployment.yaml