title: GitLab CI/CD: building multiarch Docker images
body: <p>I want an easy way to build multiarch Docker images in a GitLab runner. By easy, I mean that I just would have to add a .gitlab-ci.yml in my project and it would work.</p>
  
  <p>Here is the .gitlab-ci.yml that I wrote. It builds a multiarch image using buildx and then pushes it to the GitLab registry:</p>
  
  <pre class="lang-yaml prettyprint-override"><code>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
  </code></pre>
  
  <p>The problem is that the linux/arm64 platform isn't available.</p>
  
  <p>Here is how I built the cl00e9ment/buildx image (strongly inspired from <a href="https://gitlab.com/snadn/docker-buildx" rel="noreferrer">snadn/docker-buildx</a>):</p>
  
  <p>Here is the Dockerfile:</p>
  
  <pre><code>FROM docker:latest
  
  ENV DOCKER_CLI_EXPERIMENTAL=enabled
  ENV DOCKER_HOST=tcp://docker:2375/
  
  RUN mkdir -p ~/.docker/cli-plugins \
    &amp;&amp; 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 \
    &amp;&amp; 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 \
      &amp;&amp; docker buildx create buildx --name mybuilder \
      &amp;&amp; docker buildx use mybuilder
  RUN docker buildx inspect --bootstrap
  </code></pre>
  
  <p>...add here is the .gitlab-ci.yml file used to build and push the cl00e9ment/buildx image:</p>
  
  <pre class="lang-yaml prettyprint-override"><code>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 $1}'` --network host -t cl00e9ment/buildx .
    - docker run --add-host docker:`grep docker /etc/hosts | awk 'NR==1{print $1}'` --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 $1}'` --network host cl00e9ment/buildx docker buildx inspect --bootstrap
  </code></pre>
  
  <p>So what's happening?</p>
  
  <ul>
  <li>At the end of the build, in the Dockerfile, I run <code>docker buildx inspect --bootstrap</code> to list the available platforms. It gives <code>linux/amd64, linux/arm64, linux/riscv64, linux/ppc64le, linux/s390x, linux/386, linux/arm/v7, linux/arm/v6</code>. So it's all good.</li>
  <li>After that, I run it again (just after the build and just before the push) and it still gives <code>linux/amd64, linux/arm64, linux/riscv64, linux/ppc64le, linux/s390x, linux/386, linux/arm/v7, linux/arm/v6</code>.</li>
  <li>However, on the test stage, when the image is freshly downloaded from Docker Hub on a clean environment, it gives <code>linux/amd64, linux/386</code>.</li>
  </ul>
  
  <p>Why?</p>