使用 Docker 部署 Web 服务及数据库容器
1. 检查 Docker 镜像
在使用 Docker 部署 Web 服务时,首先需要检查已构建的 Docker 镜像。可以运行以下命令:
docker images
运行该命令后,终端输出可能如下:
| REPOSITORY | TAG | IMAGE ID | CREATED | SIZE |
| — | — | — | — | — |
| docker-rust-basic | latest | 20fe6699b10e | 9 seconds ago | 1.32GB |
这里创建了一个名为 docker-rust-basic 的 Docker 镜像,其大小为 1.32GB。这是因为 Docker 镜像包含了所有层及其依赖项,例如,Rust Docker 镜像包含了 Rust 编译器和所有中间构建工件,但这些对于运行最终应用程序并非必需。
2. 运行 Web 服务器
接下来,在 Docker 容器中运行 Web 服务器,使用以下命令:
docker run -p 8080:8080 -t docker-rust-basic
然后,在浏览器窗口中测试以下地址:
- localhost:8080
- localhost:8080/hello
应该能在浏览器窗口中看到相应的消息。
3. 多阶段 Docker 构建
为了减小 Docker 镜像的大小,可以使用多阶段 Docker 构建。具体步骤如下:
1. 在项目根目录创建一个新的 Dockerfile,命名为 Dockerfile-lite ,并添加以下内容:
# Use the main rust Docker image
FROM rust as build
# copy app into Docker image
COPY . /app
# Set the workdirectory
WORKDIR /app
# build the app
RUN cargo build --release
# use google distroless as runtime image
FROM gcr.io/distroless/cc-debian11
# copy app from builder
COPY --from=build /app/target/release/docker-rust /app/docker-rust
WORKDIR /app
# start the application
CMD ["./docker-rust"]
- 运行以下命令构建 Docker 镜像:
docker build -f Dockerfile-lite . -t docker-rust-lite
- 再次检查已构建的 Docker 镜像:
docker images
此时,终端输出可能如下:
| REPOSITORY | TAG | IMAGE ID | CREATED | SIZE |
| — | — | — | — | — |
| docker-rust-lite | latest | 40103591baaf | 12 seconds ago | 31.8MB |
可以看到,Docker 镜像的大小已减小到 31.8MB。
- 确认新的 Docker 镜像是否正常工作:
docker run -p 8080:8080 -t docker-rust-lite
检查正在运行的容器:
docker ps
在浏览器窗口中测试 localhost:8080 和 localhost:8080/hello ,应该能看到相应的问候消息。
多阶段 Docker 构建的工作原理是通过一系列步骤创建 Docker 镜像。主要好处是可以在开发构建后清理,通过移除最终 Docker 镜像中的多余文件来减小最终二进制文件的大小。它还能让开发者自动化为不同目标操作系统环境创建多个版本的二进制文件,并且具有安全和缓存优势。
多阶段构建使用多个 FROM 语句来引用特定阶段的特定镜像,每个阶段可以使用 AS 关键字命名。在 Dockerfile-lite 示例中,有两个阶段:第一个阶段构建发布二进制文件,第二个阶段使用 Google Distroless 作为运行时镜像,并复制之前创建的发布二进制文件,从而减小 Docker 镜像的大小。
4. 构建数据库容器
EzyTutors Web 后端有两个不同的组件:提供 API 的 Web 服务和 Postgres 数据库。下面将介绍如何将 Postgres 数据库打包为 Docker 容器。
4.1 打包 Postgres 数据库
- 克隆项目的 Git 仓库,导航到
chapter6/ezytutors/tutor-db,这是 Web 服务的项目根文件夹。 - 在 Ubuntu 服务器(或任何其他首选的虚拟机配置)上安装 Docker Compose,可参考 Docker 文档 。使用以下命令验证 Docker Compose 的安装:
docker compose version
输出可能如下:
Docker Compose version v2.5.0
- 创建一个新的 Docker 网络,用于连接导师 Web 服务和 Postgres 数据库容器:
docker network create tutor-network
运行 docker ls 查看网络信息,可能的输出如下:
| CONTAINER ID | IMAGE | COMMAND | CREATED | STATUS | PORTS | NAMES |
| — | — | — | — | — | — | — |
| 6fc670fb70ba | bridge | bridge | local | | | |
| 75d560b02bbe | host | host | local | | | |
| 7d2c59b2f3a5 | none | null | local | | | |
| e230e1a9c55d | tutor-network | bridge | local | | | |
4. 创建一个 Docker 卷:
docker volume create tutor-data
运行 docker volume ls 查看卷信息,输出可能如下:
| DRIVER | VOLUME NAME |
| — | — |
| local | tutor-data |
5. 如果 Docker 主机上的 Postgresql 数据库实例正在运行,停止它:
systemctl status postgresql
systemctl stop postgresql
- 创建一个新的 Docker Compose 文件,命名为
docker-compose.yml,并添加以下代码:
version: '3'
services:
db:
container_name: tutor-postgres
restart: always
image: postgres:latest
environment:
- POSTGRES_USER=postgres
- POSTGRES_PASSWORD=postgres
- POSTGRES_DB=ezytutors
volumes:
- tutor-data:/var/lib/postgresql/data
- ./c12-data/initdb.sql:/docker-entrypoint-initdb.d/initdb.sql
- ./c12-data/init-tables.sql:/docker-entrypoint-initdb.d/init-tables.sql
ports:
- 5432:5432
networks:
- tutor-network
volumes:
tutor-data:
networks:
tutor-network:
在上述代码中, services: 关键字表示一个单独的 Docker 容器。这里告诉 Docker Compose, db 是服务的名称,应该为 db 服务启动一个单独的 Docker 容器。 volumes: 关键字下,Docker 主机上的 tutor-data 卷映射到 Docker 容器内的 /var/lib/postgresql/data (Postgres 的默认数据库文件夹)。 initdb.sql 文件包含创建数据库和用户以及授予权限的数据库脚本, init-tables.sql 文件包含创建数据库表和加载初始测试数据的数据库脚本。
- 构建并运行 Postgres Docker 镜像:
docker compose up -d
运行 docker ps 查看容器信息,输出可能如下:
| CONTAINER ID | IMAGE | COMMAND | CREATED | STATUS | PORTS | NAMES |
| — | — | — | — | — | — | — |
| d43b6ae99846 | postgres:latest | “docker-entrypoint.s…” | 4 seconds ago | Up 1 second | 0.0.0.0:5432->5432/tcp, :::5432->5432/tcp | tutor-postgres |
4.2 检查数据库和用户
连接到 Docker 容器,检查数据库和表是否已创建,测试数据是否已加载:
docker exec -it d43b6ae99846 /bin/bash
psql postgres://postgres:postgres@localhost:5432/ezytutors
\list
输出可能如下:
psql (12.11 (Ubuntu 12.11-0ubuntu0.20.04.1), server 14.3 (Debian 14.3-1.pgdg110+1))
WARNING: psql major version 12, server major version 14.
Some psql features might not work.
Type "help" for help.
ezytutors=# \list
List of databases
Name | Owner | Encoding | Collate | Ctype | Access privileges
-----------+----------+----------+-----------+-----------+----------------------
ezytutors | postgres | UTF8 | en_US.utf8 | en_US.utf8 |
postgres | postgres | UTF8 | en_US.utf8 | en_US.utf8 |
template0 | postgres | UTF8 | en_US.utf8 | en_US.utf8 | =c/postgres
| | | | | postgres=CTc/postgres
template1 | postgres | UTF8 | en_US.utf8 | en_US.utf8 | =c/postgres
| | | | | postgres=CTc/postgres
(4 rows)
可以看到 ezytutors 数据库已列出。输入 \q 退出 psql shell,然后输入 exit 退出 Docker 容器。
也可以使用以下方式访问数据库:
docker ps
docker exec -it 0027d5c1cfaf /bin/bash
psql -U postgres
\list
输出类似上述结果。
检查 truuser 用户是否已创建并被授予权限:
psql -U truuser ezytutors
ezytutors=>\list
如果能看到 ezytutors 数据库列出,则表示正常。否则,在 psql shell 中执行以下步骤:
postgres=# drop database ezytutors;
postgres=# \list
然后回到 Docker 容器的 bash shell(不是 psql shell),执行以下命令:
postgres=# \i /docker-entrypoint-initdb.d/initdb.sql
输出可能如下:
CREATE DATABASE
CREATE ROLE
GRANT
ALTER ROLE
ALTER ROLE
initdb.sql 脚本创建了数据库、新的 truuser 用户,并授予该用户对 ezytutors 数据库的所有权限。
退出 psql shell,使用 truuser ID 重新登录:
psql -U truuser ezytutors
ezytutors=>\list
应该能看到 ezytutors 数据库可由 truuser 访问。
4.3 创建数据库表
从 Postgres Docker 容器的命令提示符检查数据库表是否已创建:
ezytutors=> \d
如果看到“Did not find any relations”错误消息,则需要手动运行脚本创建表并加载测试数据:
ezytutors=> \i /docker-entrypoint-initdb.d/init-tables.sql
输出可能如下:
psql:/docker-entrypoint-initdb.d/init-tables.sql:4: NOTICE:
table "ezy_course_c6" does not exist, skipping
DROP TABLE
psql:/docker-entrypoint-initdb.d/init-tables.sql:5: NOTICE:
table "ezy_tutor_c6" does not exist, skipping
DROP TABLE
CREATE TABLE
CREATE TABLE
GRANT
GRANT
INSERT 0 1
INSERT 0 1
INSERT 0 1
INSERT 0 1
再次运行 \d 查看数据库表信息:
ezytutors=> \d
输出可能如下:
| Schema | Name | Type | Owner |
| — | — | — | — |
| public | ezy_course_c6 | table | truuser |
| public | ezy_course_c6_course_id_seq | sequence | truuser |
| public | ezy_tutor_c6 | table | truuser |
| public | ezy_tutor_c6_tutor_id_seq | sequence | truuser |
检查初始测试数据是否已加载到导师和课程表中:
ezytutors=> select tutor_id, tutor_name, tutor_pic_url from ezy_tutor_c6;
ezytutors=> select course_id, tutor_id, course_name, course_format, course_level from ezy_course_c6;
为了测试数据在容器重启之间是否持久化,添加一条新记录到导师表,关闭容器,然后重启容器检查数据是否仍然存在:
ezytutors=> insert into ezy_tutor_c6 values(3, 'Johnny', 'http://s3.amazon.aws.com/pic2', 'Johnny is an expert marriage counselor');
ezytutors=> \q
exit
root@1dfd3bd87e2c:/# exit
通过以上步骤,我们完成了使用 Docker 部署 Web 服务和将 Postgres 数据库打包为 Docker 容器的过程,并且对数据库的创建、用户权限设置、表创建和数据持久化进行了测试。
5. 总结与拓展
5.1 关键步骤回顾
- Web 服务部署 :
- 构建 Docker 镜像后,使用
docker images检查镜像信息。 - 运行 Web 服务器使用
docker run -p 8080:8080 -t docker-rust-basic命令。 - 采用多阶段 Docker 构建减小镜像大小,通过创建
Dockerfile-lite并执行相应构建命令实现。
- 构建 Docker 镜像后,使用
- 数据库容器构建 :
- 克隆项目仓库,安装 Docker Compose 并验证安装。
- 创建 Docker 网络和卷,停止主机上的 Postgresql 实例。
- 编写
docker-compose.yml文件,构建并运行 Postgres Docker 镜像。 - 检查数据库和用户,创建数据库表并测试数据持久化。
5.2 多阶段 Docker 构建流程图
graph LR
classDef startend fill:#F5EBFF,stroke:#BE8FED,stroke-width:2px;
classDef process fill:#E5F6FF,stroke:#73A6FF,stroke-width:2px;
classDef decision fill:#FFF6CC,stroke:#FFBC52,stroke-width:2px;
A([开始]):::startend --> B(创建 Dockerfile-lite):::process
B --> C(第一阶段: FROM rust as build):::process
C --> D(COPY . /app):::process
D --> E(WORKDIR /app):::process
E --> F(RUN cargo build --release):::process
F --> G(第二阶段: FROM gcr.io/distroless/cc-debian11):::process
G --> H(COPY --from=build /app/target/release/docker-rust /app/docker-rust):::process
H --> I(WORKDIR /app):::process
I --> J(CMD ["./docker-rust"]):::process
J --> K(构建镜像: docker build -f Dockerfile-lite . -t docker-rust-lite):::process
K --> L([结束]):::startend
5.3 拓展思考
- 性能优化 :可以进一步优化 Docker 镜像的构建过程,例如使用缓存机制减少重复构建的时间。在多阶段构建中,合理安排每个阶段的依赖和操作,避免不必要的文件复制和安装。
- 安全性增强 :对于数据库容器,需要加强安全配置。可以设置更复杂的数据库密码,限制容器的网络访问权限,定期更新基础镜像以修复安全漏洞。
- 集群部署 :在生产环境中,通常需要将 Web 服务和数据库容器部署到集群中,以提高可用性和性能。可以使用 Docker Swarm、Kubernetes 等容器编排工具来实现集群部署和管理。
5.4 常见问题及解决方法
| 问题描述 | 可能原因 | 解决方法 |
|---|---|---|
| Docker 镜像构建失败 | 依赖安装失败、网络问题 | 检查网络连接,确保依赖源可用;查看构建日志,排查具体错误信息 |
| 数据库容器无法启动 | 配置文件错误、端口冲突 | 检查 docker-compose.yml 文件的配置,确保端口未被占用;查看容器日志,定位问题 |
| 数据持久化失败 | 卷挂载问题、文件权限问题 | 检查 Docker 卷的配置,确保挂载路径正确;检查文件权限,确保容器有读写权限 |
5.5 未来展望
随着容器技术的不断发展,Docker 在软件开发和部署中的应用将越来越广泛。未来,我们可以期待更高效的镜像构建工具、更强大的容器编排平台以及更完善的安全机制。同时,结合微服务架构,将不同的服务拆分成独立的容器,实现更灵活的部署和管理。
通过本文的介绍,我们详细了解了使用 Docker 部署 Web 服务和构建数据库容器的全过程。从 Web 服务的镜像构建和优化,到数据库容器的创建、配置和测试,每一个步骤都至关重要。希望读者能够根据这些步骤和方法,在实际项目中成功应用 Docker 技术,提高开发和部署的效率。
超级会员免费看

被折叠的 条评论
为什么被折叠?



