diff --git a/.github/workflows/builder.yml b/.github/workflows/builder.yml new file mode 100644 index 0000000..7a5f64e --- /dev/null +++ b/.github/workflows/builder.yml @@ -0,0 +1,74 @@ +name: Build and Push Builder Image + +on: + pull_request: + paths: + - 'Dockerfile.builder' + - '.github/workflows/builder.yml' + +env: + REGISTRY: ghcr.io + IMAGE_NAME: ${{ github.repository }}-builder + GOLANG_VERSION: '1.25.1' + FFMPEG_VERSION: '7.1.1' + VIPS_VERSION: '8.17.2' + +jobs: + build-builder: + runs-on: ubuntu-latest + permissions: + contents: read + packages: write + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Log in to Container Registry + uses: docker/login-action@v3 + with: + registry: ${{ env.REGISTRY }} + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Set build arguments + id: args + run: | + echo "ffmpeg_version=${{ env.FFMPEG_VERSION }}" >> $GITHUB_OUTPUT + echo "vips_version=${{ env.VIPS_VERSION }}" >> $GITHUB_OUTPUT + echo "golang_version=${{ env.GOLANG_VERSION }}" >> $GITHUB_OUTPUT + + # Create version tag + VERSION_TAG="ffmpeg-${{ env.FFMPEG_VERSION }}-vips-${{ env.VIPS_VERSION }}-go-${{ env.GOLANG_VERSION }}" + echo "version_tag=${VERSION_TAG}" >> $GITHUB_OUTPUT + + - name: Extract metadata + id: meta + uses: docker/metadata-action@v5 + with: + images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} + tags: | + type=raw,value=latest + type=raw,value=${{ steps.args.outputs.version_tag }} + + - name: Build and push builder image + uses: docker/build-push-action@v5 + with: + context: . + file: ./Dockerfile.builder + platforms: linux/amd64,linux/arm64 + push: true + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} + build-args: | + GOLANG_VERSION=${{ steps.args.outputs.golang_version }} + FFMPEG_VERSION=${{ steps.args.outputs.ffmpeg_version }} + VIPS_VERSION=${{ steps.args.outputs.vips_version }} + cache-from: type=gha + cache-to: type=gha,mode=max + + - name: Image digest + run: echo ${{ steps.build.outputs.digest }} diff --git a/Dockerfile b/Dockerfile index 44fdf1b..cff4e04 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,69 +1,9 @@ -ARG GOLANG_VERSION=1.25.0 -FROM golang:${GOLANG_VERSION}-trixie as builder +ARG BUILDER_IMAGE_TAG=ffmpeg-7.1.1-vips-8.17.2-go-1.25.1 -ARG FFMPEG_VERSION=7.1.1 -ARG VIPS_VERSION=8.17.1 -ARG TARGETARCH +# Stage 1: Build application using builder image with go + libvips + FFmpeg +FROM ghcr.io/cshum/imagorvideo-builder:${BUILDER_IMAGE_TAG} AS builder ENV PKG_CONFIG_PATH=/usr/local/lib/pkgconfig -ENV MAKEFLAGS="-j8" - -# Installs libvips + FFmpeg + required libraries including modern image formats + ImageMagick -RUN DEBIAN_FRONTEND=noninteractive \ - apt-get update && \ - apt-get install --no-install-recommends -y \ - ca-certificates \ - automake build-essential curl \ - meson ninja-build pkg-config \ - gobject-introspection gtk-doc-tools libglib2.0-dev libjpeg62-turbo-dev libpng-dev \ - libwebp-dev libtiff-dev libexif-dev libxml2-dev libpoppler-glib-dev \ - swig libpango1.0-dev libmatio-dev libopenslide-dev libcfitsio-dev libopenjp2-7-dev liblcms2-dev \ - libgsf-1-dev libfftw3-dev liborc-0.4-dev librsvg2-dev libimagequant-dev libaom-dev \ - libspng-dev libcgif-dev libheif-dev libheif-plugin-x265 libheif-plugin-aomenc libjxl-dev libavif-dev \ - libmagickwand-dev \ - yasm libx264-dev libx265-dev libnuma-dev libvpx-dev libtheora-dev \ - librtmp-dev libvorbis-dev libdav1d-dev && \ - cd /tmp && \ - curl -fsSLO https://github.com/libvips/libvips/releases/download/v${VIPS_VERSION}/vips-${VIPS_VERSION}.tar.xz && \ - tar xf vips-${VIPS_VERSION}.tar.xz && \ - cd vips-${VIPS_VERSION} && \ - meson setup _build \ - --buildtype=release \ - --strip \ - --prefix=/usr/local \ - --libdir=lib \ - -Dmagick=enabled \ - -Djpeg-xl=enabled \ - -Dintrospection=disabled && \ - ninja -C _build && \ - ninja -C _build install && \ - cd /tmp && \ - curl -fsSLO https://ffmpeg.org/releases/ffmpeg-${FFMPEG_VERSION}.tar.xz && \ - tar xf ffmpeg-${FFMPEG_VERSION}.tar.xz && \ - cd /tmp/ffmpeg-${FFMPEG_VERSION} && \ - ./configure --prefix=/usr/local \ - --disable-debug \ - --disable-doc \ - --disable-ffplay \ - --disable-static \ - --enable-shared \ - --enable-version3 \ - --enable-gpl \ - --enable-libtheora \ - --enable-libvorbis \ - --enable-librtmp \ - --enable-libwebp \ - --enable-libvpx \ - --enable-libx265 \ - --enable-libx264 \ - --enable-libdav1d \ - --enable-libaom && \ - make && make install && \ - ldconfig && \ - rm -rf /usr/local/lib/python* && \ - rm -rf /usr/local/lib/libvips-cpp.* && \ - rm -rf /usr/local/lib/*.a && \ - rm -rf /usr/local/lib/*.la WORKDIR ${GOPATH}/src/github.com/cshum/imagorvideo @@ -76,13 +16,13 @@ COPY . . RUN go build -o ${GOPATH}/bin/imagorvideo ./cmd/imagorvideo/main.go +# Stage 2: Runtime image FROM debian:trixie-slim as runtime LABEL maintainer="adrian@cshum.com" COPY --from=builder /usr/local/lib /usr/local/lib COPY --from=builder /etc/ssl/certs /etc/ssl/certs -# Install runtime dependencies including modern image formats and ImageMagick RUN DEBIAN_FRONTEND=noninteractive \ apt-get update && \ apt-get install --no-install-recommends -y \ diff --git a/Dockerfile.builder b/Dockerfile.builder new file mode 100644 index 0000000..feaa666 --- /dev/null +++ b/Dockerfile.builder @@ -0,0 +1,73 @@ +ARG GOLANG_VERSION=1.25.1 +ARG FFMPEG_VERSION=7.1.1 +ARG VIPS_VERSION=8.17.2 + +FROM golang:${GOLANG_VERSION}-trixie AS cache-builder + +ARG FFMPEG_VERSION +ARG VIPS_VERSION +ARG TARGETARCH + +ENV PKG_CONFIG_PATH=/usr/local/lib/pkgconfig +ENV MAKEFLAGS="-j8" + +# Install libvips + FFmpeg + required libraries +RUN DEBIAN_FRONTEND=noninteractive \ + apt-get update && \ + apt-get install --no-install-recommends -y \ + ca-certificates \ + automake build-essential curl \ + meson ninja-build pkg-config \ + gobject-introspection gtk-doc-tools libglib2.0-dev libjpeg62-turbo-dev libpng-dev \ + libwebp-dev libtiff-dev libexif-dev libxml2-dev libpoppler-glib-dev \ + swig libpango1.0-dev libmatio-dev libopenslide-dev libcfitsio-dev libopenjp2-7-dev liblcms2-dev \ + libgsf-1-dev libfftw3-dev liborc-0.4-dev librsvg2-dev libimagequant-dev libaom-dev \ + libspng-dev libcgif-dev libheif-dev libheif-plugin-x265 libheif-plugin-aomenc libjxl-dev libavif-dev \ + libmagickwand-dev \ + yasm libx264-dev libx265-dev libnuma-dev libvpx-dev libtheora-dev \ + librtmp-dev libvorbis-dev libdav1d-dev && \ + cd /tmp && \ + curl -fsSLO https://github.com/libvips/libvips/releases/download/v${VIPS_VERSION}/vips-${VIPS_VERSION}.tar.xz && \ + tar xf vips-${VIPS_VERSION}.tar.xz && \ + cd vips-${VIPS_VERSION} && \ + meson setup _build \ + --buildtype=release \ + --strip \ + --prefix=/usr/local \ + --libdir=lib \ + -Dmagick=enabled \ + -Djpeg-xl=enabled \ + -Dintrospection=disabled && \ + ninja -C _build && \ + ninja -C _build install && \ + cd /tmp && \ + curl -fsSLO https://ffmpeg.org/releases/ffmpeg-${FFMPEG_VERSION}.tar.xz && \ + tar xf ffmpeg-${FFMPEG_VERSION}.tar.xz && \ + cd /tmp/ffmpeg-${FFMPEG_VERSION} && \ + ./configure --prefix=/usr/local \ + --disable-debug \ + --disable-doc \ + --disable-ffplay \ + --disable-static \ + --enable-shared \ + --enable-version3 \ + --enable-gpl \ + --enable-libtheora \ + --enable-libvorbis \ + --enable-librtmp \ + --enable-libwebp \ + --enable-libvpx \ + --enable-libx265 \ + --enable-libx264 \ + --enable-libdav1d \ + --enable-libaom && \ + make && make install && \ + ldconfig && \ + rm -rf /usr/local/lib/python* && \ + rm -rf /usr/local/lib/libvips-cpp.* && \ + rm -rf /usr/local/lib/*.a && \ + rm -rf /usr/local/lib/*.la && \ + rm -rf /tmp/* + +# This cache image provides Go + compiled libvips + FFmpeg libraries +LABEL maintainer="imagorvideo"