侧边栏壁纸
博主头像
欧德的半位面 博主等级

欢迎迷途的旅人

  • 累计撰写 7 篇文章
  • 累计创建 4 个标签
  • 累计收到 5 条评论

目 录CONTENT

文章目录

【Gitlab-CICD-三】Docker设置支持跨架构镜像构建

欧德之怒
2025-04-19 / 0 评论 / 0 点赞 / 35 阅读 / 0 字

概述

  • 介绍如何通过 Docker 的 buildx 工具实现跨架构镜像的构建,并配置 GitLab CI/CD 流水线以支持多架构镜像的自动化构建、测试和推送。内容包括:
  1. 创建支持多架构的 Docker Builder
  2. 持久化相关配置,确保重启后 Builder 依然可用
  3. 在 GitLab CI/CD 中配置多架构镜像的构建、测试和推送任务的示例,能够轻松构建适用于不同架构(如 amd64arm64 等)的 Docker 镜像,并实现自动化部署流程。

操作步骤

创建 Builder

拉取必要镜像

docker pull multiarch/qemu-user-static:latest
docker pull moby/buildkit:buildx-stable-1

启用多架构支持

docker run --rm --privileged multiarch/qemu-user-static:latest --reset -p yes

创建并激活 Builder

docker buildx create --name archbuilder --use
docker buildx use archbuilder
docker buildx inspect --bootstrap

持久化配置

  1. 修改 /etc/docker/daemon.json,增加以下内容:
{ 
  "features": { 
    "buildkit": true 
  } 
}
  1. 重启 Docker 服务:
systemctl daemon-reload
systemctl restart docker

持久化设置

环境变量持久化

echo "export DOCKER_BUILDKIT=1" >> /root/.bashrc

配置 Systemd 服务

  1. 创建脚本目录:
mkdir -p /data/buildx
touch /data/buildx/buildx.sh
  1. 创建 Systemd 服务文件:
touch /etc/systemd/system/buildx.service
  1. 编辑 buildx.sh 脚本:
#!/bin/bash 
# 设置环境变量
export DOCKER_BUILDKIT=1
# 启用多架构支持
docker run --rm --privileged multiarch/qemu-user-static:latest --reset -p yes
# 检查 archbuilder 是否存在
archbuilder_exists=$(docker buildx ls | grep archbuilder)
if [[ -z "$archbuilder_exists" ]]; then 
  echo "Docker buildx archbuilder not found. Creating archbuilder..."
  docker buildx create --name archbuilder --use 
else 
  echo "Docker buildx archbuilder already exists."
fi
docker buildx use archbuilder
docker buildx inspect --bootstrap
  1. 编辑 buildx.service 文件:
[Unit]
Description=Create Docker buildx Archbuilder
After=docker.service

[Service]
Type=oneshot
ExecStart=/bin/bash /data/buildx/buildx.sh
ExecStop=/bin/bash -c "docker buildx rm archbuilder || true"
RemainAfterExit=yes

[Install]
WantedBy=multi-user.target
  1. 启动并启用服务:
systemctl daemon-reload
systemctl enable buildx
systemctl start buildx

示例:GitLab CI/CD 配置

  • 提交代码时,commit关键字中包含"镜像构建"这四个关键字即可触发Gitlab流水线
  • 支持传到多个仓库,需要在Gitlab对应组织下,设置-CI/CD-变量中补充对应的仓库变量
    • Dockhub
      • DOCKERHUB_USER:dockerhub仓库登录用户名
      • DOCKERHUB_PASSWORD:dockerhub仓库登录密码
    • 阿里云容器镜像服务/ACR
      • ALIYUN_USER: 阿里容器镜像仓库登录用户名
      • ALIYUN_PASSWORD: 阿里容器镜像仓库登录密码
    • 华为容器镜像服务/SWR
      • HW_USER: 华为容器镜像仓库登录用户名
      • HW_PASSWORD: 华为阿里容器镜像仓库登录密码
stages:
  - build
  - push

# 变量
variables:
  # 镜像构建后的tag,置空则使用当前日期作为tag
  VERSION: ""
  # 置空则为amd64,可选为all(双架构)、amd64(x86平台)、arm64
  ARCH: "amd64"
  # 仅AMD架构的时候是否可以单独上传
  AMD_PUSH: "true"
  # 上传的镜像仓库,可选为dockerhub、aliyun、huawei
  PUSH_REPO: "dockerhub aliyun huawei"
  # 上传的仓库与镜像名称,假设仓库为test,镜像为testimg
  IMAGE_NAME: "test/testimg"

# 镜像构建阶段
build_job:
  stage: build
  tags:
    - build
  variables:
	 # git clone仅克隆当前单层代码,加速代码拉取
    GIT_DEPTH: "1"
  rules:
    # 仅在当前分支提交时message包含"镜像构建"时触发
    - if: "$CI_COMMIT_MESSAGE =~ /镜像构建/"
      when: on_success
    - when: never
  script:
    - |
      if [ -z "$VERSION" ]; then
        export VERSION=$(date +%Y%m%d)
        echo "当前默认版本为:$VERSION"
      else
        echo "手动设置版本为: $VERSION"
      fi
      if [ -z "$ARCH" ]; then
        export ARCH="amd64"
        echo "当前默认架构为:$ARCH"
      else
        echo "手动设置架构为: $ARCH"
      fi
      if [ ${ARCH} == "all" ]; then
          echo "构建AMD镜像: $IMAGE_NAME:$VERSION-amd64"
          echo "----------------------------------------"
          docker build -t $IMAGE_NAME:$VERSION-amd64 --build-arg ARCH=amd64 .
          echo "----------------------------------------"
          echo "构建ARM镜像: $IMAGE_NAME:$VERSION-arm64"
          docker buildx build --platform linux/arm64 -t $IMAGE_NAME:$VERSION-arm64  --build-arg ARCH=arm64 .
      elif [ ${ARCH} == "arm64" ]; then
          echo "构建ARM镜像: $IMAGE_NAME:$VERSION-arm64"
          docker buildx build --platform linux/arm64 -t $IMAGE_NAME:$VERSION-arm64  --build-arg ARCH=arm64 .
      else
          echo "构建AMD镜像: $IMAGE_NAME:$VERSION-amd64"
          docker build -t $IMAGE_NAME:$VERSION-amd64 --build-arg ARCH=amd64 .
      fi
      echo "export VERSION=$VERSION" > env.sh
      echo "export ARCH=$ARCH" >> env.sh
  artifacts:
    paths:
      - env.sh
    expire_in: 5 minutes

# 镜像推送阶段
push_job:
  stage: push
  tags:
    - build
  dependencies:
    - build_job
  rules:
    - if: "$CI_COMMIT_MESSAGE =~ /镜像构建/"
      when: on_success
    - when: never
  script:
    - |
      source env.sh
      echo "当前镜像版本为:$VERSION"
      echo "当前镜像架构为:$ARCH"
      echo "登录Dockerhub"
      func_amd64(){
          echo "上传: $IMAGE_NAME:$VERSION-amd64"
          docker tag $IMAGE_NAME:$VERSION-amd64 $DOCKER_REGISTRY/$IMAGE_NAME:$VERSION-amd64
          docker push $DOCKER_REGISTRY/$IMAGE_NAME:$VERSION-amd64
          if [ ${AMD_PUSH} == "true" ]; then
              echo "单架构上传: $IMAGE_NAME:latest"
              docker tag $DOCKER_REGISTRY/$IMAGE_NAME:$VERSION-amd64 $DOCKER_REGISTRY/$IMAGE_NAME:latest
              docker push $DOCKER_REGISTRY/$IMAGE_NAME:latest
          fi
      }
      func_arm64(){
          echo "上传: $IMAGE_NAME:$VERSION-arm64"
          docker tag $IMAGE_NAME:$VERSION-arm64 $DOCKER_REGISTRY/$IMAGE_NAME:$VERSION-arm64
          docker push  $DOCKER_REGISTRY/$IMAGE_NAME:$VERSION-arm64
      }
      func_mix(){
          echo "上传双架构镜像:$IMAGE_NAME:$VERSION"
          docker manifest create  $DOCKER_REGISTRY/$IMAGE_NAME:$VERSION --amend $DOCKER_REGISTRY/$IMAGE_NAME:$VERSION-amd64 --amend $DOCKER_REGISTRY/$IMAGE_NAME:$VERSION-arm64
          docker manifest push $DOCKER_REGISTRY/$IMAGE_NAME:$VERSION 
          echo "上传双架构镜像:$IMAGE_NAME:latest"
          docker manifest create  $DOCKER_REGISTRY/$IMAGE_NAME:latest --amend $DOCKER_REGISTRY/$IMAGE_NAME:$VERSION-amd64 --amend $DOCKER_REGISTRY/$IMAGE_NAME:$VERSION-arm64
          docker manifest push $DOCKER_REGISTRY/$IMAGE_NAME:latest
      }  
      push_repo_array=($PUSH_REPO)
      for repo in ${push_repo_array[@]}; do
          if [ ${repo} == "dockerhub" ]; then
              DOCKER_REGISTRY=docker.io
              echo $DOCKERHUB_PASSWORD | docker login --username $DOCKERHUB_USER --password-stdin $DOCKER_REGISTRY
          elif [ ${repo} == "aliyun" ]; then
              DOCKER_REGISTRY=registry.cn-hangzhou.aliyuncs.com
              echo $ALIYUN_PASSWORD | docker login --username $ALIYUN_USER --password-stdin $DOCKER_REGISTRY
          elif [ ${repo} == "huawei" ]; then
              DOCKER_REGISTRY=swr.cn-north-4.myhuaweicloud.com
              echo $HW_PASSWORD | docker login --username $HW_USER --password-stdin $DOCKER_REGISTRY
          fi
          echo "上传镜像到仓库: $DOCKER_REGISTRY/$IMAGE_NAME:$VERSION"
          if [ ${ARCH} == "all" ]; then
              func_amd64
              func_arm64
              func_mix
          elif [ ${ARCH} == "arm64" ]; then
              func_arm64
          else
              func_amd64
          fi
      done
0
  1. 支付宝打赏

    qrcode alipay
  2. 微信打赏

    qrcode weixin

评论区