Skip to content

Commit 3df0c01

Browse files
feat: docker multi-arch composite actions (#1347)
* Initial commit with docker-build-push-image, docker-export-digest, and docker-import-digests-push-manifest * Initial commit with READMEs * Add input/output descriptions for docker-build-push-image, tidy them up, and alphabetize * docs updates and adding in QEMU to docker-build-push-action * Docs updates and including dockerhub registry input * Action doesn't like the template syntax in an input description? * docker-import-digests-push-manifest: add registries input and dry-run logic * docker-import-digests-push-manifest: add registries input and dry-run logic * docker-import-digests-push-manifest: Add some error handling * docker-import-digests-push-manifest: Add some error handling * docker-import-digests-push-manifest: Add some error handling * docker-import-digests-push-manifest: Add some error handling * docker-import-digests-push-manifest: Add some error handling * Updated error message * Add warnings when no images are pushed. * Add better handling for default buildkitd config * Add warning when default buildkitd config doesn't exist * Various docs updates * prettier * Updated inputs in README * remove test notes * Add some help text to docker-build-push-image * Switch to cloned shared workflows for docker-import-digests-push-manifest Add TODOs * Fix login to gar action in docker-import-digests-push-manifest * adding recommendations * Add login logic to docker-import-digests-push-manifest * Fix missing metadata in docker-import-digests-push-manifest * update README for docker-import-digests-push-manifest
1 parent 5f23dd6 commit 3df0c01

File tree

8 files changed

+863
-0
lines changed

8 files changed

+863
-0
lines changed
Lines changed: 138 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,138 @@
1+
# docker-build-push-image
2+
3+
This is a composite GitHub Action, used to build and push docker images to private Grafana registries.
4+
It builds registry URLs for Grafana's registries, authenticates to them, and then
5+
uses [docker/build-push-action] to build and push the image(s).
6+
7+
This action can work 1 of 2 ways:
8+
9+
1. It can be run on a single runner, and if multiple `platforms` are configured then buildx/QEMU emulation is used.
10+
2. It can be used in conjunction with [docker-export-digest] and [docker-import-digests-push-manifest] to push untagged
11+
images whose digests are later exported and merged into a tagged docker manifest. For true multi-arch builds.
12+
13+
This can push to the following registries:
14+
15+
1. Google Artifact Registry
16+
2. DockerHub
17+
18+
[docker/build-push-action]: https://github.com/docker/build-push-action
19+
[docker-build-push-image]: ../docker-build-push-image/README.md
20+
[docker-export-digest]: ../docker-export-digest/README.md
21+
[docker-import-digests-push-manifest]: ../docker-import-digests-push-manifest/README.md
22+
23+
<!-- x-release-please-start-version -->
24+
25+
```yaml
26+
name: Build a Docker Image
27+
28+
on:
29+
push:
30+
branches:
31+
- main
32+
33+
jobs:
34+
build-push-image:
35+
permissions:
36+
contents: read
37+
id-token: write
38+
steps:
39+
- uses: grafana/shared-workflows/actions/docker-build-push-image@docker-build-push-image/v0.0.0
40+
with:
41+
platforms: linux/arm64,linux/amd64
42+
tags: |
43+
${{ github.sha }}
44+
main
45+
push: true
46+
registries: "gar,dockerhub"
47+
```
48+
49+
<!-- x-release-please-end-version -->
50+
51+
## Inputs
52+
53+
| Name | Type | Description |
54+
| ----------------------------- | ------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
55+
| `build-args` | String | List of arguments necessary for the Docker image to be built. Passed to `docker/build-push-action`. |
56+
| `build-contexts` | String | List of additional build contexts (e.g., name=path). Passed to `docker/build-push-action`. |
57+
| `buildkitd-config` | String | The buildkitd config file to use. Defaults to `/etc/buildkitd.toml` if you're using Grafana's self-hosted runners. Passed to `docker/setup-buildx-action`. |
58+
| `buildkitd-config-inline` | String | The buildkitd inline config to use. Passed to `docker/setup-buildx-action`. |
59+
| `cache-from` | String | Where cache should be fetched from. Passed to `docker/build-push-action`. |
60+
| `cache-to` | String | Where cache should be stored to. Passed to `docker/build-push-action`. |
61+
| `context` | String | Path to the Docker build context. Passed to `docker/build-push-action`. |
62+
| `docker-buildx-driver` | String | The driver to use for Docker Buildx. Passed to `docker/setup-buildx-action`. |
63+
| `dockerhub-registry` | String | DockerHub Registry to store docker images in. |
64+
| `dockerhub-repository` | String | DockerHub Repository to store docker images in. Default: github.repository |
65+
| `file` | String | The dockerfile to use. Passed to `docker/build-push-action`. |
66+
| `gar-delete-credentials-file` | Boolean | Delete the Google credentials file after the action is finished. If you want to keep the credentials file for a later step, set this to false. |
67+
| `gar-environment` | String | Environment for pushing artifacts (can be either dev or prod). This sets the GAR Project (gar-project) to either `grafanalabs-dev` or `grafanalabs-global`. |
68+
| `gar-image` | String | Name of the image to build. Default: `${GitHub Repo Name}`. |
69+
| `gar-registry` | String | Google Artifact Registry to store docker images in. |
70+
| `gar-repository` | String | Override the 'repo_name' used to construct the GAR repository name. Only necessary when the GAR includes a repo name that doesn't match the GitHub repo name. Default: `docker-${GitHub Repo Name}-${gar-environment}` |
71+
| `include-tags-in-push` | Boolean | Disables the pushing of tags, and instead includes just a list of images as docker tags. Used when pushing docker digests instead of docker tags. |
72+
| `labels` | String | List of custom labels to add to the image as metadata (passed to `docker/build-push-action`). Passed to `docker/build-push-action`. |
73+
| `load` | Boolean | Whether to load the built image into the local docker daemon (passed to `docker/build-push-action`). Passed to `docker/build-push-action`. |
74+
| `outputs` | String | List of docker output destinations. Passed to `docker/build-push-action`. |
75+
| `platforms` | String | List of platforms to build the image for. Passed to `docker/build-push-action`. |
76+
| `push` | String | Whether to push the image to the configured registries. Passed to `docker/build-push-action`. |
77+
| `registries` | String | CSV list of registries to build images for. Accepted registries are "gar" and "dockerhub". |
78+
| `secrets` | String | Secrets to expose to the build. Only needed when authenticating to private repositories outside the repository in which the image is being built. Passed to `docker/build-push-action`. |
79+
| `ssh` | String | List of SSH agent socket or keys to expose to the build Passed to `docker/build-push-action`. |
80+
| `tags` | String | List of Docker tags to be pushed. Passed to `docker/build-push-action`. |
81+
| `target` | String | Sets the target stage to build. Passed to `docker/build-push-action`. |
82+
83+
## Outputs
84+
85+
| Name | Type | Description |
86+
| -------------- | ------ | ------------------------------------------------------------ |
87+
| `annotations` | String | Generated annotations (from docker/metadata-action) |
88+
| `digest` | String | Image digest (from docker/build-push-action) |
89+
| `imageid` | String | Image ID (from docker/build-push-action) |
90+
| `images` | String | Comma separated list of the images that were built |
91+
| `json` | String | JSON output of tags and labels (from docker/metadata-action) |
92+
| `labels` | String | Generated Docker labels (from docker/metadata-action) |
93+
| `metadata` | String | Build result metadata (from docker/build-push-action) |
94+
| `metadatajson` | String | Metadata JSON (from docker/metadata) |
95+
| `tags` | String | Generated Docker tags (from docker/metadata-action) |
96+
| `version` | String | Generated Docker image version (from docker/metadata-action) |
97+
98+
## How we construct Google Artifact Registry Images
99+
100+
The full GAR image is constructed as follows, where `gar-project` is determined by `inputs.gar-environment`.
101+
102+
"${{ inputs.gar-registry }}/${{ gar-project }}/${{ inputs.gar-repository }}/${{ inputs.gar-image }}"
103+
104+
## How we construct DockerHub Images
105+
106+
The full DockerHub image is constructed as follows:
107+
108+
"${{ inputs.dockerhub-registry }}/${{ inputs.dockerhub-repository }}"
109+
110+
## Adding New Registries
111+
112+
Each registry is setup as follows:
113+
114+
- All inputs for a registry share the same prefix (ex: `gar-image`, `gar-repository`).
115+
- Inputs that are used for a specific registry are _not_ required by the workflow. Instead, validation is done in a step
116+
specific to that registry.
117+
- To calculate which registries have been configured, we loop through `inputs.registries`, and for each registry
118+
configured we set the outputs `include-<registry>`. Those flags can be used to create steps that only execute when X
119+
registry is configured.
120+
- Each registry has a Setup step. This step takes the inputs specific to that registry and generates an untagged,
121+
`image` name for that specific registry.
122+
- The `setup-vars` step then loops through each configured image and creates a full list of images to push.
123+
- That's it! That list of images to push is fed to `docker/build-push-action` along with the configured tags, and each
124+
tagged image is pushed to each registry.
125+
126+
So then the full checklist of work to do to implement a new registry is:
127+
128+
- [ ] Add (and document) any inputs that you need to capture. Use the same prefix for all inputs, and all inputs must
129+
_not_ be required.
130+
- [ ] Add a step before `setup-vars` that takes those input values and constructs a valid untagged image name for the
131+
registry you'll be pushing to. Then set that as an output.
132+
Ex: `echo "image=${DOCKERHUB_REGISTRY}/${DOCKERHUB_IMAGE}" | tee -a "${GITHUB_OUTPUT}"`
133+
- [ ] Add your image into the `setup-vars` step by passing the output image into an env variable, and adding it to the
134+
list of images to be parsed. Use the existing repos as examples.
135+
- [ ] Add a login step that depends
136+
on `${{ inputs.push == 'true' && steps.registries.outputs.include-<yourRegistry> == 'true' }}`, where yourRegistry is
137+
the value that will be passed into the `registries` input. Again, use existing repos as examples.
138+
- [ ] Celebrate

0 commit comments

Comments
 (0)