将微信小程序的构建和上传流程容器化,支持公网和内网两种部署环境。
- 两层镜像架构:基础镜像 + 项目镜像,复用依赖,加速构建
- 依赖内置:
miniprogram-ci等依赖预装到基础镜像,项目镜像即时启动 - 双版本支持:公网版(Docker Hub)和内网版(Artifactory)
- Git 信息自动提取:构建时自动从 .git 提取 commit、branch 信息
- 安全设计:私钥运行时下载,不打包进镜像
- 灵活配置:支持构建时和运行时参数覆盖
┌─────────────────────────────────────────────────────────────────┐
│ 两层镜像架构 │
├─────────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ 基础镜像 (Dockerfile.base) │ │
│ │ ┌─────────────────────────────────────────────────┐ │ │
│ │ │ node:22-alpine │ │ │
│ │ │ + git, curl, bash, gcompat │ │ │
│ │ │ + miniprogram-ci, axios, chalk... │ │ │
│ │ │ + CI 脚本 (/ci/scripts/) │ │ │
│ │ │ + 配置文件 (/ci/config/) │ │ │
│ │ └─────────────────────────────────────────────────┘ │ │
│ └─────────────────────────────────────────────────────────┘ │
│ ↓ FROM │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ 项目镜像 (Dockerfile.build) │ │
│ │ ┌─────────────────────────────────────────────────┐ │ │
│ │ │ + 项目 package.json & node_modules │ │ │
│ │ │ + 项目源码 (/app/) │ │ │
│ │ │ + build-info.json (Git信息) │ │ │
│ │ └─────────────────────────────────────────────────┘ │ │
│ └─────────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────┘
┌──────────────────────────────────────────────────────────────────┐
│ docker run miniprogram:v1.0.0 │
├──────────────────────────────────────────────────────────────────┤
│ │
│ docker-entrypoint.sh │
│ │ │
│ ├─→ 1. 检查环境变量 │
│ │ │
│ ├─→ 2. 验证项目目录 (/app) │
│ │ │
│ ├─→ 3. 安装依赖 (可选,SKIP_INSTALL=true 跳过) │
│ │ │
│ ├─→ 4. 读取 build-info.json (版本、描述、Git信息) │
│ │ │
│ ├─→ 5. 执行 Taro 构建 (可选,SKIP_BUILD=true 跳过) │
│ │ └─→ BUILD_MODE=production → npm run build │
│ │ └─→ BUILD_MODE=pre/test → npm run build:pre │
│ │ │
│ ├─→ 6. 验证构建产物 (/app/dist) │
│ │ │
│ ├─→ 7. 下载私钥 (MP_PRIVATE_KEY_URL) │
│ │ │
│ ├─→ 8. 执行上传/预览 (upload-mp.js) │
│ │ └─→ ACTION=upload → 上传到微信平台 │
│ │ └─→ ACTION=preview → 生成预览二维码 │
│ │ │
│ └─→ 9. 清理私钥文件 │
│ │
└──────────────────────────────────────────────────────────────────┘
miniprogram-ci-docker/
├── public/ # 公网版本 Dockerfile
│ ├── Dockerfile.base # 基础镜像(使用 Docker Hub)
│ └── Dockerfile.build # 项目镜像模板
├── private/ # 内网版本 Dockerfile
│ ├── Dockerfile.base # 基础镜像(使用内网 Registry)
│ └── Dockerfile.build # 项目镜像模板
├── scripts/
│ ├── docker-entrypoint.sh # 容器入口脚本
│ ├── upload-mp.js # 上传主脚本
│ ├── generate-build-info.js # 构建信息生成脚本
│ ├── generate-key.js # 私钥管理脚本
│ └── utils/
│ ├── logger.js # 日志工具
│ ├── oss-uploader.js # OSS 上传工具
│ └── version.js # 版本管理工具
├── config/
│ └── ci.config.js # CI 配置文件
├── .dockerignore # Docker 忽略文件
└── README.md # 使用文档
# 公网版本
docker build -f public/Dockerfile.base \
-t your-registry/miniprogram-ci-base:1.0.2 \
.
# 内网版本
docker build -f private/Dockerfile.base \
-t artifacts.iflytek.com/cbg-docker-private/xfyun_webdev/miniprogram-ci-base:1.0.2 \
.
# 推送基础镜像
docker push your-registry/miniprogram-ci-base:1.0.2# 构建项目镜像
docker build -f private/Dockerfile.build \
--build-arg PROJECT_DIR="frontend-app" \
--build-arg BUILD_VERSION="1.0.0" \
--build-arg BUILD_DESC="新功能发布" \
--build-arg BUILDER="张三" \
-t miniprogram:v1.0.0 \
.# 上传到微信平台
docker run --rm \
-e MP_PRIVATE_KEY_URL="https://cdn.example.com/private.key" \
-e BUILD_MODE="production" \
-e BUILD_ENV="production" \
miniprogram:v1.0.0
# 生成预览二维码
docker run --rm \
-v $(pwd)/output:/app/output \
-e MP_PRIVATE_KEY_URL="https://cdn.example.com/private.key" \
-e ACTION="preview" \
-e UPLOAD_OSS="true" \
-e API_COOKIE="your-cookie" \
miniprogram:v1.0.0在 docker build 时通过 --build-arg 传入,会固化到镜像中:
| 参数名 | 必需 | 默认值 | 说明 |
|---|---|---|---|
PROJECT_DIR |
否 | . |
项目目录路径(相对于构建上下文) |
BUILD_VERSION |
否 | 从 package.json 读取 | 版本号 |
BUILD_DESC |
否 | 从 Git commit message 读取 | 版本描述 |
BUILDER |
否 | 空 | 构建人名称 |
在 docker run 时通过 -e 传入,可覆盖构建时的默认值:
| 变量名 | 必需 | 默认值 | 说明 |
|---|---|---|---|
MP_PRIVATE_KEY_URL |
是 | - | 私钥文件 CDN 下载地址 |
ACTION |
否 | upload |
操作类型:upload / preview |
BUILD_MODE |
否 | production |
构建模式:production / pre / test |
BUILD_ENV |
否 | development |
部署环境:development / staging / production |
BUILD_VERSION |
否 | 构建时值 | 版本号(覆盖构建时值) |
BUILD_DESC |
否 | 构建时值 | 版本描述(覆盖构建时值) |
BUILDER |
否 | 构建时值 | 构建人名称(覆盖构建时值) |
ROBOT |
否 | 按环境配置 | CI 机器人编号(1-30) |
UPLOAD_OSS |
否 | true |
是否上传二维码到 OSS |
API_COOKIE |
否 | - | OSS 上传所需的 Cookie |
QRCODE_PATH |
否 | /app/output/preview-qrcode.png |
二维码保存路径 |
SKIP_INSTALL |
否 | false |
跳过 npm install |
SKIP_BUILD |
否 | false |
跳过 Taro 构建 |
不同环境使用不同的 CI 机器人和配置:
| 环境 | 机器人编号 | 说明 |
|---|---|---|
development |
1 | 开发/体验版 |
staging |
2 | 预发布环境 |
production |
3 | 正式生产环境 |
上传到微信平台的描述格式:
[环境标识] 版本描述 | 构建人 (Git提交)
示例:
- 有构建人:
[生产环境] 新功能发布 | 张三 (a9d9422) - 无构建人:
[生产环境] 新功能发布 (a9d9422) - 测试环境:
[测试/预发布] 修复登录问题 | 李四 (b8c7d33)
stages:
- build
- deploy
variables:
DOCKER_REGISTRY: artifacts.iflytek.com/cbg-docker-private/xfyun_webdev
IMAGE_NAME: miniprogram
CI_BASE_IMAGE: ${DOCKER_REGISTRY}/miniprogram-ci-base:1.0.2
# 构建项目镜像
build:
stage: build
script:
- docker build -f private/Dockerfile.build
--build-arg PROJECT_DIR="."
--build-arg BUILD_VERSION="${CI_COMMIT_TAG:-$CI_COMMIT_SHORT_SHA}"
--build-arg BUILD_DESC="${CI_COMMIT_MESSAGE}"
--build-arg BUILDER="${GITLAB_USER_NAME}"
-t ${DOCKER_REGISTRY}/${IMAGE_NAME}:${CI_COMMIT_SHORT_SHA}
.
- docker push ${DOCKER_REGISTRY}/${IMAGE_NAME}:${CI_COMMIT_SHORT_SHA}
# 部署到体验版
deploy-dev:
stage: deploy
script:
- docker run --rm
-e MP_PRIVATE_KEY_URL="${MP_PRIVATE_KEY_URL}"
-e BUILD_MODE="pre"
-e BUILD_ENV="development"
-e ACTION="upload"
${DOCKER_REGISTRY}/${IMAGE_NAME}:${CI_COMMIT_SHORT_SHA}
environment:
name: development
# 部署到生产环境
deploy-prod:
stage: deploy
script:
- docker run --rm
-e MP_PRIVATE_KEY_URL="${MP_PRIVATE_KEY_URL}"
-e BUILD_MODE="production"
-e BUILD_ENV="production"
-e ACTION="upload"
${DOCKER_REGISTRY}/${IMAGE_NAME}:${CI_COMMIT_SHORT_SHA}
environment:
name: production
when: manual
only:
- tagspipeline {
agent any
environment {
DOCKER_REGISTRY = 'artifacts.iflytek.com/cbg-docker-private/xfyun_webdev'
IMAGE_NAME = 'miniprogram'
MP_PRIVATE_KEY_URL = credentials('mp-private-key-url')
}
stages {
stage('Build Image') {
steps {
script {
def version = env.TAG_NAME ?: env.GIT_COMMIT.take(7)
sh """
docker build -f private/Dockerfile.build \
--build-arg BUILD_VERSION="${version}" \
--build-arg BUILD_DESC="${env.GIT_COMMIT_MESSAGE}" \
--build-arg BUILDER="${env.BUILD_USER}" \
-t ${DOCKER_REGISTRY}/${IMAGE_NAME}:${version} \
.
"""
}
}
}
stage('Deploy') {
steps {
sh """
docker run --rm \
-e MP_PRIVATE_KEY_URL="${MP_PRIVATE_KEY_URL}" \
-e BUILD_MODE="production" \
-e BUILD_ENV="production" \
${DOCKER_REGISTRY}/${IMAGE_NAME}:${version}
"""
}
}
}
}-
私钥安全:私钥文件通过
MP_PRIVATE_KEY_URL运行时下载,运行结束后自动清理,不会保留在镜像或容器中 -
Git 信息:构建时会复制
.git目录用于提取 commit 信息,生成build-info.json后自动删除 -
Alpine 兼容性:Alpine 使用 musl libc,已添加
libc6-compat和gcompat兼容包 -
Taro 兼容:已自动安装
@tarojs/binding-linux-x64-musl以支持 Alpine 环境 -
日志持久化:可通过
-v $(pwd)/logs:/app/logs挂载日志目录 -
二维码输出:预览模式生成的二维码保存在
/app/output/目录,可通过挂载获取 -
构建指令要求:项目的
package.json中需要包含以下构建脚本:npm run build- 生产环境构建(BUILD_MODE=production时执行)npm run build:pre- 测试/预发布环境构建(BUILD_MODE=pre或BUILD_MODE=test时执行)
构建产物需要输出到
./dist目录
确保 .git 目录在构建上下文中,检查 .dockerignore 是否排除了 .git。
检查 MP_PRIVATE_KEY_URL 是否正确,确保 URL 可访问。
确保已安装 @tarojs/binding-linux-x64-musl,这是 Alpine 环境必需的。
- 检查私钥文件是否正确
- 检查
project.config.json中的 appid 是否匹配 - 查看日志文件
/app/logs/miniprogram-ci-*.log
MIT License