GitLab CI/CD:构建多架构 Docker 图像
GitLab CI/CD: building multiarch Docker images
我想要一种在 GitLab 运行 中构建多架构 Docker 图像的简单方法。简单来说,我的意思是我只需要在我的项目中添加一个 .gitlab-ci.yml 就可以了。
这是我写的.gitlab-ci.yml。它使用 buildx 构建多架构镜像,然后将其推送到 GitLab 注册表:
image: cl00e9ment/buildx
services:
- name: docker:dind
variables:
PLATFORMS: linux/amd64,linux/arm64
TAG: latest
before_script:
- docker login -u "$CI_REGISTRY_USER" -p "$CI_REGISTRY_PASSWORD" "$CI_REGISTRY"
build:
stage: build
script:
- docker buildx build --platform "$PLATFORMS" -t "${CI_REGISTRY_IMAGE}:${TAG}" . --push
问题是 linux/arm64 平台不可用。
以下是我构建 cl00e9ment/buildx 图像的方式(强烈受到 snadn/docker-buildx 的启发):
这是 Docker 文件:
FROM docker:latest
ENV DOCKER_CLI_EXPERIMENTAL=enabled
ENV DOCKER_HOST=tcp://docker:2375/
RUN mkdir -p ~/.docker/cli-plugins \
&& wget -qO- https://api.github.com/repos/docker/buildx/releases/latest | grep "browser_download_url.*linux-amd64" | cut -d : -f 2,3 | tr -d '"' | xargs wget -O ~/.docker/cli-plugins/docker-buildx \
&& chmod a+x ~/.docker/cli-plugins/docker-buildx
RUN docker run --rm --privileged multiarch/qemu-user-static --reset -p yes
RUN docker context create buildx \
&& docker buildx create buildx --name mybuilder \
&& docker buildx use mybuilder
RUN docker buildx inspect --bootstrap
...在此处添加用于构建和推送 cl00e9ment/buildx 图像的 .gitlab-ci.yml 文件:
image: docker:latest
services:
- name: docker:dind
before_script:
- docker login -u cl00e9ment -p "$DOCKER_HUB_TOKEN"
build:
stage: build
script:
- docker build --add-host docker:`grep docker /etc/hosts | awk 'NR==1{print }'` --network host -t cl00e9ment/buildx .
- docker run --add-host docker:`grep docker /etc/hosts | awk 'NR==1{print }'` --network host cl00e9ment/buildx docker buildx inspect --bootstrap
- docker push cl00e9ment/buildx
test:
stage: test
script:
- docker run --add-host docker:`grep docker /etc/hosts | awk 'NR==1{print }'` --network host cl00e9ment/buildx docker buildx inspect --bootstrap
发生了什么事?
- 构建结束时,在 Docker 文件中,我 运行
docker buildx inspect --bootstrap
列出可用平台。它给出 linux/amd64, linux/arm64, linux/riscv64, linux/ppc64le, linux/s390x, linux/386, linux/arm/v7, linux/arm/v6
。所以一切都很好。
- 在那之后,我再次 运行 它(就在构建之后和推送之前)它仍然给出
linux/amd64, linux/arm64, linux/riscv64, linux/ppc64le, linux/s390x, linux/386, linux/arm/v7, linux/arm/v6
.
- 但是,在测试阶段,当在干净的环境中从 Docker Hub 新鲜下载图像时,它会给出
linux/amd64, linux/386
.
为什么?
好的,我 认为 我知道这里发生了什么:您需要在某处调用 update-binfmts --enable
以启用 binfmt_misc 为 .
我能够使用此存储库及其 docker 图像在 gitlab-ci 上使用 buildx 获得多架构图像(经过大量搜索):https://gitlab.com/ericvh/docker-buildx-qemu
然而,该回购自依赖其自己的 docker 图像存储库来构建其自身的多体系结构版本,并且它依赖于其 ci 的 gitlab-ci 模板回购。我对这个依赖网络是如何开始的并不是很有信心,而且那个回购协议的所有者比我熟练得多,但为了我的使用,我已经分叉了回购协议,我现在正在尝试修改它 CI 减少对外部资源的依赖。
编辑:对于未来的人来说,这是 Dockerfile:
FROM debian
# Install Docker and qemu
# TODO Use docker stable once it properly supports buildx
RUN apt-get update && apt-get install -y \
apt-transport-https \
ca-certificates \
curl \
gnupg2 \
software-properties-common && \
curl -fsSL https://download.docker.com/linux/debian/gpg | apt-key add - && \
add-apt-repository "deb https://download.docker.com/linux/debian $(lsb_release -cs) stable" && \
apt-get update && apt-get install -y \
docker-ce-cli \
binfmt-support \
qemu-user-static
# Install buildx plugin
RUN mkdir -p ~/.docker/cli-plugins && \
ARCH=`dpkg --print-architecture` && echo Running on $ARCH && curl -s https://api.github.com/repos/docker/buildx/releases/latest | \
grep "browser_download_url.*linux-$ARCH" | cut -d : -f 2,3 | tr -d \" | \
xargs curl -L -o ~/.docker/cli-plugins/docker-buildx && \
chmod a+x ~/.docker/cli-plugins/docker-buildx
# Write version file
RUN printf "$(docker --version | perl -pe 's/^.*\s(\d+\.\d+\.\d+.*),.*$//')_$(docker buildx version | perl -pe 's/^.*v?(\d+\.\d+\.\d+).*$//')" > /version && \
cat /version
还有一个精简版的 .gitlab-ci.yml
build:
image: docker:dind
stage: build
services:
- name: docker:dind
entrypoint: ["env", "-u", "DOCKER_HOST"]
command: ["dockerd-entrypoint.sh"]
variables:
DOCKER_HOST: tcp://docker:2375/
DOCKER_DRIVER: overlay2
# See https://github.com/docker-library/docker/pull/166
DOCKER_TLS_CERTDIR: ""
before_script:
- |
if [[ -z "$CI_COMMIT_TAG" ]]; then
export CI_APPLICATION_REPOSITORY=${CI_APPLICATION_REPOSITORY:-$CI_REGISTRY_IMAGE/$CI_COMMIT_REF_SLUG}
export CI_APPLICATION_TAG=${CI_APPLICATION_TAG:-$CI_COMMIT_SHA}
else
export CI_APPLICATION_REPOSITORY=${CI_APPLICATION_REPOSITORY:-$CI_REGISTRY_IMAGE}
export CI_APPLICATION_TAG=${CI_APPLICATION_TAG:-$CI_COMMIT_TAG}
fi
- echo "$CI_REGISTRY_PASSWORD" | docker login -u $CI_REGISTRY_USER --password-stdin $CI_REGISTRY
script:
- docker build -t "$CI_APPLICATION_REPOSITORY:$CI_APPLICATION_TAG" -t "$CI_APPLICATION_REPOSITORY:latest" .
- docker push "$CI_APPLICATION_REPOSITORY:$CI_APPLICATION_TAG"
- docker push "$CI_APPLICATION_REPOSITORY:latest"
编辑:
此外,我发现这个使用上面构建的镜像的gitlabci配置可以使用构建缓存:
stages:
- build
variables:
CI_BUILD_ARCHS: "linux/amd64,linux/arm/v6,linux/arm/v7"
CI_BUILD_IMAGE: "registry.gitlab.com/gdunstone/docker-buildx-qemu"
build_master:
image: $CI_BUILD_IMAGE
stage: build
services:
- name: docker:dind
entrypoint: ["env", "-u", "DOCKER_HOST"]
command: ["dockerd-entrypoint.sh"]
variables:
DOCKER_HOST: tcp://docker:2375/
DOCKER_DRIVER: overlay2
# See https://github.com/docker-library/docker/pull/166
DOCKER_TLS_CERTDIR: ""
retry: 2
before_script:
- docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
# Use docker-container driver to allow useful features (push/multi-platform)
- update-binfmts --enable # Important: Ensures execution of other binary formats is enabled in the kernel
- docker buildx create --driver docker-container --use
- docker buildx inspect --bootstrap
script:
- >
docker buildx build --platform $CI_BUILD_ARCHS
--cache-from=type=registry,ref=$CI_REGISTRY_IMAGE/cache:latest
--cache-to=type=registry,ref=$CI_REGISTRY_IMAGE/cache:latest
--progress plain
--pull --push
--build-arg CI_PROJECT_PATH=$CI_PROJECT_PATH
-t "$CI_REGISTRY_IMAGE:$CI_COMMIT_SHA"
-t "$CI_REGISTRY_IMAGE:latest" .
only:
- master
不幸的是,在 GitLab CI 上有很多关于构建多架构图像的过时和不正确的信息。似乎变化相当频繁,因为它仍然是一个实验性功能。但是截至目前 post,这就是我在 GitLab public 运行 上构建多体系结构的方式 运行ners (armv6, armv6, arm64, amd64):
首先,必须构建并推送包含 buildx
二进制文件的 Docker 映像。这是我为此使用的 Docker 文件:
FROM docker:latest
ARG BUILDX_VER=0.4.2
RUN mkdir -p /root/.docker/cli-plugins && \
wget -qO ~/.docker/cli-plugins/docker-buildx \
https://github.com/docker/buildx/releases/download/v${BUILDX_VER}/buildx-v${BUILDX_VER}.linux-amd64 && \
chmod +x /root/.docker/cli-plugins/docker-buildx
当前的 GitLab 运行ner 图像没有正确初始化 binfmt
处理程序,尽管 运行 初始化代码:https://gitlab.com/gitlab-org/gitlab-runner/-/blob/523854c8/.gitlab/ci/_common.gitlab-ci.yml#L91
所以我们必须在我们的管道中这样做。我们参考 GitLab Runner 代码 MR 1861 中的注释,并在我们的 .gitlab-ci.yml
:
中添加以下魔术酱
before_script:
- docker run --rm --privileged multiarch/qemu-user-static --reset -p yes
然后我们可以 运行 我们管道脚本的其余部分 docker login
、docker buildx build --use
、docker buildx build --push ...
等等。
现在 运行ner 已准备好构建多种架构。
我的最终 .gitlab-ci.yml
可以在这里看到:https://github.com/oofnikj/nuttssh/blob/multiarch/.gitlab-ci.yml
我想要一种在 GitLab 运行 中构建多架构 Docker 图像的简单方法。简单来说,我的意思是我只需要在我的项目中添加一个 .gitlab-ci.yml 就可以了。
这是我写的.gitlab-ci.yml。它使用 buildx 构建多架构镜像,然后将其推送到 GitLab 注册表:
image: cl00e9ment/buildx
services:
- name: docker:dind
variables:
PLATFORMS: linux/amd64,linux/arm64
TAG: latest
before_script:
- docker login -u "$CI_REGISTRY_USER" -p "$CI_REGISTRY_PASSWORD" "$CI_REGISTRY"
build:
stage: build
script:
- docker buildx build --platform "$PLATFORMS" -t "${CI_REGISTRY_IMAGE}:${TAG}" . --push
问题是 linux/arm64 平台不可用。
以下是我构建 cl00e9ment/buildx 图像的方式(强烈受到 snadn/docker-buildx 的启发):
这是 Docker 文件:
FROM docker:latest
ENV DOCKER_CLI_EXPERIMENTAL=enabled
ENV DOCKER_HOST=tcp://docker:2375/
RUN mkdir -p ~/.docker/cli-plugins \
&& wget -qO- https://api.github.com/repos/docker/buildx/releases/latest | grep "browser_download_url.*linux-amd64" | cut -d : -f 2,3 | tr -d '"' | xargs wget -O ~/.docker/cli-plugins/docker-buildx \
&& chmod a+x ~/.docker/cli-plugins/docker-buildx
RUN docker run --rm --privileged multiarch/qemu-user-static --reset -p yes
RUN docker context create buildx \
&& docker buildx create buildx --name mybuilder \
&& docker buildx use mybuilder
RUN docker buildx inspect --bootstrap
...在此处添加用于构建和推送 cl00e9ment/buildx 图像的 .gitlab-ci.yml 文件:
image: docker:latest
services:
- name: docker:dind
before_script:
- docker login -u cl00e9ment -p "$DOCKER_HUB_TOKEN"
build:
stage: build
script:
- docker build --add-host docker:`grep docker /etc/hosts | awk 'NR==1{print }'` --network host -t cl00e9ment/buildx .
- docker run --add-host docker:`grep docker /etc/hosts | awk 'NR==1{print }'` --network host cl00e9ment/buildx docker buildx inspect --bootstrap
- docker push cl00e9ment/buildx
test:
stage: test
script:
- docker run --add-host docker:`grep docker /etc/hosts | awk 'NR==1{print }'` --network host cl00e9ment/buildx docker buildx inspect --bootstrap
发生了什么事?
- 构建结束时,在 Docker 文件中,我 运行
docker buildx inspect --bootstrap
列出可用平台。它给出linux/amd64, linux/arm64, linux/riscv64, linux/ppc64le, linux/s390x, linux/386, linux/arm/v7, linux/arm/v6
。所以一切都很好。 - 在那之后,我再次 运行 它(就在构建之后和推送之前)它仍然给出
linux/amd64, linux/arm64, linux/riscv64, linux/ppc64le, linux/s390x, linux/386, linux/arm/v7, linux/arm/v6
. - 但是,在测试阶段,当在干净的环境中从 Docker Hub 新鲜下载图像时,它会给出
linux/amd64, linux/386
.
为什么?
好的,我 认为 我知道这里发生了什么:您需要在某处调用 update-binfmts --enable
以启用 binfmt_misc 为 .
我能够使用此存储库及其 docker 图像在 gitlab-ci 上使用 buildx 获得多架构图像(经过大量搜索):https://gitlab.com/ericvh/docker-buildx-qemu
然而,该回购自依赖其自己的 docker 图像存储库来构建其自身的多体系结构版本,并且它依赖于其 ci 的 gitlab-ci 模板回购。我对这个依赖网络是如何开始的并不是很有信心,而且那个回购协议的所有者比我熟练得多,但为了我的使用,我已经分叉了回购协议,我现在正在尝试修改它 CI 减少对外部资源的依赖。
编辑:对于未来的人来说,这是 Dockerfile:
FROM debian
# Install Docker and qemu
# TODO Use docker stable once it properly supports buildx
RUN apt-get update && apt-get install -y \
apt-transport-https \
ca-certificates \
curl \
gnupg2 \
software-properties-common && \
curl -fsSL https://download.docker.com/linux/debian/gpg | apt-key add - && \
add-apt-repository "deb https://download.docker.com/linux/debian $(lsb_release -cs) stable" && \
apt-get update && apt-get install -y \
docker-ce-cli \
binfmt-support \
qemu-user-static
# Install buildx plugin
RUN mkdir -p ~/.docker/cli-plugins && \
ARCH=`dpkg --print-architecture` && echo Running on $ARCH && curl -s https://api.github.com/repos/docker/buildx/releases/latest | \
grep "browser_download_url.*linux-$ARCH" | cut -d : -f 2,3 | tr -d \" | \
xargs curl -L -o ~/.docker/cli-plugins/docker-buildx && \
chmod a+x ~/.docker/cli-plugins/docker-buildx
# Write version file
RUN printf "$(docker --version | perl -pe 's/^.*\s(\d+\.\d+\.\d+.*),.*$//')_$(docker buildx version | perl -pe 's/^.*v?(\d+\.\d+\.\d+).*$//')" > /version && \
cat /version
还有一个精简版的 .gitlab-ci.yml
build:
image: docker:dind
stage: build
services:
- name: docker:dind
entrypoint: ["env", "-u", "DOCKER_HOST"]
command: ["dockerd-entrypoint.sh"]
variables:
DOCKER_HOST: tcp://docker:2375/
DOCKER_DRIVER: overlay2
# See https://github.com/docker-library/docker/pull/166
DOCKER_TLS_CERTDIR: ""
before_script:
- |
if [[ -z "$CI_COMMIT_TAG" ]]; then
export CI_APPLICATION_REPOSITORY=${CI_APPLICATION_REPOSITORY:-$CI_REGISTRY_IMAGE/$CI_COMMIT_REF_SLUG}
export CI_APPLICATION_TAG=${CI_APPLICATION_TAG:-$CI_COMMIT_SHA}
else
export CI_APPLICATION_REPOSITORY=${CI_APPLICATION_REPOSITORY:-$CI_REGISTRY_IMAGE}
export CI_APPLICATION_TAG=${CI_APPLICATION_TAG:-$CI_COMMIT_TAG}
fi
- echo "$CI_REGISTRY_PASSWORD" | docker login -u $CI_REGISTRY_USER --password-stdin $CI_REGISTRY
script:
- docker build -t "$CI_APPLICATION_REPOSITORY:$CI_APPLICATION_TAG" -t "$CI_APPLICATION_REPOSITORY:latest" .
- docker push "$CI_APPLICATION_REPOSITORY:$CI_APPLICATION_TAG"
- docker push "$CI_APPLICATION_REPOSITORY:latest"
编辑:
此外,我发现这个使用上面构建的镜像的gitlabci配置可以使用构建缓存:
stages:
- build
variables:
CI_BUILD_ARCHS: "linux/amd64,linux/arm/v6,linux/arm/v7"
CI_BUILD_IMAGE: "registry.gitlab.com/gdunstone/docker-buildx-qemu"
build_master:
image: $CI_BUILD_IMAGE
stage: build
services:
- name: docker:dind
entrypoint: ["env", "-u", "DOCKER_HOST"]
command: ["dockerd-entrypoint.sh"]
variables:
DOCKER_HOST: tcp://docker:2375/
DOCKER_DRIVER: overlay2
# See https://github.com/docker-library/docker/pull/166
DOCKER_TLS_CERTDIR: ""
retry: 2
before_script:
- docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
# Use docker-container driver to allow useful features (push/multi-platform)
- update-binfmts --enable # Important: Ensures execution of other binary formats is enabled in the kernel
- docker buildx create --driver docker-container --use
- docker buildx inspect --bootstrap
script:
- >
docker buildx build --platform $CI_BUILD_ARCHS
--cache-from=type=registry,ref=$CI_REGISTRY_IMAGE/cache:latest
--cache-to=type=registry,ref=$CI_REGISTRY_IMAGE/cache:latest
--progress plain
--pull --push
--build-arg CI_PROJECT_PATH=$CI_PROJECT_PATH
-t "$CI_REGISTRY_IMAGE:$CI_COMMIT_SHA"
-t "$CI_REGISTRY_IMAGE:latest" .
only:
- master
不幸的是,在 GitLab CI 上有很多关于构建多架构图像的过时和不正确的信息。似乎变化相当频繁,因为它仍然是一个实验性功能。但是截至目前 post,这就是我在 GitLab public 运行 上构建多体系结构的方式 运行ners (armv6, armv6, arm64, amd64):
首先,必须构建并推送包含 buildx
二进制文件的 Docker 映像。这是我为此使用的 Docker 文件:
FROM docker:latest
ARG BUILDX_VER=0.4.2
RUN mkdir -p /root/.docker/cli-plugins && \
wget -qO ~/.docker/cli-plugins/docker-buildx \
https://github.com/docker/buildx/releases/download/v${BUILDX_VER}/buildx-v${BUILDX_VER}.linux-amd64 && \
chmod +x /root/.docker/cli-plugins/docker-buildx
当前的 GitLab 运行ner 图像没有正确初始化 binfmt
处理程序,尽管 运行 初始化代码:https://gitlab.com/gitlab-org/gitlab-runner/-/blob/523854c8/.gitlab/ci/_common.gitlab-ci.yml#L91
所以我们必须在我们的管道中这样做。我们参考 GitLab Runner 代码 MR 1861 中的注释,并在我们的 .gitlab-ci.yml
:
before_script:
- docker run --rm --privileged multiarch/qemu-user-static --reset -p yes
然后我们可以 运行 我们管道脚本的其余部分 docker login
、docker buildx build --use
、docker buildx build --push ...
等等。
现在 运行ner 已准备好构建多种架构。
我的最终 .gitlab-ci.yml
可以在这里看到:https://github.com/oofnikj/nuttssh/blob/multiarch/.gitlab-ci.yml