-
Notifications
You must be signed in to change notification settings - Fork 167
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
Add Workflow for Multi-Architecture Docker Image Build, Push, and Manifest Management #535
base: develop
Are you sure you want to change the base?
Changes from 10 commits
0c40761
c1455b0
780e551
1610662
53d7ba8
382d7d6
cefeab3
72fa25e
d2f3828
21ab099
fc2da26
371dda8
2b23989
6f82387
feea9f1
da7487f
c794cc9
87a948f
0cd4756
adf4917
408f261
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 |
---|---|---|
|
@@ -14,7 +14,9 @@ concurrency: | |
cancel-in-progress: true | ||
|
||
env: | ||
IMAGE_NAME: index.docker.io/metacall/core | ||
DOCKER_REGISTRY: docker.io | ||
DOCKER_USERNAME: metacall | ||
IMAGE_NAME: core | ||
BUILDKIT_VERSION: 0.13.0 | ||
|
||
jobs: | ||
|
@@ -33,34 +35,22 @@ jobs: | |
- linux/386 | ||
- linux/arm/v7 | ||
- linux/arm/v6 | ||
# - linux/mips64le | ||
# - linux/mips64 | ||
|
||
steps: | ||
- name: Checkout the code | ||
- name: Checkout Repository | ||
uses: actions/checkout@v4 | ||
with: | ||
fetch-depth: 0 | ||
|
||
- name: Docker meta | ||
id: meta | ||
uses: docker/metadata-action@v5 | ||
with: | ||
images: ${{ env.IMAGE_NAME }} | ||
|
||
- name: Set up QEMU | ||
uses: docker/setup-qemu-action@v3 | ||
|
||
- name: Docker Setup BuildX | ||
- name: Set up Docker BuildX | ||
uses: docker/setup-buildx-action@v3 | ||
with: | ||
version: v${{ env.BUILDKIT_VERSION }} | ||
|
||
- name: Verify Docker BuildX Version | ||
run: docker buildx version | ||
|
||
- name: Authenticate to Docker registry | ||
if: github.event_name != 'pull_request' | ||
- name: Login to Docker Hub | ||
uses: docker/login-action@v3 | ||
with: | ||
username: ${{ secrets.DOCKER_HUB_USERNAME }} | ||
|
@@ -70,95 +60,140 @@ jobs: | |
env: | ||
METACALL_PLATFORM: ${{ matrix.platform }} | ||
run: | | ||
export DOCKER_BUILDKIT=1 | ||
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. I think all those environment variables are already set in the script. |
||
export COMPOSE_DOCKER_CLI_BUILD=1 | ||
export BUILDKIT_PROGRESS=plain | ||
export PROGRESS_NO_TRUNC=1 | ||
./docker-compose.sh platform | ||
|
||
# - name: Generate images | ||
# if: github.event_name != 'pull_request' | ||
# run: | | ||
# for tag in "deps" "dev" "runtime" "cli"; do | ||
# mkdir -p "/tmp/images/${tag}" | ||
# digest="$(docker images --no-trunc --quiet metacall/core:${tag})" | ||
# echo "FROM metacall/core:${tag}@${digest}" &> "/tmp/images/${tag}/Dockerfile" | ||
# done | ||
|
||
# - name: Build and push by digest (deps) | ||
# id: build | ||
# uses: docker/build-push-action@v6 | ||
# if: github.event_name != 'pull_request' | ||
# with: | ||
# context: /tmp/images/deps/Dockerfile | ||
# platforms: ${{ matrix.platform }} | ||
# labels: ${{ steps.meta.outputs.labels }} | ||
# outputs: type=image,name=docker.io/${{ env.IMAGE_NAME }}:deps,push-by-digest=true,name-canonical=true,push=true | ||
|
||
- name: Export digests | ||
if: github.event_name != 'pull_request' | ||
- name: Push Platform Images | ||
run: | | ||
PLATFORM=${{ matrix.platform }} | ||
echo "PLATFORM=${PLATFORM//\//-}" >> $GITHUB_ENV | ||
platform_tag=$(echo "${{ matrix.platform }}" | tr '/' '-') | ||
for tag in "deps" "dev" "runtime" "cli"; do | ||
mkdir -p "/tmp/digests/${tag}" | ||
digest="$(docker images --no-trunc --quiet metacall/core:${tag})" | ||
touch "/tmp/digests/${tag}/${digest#sha256:}" | ||
docker tag ${DOCKER_USERNAME}/${IMAGE_NAME}:${tag} \ | ||
${DOCKER_USERNAME}/${IMAGE_NAME}:${tag}-${platform_tag} | ||
docker push ${DOCKER_USERNAME}/${IMAGE_NAME}:${tag}-${platform_tag} | ||
done | ||
|
||
- name: Upload digests | ||
if: github.event_name != 'pull_request' | ||
uses: actions/upload-artifact@v4 | ||
with: | ||
name: digests-${{ env.PLATFORM }} | ||
path: /tmp/digests/* | ||
if-no-files-found: error | ||
retention-days: 1 | ||
|
||
merge: | ||
name: Merge digests for the manifest | ||
manifest: | ||
name: Create and Push Manifest Lists | ||
needs: build | ||
runs-on: ubuntu-latest | ||
if: github.event_name != 'pull_request' | ||
needs: | ||
- build | ||
steps: | ||
- name: Download digests | ||
uses: actions/download-artifact@v4 | ||
- name: Login to Docker Hub | ||
uses: docker/login-action@v3 | ||
with: | ||
path: /tmp/digests | ||
pattern: digests-* | ||
merge-multiple: true | ||
username: ${{ secrets.DOCKER_HUB_USERNAME }} | ||
password: ${{ secrets.DOCKER_HUB_ACCESS_TOKEN }} | ||
|
||
- name: Set up Docker Buildx | ||
uses: docker/setup-buildx-action@v3 | ||
with: | ||
version: v${{ env.BUILDKIT_VERSION }} | ||
- name: Create and Push Manifest Lists | ||
run: | | ||
for tag in "deps" "dev" "runtime" "cli"; do | ||
docker manifest create ${DOCKER_USERNAME}/${IMAGE_NAME}:${tag} \ | ||
${DOCKER_USERNAME}/${IMAGE_NAME}:${tag}-linux-amd64 \ | ||
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 transform all those commands in a for using the matrix.platform as an array? |
||
${DOCKER_USERNAME}/${IMAGE_NAME}:${tag}-linux-arm64 \ | ||
${DOCKER_USERNAME}/${IMAGE_NAME}:${tag}-linux-riscv64 \ | ||
${DOCKER_USERNAME}/${IMAGE_NAME}:${tag}-linux-ppc64le \ | ||
${DOCKER_USERNAME}/${IMAGE_NAME}:${tag}-linux-s390x \ | ||
${DOCKER_USERNAME}/${IMAGE_NAME}:${tag}-linux-386 \ | ||
${DOCKER_USERNAME}/${IMAGE_NAME}:${tag}-linux-arm-v7 \ | ||
${DOCKER_USERNAME}/${IMAGE_NAME}:${tag}-linux-arm-v6 | ||
|
||
docker manifest push ${DOCKER_USERNAME}/${IMAGE_NAME}:${tag} | ||
done | ||
|
||
- name: Docker meta | ||
id: meta | ||
uses: docker/metadata-action@v5 | ||
with: | ||
images: ${{ env.IMAGE_NAME }} | ||
- name: Create Version-Specific Tags | ||
if: startsWith(github.ref, 'refs/tags/') | ||
run: | | ||
VERSION=${GITHUB_REF#refs/tags/v} | ||
for tag in "deps" "dev" "runtime" "cli"; do | ||
docker manifest create ${DOCKER_USERNAME}/${IMAGE_NAME}:${VERSION}-${tag} \ | ||
${DOCKER_USERNAME}/${IMAGE_NAME}:${tag}-linux-amd64 \ | ||
${DOCKER_USERNAME}/${IMAGE_NAME}:${tag}-linux-arm64 \ | ||
${DOCKER_USERNAME}/${IMAGE_NAME}:${tag}-linux-riscv64 \ | ||
${DOCKER_USERNAME}/${IMAGE_NAME}:${tag}-linux-ppc64le \ | ||
${DOCKER_USERNAME}/${IMAGE_NAME}:${tag}-linux-s390x \ | ||
${DOCKER_USERNAME}/${IMAGE_NAME}:${tag}-linux-386 \ | ||
${DOCKER_USERNAME}/${IMAGE_NAME}:${tag}-linux-arm-v7 \ | ||
${DOCKER_USERNAME}/${IMAGE_NAME}:${tag}-linux-arm-v6 | ||
|
||
docker manifest push ${DOCKER_USERNAME}/${IMAGE_NAME}:${VERSION}-${tag} | ||
done | ||
|
||
- name: Authenticate to Docker registry | ||
docker manifest create ${DOCKER_USERNAME}/${IMAGE_NAME}:latest \ | ||
${DOCKER_USERNAME}/${IMAGE_NAME}:cli-linux-amd64 \ | ||
${DOCKER_USERNAME}/${IMAGE_NAME}:cli-linux-arm64 \ | ||
${DOCKER_USERNAME}/${IMAGE_NAME}:cli-linux-riscv64 \ | ||
${DOCKER_USERNAME}/${IMAGE_NAME}:cli-linux-ppc64le \ | ||
${DOCKER_USERNAME}/${IMAGE_NAME}:cli-linux-s390x \ | ||
${DOCKER_USERNAME}/${IMAGE_NAME}:cli-linux-386 \ | ||
${DOCKER_USERNAME}/${IMAGE_NAME}:cli-linux-arm-v7 \ | ||
${DOCKER_USERNAME}/${IMAGE_NAME}:cli-linux-arm-v6 | ||
|
||
docker manifest push ${DOCKER_USERNAME}/${IMAGE_NAME}:latest | ||
|
||
test: | ||
name: Test CLI Image | ||
needs: manifest | ||
runs-on: ubuntu-latest | ||
strategy: | ||
fail-fast: false | ||
matrix: | ||
platform: | ||
- linux/amd64 | ||
- linux/arm64 | ||
- linux/riscv64 | ||
- linux/ppc64le | ||
- linux/s390x | ||
- linux/386 | ||
- linux/arm/v7 | ||
- linux/arm/v6 | ||
|
||
steps: | ||
- name: Login to Docker Hub | ||
uses: docker/login-action@v3 | ||
with: | ||
username: ${{ secrets.DOCKER_HUB_USERNAME }} | ||
password: ${{ secrets.DOCKER_HUB_ACCESS_TOKEN }} | ||
|
||
- name: Create manifest list and push | ||
if: github.ref == 'refs/heads/master' || contains(github.ref, 'refs/tags/') | ||
- name: Create Test Dockerfile | ||
run: | | ||
for tag in "deps" "dev" "runtime" "cli"; do | ||
cd "/tmp/digests/${tag}" | ||
IMAGE_HASHES=$(printf '${{ env.IMAGE_NAME }}:${tag}@sha256:%s ' *) | ||
for image in ${IMAGE_HASHES}; do | ||
docker image tag ${image} ${{ env.IMAGE_NAME }}:${tag} | ||
docker push ${{ env.IMAGE_NAME }}:${tag} | ||
cat <<EOF > Dockerfile | ||
FROM ${DOCKER_USERNAME}/${IMAGE_NAME}:cli | ||
RUN echo "console.log('abcde')" > script.js | ||
RUN metacallcli script.js | ||
EOF | ||
|
||
- name: Build and Test Image | ||
run: | | ||
platform_tag=$(echo "${{ matrix.platform }}" | tr '/' '-') | ||
docker pull ${DOCKER_USERNAME}/${IMAGE_NAME}:cli | ||
docker build --platform ${{ matrix.platform }} -t test-image . | ||
docker run --rm --platform=${{ matrix.platform }} test-image | ||
|
||
cleanup: | ||
name: Cleanup Platform Specific Tags | ||
needs: | ||
- build | ||
- manifest | ||
runs-on: ubuntu-latest | ||
if: always() | ||
steps: | ||
- name: Remove Platform-Specific Tags | ||
env: | ||
DOCKER_USERNAME: ${{ secrets.DOCKER_HUB_USERNAME }} | ||
DOCKER_HUB_ACCESS_TOKEN: ${{ secrets.DOCKER_HUB_ACCESS_TOKEN }} | ||
run: | | ||
platforms=("linux-amd64" "linux-arm64" "linux-riscv64" "linux-ppc64le" "linux-s390x" "linux-386" "linux-arm-v7" "linux-arm-v6") | ||
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. Same here, can't you get this directly from matrix.platform? |
||
tags=("deps" "dev" "runtime" "cli") | ||
|
||
for platform in "${platforms[@]}"; do | ||
for tag in "${tags[@]}"; do | ||
tag_to_delete="${tag}-${platform}" | ||
echo "Deleting tag: ${tag_to_delete}" | ||
|
||
curl -X DELETE \ | ||
-H "Authorization: Bearer ${DOCKER_HUB_ACCESS_TOKEN}" \ | ||
"https://hub.docker.com/v2/repositories/${DOCKER_USERNAME}/${IMAGE_NAME}/tags/${tag_to_delete}/" | ||
done | ||
docker buildx imagetools create -t ${{ env.IMAGE_NAME }}:${tag} ${IMAGE_HASHES} | ||
if [[ "${tag}" = "cli" ]]; then | ||
docker buildx imagetools create -t ${{ env.IMAGE_NAME }}:latest ${IMAGE_HASHES} | ||
if [[ "${{ contains(github.ref, 'refs/tags/') }}" = true ]]; then | ||
TAG=${GITHUB_REF#refs/*/} | ||
VERSION=${TAG#v} | ||
docker buildx imagetools create -t ${{ env.IMAGE_NAME }}:${VERSION} ${IMAGE_HASHES} | ||
fi | ||
fi | ||
done |
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.
Docker username is a secret that must be provided by GitHub secrets.