Skip to content

自建镜像 ​

平台镜像由官方仓库分发。如有定制需求(改代码、加依赖、适配私有基础镜像),可从源码自行构建。

构建环境 ​

项要求
Docker20.10 以上
网络需访问基础镜像仓库与 Go/npm 依赖源
磁盘单服务构建约 1~2 GB(含构建缓存)

各服务构建文件 ​

全部服务在同一仓内,git clone 后按下表的构建上下文执行 docker build:

服务目录构建上下文Dockerfile(相对上下文)
admin-svradmin-svr/admin-svr/serverbuild/Dockerfile
admin-uiadmin-ui/admin-uivue/build/Dockerfile
openapiopenapi/openapibuild/Dockerfile
worker-svrworker-svr/worker-svrbuild/Dockerfile
upstream-chanupstream-chan/upstream-chanbuild/Dockerfile
upstream-proxyupstream-proxy/upstream-proxybuild/Dockerfile
app-serverapp/server/app/serverDockerfile
app-webapp/app/app/appDockerfile
smssms/smsbuild/Dockerfile
botbot/botDockerfile
docsdocs/docsDockerfile
onelink-mockonelink-mock/onelink-mockDockerfile

admin-ui 的上下文必须是 admin-ui/(不是 admin-ui/vue/)——它的 Dockerfile 里引用了 vue/build/nginx.conf。

一次构建全部:make images REGISTRY=<镜像仓库>/iotlcm/iotlcm VERSION=<版本>。

基础镜像可替换 ​

所有构建用 Dockerfile 都通过 ARG BASE_REGISTRY 拼接 FROM,默认值是公共镜像仓库 docker.io/library,开箱即可构建:

dockerfile
ARG BASE_REGISTRY=docker.io/library
FROM ${BASE_REGISTRY}/golang:1.25-alpine AS builder

内网或离线环境改走自己的镜像仓库时,构建时覆盖即可,不需要改 Dockerfile:

bash
docker build --build-arg BASE_REGISTRY=harbor.internal.example.com/library \
  -f admin-svr/server/build/Dockerfile -t ... admin-svr/server

各服务实际用到的基础镜像版本:

服务基础镜像
Go 服务(admin-svr / openapi / worker-svr / upstream-chan / upstream-proxy / app-server / sms / bot)golang:1.25-alpine(bot 用 golang:1.25-alpine)、运行期 alpine:3.23
admin-ui / app-webnode:24-alpine 构建、nginx:1.30-alpine / nginx:1.27-alpine 运行
docsnode:22-alpine 构建、nginx:1.27-alpine 运行
onelink-mockgolang:1.24-alpine

*/manifest/docker/Dockerfile 是 GoFrame 脚手架留下的模板,不参与构建,可以忽略。

构建命令 ​

后端服务 ​

bash
COMMIT=$(git rev-parse --short HEAD)
VERSION=$(git describe --tags --always)
BUILD_TIME=$(date -u '+%Y-%m-%dT%H:%M:%SZ')

# 在仓库根目录执行(上下文 = openapi/)
docker build \
  --build-arg BuildVersion=$VERSION \
  --build-arg CommitID=$COMMIT \
  --build-arg BuildTime=$BUILD_TIME \
  -t your-registry/iotlcm/iotlcm:iotlcm-openapi-$VERSION \
  -f openapi/build/Dockerfile openapi/

admin-svr 与 app-server 的上下文是模块目录:

bash
docker build \
  --build-arg BuildVersion=$VERSION \
  --build-arg CommitID=$COMMIT \
  --build-arg BuildTime=$BUILD_TIME \
  -t your-registry/iotlcm/iotlcm:iotlcm-admin-svr-$VERSION \
  -f admin-svr/server/build/Dockerfile admin-svr/server/

前端服务 ​

bash
docker build -t your-registry/iotlcm/iotlcm:iotlcm-admin-ui-$VERSION \
  -f admin-ui/vue/build/Dockerfile admin-ui/
bash
docker build -t your-registry/iotlcm/iotlcm:iotlcm-app-web-$VERSION \
  -f app/app/Dockerfile app/app/
bash
docker build -t your-registry/iotlcm/iotlcm:iotlcm-app-server-$VERSION \
  -f app/server/Dockerfile app/server/

构建参数说明 ​

参数用途
BuildVersion写入二进制,可通过版本接口查询
CommitID提交号,便于追溯
BuildTime构建时间

openapi、worker-svr 等 Go 服务支持用 GOPROXY 构建参数替换代理:

bash
docker build --build-arg GOPROXY=https://goproxy.cn,direct -t ... .

镜像命名规则 ​

官方仓库把所有镜像放在同一个镜像仓库 iotlcm/iotlcm 下,靠 tag 区分服务与版本:

text
<Registry>/iotlcm/iotlcm:<服务名>-<版本>
服务tag完整示例
admin-svriotlcm-admin-svr-<TAG>.../iotlcm/iotlcm:iotlcm-admin-svr-v1.0.4
admin-uiiotlcm-admin-ui-<TAG>.../iotlcm/iotlcm:iotlcm-admin-ui-v1.0.4
openapiiotlcm-openapi-<TAG>.../iotlcm/iotlcm:iotlcm-openapi-v1.0.4
app-serveriotlcm-app-server-<TAG>.../iotlcm/iotlcm:iotlcm-app-server-v1.0.2
app-webiotlcm-app-web-<TAG>.../iotlcm/iotlcm:iotlcm-app-web-v1.0.2
upstream-chaniotlcm-upstream-chan-<TAG>.../iotlcm/iotlcm:iotlcm-upstream-chan-v1.0.4
upstream-proxyiotlcm-upstream-proxy-<TAG>.../iotlcm/iotlcm:iotlcm-upstream-proxy-v1.0.4
worker-svriotlcm-worker-svr-<TAG>.../iotlcm/iotlcm:iotlcm-worker-svr-v1.0.4
smsiotlcm-sms-<TAG>.../iotlcm/iotlcm:iotlcm-sms-v1.0.4
botiotlcm-bot-<TAG>.../iotlcm/iotlcm:iotlcm-bot-v1.0.4
docsiotlcm-docs-<TAG>.../iotlcm/iotlcm:iotlcm-docs-v1.0.4
onelink-mockiotlcm-onelink-mock-<TAG>.../iotlcm/iotlcm:iotlcm-onelink-mock-v1.0.4

基础组件(mysql、redis、rabbitmq、consul、nginx)不需要构建,从上游同步到同一仓库即可,tag 为 <组件>-<版本>,见下节。

app 线是独立版本

iotlcm-app-server 与 iotlcm-app-web 属于小程序线,版本号与平台 tag 解耦:平台发 v1.0.4 时它们仍是 v1.0.2。 自建镜像时按 iotlcm-app-<x>-v1.0.2 命名,不要跟着平台版本走。

tag 必须带上服务名

同一个仓库里 tag 不能重复。只用版本号(如 v1.0.4)会让 12 个服务互相覆盖,因此 tag 固定为 <服务名>-<版本>。

同步基础组件 ​

平台编排不再从 Docker Hub 直连基础组件(公网不稳定,且 8.0 这类 tag 会随补丁升级而漂)。部署前先把五个镜像同步到官方仓库:

bash
REPO=crpi-qflrqrxoohlkkvgc.cn-chengdu.personal.cr.aliyuncs.com

docker login --username=sdqmx $REPO

# 按 docker-compose.yml 中固定的版本拉取并推送
sync_image() {
  local src=$1 dst=$2
  docker pull "$src"
  docker tag "$src" "$REPO/iotlcm/iotlcm:$dst"
  docker push "$REPO/iotlcm/iotlcm:$dst"
}

# 参数:<上游镜像>  <目标 tag(组件名-版本)>
sync_image mysql:8.0                  mysql-8.0
sync_image redis:7.2                  redis-7.2
sync_image rabbitmq:4.3.5-management  rabbitmq-4.3.5-management
sync_image hashicorp/consul:1.22      consul-1.22
sync_image nginx:1.30                 nginx-1.30

同步时把版本号固定到补丁位

mysql:8.0 这类浮动 tag 会随上游发新补丁而变化。建议同步时锁定到具体补丁版(如 mysql:8.0.43),tag 写成 mysql-8.0.43,并把 docker-compose.yml 里对应的 image 同步改掉,保证多台机器拉到的镜像完全一致。

同步完成后校验:

bash
for tag in mysql-8.0 redis-7.2 rabbitmq-4.3.5-management consul-1.22 nginx-1.30; do
  docker manifest inspect "$REPO/iotlcm/iotlcm:$tag" >/dev/null 2>&1 \
    && echo "✅ $tag" || echo "❌ $tag"
done

推送到自己的仓库 ​

自建镜像不需要推送回官方仓库。推到自有仓库后,把 docker-compose.yml 里的镜像前缀改指向它:

bash
REG=harbor.internal.example.com
TAG=1.0.3

docker tag iotlcm-openapi:local $REG/iotlcm/iotlcm:iotlcm-openapi-$TAG
docker login $REG
docker push $REG/iotlcm/iotlcm:iotlcm-openapi-$TAG
yaml
# docker-compose.yml —— 逐个替换 image 前缀
image: 'harbor.internal.example.com/iotlcm/iotlcm:iotlcm-openapi-v1.0.4'

只覆盖部分服务

只想替换其中一两个服务时,把对应镜像推到自有仓库,其余保留官方地址。此时把 docker-compose.yml 里那几个 image 单独写成完整地址,其余保持官方仓库前缀即可。

批量构建脚本 ​

bash
#!/bin/bash
set -euo pipefail

REPO=${REPO:?请设置 REPO}
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 "$REPO/iotlcm/$image:$TAG" \
    -f "$WORKDIR/$repo/${ctx}Dockerfile" \
    "$WORKDIR/$repo/$ctx"
done

echo "全部完成,镜像标签:$REPO/iotlcm/*:$TAG"

脚本里的 sed 只能应急

上面的 sed 是粗略替换,把私有仓库地址映射为公共镜像名。仅适用于地址格式规整的情况,用前先 git diff 确认改对了。正式做法应把 Dockerfile 的修正提交回仓库。

验证构建结果 ​

bash
# 镜像大小
docker images | grep iotlcm

# 二进制能否启动
docker run --rm your-registry/iotlcm/iotlcm:iotlcm-openapi-$TAG --help 2>&1 | head

# 检查架构
docker inspect your-registry/iotlcm/iotlcm:iotlcm-openapi-$TAG \
  --format '{{.Architecture}}/{{.Os}}'

构建后按启动与验证的清单做一次完整部署验证,不要只看镜像是否构建成功。

常见问题 ​

现象原因处理
pull access denied / unauthorizedDockerfile 里是私有仓库地址按上文替换 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

iotLCM 文档中心