Skip to content

Commit 8eabed3

Browse files
committed
ci: build in GitHub workflow
fix: typo in uses ci: build node-prune, enabling it on aarch64 ci: build as prod Use multi-arch-docker-github-workflow ci: fix on ci: fix tag? ci: lowercase ci: fix lower ci: hardcode image name, fix tags ci: push latest, full sha with no prefix ci: run on publish ci: tag major too ci: build on tag ci: delete major fix: update actions/cache
1 parent d7b6ce3 commit 8eabed3

File tree

3 files changed

+291
-5
lines changed

3 files changed

+291
-5
lines changed

.github/workflows/build.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ jobs:
1111
steps:
1212
- uses: actions/checkout@v4.1.0
1313
- name: restore_cache
14-
uses: actions/cache@v3.3.2
14+
uses: actions/cache@v4
1515
with:
1616
key: yarn-packages-{{ .Branch }}-{{ checksum "yarn.lock" }}
1717
path: node_modules/

.github/workflows/docker-image.yml

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

Dockerfile

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,8 @@
1+
FROM golang:1-alpine AS nodeprune
2+
3+
RUN go install -trimpath -ldflags "-s -w" github.com/tj/node-prune@latest
4+
5+
###############################################################
16
FROM node:18 AS compiler
27

38
WORKDIR /usr/src/prism
@@ -12,6 +17,8 @@ FROM node:18 AS dependencies
1217

1318
WORKDIR /usr/src/prism/
1419

20+
COPY --from=nodeprune /go/bin/node-prune /bin/
21+
1522
COPY package.json /usr/src/prism/
1623
RUN mkdir -p /usr/src/prism/node_modules
1724

@@ -27,11 +34,10 @@ RUN mkdir -p /usr/src/prism/packages/http-server/node_modules
2734
COPY packages/cli/package.json /usr/src/prism/packages/cli/
2835
RUN mkdir -p /usr/src/prism/packages/cli/node_modules
2936

30-
ENV NODE_ENV production
37+
ENV NODE_ENV=production
3138
RUN yarn --production
3239

33-
RUN if [ $(uname -m) != "aarch64" ]; then curl -sfL https://gobinaries.com/tj/node-prune | bash; fi
34-
RUN if [ $(uname -m) != "aarch64" ]; then node-prune; fi
40+
RUN node-prune
3541

3642
###############################################################
3743
FROM node:18-alpine
@@ -41,7 +47,7 @@ RUN apk add --no-cache tini
4147

4248
WORKDIR /usr/src/prism
4349
ARG BUILD_TYPE=development
44-
ENV NODE_ENV production
50+
ENV NODE_ENV=production
4551

4652
COPY package.json /usr/src/prism/
4753
COPY packages/core/package.json /usr/src/prism/packages/core/

0 commit comments

Comments
 (0)