Docker 镜像构建与部署指南

Docker 镜像构建与部署指南

_
# Docker 镜像构建与部署指南

适用于:本地 Windows 开发机构建 → 阿里云容器镜像服务托管 → Linux 服务器拉取部署。

---

## 整体流程

```
┌─────────────────────┐     ┌──────────────────┐     ┌─────────────────┐
│  本地 Windows (PS)   │     │   阿里云镜像仓库    │     │  Linux 服务器     │
│                     │     │                  │     │                 │
│  1. docker build    │────▶│  2. 镜像托管存储   │────▶│  3. docker pull │
│     docker push     │     │                  │     │     docker run  │
└─────────────────────┘     └──────────────────┘     └─────────────────┘
```

---

## 1. 前置准备

### 1.1 阿里云容器镜像服务

- 登录 [阿里云容器镜像服务](https://cr.console.aliyun.com/)
- 创建**个人实例**(免费),选择区域(如华东1-杭州)
- 创建**命名空间**(如 `myhui`)
- 创建**镜像仓库**(如 `auto-first-backend`),代码源选"本地仓库"
- 获取仓库地址,格式:`crpi-<实例ID>.<区域>.personal.cr.aliyuncs.com/<命名空间>/<仓库名>`

### 1.2 本地 Docker 登录

```powershell
# 登录阿里云镜像仓库(密码是阿里云容器镜像服务的固定密码,不是阿里云账号密码)
docker login crpi-<实例ID>.<区域>.personal.cr.aliyuncs.com
```

### 1.3 服务器 Docker 登录

```bash
docker login crpi-<实例ID>.<区域>.personal.cr.aliyuncs.com
```

---

## 2. 环境配置文件

每个环境一份 `.env` 文件,放在项目后端目录下:

```
backend/
├── .env.example    # 模板(提交到 Git)
├── .env.test       # 测试环境(不提交,含真实密钥)
└── .env.pro        # 生产环境(不提交,含真实密钥)
```

**步骤**:

```bash
# 从模板复制
cp backend/.env.example backend/.env.test
cp backend/.env.example backend/.env.pro

# 编辑,填入对应环境的真实密钥和配置
```

> `.gitignore` 中确保已排除 `.env.test` 和 `.env.pro`。

---

## 3. Dockerfile

在 `backend/` 目录下创建 `Dockerfile`,关键点:

```dockerfile
# 构建参数:环境标识 + env 文件名
ARG CONFIG_ENV=test
ARG ENV_FILE=.env.test

# 将 env 文件打入镜像(构建时注入,运行时无需挂载)
ARG ENV_FILE
COPY ${ENV_FILE} .env
```

构建时通过 `--build-arg` 指定环境和 env 文件:

```powershell
# 测试环境
docker build --build-arg CONFIG_ENV=test --build-arg ENV_FILE=.env.test -t <镜像名>:test ./backend

# 生产环境
docker build --build-arg CONFIG_ENV=pro --build-arg ENV_FILE=.env.pro -t <镜像名>:pro ./backend
```

---

## 4. 构建脚本(本地 Windows PowerShell)

在项目根目录创建两个脚本:

### build-backend-test.ps1(测试环境)

```powershell
$ErrorActionPreference = "Stop"
$env:DOCKER_BUILDKIT = 1

# ---- 配置区(按项目修改) ----
$CONFIG_ENV = "test"
$ENV_FILE = ".env.test"
$IMAGE_REPO = "crpi-<实例ID>.<区域>.personal.cr.aliyuncs.com/<命名空间>/<仓库名>"
$TAG = "test"
# ------------------------------
$IMAGE = "${IMAGE_REPO}:${TAG}"
$BACKEND_DIR = Join-Path $PSScriptRoot "backend"
$ENV_PATH = Join-Path $BACKEND_DIR $ENV_FILE

if (-not (Test-Path $ENV_PATH)) {
    throw "Env file not found: $ENV_PATH"
}

Write-Host "========================================" -ForegroundColor Cyan
Write-Host "Building: $IMAGE" -ForegroundColor Yellow
Write-Host "Env file: $ENV_FILE" -ForegroundColor Green
Write-Host "========================================" -ForegroundColor Cyan

# 构建
docker build --build-arg CONFIG_ENV=$CONFIG_ENV --build-arg ENV_FILE=$ENV_FILE -t $IMAGE $BACKEND_DIR
if ($LASTEXITCODE -ne 0) { exit 1 }

# 推送
Write-Host "Pushing $IMAGE ..."
docker push $IMAGE
if ($LASTEXITCODE -ne 0) { exit 1 }

Write-Host "Done!" -ForegroundColor Green
```

### build-backend-pro.ps1(生产环境)

将上面脚本中的 `$CONFIG_ENV`、`$ENV_FILE`、`$TAG` 改为:

```powershell
$CONFIG_ENV = "pro"
$ENV_FILE = ".env.pro"
$TAG = "pro"
```

---

## 5. 服务器部署命令

### 5.1 首次部署

SSH 到目标服务器后执行:

```bash
# 拉取最新镜像
docker pull <镜像仓库地址>:<tag>

# 启动容器
docker run -d \
  --name <容器名> \
  -p <宿主端口>:<容器端口> \
  --restart unless-stopped \
  <镜像仓库地址>:<tag>

# 查看日志确认启动成功
docker logs -f <容器名>
```

### 5.2 更新部署(重新部署)

```bash
# 拉取最新镜像
docker pull <镜像仓库地址>:<tag>

# 停止并删除旧容器
docker rm -f <容器名>

# 启动新容器(参数与首次部署一致)
docker run -d \
  --name <容器名> \
  -p <宿主端口>:<容器端口> \
  --restart unless-stopped \
  <镜像仓库地址>:<tag>

# 查看日志
docker logs -f <容器名>
```

> 一行版(适合快速粘贴):
> ```bash
> docker pull <镜像>:<tag> && docker rm -f <容器名> 2>/dev/null; docker run -d --name <容器名> -p <端口映射> --restart unless-stopped <镜像>:<tag>
> ```

---

## 6. 完整操作速查

```
# ===== 本地 Windows =====

# 1. 确认 env 文件存在且配置正确
#    backend/.env.test  → 测试环境
#    backend/.env.pro   → 生产环境

# 2. 执行构建脚本
.\build-backend-test.ps1    # 测试环境
.\build-backend-pro.ps1     # 生产环境

# ===== 服务器 Linux =====

# 3. SSH 登录后,拉取并重启
docker pull <镜像>:test && docker rm -f <容器名> 2>/dev/null; docker run -d --name <容器名> -p 18008:18008 --restart unless-stopped <镜像>:test

# 4. 检查
docker logs -f <容器名>
```

---

## 7. 常见问题

### Q: docker push 报 "unauthorized"
重新登录:`docker login <镜像仓库地址>`

### Q: 服务器 docker pull 报 "unauthorized"
服务器也需要登录:`docker login <镜像仓库地址>`

### Q: 如何查看容器运行状态
```bash
docker ps                    # 运行中的容器
docker logs --tail 100 <容器名>  # 最近100行日志
docker inspect <容器名>      # 容器详细信息
```

### Q: 如何回滚到上一个版本
阿里云镜像服务会保留历史版本,通过 digest 拉取指定版本:
```bash
# 查看镜像历史
docker images <镜像名>

# 指定 digest 拉取
docker pull <镜像名>@<digest>
```

### Q: 容器内环境变量不想打入镜像怎么办
用 `-e` 参数在运行时覆盖,或挂载 env 文件:
```bash
docker run -d --name <容器名> --env-file /path/to/.env -p 18008:18008 <镜像>
```

U盘文件系统格式对比 2026-03-24

评论区