Record of a GitHub Actions Optimization (Docker Build)
When building multi-platform compatible Docker images using Github Actions, the execution was always slow. I had AI optimize the task configuration file.
Rendering...
## Key Improvements (What's Done Well)
1. Checkout added `fetch-depth: 0`: Before the improvement, it defaulted to shallow clone (`depth=1`), and `git describe --tags` often failed to correctly retrieve historical tags, leading to version extraction failures. Adding `fetch-depth: 0` significantly improves reliability.
2. Version number output changed to `$GITHUB_OUTPUT`: This is the correct and recommended practice. Before the improvement, using `>> $GITHUB_ENV` worked, but `GITHUB_OUTPUT` is a more modern and clearly scoped approach (especially for referencing in subsequent steps).
3. Switched to the official `docker/build-push-action@v5`: This is the biggest and most important improvement.
* No longer manually writing `docker buildx build ...` commands, reducing the risk of syntax errors.
* Automatically handles multi-platform manifests, pushes, tags, etc.
* Code is more concise and readable.
4. Added `setup-qemu-action`: For `linux/arm64` platforms, QEMU emulation is required when building on `ubuntu-latest (x86_64)`. The previous version lacked this step, making arm64 builds very likely to fail or be extremely slow. Adding it provides more complete multi-platform support.
5. Enabled Buildx cache (`cache-from + cache-to: type=gha,mode=max`): This can significantly speed up subsequent build times, especially with multi-platform + multi-stage Dockerfiles.
6. Explicitly specified `context: .` and `file: ./Dockerfile`: This is clearer. Although `.` is the default, writing it out makes it easier to maintain.
7. Used `steps.get_version.outputs.VERSION` for referencing the version: This works in conjunction with `GITHUB_OUTPUT`.
## Original Configuration
```yaml
name: Docker
on:
push:
tags:
- v*.*.*
jobs:
docker_build:
environment: docker_hub
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Get version
id: get_version
run: |
VERSION=$(git describe --tags --always --match 'v*' | sed -n 's|^v\([0-9]*\.[0-9]*\.[0-9]*\)\(-.*\)\{0,1\}|\1|p')
echo "VERSION=$VERSION" >> $GITHUB_ENV # Store version as an environment variable
- name: Log in to Docker Hub
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
# Set up Docker Buildx (supports multi-platform builds)
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
# Build and push multi-platform image in a single step
- name: Build and push multi-platform image
run: |
docker buildx build \
--platform linux/amd64,linux/arm64 \
--tag dingdangdog/jimily:${VERSION} \
--tag dingdangdog/jimily:latest \
--push .
- name: Clean up Docker images
run: docker system prune -af
```
## New Configuration
```yaml
name: Docker
on:
push:
tags:
- v*.*.*
jobs:
docker_build:
environment: docker_hub
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
fetch-depth: 0 # Ensure tags are fetched for version generation
- name: Get version
id: get_version
# Extract semantic version, e.g., extract 5.1.3 from v5.1.3
run: |
VERSION=$(git describe --tags --always --match 'v*' | sed -n 's|^v\([0-9]*\.[0-9]*\.[0-9]*\)\(-.*\)\{0,1\}|\1|p')
echo "VERSION=$VERSION" >> $GITHUB_OUTPUT
- name: Log in to Docker Hub
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
- name: Set up QEMU
uses: docker/setup-qemu-action@v3
with:
platforms: arm64 # Explicitly specify platforms to emulate
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Build and push multi-platform image
uses: docker/build-push-action@v5
with:
context: .
file: ./Dockerfile
platforms: linux/amd64,linux/arm64
push: true
tags: |
dingdangdog/jimily:${{ steps.get_version.outputs.VERSION }}
dingdangdog/jimily:latest
# Key improvement: Enable GitHub Actions cache backend
cache-from: type=gha
cache-to: type=gha,mode=max
# Pass build arguments (if your Dockerfile needs the VERSION variable, uncomment the following line)
# build-args: |
# APP_VERSION=${{ steps.get_version.outputs.VERSION }}
```Comments
Please login to view and post comments
Go to Login