» Rust:使用Rocket构建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 a Rust Docker image as the base
FROM rust:1.76-alpine3.19 as builder

# Set the working directory inside the container
WORKDIR /app

# Install necessary packages
RUN apk update && \
    apk add --no-cache musl-dev pkgconfig openssl-dev

# Copy the Rust project files to the container
COPY Cargo.toml .
COPY src/ /app/src

# Define a build argument with a default value
ARG BINARY_NAME=lrbooks

# Build the Rust project
# See: https://github.com/rust-lang/rust/issues/115430
RUN RUSTFLAGS="-Ctarget-feature=-crt-static" cargo build --release --bin ${BINARY_NAME}

# Start a new stage from Alpine Linux
FROM alpine:3.19

# Install required packages
RUN apk update && \
    apk add --no-cache libgcc

# Define an environment variable from the build argument
ENV BINARY_NAME=lrbooks

# Set the working directory inside the container
WORKDIR /app

# Copy the built binary from the previous stage to the current stage
COPY --from=builder /app/target/release/${BINARY_NAME} .

# Command to run the binary when the container starts
CMD ./${BINARY_NAME}

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

构建你的 docker 镜像:

docker build . -t lrbooks-rust:latest

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

执行 docker images 来检查镜像:

docker images

结果:

REPOSITORY                 TAG       IMAGE ID       CREATED          SIZE
lrbooks-rust               latest    065660b9adf3   15 seconds ago   32.4MB
...

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-rust:latest
    ports:
      - 8000:8000
    volumes:
      - ./config.toml:/app/config.toml
    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.toml:

[app]
port = 8000
page_size = 5
token_secret = "I_Love_LiteRank"
token_hours = 48

[db]
file_name = "test.db"
dsn = "mysql://test_user:test_pass@mysql:3306/lr_book"
mongo_uri = "mongodb://mongo:27017"
mongo_db_name = "lr_book"

[cache]
redis_uri = "redis://:test_pass@redis:6379/0"

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

REDIS_PASSWORD=test_pass
MYSQL_PASSWORD=test_pass
MYSQL_ROOT_PASSWORD=test_root_pass

警告.env 文件应该在 .gitignore 中添加以告知 git 忽略该文件。

更改 .gitignore:

@@ -22,3 +22,4 @@ go.work
 
 test.db
 .vscode
+.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 搞定了。

如果你发一些请求到 8000 端口的 api 服务器,你将看到与之前类似的响应。

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

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

再次运行:

docker compose up

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

[+] Building 2.8s (18/18) FINISHED                                                                                                                                                                                     docker:desktop-linux
 => [lr-rest-books internal] load build definition from Dockerfile                                                                                                                                                                     0.0s
 => => transferring dockerfile: 1.09kB                                                                                                                                                                                                 0.0s
 => [lr-rest-books internal] load metadata for docker.io/library/alpine:3.19                                                                                                                                                           2.5s
 => [lr-rest-books internal] load metadata for docker.io/library/rust:1.76-alpine3.19                                                                                                                                                  2.5s
 => [lr-rest-books auth] library/alpine:pull token for registry-1.docker.io                                                                                                                                                            0.0s
 => [lr-rest-books auth] library/rust:pull token for registry-1.docker.io                                                                                                                                                              0.0s
 => [lr-rest-books internal] load .dockerignore                                                                                                                                                                                        0.0s
 => => transferring context: 2B                                                                                                                                                                                                        0.0s
 => [lr-rest-books builder 1/6] FROM docker.io/library/rust:1.76-alpine3.19@sha256:e594a9705c4514c0e0b5ed2409f7ec34f20af09a33d242524281247b74196c43                                                                                    0.0s
 => [lr-rest-books stage-1 1/4] FROM docker.io/library/alpine:3.19@sha256:c5b1261d6d3e43071626931fc004f70149baeba2c8ec672bd4f27761f8e1ad6b                                                                                             0.0s
 => [lr-rest-books internal] load build context                                                                                                                                                                                        0.0s
 => => transferring context: 2.15kB                                                                                                                                                                                                    0.0s
 => CACHED [lr-rest-books stage-1 2/4] RUN apk update &&     apk add --no-cache libgcc                                                                                                                                                 0.0s
 => CACHED [lr-rest-books stage-1 3/4] WORKDIR /app                                                                                                                                                                                    0.0s
 => CACHED [lr-rest-books builder 2/6] WORKDIR /app                                                                                                                                                                                    0.0s
 => CACHED [lr-rest-books builder 3/6] RUN apk update &&     apk add --no-cache musl-dev pkgconfig openssl-dev                                                                                                                         0.0s
 => CACHED [lr-rest-books builder 4/6] COPY Cargo.toml .                                                                                                                                                                               0.0s
 => CACHED [lr-rest-books builder 5/6] COPY src/ /app/src                                                                                                                                                                              0.0s
 => CACHED [lr-rest-books builder 6/6] RUN RUSTFLAGS="-Ctarget-feature=-crt-static" cargo build --release --bin lrbooks                                                                                                                0.0s
 => CACHED [lr-rest-books stage-1 4/4] COPY --from=builder /app/target/release/lrbooks .                                                                                                                                               0.0s
 => [lr-rest-books] exporting to image                                                                                                                                                                                                 0.0s
 => => exporting layers                                                                                                                                                                                                                0.0s
 => => writing image sha256:945642d6d2ff652f3e5c53ebc8ddf457f3ed1f7e8b80d6db73616667f08c76a6                                                                                                                                           0.0s
 => => naming to docker.io/library/compose-lr-rest-books                                                                                                                                                                               0.0s
[+] Running 4/0
 ✔ Container compose-redis-1          Created                                                                                                                                                                                          0.0s 
 ✔ Container compose-mongo-1          Created                                                                                                                                                                                          0.0s 
 ✔ Container compose-mysql-1          Created                                                                                                                                                                                          0.0s 
 ✔ Container compose-lr-rest-books-1  Created                                                                                                                                                                                          0.1s 
Attaching to lr-rest-books-1, mongo-1, mysql-1, redis-1
...

现在,你可以用 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: 8000

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

kubectl apply -f lr-books-deployment.yaml