Skip to content

Commit

Permalink
Improved Docker image + publish on ghcr.io (#642)
Browse files Browse the repository at this point in the history
Fix #610

- [x] Native cross-compilation support in Dockerfile. Only `linux/amd64`
and `linux/arm64` supported and tested (Tier 1 platform support from
Rust)
- [x] Cache support for cargo downloads and compilation results in
Dockerfile
- [x] Open Container's
[annotations](https://github.com/opencontainers/image-spec/blob/main/annotations.md)
in Dockerfile
- [x] GitHub Actions workflow to build the image for both platforms,
publishing to ghcr.io on tags and master branch pushes.
- [x] Disable use of GitHub Actions cache for tags build, allow manually
triggering the workflow with or without cache.
- [x] [Attestation
artifacts](https://docs.github.com/en/actions/security-for-github-actions/using-artifact-attestations/using-artifact-attestations-to-establish-provenance-for-builds)
for builds
- [x] Add basic informations about the use of the Docker image in README

I also changed the WORKDIR from `/src` to `/work`, because if got me
confused with the use of the src folder for the project source in the
first stage of the Dockerfile. It doesn't impact anything anyways since
you can mount the file where you want and have the program options point
to it.

**How to test?**
_After checking out the branch and making sure you have QEMU installed
to build/test_
```shell
# Docker sadly doesn't have yet the way to have locally a tag with multiple platforms
# despite being able to pass multiple platforms to the build command, so we have to use two distinct tags.
docker build --platform=linux/amd64 --tag test-oxipng-amd:latest --load .
docker build --platform=linux/arm64 --tag test-oxipng-arm:latest --load .

docker run --rm test-oxipng-amd:latest --version
docker run --rm test-oxipng-arm:latest --version

# Run on some files
docker run --rm -it -v $(pwd):/work test-oxipng-amd:latest -a /work/tests/files/apng_file.png
docker run --rm -it -v $(pwd):/work test-oxipng-arm:latest -a /work/tests/files/apng_file.png

# Remove the images
docker image rm test-oxipng-amd:latest
docker image rm test-oxipng-arm:latest
```

For the workflow, see the GitHub Actions logs. If you want to test the
ghcr.io publishing you can merge the branch into a fork and see the
result.

---------

Co-authored-by: Alejandro González <me@alegon.dev>
  • Loading branch information
AFCMS and AlexTMjugador authored Nov 24, 2024
1 parent c81a863 commit ef64dd0
Show file tree
Hide file tree
Showing 4 changed files with 141 additions and 10 deletions.
4 changes: 4 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
scripts
.github
.editorconfig
.pre-commit-hooks.yaml
92 changes: 92 additions & 0 deletions .github/workflows/docker.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
name: docker
on:
push:
branches:
- 'master'
tags:
- 'v*.*.*'
pull_request:
types:
- opened
- synchronize
workflow_dispatch:
inputs:
use_cache:
description: "Use build cache"
required: true
type: boolean
default: true

env:
REGISTRY: ghcr.io
# ghcr.io/OWNER/REPO
IMAGE_NAME: ${{ github.repository }}

jobs:
build:
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
id-token: write
attestations: write

steps:
- name: Checkout repository
uses: actions/checkout@v4

- name: Set up QEMU
uses: docker/setup-qemu-action@v3

# Workaround: https://github.com/docker/build-push-action/issues/461
- name: Setup Docker buildx
uses: docker/setup-buildx-action@v3

# Login against a Docker registry except on PR
# https://github.com/docker/login-action
- name: Log into registry ${{ env.REGISTRY }}
if: github.event_name != 'pull_request'
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}

# Extract metadata (tags, labels) for Docker
# For some reason the title have to be set manually
# https://github.com/docker/metadata-action
- name: Extract Docker metadata
id: meta
uses: docker/metadata-action@v5
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
labels: |
org.opencontainers.image.title=Oxipng
annotations: |
org.opencontainers.image.title=Oxipng
# Build and push Docker image with Buildx (don't push on PR)
# Cache isn't used for tags and on workflow_dispatch if specified
# https://github.com/docker/build-push-action
- name: Build and push Docker image
id: build-and-push
uses: docker/build-push-action@v6
with:
context: .
platforms: linux/amd64,linux/arm64
push: ${{ github.event_name != 'pull_request' }}
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=gha
cache-to: type=gha,mode=max
no-cache: ${{ (github.event_name == 'workflow_dispatch' && !inputs.use_cache) || startsWith(github.ref, 'refs/tags/') }}

# Attest the build provenance
# TODO: enable push to registry when referrers API will be supported by ghcr.io
- name: Attest Build Provenance
if: github.event_name != 'pull_request'
uses: actions/attest-build-provenance@v1
with:
subject-name: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
subject-digest: ${{ steps.build-and-push.outputs.digest }}
push-to-registry: false
45 changes: 35 additions & 10 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,20 +1,45 @@
FROM rust:alpine as base
# syntax=docker/dockerfile:1
FROM --platform=$BUILDPLATFORM tonistiigi/xx AS xx

COPY . /src
FROM --platform=$BUILDPLATFORM rust:1.74-alpine AS base

RUN rustup update 1.74 && rustup default 1.74

RUN apk update \
&& apk add \
RUN apk update && \
apk add \
gcc \
g++
g++ \
clang

RUN cd /src && cargo build --release
COPY --from=xx / /

FROM alpine as tool
ARG TARGETPLATFORM
RUN xx-info env

COPY --from=base /src/target/release/oxipng /usr/local/bin
RUN xx-apk add \
gcc \
musl-dev \
libdeflate

WORKDIR /src

COPY . .

RUN --mount=type=cache,target=/root/.cargo/git/db \
--mount=type=cache,target=/root/.cargo/registry/cache \
--mount=type=cache,target=/root/.cargo/registry/index \
xx-cargo build --release && \
xx-verify /src/target/$(xx-cargo --print-target-triple)/release/oxipng && \
cp /src/target/$(xx-cargo --print-target-triple)/release/oxipng /src/target/oxipng

FROM alpine AS tool

LABEL org.opencontainers.image.title="Oxipng"
LABEL org.opencontainers.image.description="Multithreaded PNG optimizer written in Rust"
LABEL org.opencontainers.image.authors="Joshua Holmer <jholmer.in@gmail.com>"
LABEL org.opencontainers.image.licenses="MIT"
LABEL org.opencontainers.image.source="https://github.com/shssoichiro/oxipng"

COPY --from=base /src/target/oxipng /usr/local/bin

WORKDIR /work
ENTRYPOINT [ "oxipng" ]
CMD [ "--help" ]
10 changes: 10 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,16 @@ trunk actions enable trunk-fmt-pre-commit

[trunk]: https://docs.trunk.io

## Docker

A Docker image is availlable at `ghcr.io/shssoichiro/oxipng` for `linux/amd64` and `linux/arm64`.

You can use it the following way:

```bash
docker run --rm -v $(pwd):/work ghcr.io/shssoichiro/oxipng -o 4 /work/file.png
```

## Library Usage

Although originally intended to be used as an executable, oxipng can also be used as a library in
Expand Down

0 comments on commit ef64dd0

Please sign in to comment.