容器化服务器打包:从微服务镜像构建到应用部署
在现代软件开发中,容器化技术为微服务的部署和管理带来了极大的便利。本文将详细介绍如何将多个微服务打包成 Docker 镜像,并使用 Docker Compose 工具将它们组合成一个完整的应用程序。
1. 启动容器
首先,我们已经构建好的镜像存储在 Docker 中,可以使用
docker images
命令查看:
REPOSITORY TAG IMAGE ID CREATED SIZE
users-microservice latest 4b6fc8aa6f1b 7 minutes ago 2.3GB
rust nightly 91e52fb2cea5 3 hours ago 1.67GB
要从镜像启动微服务,可以使用以下命令:
docker run -it --rm -p 8080:8000 users-microservice
不过,由于还没有启动包含数据库实例的容器,这个微服务实例虽然会启动,但无法正常工作。我们不会手动连接容器,后续会使用 Docker Compose 工具来完成这一任务。
2. 构建微服务镜像
接下来,我们将为不同的微服务构建 Docker 镜像。
2.1 内容微服务镜像
内容微服务是我们要构建的第二个微服务。我们借用了之前的
.dockerignore
文件,并为这个微服务调整了
Dockerfile
:
FROM rust:nightly
RUN USER=root cargo new --bin content-microservice
WORKDIR /content-microservice
COPY ./Cargo.toml ./Cargo.toml
RUN cargo build
RUN rm src/*.rs
COPY ./src ./src
RUN rm ./target/debug/deps/content_microservice*
RUN cargo build
CMD ["./target/debug/content-microservice"]
EXPOSE 8000
这个
Dockerfile
与之前的类似,但不复制任何配置文件,我们将在 Docker Compose 文件中使用环境变量来设置所有参数。可以使用以下命令构建这个镜像进行测试:
docker build -t content-microservice:latest .
不过,由于我们将使用 Docker Compose 启动容器,所以不需要手动构建这个镜像。
2.2 邮件微服务镜像
邮件微服务不使用
diesel
crate,我们可以使用官方的 Rust 镜像来构建它。同时,邮件微服务有用于准备邮件内容的模板。以下是它的
Dockerfile
:
FROM rust:1.30.1
RUN USER=root cargo new --bin mails-microservice
WORKDIR /mails-microservice
COPY ./Cargo.toml ./Cargo.toml
RUN cargo build
RUN rm src/*.rs
COPY ./src ./src
COPY ./templates ./templates
RUN rm ./target/debug/deps/mails_microservice*
RUN cargo build
CMD ["./target/debug/mails-microservice"]
我们从
rust:1.30.1
镜像创建了这个镜像,稳定版本的编译器适合编译这个简单的微服务。同时,添加了复制所有模板到镜像的命令。
2.3 路由微服务镜像
路由微服务在之前的开发中已经创建,它需要与其他微服务协同工作,并且会提供
static
文件夹中的静态资源。其
Dockerfile
如下:
FROM rust:1.30.1
RUN USER=root cargo new --bin router-microservice
WORKDIR /router-microservice
COPY ./Cargo.toml ./Cargo.toml
RUN cargo build
RUN rm src/*.rs
COPY ./src ./src
COPY ./static ./static
RUN rm ./target/debug/deps/router_microservice*
RUN cargo build
CMD ["./target/debug/router-microservice"]
EXPOSE 8000
与之前的镜像类似,使用了官方的 Rust 镜像,但增加了复制
static
文件夹到镜像的操作。
2.4 DBSync 工作器镜像
DBSync 工作器的主要功能是等待与数据库的连接并应用所有迁移。首先,我们需要添加以下依赖到
Cargo.toml
:
clap = "2.32"
config = "0.9"
diesel = { version = "^1.1.0", features = ["postgres", "r2d2"] }
diesel_migrations = "1.3"
env_logger = "0.6"
failure = "0.1"
log = "0.4"
postgres = "0.15"
r2d2 = "0.8"
serde = "1.0"
serde_derive = "1.0"
然后,在代码中导入所需的类型:
use diesel::prelude::*;
use diesel::connection::Connection;
use failure::{format_err, Error};
use log::debug;
use serde_derive::Deserialize;
在
main
函数之前,我们使用
embed_migrations!
宏嵌入迁移:
embed_migrations!();
定义
Config
结构体来读取数据库连接链接:
#[derive(Deserialize)]
struct Config {
database: Option<String>,
}
以下是完整的
main
函数:
fn main() -> Result<(), Error> {
env_logger::init();
let mut config = config::Config::default();
config.merge(config::Environment::with_prefix("DBSYNC"))?;
let config: Config = config.try_into()?;
let db_address = config.database.unwrap_or("postgres://localhost/".into());
debug!("Waiting for database...");
loop {
let conn: Result<PgConnection, _> = Connection::establish(&db_address);
if let Ok(conn) = conn {
debug!("Database connected");
embedded_migrations::run(&conn)?;
break;
}
}
debug!("Database migrated");
Ok(())
}
3. 隐藏微服务源代码
在镜像中构建微服务的一个主要缺点是,所有源代码和构建工件对有权访问 Docker 镜像的人都是可见的。为了隐藏这些信息,我们可以使用以下两种方法:
3.1 方法一:通过挂载卷构建
使用带有 Rust 编译器的 Docker 镜像构建所有源代码,并通过挂载卷提供对源代码的访问。可以使用
docker run
命令的
-v
参数将本地文件夹映射到容器内的卷。但这种方法的缺点是,Docker 在容器内使用的 ID 与本地会话不同,可能会创建一些在不更改用户 ID 的情况下无法删除的文件,并且维护起来比较困难。如果只需要编译结果,这种方法是有用的;如果计划在容器内运行微服务,最好在镜像内构建所有内容。
3.2 方法二:使用构建缓存
使用 Docker 构建所有内容,但使用构建缓存获取编译结果,并将其放入新创建的容器中。以下是实现这种方法的
Dockerfile
:
FROM rust:nightly as builder
RUN USER=root cargo new --bin dbsync-worker
WORKDIR /dbsync-worker
COPY ./Cargo.toml ./Cargo.toml
RUN cargo build
RUN rm src/*.rs
COPY ./src ./src
COPY ./migrations ./migrations
COPY ./diesel.toml ./diesel.toml
RUN rm ./target/debug/deps/dbsync_worker*
RUN cargo build
FROM buildpack-deps:stretch
COPY --from=builder /dbsync-worker/target/debug/dbsync-worker /app/
ENV RUST_LOG=debug
EXPOSE 8000
ENTRYPOINT ["/app/dbsync-worker"]
通过这种方式,我们可以构建一个只包含微服务二进制文件的镜像。
4. 使用 Docker Compose 组合微服务
Docker Compose 是一个强大的工具,用于部署和运行一组相互连接的微服务。它允许我们在一个人类可读的 YAML 文件中定义多容器应用程序。
4.1 应用定义
创建一个
docker-compose.test.yml
文件,并添加以下内容:
version: "3.6"
services:
# 容器定义的位置
接下来,我们将为每个微服务和相关组件配置容器。
4.2 数据库容器
我们的应用程序需要一个数据库实例,这里使用 PostgreSQL 数据库:
db:
image: postgres:latest
restart: always
environment:
- POSTGRES_USER=postgres
- POSTGRES_PASSWORD=password
ports:
- 5432:5432
如果数据库失败,容器将自动重启。同时,我们通过环境变量设置了用户和密码,并将容器的 5432 端口映射到本地的 5432 端口,方便本地客户端连接。
4.3 邮件服务器容器
我们使用
juanluisbaptiste/postfix
镜像作为 SMTP 服务器:
smtp:
image: juanluisbaptiste/postfix
restart: always
environment:
- SMTP_SERVER=smtp.example.com
- SMTP_USERNAME=admin@example.com
- SMTP_PASSWORD=password
- SERVER_HOSTNAME=smtp.example.com
ports:
- "2525:25"
同样,设置了重启策略和环境变量,并将容器的 25 端口映射到本地的 2525 端口,用于测试邮件服务器。
4.4 DBSync 工作器容器
DBSync 工作器用于应用数据库迁移,它依赖于数据库容器:
dbsync:
build: ./microservices/dbsync
depends_on:
- db
environment:
- RUST_LOG=dbsync_worker=debug
- RUST_BACKTRACE=1
- DBSYNC_DATABASE=postgresql://postgres:password@db:5432
我们设置了日志级别、回溯打印和数据库连接链接。
4.5 邮件微服务容器
邮件微服务依赖于 SMTP 服务器:
mails:
build: ./microservices/mails
depends_on:
- smtp
environment:
- RUST_LOG=mails_microservice=debug
- RUST_BACKTRACE=1
- MAILS_ADDRESS=0.0.0.0:8000
- MAILS_SMTP_ADDRESS=smtp:2525
- MAILS_SMTP_LOGIN=admin@example.com
- MAILS_SMTP_PASSWORD=password
ports:
- 8002:8000
配置了环境变量,并将容器的 8000 端口映射到本地的 8002 端口。
4.6 用户微服务容器
用户微服务依赖于 DBSync 工作器和邮件微服务:
users:
build: ./microservices/users
environment:
- RUST_LOG=users_microservice=debug
- RUST_BACKTRACE=1
- USERS_ADDRESS=0.0.0.0:8000
- USERS_DATABASE=postgresql://postgres:password@db:5432
depends_on:
- dbsync
- mails
ports:
- 8001:8000
设置了日志级别、数据库连接链接和端口映射。
4.7 内容微服务容器
内容微服务依赖于 DBSync 工作器:
content:
build: ./microservices/content
depends_on:
- dbsync
ports:
- 8888:8000
environment:
- RUST_LOG=content_microservice=debug
- RUST_BACKTRACE=1
- ROCKET_ADDRESS=0.0.0.0
- ROCKET_PORT=8000
- ROCKET_DATABASES={postgres_database={url="postgresql://postgres:password@db:5432"}}
ports:
- 8003:8000
配置了环境变量和端口映射。
4.8 路由微服务容器
路由微服务依赖于用户微服务和内容微服务:
router:
build: ./microservices/router
depends_on:
- users
- content
environment:
- RUST_LOG=router_microservice=debug
- RUST_BACKTRACE=1
- ROUTER_ADDRESS=0.0.0.0:8000
- ROUTER_USERS=http://users:8000
- ROUTER_CONTENT=http://content:8000
ports:
- 8000:8000
配置了日志级别、微服务地址和端口映射。
5. 运行应用程序
使用以下命令启动应用程序:
docker-compose -f docker-compose.test.yml up
这将根据需要构建所有镜像并启动应用程序。启动后,可以在浏览器中访问
http://localhost:8000
来测试应用程序。要停止应用程序,使用
Ctrl+C
组合键。
通过以上步骤,我们成功地将多个微服务打包成 Docker 镜像,并使用 Docker Compose 工具将它们组合成一个完整的应用程序。这种方法不仅提高了开发和部署的效率,还增强了应用程序的可维护性和可扩展性。
容器化服务器打包:从微服务镜像构建到应用部署
6. 应用部署流程总结
为了更清晰地展示整个应用部署的流程,我们可以用一个 mermaid 流程图来表示:
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(构建微服务镜像):::process
B --> C(隐藏微服务源代码):::process
C --> D(创建 Docker Compose 文件):::process
D --> E(运行应用程序):::process
E --> F{应用是否正常运行?}:::decision
F -->|是| G([结束]):::startend
F -->|否| H(检查配置和日志):::process
H --> B
这个流程图展示了从构建微服务镜像到最终运行应用程序的整个过程。如果应用程序不能正常运行,需要检查配置和日志,然后重新开始构建镜像的步骤。
7. 各微服务依赖关系分析
为了更好地理解各个微服务之间的依赖关系,我们可以用表格来总结:
| 微服务名称 | 依赖的微服务或组件 | 说明 |
|---|---|---|
| DBSync 工作器 | 数据库(db) | 等待数据库连接并应用迁移 |
| 邮件微服务 | SMTP 服务器(smtp) | 需要 SMTP 服务器来发送邮件 |
| 用户微服务 | DBSync 工作器(dbsync)、邮件微服务(mails) | 需要数据库表和邮件通知功能 |
| 内容微服务 | DBSync 工作器(dbsync) | 需要数据库中的数据 |
| 路由微服务 | 用户微服务(users)、内容微服务(content) | 代理用户和内容微服务的请求 |
从这个表格中可以清晰地看到各个微服务之间的依赖关系,这有助于在部署和维护应用程序时更好地管理这些依赖。
8. 日志分析与问题排查
在应用程序运行过程中,日志是排查问题的重要依据。当使用
docker-compose -f docker-compose.test.yml up
启动应用程序后,会在终端看到各个容器的日志,这些日志以容器名称为前缀。例如:
smtp_1 | Setting configuration option smtp_sasl_password_maps with
value: hash:\/etc\/postfix\/sasl_passwd
mails_1 | [2018-12-24T19:08:20Z DEBUG mails_microservice] Waiting for
SMTP server
smtp_1 | Setting configuration option smtp_sasl_security_options with
value: noanonymous
dbsync_1 | [2018-12-24T19:08:20Z DEBUG dbsync_worker] Waiting for
database...
db_1 |
db_1 | fixing permissions on existing directory
/var/lib/postgresql/data ... ok
mails_1 | [2018-12-24T19:08:20Z DEBUG mails_microservice] SMTP connected
smtp_1 | Adding SASL authentication configuration
mails_1 | Listening on http://0.0.0.0:8000
mails_1 | Ctrl-C to shutdown server
content_1 | Configured for development.
router_1 | DEBUG 2018-12-24T19:08:22Z: router_microservice: Started http
server: 0.0.0.0:8000
content_1 | Rocket has launched from http://0.0.0.0:8000
users_1 | [2018-12-24T19:08:24Z DEBUG users_microservice] Starting
microservice...
通过分析这些日志,可以了解各个微服务的启动状态和运行情况。如果某个微服务出现问题,日志中会有相应的错误信息,根据这些信息可以定位问题所在。例如,如果邮件微服务一直显示
Waiting for SMTP server
而没有
SMTP connected
的信息,可能是 SMTP 服务器配置有问题或者 SMTP 服务器没有正常启动。
9. 不同环境的配置管理
在实际开发中,我们通常会有测试环境和生产环境。为了适应不同环境的需求,我们可以创建不同的 Docker Compose 文件。例如,我们之前创建的
docker-compose.test.yml
是用于测试环境的。对于生产环境,我们可以创建一个
docker-compose.prod.yml
文件,在这个文件中可以调整一些配置,如数据库的连接信息、日志级别等。
以下是一个简单的
docker-compose.prod.yml
文件示例:
version: "3.6"
services:
db:
image: postgres:latest
restart: always
environment:
- POSTGRES_USER=prod_user
- POSTGRES_PASSWORD=prod_password
ports:
- 5432:5432
smtp:
image: juanluisbaptiste/postfix
restart: always
environment:
- SMTP_SERVER=prod_smtp.example.com
- SMTP_USERNAME=prod_admin@example.com
- SMTP_PASSWORD=prod_password
- SERVER_HOSTNAME=prod_smtp.example.com
ports:
- "2525:25"
# 其他微服务的配置也可以相应调整
在生产环境中,使用以下命令启动应用程序:
docker-compose -f docker-compose.prod.yml up
这样可以根据不同的环境灵活配置应用程序,提高应用程序的适应性和稳定性。
10. 总结与展望
通过本文的介绍,我们详细了解了如何将多个微服务打包成 Docker 镜像,并使用 Docker Compose 工具将它们组合成一个完整的应用程序。从构建微服务镜像、隐藏源代码到配置 Docker Compose 文件和运行应用程序,每一个步骤都有其重要性。
在实际应用中,我们还可以进一步优化这个过程。例如,可以使用自动化工具来实现镜像的构建和部署,提高开发和部署的效率。同时,还可以结合容器编排工具如 Kubernetes 来实现更高级的容器管理和调度。
总之,容器化技术为微服务的开发和部署带来了很多便利,通过合理运用这些技术,可以构建出更加高效、可维护和可扩展的应用程序。
超级会员免费看

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



