開發您的 Rust 應用程式

先決條件

  • 您已安裝最新版本的 Docker Desktop
  • 您已完成 Docker Desktop 學習中心 中的逐步解說,以了解 Docker 概念。
  • 您有一個 git 用戶端。本節中的範例使用基於命令列的 git 用戶端,但您可以使用任何用戶端。

概觀

在本節中,您將學習如何在 Docker 中使用儲存空間和網路。您還將使用 Docker 建置映像檔,並使用 Docker Compose 讓一切變得更輕鬆。

首先,您將了解如何在容器中執行資料庫,以及如何使用儲存空間和網路來保存資料並讓應用程式與資料庫通訊。然後,您將所有內容整合到一個 Compose 檔案中,讓您可以使用一個命令設定和執行本地開發環境。

在容器中執行資料庫

您不必下載 PostgreSQL、安裝、設定,然後將 PostgreSQL 資料庫作為服務運行,而是可以使用 PostgreSQL 的 Docker 官方映像檔並在容器中運行它。

在您在容器中執行 PostgreSQL 之前,請建立一個 Docker 可以管理的儲存空間來儲存您的持久性資料和設定。使用 Docker 提供的命名儲存空間功能,而不是使用繫結掛載。

執行以下命令來建立您的儲存空間。

$ docker volume create db-data

現在建立一個您的應用程式和資料庫將用來互相通訊的網路。該網路稱為使用者定義的橋接網路,它為您提供了一個良好的 DNS 查找服務,您可以在建立連接字串時使用它。

$ docker network create postgresnet

現在,您可以在容器中執行 PostgreSQL,並連接到您先前建立的儲存空間和網路。Docker 從 Hub 下載映像檔並在本地為您運行它。在以下命令中,選項 --mount 用於使用儲存空間啟動容器。如需更多資訊,請參閱 Docker 儲存空間

$ docker run --rm -d --mount \
  "type=volume,src=db-data,target=/var/lib/postgresql/data" \
  -p 5432:5432 \
  --network postgresnet \
  --name db \
  -e POSTGRES_PASSWORD=mysecretpassword \
  -e POSTGRES_DB=example \
  postgres

現在,請確定您的 PostgreSQL 資料庫正在運行,並且您可以連接到它。連接到容器內正在運行的 PostgreSQL 資料庫。

$ docker exec -it db psql -U postgres

您應該會看到如下所示的輸出。

psql (15.3 (Debian 15.3-1.pgdg110+1))
Type "help" for help.

postgres=#

在上一個命令中,您透過將 psql 命令傳遞給 db 容器來登入 PostgreSQL 資料庫。按 ctrl-d 退出 PostgreSQL 交互式終端機。

取得並執行範例應用程式

對於範例應用程式,您將使用 Awesome Compose 中 react-rust-postgres 應用程式的後端變體。

  1. 使用以下命令複製範例應用程式儲存庫。

    $ git clone https://github.com/docker/docker-rust-postgres
    
  2. 在複製的儲存庫目錄中,執行 docker init 來建立必要的 Docker 檔案。參考以下範例來回答 docker init 的提示。

    $ docker init
    Welcome to the Docker Init CLI!
    
    This utility will walk you through creating the following files with sensible defaults for your project:
      - .dockerignore
      - Dockerfile
      - compose.yaml
      - README.Docker.md
    
    Let's get started!
    
    ? What application platform does your project use? Rust
    ? What version of Rust do you want to use? 1.70.0
    ? What port does your server listen on? 8000
    
  3. 在複製的儲存庫目錄中,在 IDE 或文字編輯器中開啟 Dockerfile 以更新它。

    docker init 處理了 Dockerfile 中大多數指令的建立,但您需要針對您的唯一應用程式更新它。除了 src 目錄外,此應用程式還包含一個 migrations 目錄來初始化資料庫。將 migrations 目錄的繫結掛載新增到 Dockerfile 中的建置階段。以下是更新後的 Dockerfile。

    # syntax=docker/dockerfile:1
    
    # Comments are provided throughout this file to help you get started.
    # If you need more help, visit the Dockerfile reference guide at
    # https://docker-docs.dev.org.tw/reference/dockerfile/
    
    ################################################################################
    # Create a stage for building the application.
    
    ARG RUST_VERSION=1.70.0
    ARG APP_NAME=react-rust-postgres
    FROM rust:${RUST_VERSION}-slim-bullseye AS build
    ARG APP_NAME
    WORKDIR /app
    
    # Build the application.
    # Leverage a cache mount to /usr/local/cargo/registry/
    # for downloaded dependencies and a cache mount to /app/target/ for
    # compiled dependencies which will speed up subsequent builds.
    # Leverage a bind mount to the src directory to avoid having to copy the
    # source code into the container. Once built, copy the executable to an
    # output directory before the cache mounted /app/target is unmounted.
    RUN --mount=type=bind,source=src,target=src \
        --mount=type=bind,source=Cargo.toml,target=Cargo.toml \
        --mount=type=bind,source=Cargo.lock,target=Cargo.lock \
        --mount=type=cache,target=/app/target/ \
        --mount=type=cache,target=/usr/local/cargo/registry/ \
        --mount=type=bind,source=migrations,target=migrations \
        <<EOF
    set -e
    cargo build --locked --release
    cp ./target/release/$APP_NAME /bin/server
    EOF
    
    ################################################################################
    # Create a new stage for running the application that contains the minimal
    # runtime dependencies for the application. This often uses a different base
    # image from the build stage where the necessary files are copied from the build
    # stage.
    #
    # The example below uses the debian bullseye image as the foundation for    running the app.
    # By specifying the "bullseye-slim" tag, it will also use whatever happens to    be the
    # most recent version of that tag when you build your Dockerfile. If
    # reproducibility is important, consider using a digest
    # (e.g.,    debian@sha256:ac707220fbd7b67fc19b112cee8170b41a9e97f703f588b2cdbbcdcecdd8af57).
    FROM debian:bullseye-slim AS final
    
    # Create a non-privileged user that the app will run under.
    # See https://docker-docs.dev.org.tw/develop/develop-images/dockerfile_best-practices/   #user
    ARG UID=10001
    RUN adduser \
        --disabled-password \
        --gecos "" \
        --home "/nonexistent" \
        --shell "/sbin/nologin" \
        --no-create-home \
        --uid "${UID}" \
        appuser
    USER appuser
    
    # Copy the executable from the "build" stage.
    COPY --from=build /bin/server /bin/
    
    # Expose the port that the application listens on.
    EXPOSE 8000
    
    # What the container should run when it is started.
    CMD ["/bin/server"]
  4. 在複製的儲存庫目錄中,執行 docker build 來建置映像檔。

    $ docker build -t rust-backend-image .
    
  5. 使用以下選項執行 docker run,以將映像檔作為容器在與資料庫相同的網路上運行。

    $ docker run \
      --rm -d \
      --network postgresnet \
      --name docker-develop-rust-container \
      -p 3001:8000 \
      -e PG_DBNAME=example \
      -e PG_HOST=db \
      -e PG_USER=postgres \
      -e PG_PASSWORD=mysecretpassword \
      -e ADDRESS=0.0.0.0:8000 \
      -e RUST_LOG=debug \
      rust-backend-image
    
  6. 捲曲應用程式以驗證它是否連接到資料庫。

    $ curl http://localhost:3001/users
    

    您應該會得到如下所示的回應。

    [{ "id": 1, "login": "root" }]

使用 Compose 在本地開發

當您執行 docker init 時,除了 Dockerfile 之外,它還會建立一個 compose.yaml 檔案。

這個 Compose 檔案非常方便,因為您不必輸入所有要傳遞給 docker run 命令的參數。您可以使用 Compose 檔案以宣告方式執行此操作。

在複製的儲存庫目錄中,在 IDE 或文字編輯器中開啟 compose.yaml 檔案。docker init 處理了大多數指令的建立,但您需要針對您的唯一應用程式更新它。

您需要更新 compose.yaml 檔案中的以下項目

  • 取消註釋所有資料庫指令。
  • 在伺服器服務下新增環境變數。

以下是更新後的 compose.yaml 檔案。

# Comments are provided throughout this file to help you get started.
# If you need more help, visit the Docker compose reference guide at
# https://docker-docs.dev.org.tw/reference/compose-file/

# Here the instructions define your application as a service called "server".
# This service is built from the Dockerfile in the current directory.
# You can add other services your application may depend on here, such as a
# database or a cache. For examples, see the Awesome Compose repository:
# https://github.com/docker/awesome-compose
services:
  server:
    build:
      context: .
      target: final
    ports:
      - 8000:8000
    environment:
      - PG_DBNAME=example
      - PG_HOST=db
      - PG_USER=postgres
      - PG_PASSWORD=mysecretpassword
      - ADDRESS=0.0.0.0:8000
      - RUST_LOG=debug
    # The commented out section below is an example of how to define a PostgreSQL
    # database that your application can use. `depends_on` tells Docker Compose to
    # start the database before your application. The `db-data` volume persists the
    # database data between container restarts. The `db-password` secret is used
    # to set the database password. You must create `db/password.txt` and add
    # a password of your choosing to it before running `docker compose up`.
    depends_on:
      db:
        condition: service_healthy
  db:
    image: postgres
    restart: always
    user: postgres
    secrets:
      - db-password
    volumes:
      - db-data:/var/lib/postgresql/data
    environment:
      - POSTGRES_DB=example
      - POSTGRES_PASSWORD_FILE=/run/secrets/db-password
    expose:
      - 5432
    healthcheck:
      test: ["CMD", "pg_isready"]
      interval: 10s
      timeout: 5s
      retries: 5
volumes:
  db-data:
secrets:
  db-password:
    file: db/password.txt

請注意,該檔案沒有為這兩個服務指定網路。當您使用 Compose 時,它會自動建立一個網路並將服務連接到它。如需更多資訊,請參閱 Compose 中的網路

在您使用 Compose 執行應用程式之前,請注意,此 Compose 檔案指定了一個 password.txt 檔案來存放資料庫的密碼。您必須建立此檔案,因為它不包含在原始碼儲存庫中。

在複製的儲存庫目錄中,建立一個名為 db 的新目錄,並在該目錄內建立一個名為 password.txt 的檔案,其中包含資料庫的密碼。使用您喜歡的 IDE 或文字編輯器,將以下內容新增到 password.txt 檔案中。

mysecretpassword

如果您有任何其他容器從先前章節運行,請立即將它們 停止

現在,執行以下 docker compose up 命令來啟動您的應用程式。

$ docker compose up --build

該命令傳遞了 --build 旗標,因此 Docker 將編譯您的映像檔,然後啟動容器。

現在測試您的 API 端點。開啟一個新的終端機,然後使用 curl 命令向伺服器發出請求

$ curl http://localhost:8000/users

您應該會收到以下回應

[{ "id": 1, "login": "root" }]

摘要

在本節中,您了解了如何設定 Compose 檔案以使用單個命令運行您的 Rust 應用程式和資料庫。

相關資訊

後續步驟

在下一節中,您將了解如何使用 GitHub Actions 設定 CI/CD 管線。