Skip to content

Docker (v2)

This will be available in the next release (v2.12). Stay tuned!

alpha

This feature is in alpha state. It will be improved until its deemed stable, at which point we'll officially deprecate dockers and docker_manifests in preparations for GoReleaser v3, which should take over both of them.

This feature uses docker buildx to build multi-arch manifests, reusing the previously built binaries and/or packages.

Customization

Here's a commented out configuration:

.goreleaser.yaml
dockers_v2:
  # You can have multiple Docker images.
  - #
    # ID of the image, needed if you want to filter by it later on (e.g. on custom publishers).
    # Default: project name
    id: myimg

    # Path to the Dockerfile (from the project root).
    #
    # Default: 'Dockerfile'.
    # Templates: allowed.
    dockerfile: "{{ .Env.DOCKERFILE }}"

    # IDs to filter the binaries/packages.
    #
    # Make sure to only include the IDs of binaries you want to `COPY` in your
    # Dockerfile.
    #
    # If you include IDs that don't exist or are not available for the current
    # architecture being built, the build of the image will be skipped.
    ids:
      - mybuild
      - mynfpm

    # Image names.
    #
    # Empty image names are ignored.
    #
    # Templates: allowed.
    image:
      - "myuser/myimage"
      - "gcr.io/myuser/myimage"

    # Tag names.
    #
    # Empty tags are ignored.
    #
    # Templates: allowed.
    tags:
      - "v{{ .Version }}"
      - "{{ if .IsNightly }}nightly{{ end }}"
      - "{{ if not .IsNightly }}latest{{ end }}"

    # If your Dockerfile copies files other than binaries and packages,
    # you should list them here as well.
    # Note that GoReleaser will create the same structure inside a temporary
    # directory, so if you add `foo/bar.json` here, on your Dockerfile you can
    # `COPY foo/bar.json /whatever.json`.
    # Also note that the paths here are relative to the directory in which
    # GoReleaser is being run (usually the repository root directory).
    # This field does not support wildcards, you can add an entire directory here
    # and use wildcards when you `COPY`/`ADD` in your Dockerfile.
    extra_files:
      - config.yml

    # Labels to be added to the image.
    #
    # Items with empty keys or values will be ignored.
    #
    # Templates: allowed.
    labels:
      "org.opencontainers.image.description": "My software"
      "org.opencontainers.image.created": "{{.Date}}"
      "org.opencontainers.image.name": "{{.ProjectName}}"
      "org.opencontainers.image.revision": "{{.FullCommit}}"
      "org.opencontainers.image.version": "{{.Version}}"
      "org.opencontainers.image.source": "{{.GitURL}}"

    # Annotations to be added to the image.
    #
    # Items with empty keys or values will be ignored.
    #
    # Templates: allowed.
    annotations:
      "foo": "bar"
      "project": "{{.ProjectName}}"

    # Platforms to build.
    #
    # Default: [ linux/amd64 linux/arm64 ]
    platforms:
      - linux/amd64
      - linux/arm64

    # Additional `--build-arg`s to be passed.
    #
    # Templates: allowed.
    build_args:
      FOO: bar

    # Arbitrary flags to pass to the build command.
    #
    # Note: use this at your own risk.
    # Note: flags must have the `=` sign between flag name and value.
    #
    # Templates: allowed.
    flags:
      - "--ulimit=10"

    # Retry configuration.
    retry:
      # Attempts of retry.
      #
      # Default: 10.
      attempts: 5

      # Delay between retry attempts.
      #
      # Default: 10s.
      delay: 5s

      # Maximum delay between retry attempts.
      #
      # Default: 5m.
      max_delay: 2m

dockers_v2

The dockers_v2 name is provisional.

It will replace dockers and docker_manifests in GoReleaser v3 (no ETA), and will then be simply dockers.

We are doing it this way to prevent breaking changes releases now, so we can test this new version for a while, before launching v3.

Template Language

Discover more about the name template engine.

Testing locally

Docker buildx won't allow us to build a manifest without pushing it. To get around this, when we build with --snapshot, GoReleaser will not build the manifest anymore, and will instead build separated images, adding a platform suffix to each tag.

Let's see what this means in practice. Assume we have a configuration like this:

.goreleaser.yaml
snapshot:
  version_template: "{{ incpatch .Version }}"
dockers_v2:
  - images:
      - user/repo
    tags:
      - "{{.Version}}"
    platform:
      - linux/amd64
      - linux/arm64

If we run goreleaser release, i.e., a production build, it'll build and publish user/repo:1.2.3, for example.

If we run goreleaser release --snapshot, it'll build two images instead: user/repo:1.2.4-amd64 and user/repo:1.2.4-arm64.

This way you can verify that your Docker build and Docker image work as expected.

How it works

You can declare multiple Docker images. They will be matched against the binaries generated by your builds section and packages generated by your nfpms section.

If you have only one item in the builds list, the configuration can be as easy as adding the name and tags of your images to your .goreleaser.yaml file:

.goreleaser.yaml
dockers_v2:
  - images:
      - user/repo

You also need to create a Dockerfile in your project's root directory:

Dockerfile
FROM scratch
ARG TARGETPLATFORM
ENTRYPOINT ["/usr/bin/myprogram"]
COPY $TARGETPLATFORM/myprogram /usr/bin/

This configuration will build and push a Docker image named user/repo:tagname.

The Docker build context

Note that we are not building any binaries in the Dockerfile, we are instead merely copying the binary to a scratch image and setting up the entrypoint.

The idea is that you reuse the previously built binaries instead of building them again when creating the Docker image.

The build context itself is a temporary directory which contains the binaries and packages for the each of the defined target platforms. You can then COPY them into your image (mind the use of $TARGETPLATFORM above).

A corollary of it being a temporary directory is that the context does not contain the source files. If you need to add some other file that is in your source directory, you'll need to add it to the extra_files property, so it'll get copied into the context.

All that being said, your Docker build context will usually look like this:

temp-context-dir
├── Dockerfile
├── linux/arm64/myprogram
├── linux/arm64/myprogram.rpm
├── linux/arm64/myprogram.apk
├── linux/arm64/myprogram.deb
├── linux/amd64/myprogram
├── linux/amd64/myprogram.rpm
├── linux/amd64/myprogram.apk
└── linux/amd64/myprogram.deb

myprogram would actually be your binary name, and the Linux package names would follow their respective configuration's names.

Setting up a builder

For buildx to work, you'll need to have a builder that supports multi-platform builds set up.

On Linux, you can do it with:

docker buildx create --name=goreleaser --use
docker run --privileged --rm tonistiigi/binfmt --install all

For what it's worth, this feature was built and tested with buildx v0.24.0.