-
Notifications
You must be signed in to change notification settings - Fork 29
docker images
: Multi-platform builds for docker images using self-hosted runners
#135
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
c6f57c5
aa11cb5
98f4728
ff1cdf8
a429419
879ba70
de9b1e7
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
@@ -0,0 +1,131 @@ | ||||||
name: Multi-platform Docker image push to Google Artifact Registry | ||||||
|
||||||
on: | ||||||
workflow_call: | ||||||
inputs: | ||||||
platforms: | ||||||
default: "['amd64']" | ||||||
type: string | ||||||
image_name: | ||||||
required: true | ||||||
type: string | ||||||
registry: | ||||||
description: | | ||||||
Google Artifact Registry to store docker images in. | ||||||
default: "us-docker.pkg.dev" | ||||||
type: string | ||||||
tags: | ||||||
type: string | ||||||
description: | | ||||||
List of Docker images to be pushed. | ||||||
required: true | ||||||
context: | ||||||
description: | | ||||||
Path to the Docker build context. | ||||||
default: "." | ||||||
type: string | ||||||
environment: | ||||||
description: | | ||||||
Environment for pushing artifacts (can be either dev or prod). | ||||||
default: dev | ||||||
type: string | ||||||
build-args: | ||||||
type: string | ||||||
description: | | ||||||
List of arguments necessary for the Docker image to be built. | ||||||
default: "" | ||||||
file: | ||||||
type: string | ||||||
description: | | ||||||
The dockerfile to use. | ||||||
required: false | ||||||
cache-from: | ||||||
type: string | ||||||
description: | | ||||||
Where cache should be fetched from | ||||||
required: false | ||||||
default: "type=gha" | ||||||
cache-to: | ||||||
type: string | ||||||
description: | | ||||||
Where cache should be stored to | ||||||
required: false | ||||||
default: "type=gha,mode=max" | ||||||
ssh: | ||||||
type: string | ||||||
description: | | ||||||
List of SSH agent socket or keys to expose to the build | ||||||
|
||||||
permissions: | ||||||
contents: read | ||||||
id-token: write | ||||||
|
||||||
env: | ||||||
platform_env: ${{ inputs.platforms }} | ||||||
|
||||||
jobs: | ||||||
build-multi-arch: | ||||||
outputs: | ||||||
full_image_name: ${{ steps.build-multiarch.outputs.full_image_name }} | ||||||
strategy: | ||||||
matrix: | ||||||
os: ${{ fromJson(inputs.platforms ) }} | ||||||
tag: ${{ fromJson(inputs.tags ) }} | ||||||
runs-on: ubuntu-${{ matrix.os }}-large | ||||||
name: build-${{ matrix.os }}-image-for-tag-${{ matrix.tag }} | ||||||
steps: | ||||||
- name: Checkout | ||||||
env: | ||||||
action_repo: ${{ github.action_repository }} | ||||||
action_ref: ${{ github.action_ref }} | ||||||
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 | ||||||
with: | ||||||
repository: ${{ env.action_repo }} | ||||||
ref: ${{ env.action_ref }} | ||||||
- name: Checkout | ||||||
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 | ||||||
with: | ||||||
repository: grafana/shared-workflows | ||||||
ref: multiarch-docker-builds-using-sh-runners | ||||||
path: shared-workflows | ||||||
Comment on lines
+77
to
+90
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Aren't these the same? I thought |
||||||
- name: Build multi-arch | ||||||
id: build-multiarch | ||||||
uses: ./shared-workflows/actions/build-and-push-image-digest | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
with: | ||||||
platform: "linux/${{ matrix.os }}" | ||||||
image_name: ${{ inputs.image_name }} | ||||||
tags: ${{ matrix.tag }} | ||||||
context: ${{ inputs.context }} | ||||||
build-args: ${{ inputs.build-args }} | ||||||
cache-from: ${{ inputs.cache-from }} | ||||||
cache-to: ${{ inputs.cache-to }} | ||||||
file: ${{ inputs.file }} | ||||||
ssh: ${{ inputs.ssh }} | ||||||
push-manifest: | ||||||
strategy: | ||||||
matrix: | ||||||
tag: ${{ fromJson(inputs.tags ) }} | ||||||
needs: [build-multi-arch] | ||||||
name: push-manifest | ||||||
runs-on: ubuntu-x64-small | ||||||
steps: | ||||||
- name: Checkout | ||||||
env: | ||||||
action_repo: ${{ github.action_repository }} | ||||||
action_ref: ${{ github.action_ref }} | ||||||
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 | ||||||
with: | ||||||
repository: ${{ env.action_repo }} | ||||||
ref: ${{ env.action_ref }} | ||||||
- name: Checkout | ||||||
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 | ||||||
with: | ||||||
repository: grafana/shared-workflows | ||||||
ref: multiarch-docker-builds-using-sh-runners | ||||||
path: shared-workflows | ||||||
- name: Create and push image manifests | ||||||
uses: ./shared-workflows/actions/create-and-push-image-manifests | ||||||
with: | ||||||
full-image-name: ${{ needs.build-multi-arch.outputs.full_image_name }} | ||||||
tag: ${{ matrix.tag }} | ||||||
environment: ${{ inputs.environment }} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1,2 @@ | ||
.idea/ | ||
.vscode/ |
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
@@ -0,0 +1,56 @@ | ||||||
# build-and-push-image-digests | ||||||
|
||||||
This is a composite GitHub Action, used to build and push image digests to GitHub, so then they can be picked up by the `push-to-gar-docker-multiarch` action, to create a manifest and push the actual image to GAR. | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
|
||||||
The user is able to see digests appearing on the github action level after every successful run. | ||||||
|
||||||
This action can be used together with the [create-and-push-image-manifests](../create-and-push-image-manifests/README.md) action so the digests can form a manifest and push it to GAR. | ||||||
|
||||||
```yaml | ||||||
name: CI | ||||||
on: | ||||||
pull_request: | ||||||
|
||||||
# These permissions are needed to assume roles from Github's OIDC. | ||||||
permissions: | ||||||
contents: read | ||||||
id-token: write | ||||||
|
||||||
jobs: | ||||||
build-and-push: | ||||||
runs-on: ubuntu-latest | ||||||
|
||||||
steps: | ||||||
- id: checkout | ||||||
uses: actions/checkout@v4 | ||||||
|
||||||
- id: build-and-push-image-digests | ||||||
uses: grafana/shared-workflows/actions/build-and-push-image-digests@main | ||||||
with: | ||||||
registry: "<YOUR-GAR>" # e.g. us-docker.pkg.dev, optional | ||||||
tags: "<IMAGE_TAG>" | ||||||
context: "<YOUR_CONTEXT>" # e.g. "." - where the Dockerfile is | ||||||
image_name: "backstage" # name of the image to be published, required | ||||||
environment: "dev" # can be either dev/prod | ||||||
``` | ||||||
|
||||||
## Inputs | ||||||
|
||||||
| Name | Type | Description | | ||||||
| ---------------------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | ||||||
| `registry` | String | Google Artifact Registry to store docker images in. | | ||||||
| `tags` | List | Tags that should be used for the image (see the [metadata-action][mda] for details) | | ||||||
| `context` | List | Path to the Docker build context. | | ||||||
| `environment` | Bool | Environment for pushing artifacts (can be either dev or prod). | | ||||||
| `image_name` | String | Name of the image to be pushed to GAR. | | ||||||
| `build-args` | String | List of arguments necessary for the Docker image to be built. | | ||||||
| `push` | Boolean | Whether to push the image to the registry. | | ||||||
| `file` | String | Path and filename of the dockerfile to build from. (Default: `{context}/Dockerfile`) | | ||||||
| `platforms` | List | List of platforms the image should be built for (e.g. `linux/amd64,linux/arm64`) | | ||||||
| `cache-from` | String | Where cache should be fetched from ([more about GHA and container caching](https://www.kenmuse.com/blog/implementing-docker-layer-caching-in-github-actions/)) | | ||||||
| `cache-to` | String | Where cache should be stored to ([more about GHA and container caching](https://www.kenmuse.com/blog/implementing-docker-layer-caching-in-github-actions/)) | | ||||||
| `ssh` | List | List of SSH agent socket or keys to expose to the build ([more about ssh for docker/build-push-action](https://github.com/docker/build-push-action?tab=readme-ov-file#inputs)) | | ||||||
| `build-contexts` | List | List of additional [build contexts](https://github.com/docker/build-push-action?tab=readme-ov-file#inputs) (e.g., `name=path`) | | ||||||
| `docker-buildx-driver` | String | The [driver](https://github.com/docker/setup-buildx-action/tree/v3/?tab=readme-ov-file#customizing) to use for Docker Buildx | | ||||||
|
||||||
[mda]: https://github.com/docker/metadata-action?tab=readme-ov-file#tags-input |
Original file line number | Diff line number | Diff line change | ||||||||
---|---|---|---|---|---|---|---|---|---|---|
@@ -0,0 +1,147 @@ | ||||||||||
name: Build and push image digests to GitHub | ||||||||||
description: Composite action to build and push image digests to GitHub | ||||||||||
|
||||||||||
inputs: | ||||||||||
registry: | ||||||||||
description: | | ||||||||||
Google Artifact Registry to store docker images in. | ||||||||||
default: "us-docker.pkg.dev" | ||||||||||
tag: | ||||||||||
description: | | ||||||||||
Docker images tag to be pushed. | ||||||||||
required: true | ||||||||||
context: | ||||||||||
description: | | ||||||||||
Path to the Docker build context. | ||||||||||
default: "." | ||||||||||
environment: | ||||||||||
description: | | ||||||||||
Environment for pushing artifacts (can be either dev or prod). | ||||||||||
default: dev | ||||||||||
image_name: | ||||||||||
description: | | ||||||||||
Name of the image to be pushed to GAR. | ||||||||||
required: true | ||||||||||
build-args: | ||||||||||
description: | | ||||||||||
List of arguments necessary for the Docker image to be built. | ||||||||||
default: "" | ||||||||||
file: | ||||||||||
description: | | ||||||||||
The dockerfile to use. | ||||||||||
required: false | ||||||||||
platform: | ||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. In the README that input is called |
||||||||||
description: | | ||||||||||
Platforms to build the image for | ||||||||||
required: true | ||||||||||
cache-from: | ||||||||||
description: | | ||||||||||
Where cache should be fetched from | ||||||||||
required: false | ||||||||||
default: "type=gha" | ||||||||||
cache-to: | ||||||||||
description: | | ||||||||||
Where cache should be stored to | ||||||||||
required: false | ||||||||||
default: "type=gha,mode=max" | ||||||||||
ssh: | ||||||||||
description: | | ||||||||||
List of SSH agent socket or keys to expose to the build | ||||||||||
build-contexts: | ||||||||||
description: | | ||||||||||
List of additional build contexts (e.g., name=path) | ||||||||||
required: false | ||||||||||
docker-buildx-driver: | ||||||||||
description: | | ||||||||||
The driver to use for Docker Buildx | ||||||||||
required: false | ||||||||||
default: "docker-container" | ||||||||||
|
||||||||||
outputs: | ||||||||||
full_image_name: | ||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Dirty but for now re-calculating the whole image name for GAR is difficult, we can get away with it using a simple output. |
||||||||||
description: Full image name | ||||||||||
value: ${{ steps.export-full-image-name.outputs.full_image_name }} | ||||||||||
|
||||||||||
runs: | ||||||||||
using: composite | ||||||||||
steps: | ||||||||||
- name: try printing env | ||||||||||
shell: bash | ||||||||||
run: | | ||||||||||
echo ${{ env.platform_env }} | ||||||||||
Comment on lines
+68
to
+71
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||
- name: Prepare | ||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can you add a comment saying what this is doing, or make the name more descriptive? |
||||||||||
shell: bash | ||||||||||
run: | | ||||||||||
platform=${{ inputs.platform }} | ||||||||||
echo "PLATFORM_PAIR=${platform//\//-}" >> $GITHUB_ENV | ||||||||||
- name: Checkout | ||||||||||
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 | ||||||||||
with: | ||||||||||
repository: grafana/shared-workflows | ||||||||||
ref: multiarch-docker-builds-using-sh-runners | ||||||||||
path: shared-workflows | ||||||||||
- name: Get repository name | ||||||||||
id: get-repository-name | ||||||||||
shell: bash | ||||||||||
run: | | ||||||||||
REPO_NAME=$(echo ${{ github.repository }} | awk -F'/' '{print $2}') | ||||||||||
echo "repo_name=${REPO_NAME}" >> ${GITHUB_OUTPUT} | ||||||||||
Comment on lines
+83
to
+88
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This could be merged into |
||||||||||
- name: Resolve GCP project | ||||||||||
id: resolve-project | ||||||||||
shell: bash | ||||||||||
run: | | ||||||||||
if [ "${{ inputs.environment }}" == 'dev' ]; then | ||||||||||
PROJECT="grafanalabs-dev" | ||||||||||
elif [ "${{ inputs.environment }}" == 'prod' ]; then | ||||||||||
PROJECT="grafanalabs-global" | ||||||||||
else | ||||||||||
echo "Invalid environment. Valid environment variable inputs: dev, prod" | ||||||||||
exit 1 | ||||||||||
fi | ||||||||||
echo "project=${PROJECT}" >> ${GITHUB_OUTPUT} | ||||||||||
Comment on lines
+89
to
+101
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. And this probably, or alternatively made into a standalone action since we repeat it all over the place. |
||||||||||
- name: Login to GAR | ||||||||||
uses: ./shared-workflows/actions/login-to-gar | ||||||||||
with: | ||||||||||
environment: ${{ inputs.environment }} | ||||||||||
- name: Export full image name | ||||||||||
id: export-full-image-name | ||||||||||
shell: bash | ||||||||||
run: | | ||||||||||
FULL_IMAGE_NAME="${{ inputs.registry }}/${{ steps.resolve-project.outputs.project }}/docker-${{ steps.get-repository-name.outputs.repo_name }}-${{ inputs.environment }}/${{ inputs.image_name }}" | ||||||||||
echo "full_image_name=${FULL_IMAGE_NAME}" >> ${GITHUB_OUTPUT} | ||||||||||
- name: Extract metadata (tags, labels) for Docker | ||||||||||
id: meta | ||||||||||
uses: docker/metadata-action@8e5442c4ef9f78752691e2d8f8d19755c6f78e81 # v5.5.1 | ||||||||||
with: | ||||||||||
images: ${FULL_IMAGE_NAME} | ||||||||||
- name: Set up Docker Buildx | ||||||||||
uses: docker/setup-buildx-action@f95db51fddba0c2d1ec667646a06c2ce06100226 # v3.0.0 | ||||||||||
with: | ||||||||||
driver: ${{ inputs.docker-buildx-driver }} | ||||||||||
- name: Build the container | ||||||||||
uses: docker/build-push-action@4a13e500e55cf31b7a5d59a38ab2040ab0f42f56 # v5.1.0 | ||||||||||
id: build | ||||||||||
with: | ||||||||||
context: ${{ inputs.context }} | ||||||||||
labels: ${{ steps.meta.outputs.labels }} | ||||||||||
outputs: type=image,name=${{ steps.export-full-image-name.outputs.full_image_name }},push-by-digest=true,name-canonical=true,push=true | ||||||||||
build-args: ${{ inputs.build-args }} | ||||||||||
cache-from: ${{ inputs.cache-from }} | ||||||||||
cache-to: ${{ inputs.cache-to }} | ||||||||||
file: ${{ inputs.file }} | ||||||||||
platforms: ${{ inputs.platform }} | ||||||||||
ssh: ${{ inputs.ssh }} | ||||||||||
build-contexts: ${{ inputs.build-contexts }} | ||||||||||
- name: Export digest | ||||||||||
shell: bash | ||||||||||
run: | | ||||||||||
mkdir -p /tmp/digests | ||||||||||
digest="${{ steps.build.outputs.digest }}" | ||||||||||
touch "/tmp/digests/${digest#sha256:}" | ||||||||||
- name: Upload digest | ||||||||||
uses: actions/upload-artifact@v4 | ||||||||||
with: | ||||||||||
name: digests-${{ env.PLATFORM_PAIR }}-${{ inputs.tag }}-${{ inputs.environment }} | ||||||||||
path: /tmp/digests/* | ||||||||||
if-no-files-found: error | ||||||||||
retention-days: 1 |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
# create-and-push-image-manifests | ||
|
||
This is a composite GitHub Action, used to create and push image manifests to GAR. | ||
|
||
This action can be used together with the [build-and-push-image-digests](../build-and-push-image-digests/README.md) action so the digests can be built and then use the current action to form a manifest. | ||
|
||
```yaml | ||
name: CI | ||
on: | ||
pull_request: | ||
|
||
# These permissions are needed to assume roles from Github's OIDC. | ||
permissions: | ||
contents: read | ||
id-token: write | ||
|
||
jobs: | ||
push-manifest: | ||
runs-on: ubuntu-x64-small | ||
steps: | ||
- name: Checkout | ||
env: | ||
action_repo: ${{ github.action_repository }} | ||
action_ref: ${{ github.action_ref }} | ||
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 | ||
with: | ||
repository: ${{ env.action_repo }} | ||
ref: ${{ env.action_ref }} | ||
- name: Create and push image manifests | ||
uses: grafana/shared-workflows/actions/create-and-push-image-manifests@main | ||
with: | ||
full-image-name: <FULL_IMAGE_NAME> | ||
tag: <TAG> | ||
environment: <ENVIRONMENT> | ||
``` | ||
|
||
## Inputs | ||
|
||
| Name | Type | Description | | ||
| ----------------- | ------ | --------------------------------------------------------------------------------------------------------------------------- | | ||
| `full-image-name` | String | Full image name for docker image, e.g. `us-docker.pkg.dev/grafanalabs-dev/docker-grafana-enterprise-dev/grafana-enterprise` | | ||
| `tag` | String | Tag for the image you want to push | | ||
| `environment` | String | Environment for pushing artifacts (can be either dev or prod). | |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would it perhaps be better to also use the same format as we have with the docker/build-push-action?