Docker build & push to a container registry

Docker build & push to a container registry

Building and pushing a Docker image is the second-most-common CI workload after test+build. The shape is consistent: log in to a registry, set up buildx for multi-arch, build, push, and (sometimes) scan. Where the platforms differ is in registry-credential management and DinD/Buildkit availability.

Conversion notes

  • GitHub Actions has the most sophisticated set of officially-maintained Docker actions (login, buildx, build-push, metadata).
  • GitLab CI requires the docker:24-dind service and a TLS-aware DOCKER_TLS_CERTDIR variable to run buildx.
  • CircleCI has setup_remote_docker for outer Docker access; for buildx you usually start a Docker executor and run docker buildx commands directly.
  • Bitbucket Pipelines provides Docker by default; just run docker buildx in any step.

Side-by-side implementation

GitHub Actions
name: build-and-push
on:
  push:
    branches: [main]
    tags: ['v*']

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: docker/setup-qemu-action@v3
      - uses: docker/setup-buildx-action@v3
      - uses: docker/login-action@v3
        with:
          username: ${{ secrets.DOCKERHUB_USERNAME }}
          password: ${{ secrets.DOCKERHUB_TOKEN }}
      - uses: docker/metadata-action@v5
        id: meta
        with:
          images: myorg/myapp
      - uses: docker/build-push-action@v5
        with:
          context: .
          push: true
          platforms: linux/amd64,linux/arm64
          tags: ${{ steps.meta.outputs.tags }}
          labels: ${{ steps.meta.outputs.labels }}
GitLab CI
build:
  image: docker:24
  services:
    - docker:24-dind
  variables:
    DOCKER_TLS_CERTDIR: /certs
    DOCKER_BUILDKIT: 1
  before_script:
    - echo "$CI_REGISTRY_PASSWORD" | docker login $CI_REGISTRY -u "$CI_REGISTRY_USER" --password-stdin
  script:
    - docker buildx create --use --name builder
    - docker buildx build --platform linux/amd64,linux/arm64 --tag $CI_REGISTRY_IMAGE:$CI_COMMIT_REF_NAME --push .
CircleCI
version: 2.1

jobs:
  build:
    docker:
      - image: cimg/base:stable
    steps:
      - checkout
      - setup_remote_docker:
          docker_layer_caching: true
      - run: |
          docker buildx create --use --name builder
          echo "$DOCKERHUB_TOKEN" | docker login -u "$DOCKERHUB_USERNAME" --password-stdin
          docker buildx build --platform linux/amd64,linux/arm64 --tag myorg/myapp:<< pipeline.git.revision >> --push .

workflows:
  main:
    jobs:
      - build:
          filters:
            branches:
              only: [main]
            tags:
              only: /^v.*/
Bitbucket Pipelines
image: atlassian/default-image:4

pipelines:
  branches:
    main:
      - step:
          name: Docker build & push
          services: [docker]
          script:
            - echo "$DOCKERHUB_TOKEN" | docker login -u "$DOCKERHUB_USERNAME" --password-stdin
            - docker buildx create --use --name builder
            - docker buildx build --platform linux/amd64,linux/arm64 --tag myorg/myapp:$BITBUCKET_COMMIT --push .

Related Tools