跳到内容
欧德之怒的博客
返回

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

编辑此页

概述

  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 配置

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

编辑此页
分享这篇文章:

上一篇
【Gitlab-CICD-一】Docker-Compose方式安装Gitlab
下一篇
【Gitlab-CICD-二】GitlabCICD基本概念与GitlabRunner部署