首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >MinIO信创迁移:从镜像下载受阻到流水线部署的完整踩坑记录

MinIO信创迁移:从镜像下载受阻到流水线部署的完整踩坑记录

作者头像
程序员架构进阶
发布2026-07-13 20:09:37
发布2026-07-13 20:09:37
290
举报
文章被收录于专栏:架构进阶架构进阶

本篇是实际项目中的信创迁移操作,基于信创ARM64服务器,K8s集群环境下的MinIO部署实战。没有套路,只有真实踩过的坑。

背景

公司推进项目信创改造,要求所有中间件迁移到ARM64架构的K8s集群中。消息队列用的是QMQ,对象存储选了MinIO。

环境信息:

  • CPU架构:ARM64(aarch64)
  • 本地用于构建镜像和验证的K8s环境:minikube本地集群
  • 网络:企业内部的代理 ,Docker Hub被阻断,GitHub时好时坏
  • 数据库:MariaDB替代MySQL(同样因为Docker Hub拉不动),实际操作也可以替换成已有的mysql地址

MinIO的部署看起来很简单——拉个镜像跑起来就行。但实际操作时,光是拿到一个可用的ARM64二进制文件,就折腾了大半天,尤其是在公司网络有限制的情况下。

第一个问题:二进制怎么下载?

尝试1:官网直连

MinIO官方下载地址是 https://dl.min.io/server/minio/release/linux-arm64/minio

代码语言:javascript
复制
curl -L -C - --noproxy '*' --connect-timeout 30 -o minio \
  https://dl.min.io/server/minio/release/linux-arm64/minio

在公司内网络下速度大概25KB/s,105MB的文件,下了将近一个小时,到24MB断了。加了 --retry 10 自动重试,还是断断续续,最终没能下完。

尝试2:公司代理下载

代码语言:javascript
复制
curl -L -x http://代理ip:代理端口 --connect-timeout 30 \
  -o minio https://dl.min.io/server/minio/release/linux-arm64/minio

直接超时,公司代理对dl.min.io的HTTPS连接不稳定,SSL握手经常中断。

尝试3:GitHub社区构建

有人在上游维护了ARM64构建版本(golithus/minio-builds),试了公司代理、直连,全部失败。

尝试4:SourceForge镜像

也试了,无响应。

尝试5:DaoCloud Docker镜像 —— 成了

之前部署MariaDB时发现DaoCloud的Docker镜像源(docker.m.daocloud.io)在国内速度极快,秒拉。

代码语言:javascript
复制
docker pull docker.m.daocloud.io/minio/minio:latest

很快就完成了镜像拉取,然后从镜像里把二进制抠出来:

代码语言:javascript
复制
docker create --name minio-extract docker.m.daocloud.io/minio/minio:latest
docker cp minio-extract:/usr/bin/minio ./minio
docker rm minio-extract

验证一下:

代码语言:javascript
复制
$ ls -lh minio
-rwxr-xr-x  100M  minio

$ file minio
ELF 64-bit LSB executable, ARM aarch64, version 1 (SYSV),
statically linked, stripped

补充说明:2025年10月起,MinIO官方不再提供预编译二进制下载,dl.min.io上的旧版本链接也可能随时失效。通过Docker镜像提取是目前最可靠的方式。

第二个问题:Dockerfile怎么写?

第一版:照搬QMQ的思路

项目里QMQ的Dockerfile长这样:

代码语言:javascript
复制
FROM nexus.xx.in:8082/baseimage/openjdk8:latest
WORKDIR /app
COPY app/ /app/
RUN ... mkdir -p /app/qmq/logs ...
CMD ["/app/start_metaserver.sh", "start"]

照着写了一版MinIO的,基础镜像用了 eclipse-temurin:8-jre-jammy。构建完了才反应过来——MinIO是Go写的静态二进制,根本不需要JRE,白白多耗了几百M的空间。

第二版:改用alpine

代码语言:javascript
复制
FROM alpine:3.19
WORKDIR /app
COPY minio /app/minio
COPY docker-entrypoint.sh /app/docker-entrypoint.sh
RUN apk add --no-cache ca-certificates \
    && chmod +x /app/minio /app/docker-entrypoint.sh \
    && addgroup -S minio \
    && adduser -S -G minio minio \
    && mkdir -p /data \
    && chown -R minio:minio /data /app
USER minio
EXPOSE 9000 9500
ENTRYPOINT ["/app/docker-entrypoint.sh"]
CMD ["minio", "server", "/data", "--console-address", ":9500"]

构建报错:apk add ca-certificates 失败。原因还是公司代理——Alpine的apk仓库走HTTPS,被SSL拦截了。

第三版:去掉ca-certificates,最终版

MinIO是静态链接,不需要动态库。ca-certificates只是用于HTTPS客户端验证,内网环境下HTTP访问完全够用。如果后续需要HTTPS,可以在K8s里挂载证书文件。

另外把minio二进制放到根目录,调整后的Dockerfile如下:

代码语言:javascript
复制
FROM alpine:3.19

WORKDIR /

LABEL maintainer="MinIO, Inc." \
      description="MinIO high performance object storage"

COPY minio /minio
COPY docker-entrypoint.sh /docker-entrypoint.sh

RUN chmod +x /minio /docker-entrypoint.sh \
    && addgroup -S minio \
    && adduser -S -G minio minio \
    && mkdir -p /data \
    && chown -R minio:minio /data

USER minio

EXPOSE 9000 9500

ENTRYPOINT ["/docker-entrypoint.sh"]
CMD ["/minio", "server", "/data", "--console-address", ":9500"]

入口脚本:

代码语言:javascript
复制
#!/bin/sh
# 如果参数不是以 /minio 开头,自动补上
if [ "${1}" != "/minio" ]; then
    if [ -n "${1}" ]; then
        set -- /minio "$@"
    fi
fi
exec "$@"

构建验证:

代码语言:javascript
复制
$ docker build -t minio:latest .

$ docker images minio:latest
minio:latest  218MB

$ docker run --rm -d --name minio-test \
    -p 19000:9000 -p 19500:9500 \
    -e MINIO_ROOT_USER=minioadmin \
    -e MINIO_ROOT_PASSWORD=minioadmin123 \
    minio:latest

$ sleep 5 && curl -s http://localhost:19000/minio/health/live
# 空响应 = 200 OK

$ curl -s http://localhost:19500/ | head -3
<!doctype html>...MinIO Console...

API和Console都正常。

第三个问题:在K8s集群中部署YAML

volumeClaimTemplates vs 预创建PVC

最初用 volumeClaimTemplates 自动创建PVC,后来对齐了公司现有的部署规范,改用预创建PVC。

这个改动有个坑:StatefulSet的 volumeClaimTemplates 是不可变字段,改不了。必须先删掉旧StatefulSet再重新创建:

代码语言:javascript
复制
# 删StatefulSet(用--cascade=orphan保留Pod,可选)
kubectl -n goo delete statefulset minio --cascade=orphan
# 删旧PVC
kubectl -n goo delete pvc data-minio-0

验证后,得到最终的YAML文件,完整内容如下所示:

代码语言:javascript
复制
apiVersion: v1
kind: Service
metadata:
  name: minio
  namespace: goo
  labels:
    app: minio
spec:
  type: ClusterIP
  ports:
    - name: api
      port: 9000
      targetPort: 9000
    - name: console
      port: 9500
      targetPort: 9500
  selector:
    app: minio
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: minio
  namespace: goo
  labels:
    app: minio
spec:
  serviceName: minio
  replicas: 1
  podManagementPolicy: OrderedReady
  updateStrategy:
    type: RollingUpdate
  selector:
    matchLabels:
      app: minio
  template:
    metadata:
      labels:
        app: minio
    spec:
      containers:
        - name: minio
          image: minio:latest
          imagePullPolicy: IfNotPresent
          args:
            - server
            - /minio
            - --console-address
            - ":9500"
          env:
            - name: TZ
              value: Asia/Shanghai
            - name: MINIO_ROOT_USER
              value: "minioadmin"
            - name: MINIO_ROOT_PASSWORD
              value: "minioadmin123"
          ports:
            - containerPort: 9000
            - containerPort: 9500
          readinessProbe:
            httpGet:
              path: /minio/health/live
              port: 9000
            initialDelaySeconds: 30
            periodSeconds: 10
            timeoutSeconds: 5
          livenessProbe:
            httpGet:
              path: /minio/health/live
              port: 9000
            initialDelaySeconds: 60
            periodSeconds: 20
            timeoutSeconds: 5
          resources:
            requests:
              cpu: "500m"
              memory: "1Gi"
            limits:
              cpu: "2"
              memory: "2Gi"
          volumeMounts:
            - name: kmp-nas
              mountPath: /minio
      volumes:
        - name: kmp-nas
          persistentVolumeClaim:
            claimName: kmp-nas-pvc

这里面有三点需要特别注意,否则无法启动,或及时启动显示的bucket也不对:

1.数据目录和挂载路径必须一致

-- args里的 /miniovolumeMountsmountPath: /minio 要对上,否则MinIO写的数据不在PVC上,Pod重建就丢。

2.PVC要提前创建

-- 改用预创建PVC后,volumeClaimTemplates 删掉了,K8s不会自动创建PVC。

3.健康检查用MinIO原生端点

--/minio/health/live 是MinIO标准健康检查接口,不要用Spring Boot的 /actuator/health(MinIO没有这个端点)。

流水线集成

Dockerfile支持通过 ARG 指定基础镜像地址,方便对接公司内部镜像仓库:

代码语言:javascript
复制
ARG BASE_IMAGE=alpine:3.19
FROM ${BASE_IMAGE}

流水线命令:

代码语言:javascript
复制
# 构建
docker build \
  --build-arg BASE_IMAGE=nexus.xx.in:8082/library/alpine:3.19 \
  -t nexus.xx.in:8082/library/minio:latest .

# 推送
docker push nexus.xx.in:8082/library/minio:latest

# 部署
kubectl apply -f k8s-minio.yaml

前提是alpine基础镜像已经推到公司仓库。这是一次性操作:

代码语言:javascript
复制
docker pull docker.m.daocloud.io/library/alpine:3.19
docker tag docker.m.daocloud.io/library/alpine:3.19 \
  nexus.xx.in:8082/library/alpine:3.19
docker push nexus.xx.in:8082/library/alpine:3.19

MinIO数据迁移

部署完新MinIO后,如果需要从旧实例迁移数据,下面是实操方法。

方式一:mc mirror(推荐)

MinIO官方客户端 mc 支持 mirror 命令,可以在两个MinIO实例之间实现数据同步:

代码语言:javascript
复制
# 安装mc(同样从Docker镜像提取)
docker create --name mc-extract docker.m.daocloud.io/minio/mc:latest
docker cp mc-extract:/usr/bin/mc ./mc
docker rm mc-extract

# 配置源和目标
./mc alias set old http://旧MinIO地址:9000 olduser oldpass
./mc alias set new http://新MinIO地址:9000 minioadmin minioadmin123

# 全量同步
./mc mirror --overwrite --watch old new

--watch 参数会持续监听源端变化,适合不停机迁移。去掉 --watch 就是一次性全量同步。

方式二:直接拷贝数据目录

如果两个MinIO版本一致,且能直接访问存储卷,最简单的方式是停掉旧实例,把数据目录整体拷贝过来:

代码语言:javascript
复制
# 停旧实例
kubectl -n goo scale statefulset minio-old --replicas=0

# 拷贝数据
kubectl -n goo cp minio-old-0:/minio/data-new/ ./minio-backup/
kubectl -n goo cp ./minio-backup/ minio-0:/minio/

# 启新实例
kubectl -n goo scale statefulset minio --replicas=1

迁移注意事项

1. 版本兼容性

MinIO的存储格式在不同大版本间可能不兼容。建议新旧实例使用相同版本。可以用 minio --version 确认:

代码语言:javascript
复制
$ docker run --rm minio:latest minio --version
minio version RELEASE.2025-09-07T16-13-09Z (commit-id=07c3a429)
Runtime: go1.24.6 linux/arm64

2. Bucket和Access Key需要手动迁移

mc mirror 只同步对象数据,不会迁移Bucket配置、访问策略、Access Key。迁移完后需要手动创建:

代码语言:javascript
复制
# 列出旧实例所有bucket
./mc ls old/

# 逐个创建并同步策略
./mc mb new/mybucket
./mc policy set download new/mybucket  # 按需设置策略

# Access Key需要在Console中手动创建,或通过mc admin命令
./mc admin user add new newuser newpassword

3. 确认数据完整性

代码语言:javascript
复制
# 对比两边文件数量
./mc ls --recursive old/ | wc -l
./mc ls --recursive new/ | wc -l

# 抽样校验MD5
./mc cat --json old/mybucket/file.json | jq .etag
./mc cat --json new/mybucket/file.json | jq .etag

4. 不要同时写两端

迁移过程中,必须确保只有一个实例在接收写入,否则会导致最终数据不一致。正确的操作顺序是:旧实例停写 → 全量同步 → 切换流量到新实例 → 旧实例下线。

5. 大数据量迁移的带宽问题

如果数据量在TB级别,那么跨网络迁移会很慢。mc mirror 支持断点续传(--overwrite 会跳过已存在的且大小一致的对象),但如果网络不稳定,建议先导出到本地存储再导入,这样可靠性会提高很多:

代码语言:javascript
复制
# 导出到本地
./mc mirror old/ /local-backup/minio/

# 从本地导入
./mc mirror /local-backup/minio/ new/

踩坑总结

原因

解决方案

dl.min.io下载断断续续

公司代理SSL拦截 + 国际网络不稳定

从DaoCloud Docker镜像提取二进制

apk add 失败

Alpine仓库HTTPS被代理拦截

去掉ca-certificates,内网HTTP够用

Dockerfile用JRE基础镜像

照搬Java项目思路

MinIO是Go静态二进制,用alpine即可

entrypoint报 minio: not found

二进制不在PATH中

入口脚本中用绝对路径 /minio

StatefulSet改volumeClaimTemplates报错

该字段不可变

先删除StatefulSet再重新创建

Console打开看不到菜单

未登录

用root账号登录后菜单完整显示

Readiness探针一直失败

用了 /actuator/health(Spring端点)

MinIO原生端点是 /minio/health/live

最终文件清单

minio-pipeline/ ├── Dockerfile # 构建文件 ├── docker-entrypoint.sh # 入口脚本 ├── minio # ARM64二进制(100MB) ├── k8s-minio.yaml # K8s部署文件 └── build.sh # 可选构建脚本

镜像信息:

  • 版本:RELEASE.2025-09-07T16-13-09Z
  • 架构:linux/arm64
  • 最终镜像大小:218MB
  • 基础镜像:alpine:3.19

写在最后

信创环境下部署开源组件,最大的障碍往往不是技术本身,而是网络限制。Docker Hub被阻断、GitHub不稳定、各种CDN被代理拦截——这些问题在x86环境用国内镜像源很容易解决,但到了ARM64信创环境,由于很多镜像源没有对应的ARM64版本,只能自己折腾,通过源码编译、翻箱倒柜寻找镜像的方式解决。

整个过程的核心经验就一条:善用Docker镜像提取二进制。DaoCloud(docker.m.daocloud.io)在国内的加速效果很好,几乎所有官方镜像都能秒拉。拉下来之后 docker create + docker cp 就能把需要的文件抠出来,比直接下载二进制靠谱得多。

希望这篇文章能帮到同样在信创环境踩坑的同学。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2026-07-10,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 程序员架构进阶 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 背景
  • 第一个问题:二进制怎么下载?
    • 尝试1:官网直连
    • 尝试2:公司代理下载
    • 尝试3:GitHub社区构建
    • 尝试4:SourceForge镜像
    • 尝试5:DaoCloud Docker镜像 —— 成了
  • 第二个问题:Dockerfile怎么写?
    • 第一版:照搬QMQ的思路
    • 第二版:改用alpine
    • 第三版:去掉ca-certificates,最终版
  • 第三个问题:在K8s集群中部署YAML
    • volumeClaimTemplates vs 预创建PVC
  • 流水线集成
  • MinIO数据迁移
    • 方式一:mc mirror(推荐)
    • 方式二:直接拷贝数据目录
    • 迁移注意事项
  • 踩坑总结
  • 最终文件清单
  • 写在最后
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档