- 新增 Go、Node.js、Rust 服务的 Dockerfile 模板 - 新增 Rust 快速参考指南 - 新增 Rust 后端工作流模板 - 优化 create-runner.md,明确 host 网络模式为缓存必需条件 - 更新 gitea skill 主文档
572 lines
13 KiB
Markdown
572 lines
13 KiB
Markdown
# Rust 服务 Dockerfile 模板
|
||
|
||
Rust 项目的 Docker 容器化模板,支持多种构建场景。
|
||
|
||
## 模板类型
|
||
|
||
### 1. CI 构建镜像(Dockerfile.ci)
|
||
|
||
**适用场景**:在 CI/CD 中使用,二进制文件已在外部构建完成。
|
||
|
||
**优点**:
|
||
- 镜像体积最小(~20MB)
|
||
- 构建速度快
|
||
- 适合生产环境
|
||
|
||
```dockerfile
|
||
FROM alpine:3.21
|
||
|
||
# 安装运行时依赖
|
||
RUN apk add --no-cache ca-certificates tzdata curl && \
|
||
ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
|
||
|
||
WORKDIR /app
|
||
|
||
# 复制编译好的二进制文件(由 CI workflow 构建)
|
||
COPY your-binary-name .
|
||
|
||
# 环境变量
|
||
ENV TZ=Asia/Shanghai
|
||
ENV RUST_LOG=info
|
||
|
||
# 暴露端口
|
||
EXPOSE 9090
|
||
|
||
# 健康检查
|
||
# 根据你的服务实际情况修改端点和端口
|
||
HEALTHCHECK --interval=30s --timeout=5s --start-period=10s --retries=3 \
|
||
CMD curl -sf http://localhost:9090/healthz || exit 1
|
||
|
||
CMD ["./your-binary-name"]
|
||
```
|
||
|
||
**使用说明**:
|
||
1. 将 `your-binary-name` 替换为实际的二进制文件名
|
||
2. 修改 `EXPOSE` 端口号
|
||
3. 修改 `HEALTHCHECK` 的端点和端口
|
||
4. 在 CI workflow 中先构建二进制,再构建镜像
|
||
|
||
### 2. 完整构建镜像(Dockerfile)
|
||
|
||
**适用场景**:本地开发、无 CI 环境、独立构建。
|
||
|
||
**优点**:
|
||
- 自包含构建流程
|
||
- 可在任何环境构建
|
||
- 利用 Docker 缓存加速
|
||
|
||
```dockerfile
|
||
# ============================================
|
||
# 构建阶段
|
||
# ============================================
|
||
FROM rust:1.83-alpine AS builder
|
||
|
||
# 安装构建依赖
|
||
# musl-dev: musl libc 开发包(静态链接)
|
||
# openssl-dev: OpenSSL 开发包(如果项目依赖 openssl)
|
||
# pkgconfig: pkg-config 工具
|
||
RUN apk add --no-cache musl-dev openssl-dev pkgconfig
|
||
|
||
# 配置 Cargo 镜像加速(使用 rsproxy.cn)
|
||
RUN mkdir -p /root/.cargo && \
|
||
echo '[source.crates-io]' > /root/.cargo/config.toml && \
|
||
echo 'replace-with = "rsproxy-sparse"' >> /root/.cargo/config.toml && \
|
||
echo '[source.rsproxy-sparse]' >> /root/.cargo/config.toml && \
|
||
echo 'registry = "sparse+https://rsproxy.cn/index/"' >> /root/.cargo/config.toml
|
||
|
||
WORKDIR /build
|
||
|
||
# 先复制依赖文件,利用 Docker 层缓存
|
||
# 只要 Cargo.toml 和 Cargo.lock 不变,依赖层就会被缓存
|
||
COPY Cargo.toml Cargo.lock ./
|
||
|
||
# 创建虚拟 src 目录,预先下载和编译依赖
|
||
# 这样修改源码时不需要重新编译依赖
|
||
RUN mkdir src && \
|
||
echo "fn main() {}" > src/main.rs && \
|
||
cargo build --release --target x86_64-unknown-linux-musl && \
|
||
rm -rf src
|
||
|
||
# 复制实际源码
|
||
COPY src ./src
|
||
|
||
# 构建 Release 版本(musl 静态链接)
|
||
RUN cargo build --release --target x86_64-unknown-linux-musl
|
||
|
||
# ============================================
|
||
# 运行阶段
|
||
# ============================================
|
||
FROM alpine:3.21
|
||
|
||
# 安装运行时依赖
|
||
RUN apk add --no-cache ca-certificates tzdata curl && \
|
||
ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
|
||
|
||
WORKDIR /app
|
||
|
||
# 从构建阶段复制二进制文件
|
||
COPY --from=builder /build/target/x86_64-unknown-linux-musl/release/your-binary-name .
|
||
|
||
# 环境变量
|
||
ENV TZ=Asia/Shanghai
|
||
ENV RUST_LOG=info
|
||
|
||
# 暴露端口
|
||
EXPOSE 9090
|
||
|
||
# 健康检查
|
||
HEALTHCHECK --interval=30s --timeout=5s --start-period=10s --retries=3 \
|
||
CMD curl -sf http://localhost:9090/healthz || exit 1
|
||
|
||
CMD ["./your-binary-name"]
|
||
```
|
||
|
||
**使用说明**:
|
||
1. 将 `your-binary-name` 替换为 `Cargo.toml` 中的 `[[bin]]` name
|
||
2. 如果不需要 OpenSSL,可移除 `openssl-dev`
|
||
3. 修改端口和健康检查配置
|
||
|
||
### 3. 依赖缓存优化版(Dockerfile.cache)
|
||
|
||
**适用场景**:本地开发,频繁构建。
|
||
|
||
**优点**:
|
||
- 最大化利用缓存
|
||
- 依赖只编译一次
|
||
- 适合迭代开发
|
||
|
||
```dockerfile
|
||
# ============================================
|
||
# 依赖缓存阶段
|
||
# ============================================
|
||
FROM rust:1.83-alpine AS dependencies
|
||
|
||
RUN apk add --no-cache musl-dev openssl-dev pkgconfig
|
||
|
||
# 配置 Cargo 镜像
|
||
RUN mkdir -p /root/.cargo && \
|
||
echo '[source.crates-io]' > /root/.cargo/config.toml && \
|
||
echo 'replace-with = "rsproxy-sparse"' >> /root/.cargo/config.toml && \
|
||
echo '[source.rsproxy-sparse]' >> /root/.cargo/config.toml && \
|
||
echo 'registry = "sparse+https://rsproxy.cn/index/"' >> /root/.cargo/config.toml
|
||
|
||
WORKDIR /build
|
||
|
||
# 只复制依赖文件
|
||
COPY Cargo.toml Cargo.lock ./
|
||
|
||
# 创建虚拟 main.rs,编译依赖
|
||
RUN mkdir -p src && \
|
||
echo "fn main() {}" > src/main.rs && \
|
||
cargo build --release --target x86_64-unknown-linux-musl
|
||
|
||
# 删除虚拟源码编译产物
|
||
RUN rm -f target/x86_64-unknown-linux-musl/release/deps/your_binary_name*
|
||
|
||
# ============================================
|
||
# 构建阶段
|
||
# ============================================
|
||
FROM rust:1.83-alpine AS builder
|
||
|
||
RUN apk add --no-cache musl-dev openssl-dev pkgconfig
|
||
|
||
WORKDIR /build
|
||
|
||
# 从依赖阶段复制编译缓存
|
||
COPY --from=dependencies /root/.cargo /root/.cargo
|
||
COPY --from=dependencies /build/target target
|
||
|
||
# 复制所有文件
|
||
COPY . .
|
||
|
||
# 构建项目
|
||
RUN cargo build --release --target x86_64-unknown-linux-musl
|
||
|
||
# ============================================
|
||
# 运行阶段
|
||
# ============================================
|
||
FROM alpine:3.21
|
||
|
||
RUN apk add --no-cache ca-certificates tzdata curl && \
|
||
ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
|
||
|
||
WORKDIR /app
|
||
|
||
COPY --from=builder /build/target/x86_64-unknown-linux-musl/release/your-binary-name .
|
||
|
||
ENV TZ=Asia/Shanghai
|
||
ENV RUST_LOG=info
|
||
|
||
EXPOSE 9090
|
||
|
||
HEALTHCHECK --interval=30s --timeout=5s --start-period=10s --retries=3 \
|
||
CMD curl -sf http://localhost:9090/healthz || exit 1
|
||
|
||
CMD ["./your-binary-name"]
|
||
```
|
||
|
||
**使用说明**:
|
||
1. 将 `your_binary_name` 替换为二进制文件名(下划线形式)
|
||
2. 适合本地 `docker build` 使用
|
||
|
||
### 4. 多平台构建版(Dockerfile.multiarch)
|
||
|
||
**适用场景**:需要支持 ARM64 和 AMD64。
|
||
|
||
```dockerfile
|
||
# ============================================
|
||
# 构建阶段(支持多平台)
|
||
# ============================================
|
||
FROM --platform=$BUILDPLATFORM rust:1.83-alpine AS builder
|
||
|
||
# 安装构建依赖
|
||
RUN apk add --no-cache musl-dev openssl-dev pkgconfig clang
|
||
|
||
# 配置 Cargo 镜像
|
||
RUN mkdir -p /root/.cargo && \
|
||
echo '[source.crates-io]' > /root/.cargo/config.toml && \
|
||
echo 'replace-with = "rsproxy-sparse"' >> /root/.cargo/config.toml && \
|
||
echo '[source.rsproxy-sparse]' >> /root/.cargo/config.toml && \
|
||
echo 'registry = "sparse+https://rsproxy.cn/index/"' >> /root/.cargo/config.toml
|
||
|
||
# 安装目标架构支持
|
||
ARG TARGETARCH
|
||
RUN case "$TARGETARCH" in \
|
||
"amd64") echo "x86_64-unknown-linux-musl" > /target.txt ;; \
|
||
"arm64") echo "aarch64-unknown-linux-musl" > /target.txt ;; \
|
||
*) echo "Unsupported architecture: $TARGETARCH" && exit 1 ;; \
|
||
esac && \
|
||
rustup target add $(cat /target.txt)
|
||
|
||
WORKDIR /build
|
||
|
||
COPY Cargo.toml Cargo.lock ./
|
||
COPY src ./src
|
||
|
||
# 构建对应架构
|
||
RUN cargo build --release --target $(cat /target.txt)
|
||
|
||
# 复制二进制到统一路径
|
||
RUN mkdir -p /app && \
|
||
cp target/$(cat /target.txt)/release/your-binary-name /app/
|
||
|
||
# ============================================
|
||
# 运行阶段
|
||
# ============================================
|
||
FROM alpine:3.21
|
||
|
||
RUN apk add --no-cache ca-certificates tzdata curl && \
|
||
ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
|
||
|
||
WORKDIR /app
|
||
|
||
COPY --from=builder /app/your-binary-name .
|
||
|
||
ENV TZ=Asia/Shanghai
|
||
ENV RUST_LOG=info
|
||
|
||
EXPOSE 9090
|
||
|
||
HEALTHCHECK --interval=30s --timeout=5s --start-period=10s --retries=3 \
|
||
CMD curl -sf http://localhost:9090/healthz || exit 1
|
||
|
||
CMD ["./your-binary-name"]
|
||
```
|
||
|
||
**使用说明**:
|
||
```bash
|
||
# 构建多平台镜像
|
||
docker buildx build --platform linux/amd64,linux/arm64 -t your-image:latest .
|
||
```
|
||
|
||
## 高级配置
|
||
|
||
### 健康检查配置
|
||
|
||
```dockerfile
|
||
# 存活探针(Liveness Probe)
|
||
HEALTHCHECK --interval=30s --timeout=5s --start-period=10s --retries=3 \
|
||
CMD curl -sf http://localhost:9090/healthz || exit 1
|
||
|
||
# 参数说明:
|
||
# --interval=30s 每 30 秒检查一次
|
||
# --timeout=5s 单次检查超时 5 秒
|
||
# --start-period=10s 容器启动后 10 秒开始检查
|
||
# --retries=3 失败 3 次后认为不健康
|
||
```
|
||
|
||
### 多端点健康检查
|
||
|
||
```dockerfile
|
||
# 使用脚本检查多个端点
|
||
RUN echo '#!/bin/sh' > /healthcheck.sh && \
|
||
echo 'curl -sf http://localhost:9090/healthz || exit 1' >> /healthcheck.sh && \
|
||
echo 'curl -sf http://localhost:9090/readyz || exit 1' >> /healthcheck.sh && \
|
||
chmod +x /healthcheck.sh
|
||
|
||
HEALTHCHECK --interval=30s --timeout=5s --start-period=10s --retries=3 \
|
||
CMD ["/healthcheck.sh"]
|
||
```
|
||
|
||
### 环境变量配置
|
||
|
||
```dockerfile
|
||
# 基础环境变量
|
||
ENV TZ=Asia/Shanghai
|
||
ENV RUST_LOG=info
|
||
ENV RUST_BACKTRACE=1
|
||
|
||
# 应用配置(可在 docker run 时覆盖)
|
||
ENV CONFIG_FILE=production.yaml
|
||
ENV HTTP_PORT=9090
|
||
ENV LOG_LEVEL=info
|
||
|
||
# 数据库配置(敏感信息应通过运行时注入)
|
||
# ENV DATABASE_URL=postgresql://...
|
||
```
|
||
|
||
### 非 root 用户运行
|
||
|
||
```dockerfile
|
||
# 创建非特权用户
|
||
RUN addgroup -g 1000 appuser && \
|
||
adduser -D -u 1000 -G appuser appuser
|
||
|
||
WORKDIR /app
|
||
|
||
# 复制二进制文件
|
||
COPY --from=builder /build/target/x86_64-unknown-linux-musl/release/your-binary-name .
|
||
|
||
# 修改所有权
|
||
RUN chown -R appuser:appuser /app
|
||
|
||
# 切换用户
|
||
USER appuser
|
||
|
||
CMD ["./your-binary-name"]
|
||
```
|
||
|
||
### 配置文件挂载
|
||
|
||
```dockerfile
|
||
# 在 Dockerfile 中创建配置目录
|
||
RUN mkdir -p /app/configs /app/logs
|
||
|
||
# 在 docker run 时挂载
|
||
# docker run -v ./configs:/app/configs -v ./logs:/app/logs your-image
|
||
```
|
||
|
||
## 构建命令示例
|
||
|
||
### 本地构建
|
||
|
||
```bash
|
||
# 基础构建
|
||
docker build -t your-service:latest .
|
||
|
||
# 指定 Dockerfile
|
||
docker build -f Dockerfile.ci -t your-service:latest .
|
||
|
||
# 传递构建参数
|
||
docker build --build-arg GIT_TAG=1.0.0 -t your-service:1.0.0 .
|
||
|
||
# 查看构建过程
|
||
docker build --progress=plain -t your-service:latest .
|
||
```
|
||
|
||
### 多平台构建
|
||
|
||
```bash
|
||
# 创建 buildx builder
|
||
docker buildx create --name mybuilder --use
|
||
|
||
# 构建并推送
|
||
docker buildx build \
|
||
--platform linux/amd64,linux/arm64 \
|
||
-t registry.example.com/your-service:latest \
|
||
--push \
|
||
.
|
||
```
|
||
|
||
### 优化构建速度
|
||
|
||
```bash
|
||
# 使用 BuildKit 缓存
|
||
export DOCKER_BUILDKIT=1
|
||
|
||
# 使用外部缓存
|
||
docker build \
|
||
--cache-from=type=registry,ref=your-service:buildcache \
|
||
--cache-to=type=registry,ref=your-service:buildcache,mode=max \
|
||
-t your-service:latest \
|
||
.
|
||
```
|
||
|
||
## 镜像大小优化
|
||
|
||
### 1. 使用 Alpine 基础镜像
|
||
|
||
```dockerfile
|
||
# Alpine 镜像体积小(~5MB)
|
||
FROM alpine:3.21
|
||
```
|
||
|
||
### 2. 静态链接(musl)
|
||
|
||
```dockerfile
|
||
# 构建时使用 musl 目标,生成静态链接二进制
|
||
RUN cargo build --release --target x86_64-unknown-linux-musl
|
||
```
|
||
|
||
### 3. Strip 二进制文件
|
||
|
||
```toml
|
||
# Cargo.toml
|
||
[profile.release]
|
||
strip = true # 去除符号表
|
||
```
|
||
|
||
或在 Dockerfile 中:
|
||
|
||
```dockerfile
|
||
# 手动 strip
|
||
RUN strip target/x86_64-unknown-linux-musl/release/your-binary-name
|
||
```
|
||
|
||
### 4. 最小化层数
|
||
|
||
```dockerfile
|
||
# 合并多个 RUN 命令
|
||
RUN apk add --no-cache ca-certificates tzdata curl && \
|
||
ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime && \
|
||
addgroup -g 1000 appuser
|
||
```
|
||
|
||
### 5. 使用 .dockerignore
|
||
|
||
```
|
||
# .dockerignore
|
||
target/
|
||
.git/
|
||
.gitignore
|
||
*.md
|
||
tests/
|
||
benches/
|
||
```
|
||
|
||
## 安全建议
|
||
|
||
### 1. 使用特定版本标签
|
||
|
||
```dockerfile
|
||
# 不推荐:使用 latest
|
||
FROM alpine:latest
|
||
|
||
# 推荐:使用特定版本
|
||
FROM alpine:3.21
|
||
```
|
||
|
||
### 2. 定期更新依赖
|
||
|
||
```bash
|
||
# 更新 Cargo 依赖
|
||
cargo update
|
||
|
||
# 检查安全漏洞
|
||
cargo audit
|
||
```
|
||
|
||
### 3. 最小权限原则
|
||
|
||
```dockerfile
|
||
# 使用非 root 用户
|
||
USER appuser
|
||
|
||
# 只读文件系统(根据需要)
|
||
# docker run --read-only your-service
|
||
```
|
||
|
||
### 4. 不在镜像中包含敏感信息
|
||
|
||
```dockerfile
|
||
# 错误示例
|
||
# ENV DATABASE_PASSWORD=secret123
|
||
|
||
# 正确做法:通过运行时注入
|
||
# docker run -e DATABASE_PASSWORD=secret123 your-service
|
||
```
|
||
|
||
## 常见问题
|
||
|
||
### Q1: 镜像体积过大
|
||
|
||
**原因**:
|
||
- 使用 `rust:latest` 作为运行镜像(>1GB)
|
||
- 没有使用多阶段构建
|
||
- 包含 debug 符号
|
||
|
||
**解决方案**:
|
||
```dockerfile
|
||
# 使用多阶段构建 + Alpine
|
||
FROM rust:1.83-alpine AS builder
|
||
# ... 构建步骤 ...
|
||
|
||
FROM alpine:3.21 # 最终镜像只有 ~20MB
|
||
COPY --from=builder /build/target/.../your-binary .
|
||
```
|
||
|
||
### Q2: openssl 链接错误
|
||
|
||
**错误信息**:
|
||
```
|
||
error: linking with `cc` failed
|
||
ld: library not found for -lssl
|
||
```
|
||
|
||
**解决方案**:
|
||
```dockerfile
|
||
# 方案 1:安装 openssl-dev
|
||
RUN apk add --no-cache openssl-dev
|
||
|
||
# 方案 2:使用 rustls 替代 openssl
|
||
# 在 Cargo.toml 中使用 rustls feature
|
||
```
|
||
|
||
### Q3: 交叉编译失败
|
||
|
||
**错误信息**:
|
||
```
|
||
error: linker `aarch64-linux-musl-gcc` not found
|
||
```
|
||
|
||
**解决方案**:
|
||
```bash
|
||
# 安装 musl 交叉编译工具链
|
||
rustup target add aarch64-unknown-linux-musl
|
||
|
||
# 或使用 cargo-zigbuild
|
||
cargo install cargo-zigbuild
|
||
cargo zigbuild --target aarch64-unknown-linux-musl
|
||
```
|
||
|
||
### Q4: 容器启动失败
|
||
|
||
**检查步骤**:
|
||
```bash
|
||
# 查看日志
|
||
docker logs your-container
|
||
|
||
# 进入容器调试
|
||
docker run -it --entrypoint /bin/sh your-image
|
||
|
||
# 检查二进制是否可执行
|
||
docker run your-image ls -lh /app/
|
||
```
|
||
|
||
## 参考资源
|
||
|
||
- [Rust 官方 Docker 指南](https://docs.docker.com/language/rust/)
|
||
- [Alpine Linux 包搜索](https://pkgs.alpinelinux.org/packages)
|
||
- [Docker 多阶段构建文档](https://docs.docker.com/build/building/multi-stage/)
|
||
- [cargo-zigbuild](https://github.com/rust-cross/cargo-zigbuild)
|