Skip to content

Commit 54afbc6

Browse files
committed
First commit
0 parents  commit 54afbc6

File tree

10 files changed

+626
-0
lines changed

10 files changed

+626
-0
lines changed

.editorconfig

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
# EditorConfig is awesome: https://EditorConfig.org
2+
3+
# top-most EditorConfig file
4+
root = true
5+
6+
[*]
7+
indent_style = space
8+
indent_size = 2
9+
end_of_line = lf
10+
charset = utf-8
11+
trim_trailing_whitespace = false
12+
insert_final_newline = true

.github/workflows/multi-build.yaml

Lines changed: 272 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,272 @@
1+
# This workflow builds a multi-arch Docker image using GitHub Actions and separated Github Runners with native support for ARM64 and AMD64 architectures, without using QEMU emulation.
2+
# It uses Docker Buildx to build and push the image to GitHub Container Registry (GHCR).
3+
name: Build multi arch Docker Image with separate Github Runners
4+
5+
on:
6+
workflow_dispatch:
7+
push:
8+
branches:
9+
- main
10+
paths:
11+
- 'Dockerfile'
12+
- '.github/workflows/multi-build.yaml'
13+
env:
14+
# The name of the Docker image to be built and pushed to GHCR
15+
# The image name is derived from the GitHub repository name and the GitHub Container Registry (GHCR) URL.
16+
# The image name will be in the format: ghcr.io/<owner>/<repo>
17+
GHCR_IMAGE: ghcr.io/${{ github.repository }}
18+
19+
permissions:
20+
# Global permissions for the workflow, which can be overridden at the job level
21+
contents: read
22+
23+
concurrency:
24+
# This concurrency group ensures that only one job in the group runs at a time.
25+
# If a new job is triggered, the previous one will be canceled.
26+
group: ${{ github.workflow }}-${{ github.ref }}
27+
cancel-in-progress: true
28+
29+
jobs:
30+
# The build job builds the Docker image for each platform specified in the matrix.
31+
build:
32+
strategy:
33+
fail-fast: false
34+
matrix:
35+
platform:
36+
- linux/amd64
37+
- linux/arm64
38+
# The matrix includes two platforms: linux/amd64 and linux/arm64.
39+
# The build job will run for each platform in the matrix.
40+
41+
permissions:
42+
# Permissions for the build job, which can be overridden at the step level
43+
# The permissions are set to allow the job to write to the GitHub Container Registry (GHCR) and read from the repository.
44+
attestations: write
45+
actions: read
46+
checks: write
47+
contents: write
48+
deployments: none
49+
id-token: write
50+
issues: read
51+
discussions: read
52+
packages: write
53+
pages: none
54+
pull-requests: read
55+
repository-projects: read
56+
security-events: read
57+
statuses: read
58+
59+
runs-on: ${{ matrix.platform == 'linux/amd64' && 'ubuntu-latest' || matrix.platform == 'linux/arm64' && 'ubuntu-24.04-arm' }}
60+
# The job runs on different runners based on the platform.
61+
# For linux/amd64, it runs on the latest Ubuntu runner.
62+
# For linux/arm64, it runs on an Ubuntu 24.04 ARM runner.
63+
# The runner is selected based on the platform specified in the matrix.
64+
65+
name: Build Docker image for ${{ matrix.platform }}
66+
67+
steps:
68+
-
69+
name: Prepare environment for current platform
70+
# This step sets up the environment for the current platform being built.
71+
# It replaces the '/' character in the platform name with '-' and sets it as an environment variable.
72+
# This is useful for naming artifacts and other resources that cannot contain '/'.
73+
# The environment variable PLATFORMS_PAIR will be used later in the workflow.
74+
id: prepare
75+
run: |
76+
platform=${{ matrix.platform }}
77+
echo "PLATFORM_PAIR=${platform//\//-}" >> $GITHUB_ENV
78+
79+
- name: Checkout
80+
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
81+
# This step checks out the code from the repository.
82+
# It uses the actions/checkout action to clone the repository into the runner's workspace.
83+
84+
- name: Docker meta default
85+
# This step generates metadata for the Docker image.
86+
# It uses the docker/metadata-action to create metadata based on the repository information.
87+
# The metadata includes information such as the image name, tags, and labels.
88+
# The metadata will be used later in the workflow to build and push the Docker image.
89+
id: meta
90+
uses: docker/metadata-action@902fa8ec7d6ecbf8d84d538b9b233a880e428804 # v5.7.0
91+
with:
92+
images: ${{ env.GHCR_IMAGE }}
93+
94+
- name: Set up Docker Context for Buildx
95+
# This step sets up a Docker context for Buildx.
96+
# It creates a new context named "builders" that will be used for building the Docker image.
97+
# The context allows Buildx to use the Docker daemon for building images.
98+
id: buildx-context
99+
run: |
100+
docker context create builders
101+
102+
- name: Set up Docker Buildx
103+
# This step sets up Docker Buildx, which is a Docker CLI plugin for extended build capabilities with BuildKit.
104+
# It uses the docker/setup-buildx-action to configure Buildx with the specified context and platforms.
105+
# The platforms are specified in the matrix and will be used for building the Docker image.
106+
uses: docker/setup-buildx-action@b5ca514318bd6ebac0fb2aedd5d36ec1b5c232a2 # v3.10.0
107+
with:
108+
endpoint: builders
109+
platforms: ${{ matrix.platform }}
110+
111+
- name: Login to GitHub Container Registry
112+
# This step logs in to the GitHub Container Registry (GHCR) using the docker/login-action.
113+
# It uses the GitHub actor's username and the GITHUB_TOKEN secret for authentication.
114+
uses: docker/login-action@74a5d142397b4f367a81961eba4e8cd7edddf772 # v3.4.0
115+
with:
116+
registry: ghcr.io
117+
username: ${{ github.actor }}
118+
password: ${{ secrets.GITHUB_TOKEN }}
119+
120+
121+
- name: Build and push by digest
122+
# This step builds and pushes the Docker image using Buildx.
123+
# It uses the docker/build-push-action to build the image with the specified context and platforms.
124+
# The image is built with the labels and annotations generated in the previous steps.
125+
# The outputs are configured to push the image by digest, which allows for better caching and versioning.
126+
# The cache-from and cache-to options are used to enable caching for the build process.
127+
# The cache is stored in GitHub Actions cache and is scoped to the repository, branch, and platform.
128+
id: build
129+
uses: docker/build-push-action@471d1dc4e07e5cdedd4c2171150001c434f0b7a4 # v6.15.0
130+
env:
131+
DOCKER_BUILDKIT: 1
132+
with:
133+
context: .
134+
platforms: ${{ matrix.platform }}
135+
labels: ${{ steps.meta.outputs.labels }}
136+
annotations: ${{ steps.meta.outputs.annotations }}
137+
outputs: type=image,name=${{ env.GHCR_IMAGE }},push-by-digest=true,name-canonical=true,push=true,oci-mediatypes=true
138+
cache-from: type=gha,scope=${{ github.repository }}-${{ github.ref_name }}-${{ matrix.platform }}
139+
cache-to: type=gha,scope=${{ github.repository }}-${{ github.ref_name }}-${{ matrix.platform }}
140+
141+
142+
- name: Export digest
143+
# This step exports the digest of the built image to a file.
144+
# It creates a directory in /tmp/digests and saves the digest of the image to a file.
145+
# The digest is obtained from the output of the build step.
146+
# The digest is used to uniquely identify the built image and can be used for further processing or verification.
147+
run: |
148+
mkdir -p /tmp/digests
149+
digest="${{ steps.build.outputs.digest }}"
150+
touch "/tmp/digests/${digest#sha256:}"
151+
152+
- name: Upload digest
153+
# This step uploads the digest file to the GitHub Actions artifact storage.
154+
# It uses the actions/upload-artifact action to upload the file created in the previous step.
155+
# The artifact is named digests-${{ env.PLATFORM_PAIR }}, where PLATFORM_PAIR is the platform name with '/' replaced by '-'.
156+
# The artifact is retained for 1 day, and if no files are found, it will throw an error.
157+
uses: actions/upload-artifact@4cec3d8aa04e39d1a68397de0c4cd6fb9dce8ec1 # v4.6.1
158+
with:
159+
name: digests-${{ env.PLATFORM_PAIR }}
160+
path: /tmp/digests/*
161+
if-no-files-found: error
162+
retention-days: 1
163+
164+
165+
merge:
166+
# This job merges the Docker manifests for the different platforms built in the previous job.
167+
name: Merge Docker manifests
168+
runs-on: ubuntu-latest
169+
permissions:
170+
attestations: write
171+
actions: read
172+
checks: read
173+
contents: read
174+
deployments: none
175+
id-token: write
176+
issues: read
177+
discussions: read
178+
packages: write
179+
pages: none
180+
pull-requests: read
181+
repository-projects: read
182+
security-events: read
183+
statuses: read
184+
185+
needs:
186+
- build
187+
# This job depends on the build job to complete before it starts.
188+
# It ensures that the Docker images for all platforms are built before merging the manifests.
189+
steps:
190+
- name: Download digests
191+
# This step downloads the digest files uploaded in the build job.
192+
# It uses the actions/download-artifact action to download the artifacts with the pattern digests-*.
193+
# The downloaded files are merged into the /tmp/digests directory.
194+
uses: actions/download-artifact@cc203385981b70ca67e1cc392babf9cc229d5806 # v4.1.9
195+
with:
196+
path: /tmp/digests
197+
pattern: digests-*
198+
merge-multiple: true
199+
200+
201+
- name: Docker meta
202+
# This step generates metadata for the Docker image.
203+
# It uses the docker/metadata-action to create metadata based on the repository information.
204+
# The metadata includes information such as the image name, tags, and labels.
205+
id: meta
206+
uses: docker/metadata-action@902fa8ec7d6ecbf8d84d538b9b233a880e428804 # v5.7.0
207+
with:
208+
images: ${{ env.GHCR_IMAGE }}
209+
annotations: |
210+
type=org.opencontainers.image.description,value=${{ github.event.repository.description || 'No description provided' }}
211+
212+
- name: Set up Docker Buildx
213+
uses: docker/setup-buildx-action@b5ca514318bd6ebac0fb2aedd5d36ec1b5c232a2 # v3.10.0
214+
# This step sets up Docker Buildx, which is a Docker CLI plugin for extended build capabilities with BuildKit.
215+
with:
216+
driver-opts: |
217+
network=host
218+
219+
- name: Login to GitHub Container Registry
220+
uses: docker/login-action@74a5d142397b4f367a81961eba4e8cd7edddf772 # v3.4.0
221+
# This step logs in to the GitHub Container Registry (GHCR) using the docker/login-action.
222+
# It uses the GitHub actor's username and the GITHUB_TOKEN secret for authentication.
223+
# The login is necessary to push the merged manifest list to GHCR.
224+
with:
225+
registry: ghcr.io
226+
username: ${{ github.actor }}
227+
password: ${{ secrets.GITHUB_TOKEN }}
228+
229+
- name: Get execution timestamp with RFC3339 format
230+
# This step gets the current execution timestamp in RFC3339 format.
231+
# It uses the date command to get the current UTC time and formats it as a string.
232+
# The timestamp is used for annotating the Docker manifest list.
233+
id: timestamp
234+
run: |
235+
echo "timestamp=$(date -u +"%Y-%m-%dT%H:%M:%SZ")" >> $GITHUB_OUTPUT
236+
237+
- name: Create manifest list and pushs
238+
# This step creates a manifest list for the Docker images built for different platforms.
239+
# It uses the docker buildx imagetools create command to create the manifest list.
240+
# The manifest list is annotated with metadata such as description, creation timestamp, and source URL.
241+
# The annotations are obtained from the metadata generated in the previous steps.
242+
# The manifest list is pushed to the GitHub Container Registry (GHCR) with the specified tags.
243+
working-directory: /tmp/digests
244+
id: manifest-annotate
245+
continue-on-error: true
246+
run: |
247+
docker buildx imagetools create \
248+
$(jq -cr '.tags | map("-t " + .) | join(" ")' <<< "$DOCKER_METADATA_OUTPUT_JSON") \
249+
--annotation='index:org.opencontainers.image.description=${{ github.event.repository.description }}' \
250+
--annotation='index:org.opencontainers.image.created=${{ steps.timestamp.outputs.timestamp }}' \
251+
--annotation='index:org.opencontainers.image.url=${{ github.event.repository.url }}' \
252+
--annotation='index:org.opencontainers.image.source=${{ github.event.repository.url }}' \
253+
$(printf '${{ env.GHCR_IMAGE }}@sha256:%s ' *)
254+
255+
- name: Create manifest list and push without annotations
256+
# This step creates a manifest list for the Docker images built for different platforms.
257+
# It uses the docker buildx imagetools create command to create the manifest list.
258+
# The manifest list is created without annotations if the previous step fails.
259+
# The manifest list is pushed to the GitHub Container Registry (GHCR) with the specified tags.
260+
if: steps.manifest-annotate.outcome == 'failure'
261+
working-directory: /tmp/digests
262+
run: |
263+
docker buildx imagetools create $(jq -cr '.tags | map("-t " + .) | join(" ")' <<< "$DOCKER_METADATA_OUTPUT_JSON") \
264+
$(printf '${{ env.GHCR_IMAGE }}@sha256:%s ' *)
265+
266+
- name: Inspect image
267+
# This step inspects the created manifest list to verify its contents.
268+
# It uses the docker buildx imagetools inspect command to display information about the manifest list.
269+
# The inspection output will show the platforms and tags associated with the manifest list.
270+
id: inspect
271+
run: |
272+
docker buildx imagetools inspect '${{ env.GHCR_IMAGE }}:${{ steps.meta.outputs.version }}'

.gitignore

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
# General
2+
.DS_Store
3+
.AppleDouble
4+
.LSOverride
5+
6+
# Icon must end with two \r
7+
Icon
8+
9+
# Thumbnails
10+
._*
11+
12+
# Files that might appear in the root of a volume
13+
.DocumentRevisions-V100
14+
.fseventsd
15+
.Spotlight-V100
16+
.TemporaryItems
17+
.Trashes
18+
.VolumeIcon.icns
19+
.com.apple.timemachine.donotpresent
20+
21+
# Directories potentially created on remote AFP share
22+
.AppleDB
23+
.AppleDesktop
24+
Network Trash Folder
25+
Temporary Items
26+
.apdisk

CODEOWNERS

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
# Lines starting with '#' are comments.
2+
# Each line is a file pattern followed by one or more owners.
3+
4+
# More details are here: https://help.github.com/articles/about-codeowners/
5+
6+
# The '*' pattern is global owners.
7+
8+
# Order is important. The last matching pattern has the most precedence.
9+
# The folders are ordered as follows:
10+
11+
# In each subsection folders are ordered first by depth, then alphabetically.
12+
# This should make it easy to add new rules without breaking existing ones.
13+
14+
# Global rule:
15+
* @ngeorger

0 commit comments

Comments
 (0)