--- title: 自建镜像 description: 从源码构建各服务的 Docker 镜像 outline: deep --- # 自建镜像 平台镜像由官方仓库分发。如有定制需求(改代码、加依赖、适配私有基础镜像),可从源码自行构建。 ## 构建环境 | 项 | 要求 | | --- | --- | | Docker | 20.10 以上 | | 网络 | 需访问基础镜像仓库与 Go/npm 依赖源 | | 磁盘 | 单服务构建约 1~2 GB(含构建缓存) | ## 各服务构建文件 | 服务 | 仓库 | Dockerfile | 构建上下文 | | --- | --- | --- | --- | | admin-svr | `iotlcm-admin-svr` | `server/build/Dockerfile` | `server/` | | openapi | `iotlcm-openapi` | `build/Dockerfile` | 仓库根目录 | | worker-svr | `iotlcm-worker-svr` | `build/Dockerfile` | 仓库根目录 | | upstream-chan | `iotlcm-upstream-chan` | `build/Dockerfile` | 仓库根目录 | | upstream-proxy | `iotlcm-upstream-proxy` | `build/Dockerfile` | 仓库根目录 | | app-server | `iotlcm-app` | `server/Dockerfile` | `server/` | | app-web | `iotlcm-app` | `app/Dockerfile` | `app/` | | admin-ui | `iotlcm-admin-ui` | `vue/build/Dockerfile` | `vue/` | | sms | `iotlcm-sms` | `build/Dockerfile` | 仓库根目录 | | bot | `iotlcm-bot` | `Dockerfile` | 仓库根目录 | | docs | `iotlcm-docs` | `Dockerfile` | 仓库根目录 | | onelink-mock | `iotlcm-onelink-mock` | `Dockerfile` | 仓库根目录 | ## ⚠️ 先处理私有基础镜像 **当前部分仓库的 Dockerfile 仍指向私有镜像仓库**,外部环境无法拉取,直接构建会失败: | 仓库 | 文件 | 问题 | | --- | --- | --- | | `iotlcm-openapi` | `manifest/docker/Dockerfile` | `FROM` 指向私有仓库 | | `iotlcm-app` | `app/Dockerfile` | 2 处 `FROM` 指向私有仓库 | | `iotlcm-app` | `server/Dockerfile` | 2 处 `FROM` 指向私有仓库 | | `iotlcm-admin-ui` | `vue/build/Dockerfile` | 2 处 `FROM` 指向私有仓库 | | `iotlcm-admin-ui` | `vue/build/DockerfileNoBuild` | `FROM` 指向私有仓库 | 构建前把这些 `FROM` 改为公共镜像: ```dockerfile # 修改前(私有仓库,外部不可达) FROM crpi-xxxxxxxx.cn-beijing.personal.cr.aliyuncs.com/xxx/golangalpine:1.25.7-alpine3.23 AS builder # 修改后(公共镜像) FROM golang:1.25-alpine AS builder ``` ```dockerfile FROM crpi-xxxxxxxx.cn-beijing.personal.cr.aliyuncs.com/xxx/nginx:1.30.0-alpine # 改为 FROM nginx:1.30-alpine ``` ::: tip 其余仓库的 Dockerfile 已可用 `admin-svr`、`worker-svr`、`upstream-chan`、`upstream-proxy`、`sms`、`bot`、`docs`、`onelink-mock` 的 Dockerfile 基础镜像均为公共镜像,可直接构建。 ::: ## 构建命令 ### 后端服务 ```bash COMMIT=$(git rev-parse --short HEAD) VERSION=$(git describe --tags --always) BUILD_TIME=$(date -u '+%Y-%m-%dT%H:%M:%SZ') docker build \ --build-arg BuildVersion=$VERSION \ --build-arg CommitID=$COMMIT \ --build-arg BuildTime=$BUILD_TIME \ -t your-registry/iotlcm/iotlcm-openapi:$VERSION \ . ``` `admin-svr` 与 `app-server` 需指定上下文目录: ```bash cd iotlcm-admin-svr docker build \ --build-arg BuildVersion=$VERSION \ --build-arg CommitID=$COMMIT \ --build-arg BuildTime=$BUILD_TIME \ -t your-registry/iotlcm/iotlcm-admin-svr:$VERSION \ -f server/build/Dockerfile server/ ``` ### 前端服务 ```bash cd iotlcm-admin-ui/vue docker build -t your-registry/iotlcm/iotlcm-admin-ui:$VERSION -f build/Dockerfile . ``` ```bash cd iotlcm-app/app docker build -t your-registry/iotlcm/iotlcm-app-web:$VERSION . ``` ### 构建参数说明 | 参数 | 用途 | | --- | --- | | `BuildVersion` | 写入二进制,可通过版本接口查询 | | `CommitID` | 提交号,便于追溯 | | `BuildTime` | 构建时间 | `openapi`、`worker-svr` 等仓库支持用 `GOPROXY` 构建参数替换代理: ```bash docker build --build-arg GOPROXY=https://goproxy.cn,direct -t ... . ``` ## 镜像命名规则 部署编排按以下名称拉取镜像,自建时需保持一致: | 服务 | 镜像名 | | --- | --- | | admin-svr | `/iotlcm/iotlcm-admin-svr:` | | admin-ui | `/iotlcm/iotlcm-admin-ui:` | | openapi | `/iotlcm/iotlcm-openapi:` | | app-server | `/iotlcm/iotlcm-app-server:` | | app-web | `/iotlcm/iotlcm-app-web:` | | upstream-chan | `/iotlcm/iotlcm-upstream-chan:` | | upstream-proxy | `/iotlcm/iotlcm-upstream-proxy:` | | worker-svr | `/iotlcm/iotlcm-worker-svr:` | | sms | `/iotlcm/iotlcm-sms:` | | bot | `/iotlcm/iotlcm-bot:` | | docs | `/iotlcm/iotlcm-docs:` | | onelink-mock | `/iotlcm/iotlcm-onelink-mock:` | 基础组件(`library/mysql`、`library/redis` 等)直接使用上游官方镜像,无需自建。 ## 推送到自己的仓库 ```bash REGISTRY=harbor.internal.example.com TAG=1.0.3 docker tag iotlcm-openapi:local $REGISTRY/iotlcm/iotlcm-openapi:$TAG docker push $REGISTRY/iotlcm/iotlcm-openapi:$TAG ``` 部署时 `.env` 改为: ```bash REGISTRY=harbor.internal.example.com TAG=1.0.3 ``` ## 批量构建脚本 ```bash #!/bin/bash set -euo pipefail REGISTRY=${REGISTRY:?请设置 REGISTRY} TAG=${TAG:-$(date +%Y%m%d)} WORKDIR=${WORKDIR:-./repos} # 服务:仓库:上下文:产物镜像名 SERVICES=( "admin-svr:iotlcm-admin-svr:server/:iotlcm-admin-svr" "openapi:iotlcm-openapi:.:iotlcm-openapi" "worker-svr:iotlcm-worker-svr:.:iotlcm-worker-svr" "upstream-chan:iotlcm-upstream-chan:.:iotlcm-upstream-chan" "upstream-proxy:iotlcm-upstream-proxy:.:iotlcm-upstream-proxy" "app-server:iotlcm-app:server/:iotlcm-app-server" "sms:iotlcm-sms:.:iotlcm-sms" "bot:iotlcm-bot:.:iotlcm-bot" ) mkdir -p "$WORKDIR" for item in "${SERVICES[@]}"; do IFS=':' read -r name repo ctx image <<< "$item" echo "=== 构建 $name ===" if [ ! -d "$WORKDIR/$repo" ]; then git clone "https://git.5iot.com/iotlcm-public/$repo.git" "$WORKDIR/$repo" fi VERSION=$(git -C "$WORKDIR/$repo" describe --tags --always 2>/dev/null || echo unknown) COMMIT=$(git -C "$WORKDIR/$repo" rev-parse --short HEAD 2>/dev/null || echo unknown) find "$WORKDIR/$repo" -name Dockerfile -exec \ sed -i 's#FROM crpi-[^ ]*/\([a-z]*\):\([0-9.]*-alpine[0-9.]*\)#FROM \1:\2#' {} \; docker build \ --build-arg BuildVersion="$VERSION" \ --build-arg CommitID="$COMMIT" \ --build-arg BuildTime="$(date -u '+%Y-%m-%dT%H:%M:%SZ')" \ -t "$REGISTRY/iotlcm/$image:$TAG" \ -f "$WORKDIR/$repo/${ctx}Dockerfile" \ "$WORKDIR/$repo/$ctx" done echo "全部完成,镜像标签:$REGISTRY/iotlcm/*:$TAG" ``` ::: warning 脚本里的 sed 只能应急 上面的 `sed` 是粗略替换,把私有仓库地址映射为公共镜像名。仅适用于地址格式规整的情况,用前先 `git diff` 确认改对了。正式做法应把 Dockerfile 的修正提交回仓库。 ::: ## 验证构建结果 ```bash # 镜像大小 docker images | grep iotlcm # 二进制能否启动 docker run --rm your-registry/iotlcm/iotlcm-openapi:$TAG --help 2>&1 | head # 检查架构 docker inspect your-registry/iotlcm/iotlcm-openapi:$TAG \ --format '{{.Architecture}}/{{.Os}}' ``` 构建后按[启动与验证](install)的清单做一次完整部署验证,不要只看镜像是否构建成功。 ## 常见问题 | 现象 | 原因 | 处理 | | --- | --- | --- | | `pull access denied` / `unauthorized` | Dockerfile 里是私有仓库地址 | 按上文替换 `FROM` | | `go mod download` 超时 | 网络无法访问 Go 模块代理 | 加 `--build-arg GOPROXY=https://goproxy.cn,direct` | | `npm ci` 失败 | 前端仓库 lock 文件与 package.json 不一致 | 改用 `npm install`,并注意提交 lock 变更 | | 镜像体积过大 | 未使用多阶段构建,或缓存未清理 | 确认用的是仓库自带的 Dockerfile(均为多阶段) | | 容器启动后立即退出 | 镜像内缺少配置文件 | 容器认为 `config/config.yaml` 必须存在,需挂载或用占位配置 | | `exec format error` | 构建架构与运行架构不一致 | 加 `--platform linux/amd64` |