From b57992a75417f6d570e1b595a2c47448435f39a3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Cerezo?= <104803561+joseenrique61@users.noreply.github.com> Date: Tue, 11 Nov 2025 21:42:44 -0500 Subject: [PATCH] Optimize docker image (#1157) * Optimized Docker image * Divided Dockerfile into two images * Fixed dockerfile path * Updated workflows * Added remaining packages in Dockerfile-base * Updated workflows * Unified workflows for docker images * Added LABELs to docker images * pull from ciromattia cache * docker2 * Optimized Docker image * fix tags * Added installation stage and optimized workflow for Docker image * Deleted one stage from the dockerfile to optimize build * copy requirements file after numpy and pymupdf * don't change primary requirements --------- Co-authored-by: Alex Xu --- .dockerignore | 29 +++- .github/workflows/docker-base-publish.yml | 34 ----- .github/workflows/docker-publish.yml | 64 ++++++--- Dockerfile | 89 +++++++++--- Dockerfile-base | 164 ---------------------- entrypoint.sh | 22 +++ requirements-docker.txt | 11 ++ 7 files changed, 181 insertions(+), 232 deletions(-) delete mode 100644 .github/workflows/docker-base-publish.yml delete mode 100644 Dockerfile-base create mode 100644 entrypoint.sh create mode 100644 requirements-docker.txt diff --git a/.dockerignore b/.dockerignore index 590e766..a72e77b 100644 --- a/.dockerignore +++ b/.dockerignore @@ -1,13 +1,40 @@ .git .github + build dist KindleComicConverter.egg-info + .dockerignore .gitignore .travis.yml + Dockerfile venv +.venv +__pycache__/ +*/__pycache__/ +*.pyc + *.md -LICENSE.txt +*.txt +!requirements-docker.txt MANIFEST.in + +*.yml +*.spec + +*.svg +*.jpg +*.json + +gen_ui_files.bat +gen_ui_files.sh + +gui/ +icons/ + +kindlecomicconverter/KCC_gui.py +kindlecomicconverter/KCC_rc.py +kindlecomicconverter/KCC_ui_editor.py +kindlecomicconverter/KCC_ui.py diff --git a/.github/workflows/docker-base-publish.yml b/.github/workflows/docker-base-publish.yml deleted file mode 100644 index 7c692a4..0000000 --- a/.github/workflows/docker-base-publish.yml +++ /dev/null @@ -1,34 +0,0 @@ -name: Docker base - -on: - workflow_dispatch: - push: - tags: [ 'docker-base-*' ] - - # Don't trigger if it's just a documentation update - paths-ignore: - - '**.md' - - '**.MD' - - '**.yml' - - 'docs/**' - - 'LICENSE' - - '.gitattributes' - - '.gitignore' - - '.dockerignore' - - -jobs: - build_and_push: - uses: sdr-enthusiasts/common-github-workflows/.github/workflows/build_and_push_image.yml@main - with: - docker_build_file: ./Dockerfile-base - platform_linux_arm32v7_enabled: true - platform_linux_arm64v8_enabled: true - platform_linux_amd64_enabled: true - push_enabled: true - build_nohealthcheck: false - ghcr_repo_owner: ${{ github.repository_owner }} - ghcr_repo: ${{ github.repository }} - build_latest: false - secrets: - ghcr_token: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/docker-publish.yml b/.github/workflows/docker-publish.yml index be58fd2..8e54c38 100644 --- a/.github/workflows/docker-publish.yml +++ b/.github/workflows/docker-publish.yml @@ -1,10 +1,10 @@ -name: Docker +name: Build and Publish Docker Image on: workflow_dispatch: push: - # Publish semver tags as releases. - tags: [ 'v*.*.*' ] + tags: + - 'v*.*.*' # Don't trigger if it's just a documentation update paths-ignore: @@ -15,19 +15,49 @@ on: - 'LICENSE' - '.gitattributes' - '.gitignore' - - '.dockerignore' - jobs: - build_and_push: - uses: sdr-enthusiasts/common-github-workflows/.github/workflows/build_and_push_image.yml@main - with: - platform_linux_arm32v7_enabled: true - platform_linux_arm64v8_enabled: true - platform_linux_amd64_enabled: true - push_enabled: true - build_nohealthcheck: false - ghcr_repo_owner: ${{ github.repository_owner }} - ghcr_repo: ${{ github.repository }} - secrets: - ghcr_token: ${{ secrets.GITHUB_TOKEN }} + build_and_publish_base_image: + runs-on: ubuntu-latest + steps: + - name: Login to GitHub Container Registry + uses: docker/login-action@v3 + with: + registry: ghcr.io + username: ${{ github.repository_owner }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Set up QEMU + uses: docker/setup-qemu-action@v3 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Set Release Date + id: release_date + run: | + echo "release_date=$(date --rfc-3339=date)" >> $GITHUB_OUTPUT + + - name: Docker meta + id: meta + uses: docker/metadata-action@v5 + with: + images: ghcr.io/${{ github.repository_owner }}/kcc + # Always creates the "latest" tag + flavor: | + latest=true + tags: | + type=ref,event=tag + type=raw,value=${{ steps.release_date.outputs.release_date }} + + - name: Build and push + uses: docker/build-push-action@v6 + with: + platforms: linux/amd64,linux/arm64,linux/arm/v7 + push: true + tags: | + ${{ steps.meta.outputs.tags }} + cache-from: | + type=registry,ref=ghcr.io/ciromattia/kcc:cache + type=registry,ref=ghcr.io/${{ github.repository_owner }}/kcc:cache + cache-to: type=registry,ref=ghcr.io/${{ github.repository_owner }}/kcc:cache,mode=max diff --git a/Dockerfile b/Dockerfile index e9581fe..0880953 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,19 +1,76 @@ -# Select final stage based on TARGETARCH ARG -FROM ghcr.io/ciromattia/kcc:docker-base-20241116 -LABEL com.kcc.name="Kindle Comic Converter" -LABEL com.kcc.author="Ciro Mattia Gonano, Paweł Jastrzębski and Darodi" -LABEL org.opencontainers.image.description='Kindle Comic Converter' -LABEL org.opencontainers.image.documentation='https://github.com/ciromattia/kcc' -LABEL org.opencontainers.image.source='https://github.com/ciromattia/kcc' -LABEL org.opencontainers.image.authors='darodi' -LABEL org.opencontainers.image.url='https://github.com/ciromattia/kcc' -LABEL org.opencontainers.image.documentation='https://github.com/ciromattia/kcc' -LABEL org.opencontainers.image.vendor='ciromattia' -LABEL org.opencontainers.image.licenses='ISC' -LABEL org.opencontainers.image.title="Kindle Comic Converter" +# STAGE 1: BUILDER +# Contains all build tools and dev dependencies, will be discarded +FROM python:3.13-slim-bullseye AS builder -COPY . /opt/kcc -RUN cat /opt/kcc/kindlecomicconverter/__init__.py | grep version | awk '{print $3}' | sed "s/'//g" > /IMAGE_VERSION +# Install system dependencies +RUN set -x && \ + BUILD_DEPS="build-essential cmake libffi-dev libfreetype6-dev libfontconfig1-dev libpng-dev libjpeg-dev libssl-dev libxft-dev make python3-dev python3-setuptools python3-wheel" && \ + RUNTIME_DEPS="bash ca-certificates chrpath locales locales-all libfreetype6 libfontconfig1 p7zip-full python3 python3-pip libgl1" && \ + DEBIAN_FRONTEND=noninteractive apt-get update -y && \ + apt-get install -y --no-install-recommends ${BUILD_DEPS} ${RUNTIME_DEPS} -ENTRYPOINT ["/opt/kcc/kcc-c2e.py"] +RUN \ + set -x && \ + python -m venv /opt/venv && \ + . /opt/venv/bin/activate && \ + pip install --upgrade pip + +# Install numpy first, as it is unlikely to change and takes too long to compile +RUN \ + set -x && \ + . /opt/venv/bin/activate && \ + pip install --no-cache-dir numpy==2.3.4 + +# Install PyMuPDF separately, as it is likely to change but still takes too long to compile +RUN \ + set -x && \ + . /opt/venv/bin/activate && \ + pip install --no-cache-dir PyMuPDF==1.26.6 + +# Install Python dependencies using virtual environment +COPY requirements-docker.txt . + +RUN \ + set -x && \ + . /opt/venv/bin/activate && \ + pip install --no-cache-dir -r requirements-docker.txt + +# STAGE 2: FINAL +# Clean, small and secure image with only runtime dependencies +FROM python:3.13-slim-bullseye + +# Install runtime dependencies only +RUN \ + set -x && \ + DEBIAN_FRONTEND=noninteractive apt-get update -y && \ + apt-get install -y --no-install-recommends p7zip-full && \ + rm -rf /var/lib/apt/lists/* + +# Copy artifacts from builder +COPY --from=builder /opt/venv /opt/venv +COPY . /opt/kcc/ + +WORKDIR /opt/kcc +ENV PATH="/opt/venv/bin:$PATH" + +# Setup executable and version file +RUN \ + chmod +x /opt/kcc/entrypoint.sh && \ + ln -s /opt/kcc/kcc-c2e.py /usr/local/bin/c2e && \ + ln -s /opt/kcc/kcc-c2p.py /usr/local/bin/c2p && \ + ln -s /opt/kcc/entrypoint.sh /usr/local/bin/entrypoint && \ + cat /opt/kcc/kindlecomicconverter/__init__.py | grep version | awk '{print $3}' | sed "s/'//g" > /IMAGE_VERSION + +LABEL com.kcc.name="Kindle Comic Converter" \ + com.kcc.author="Ciro Mattia Gonano, Paweł Jastrzębski and Darodi" \ + org.opencontainers.image.title="Kindle Comic Converter" \ + org.opencontainers.image.description='Kindle Comic Converter' \ + org.opencontainers.image.documentation='https://github.com/ciromattia/kcc' \ + org.opencontainers.image.source='https://github.com/ciromattia/kcc' \ + org.opencontainers.image.authors='Darodi and José Cerezo' \ + org.opencontainers.image.url='https://github.com/ciromattia/kcc' \ + org.opencontainers.image.vendor='ciromattia' \ + org.opencontainers.image.licenses='ISC' + +ENTRYPOINT ["entrypoint"] CMD ["-h"] diff --git a/Dockerfile-base b/Dockerfile-base deleted file mode 100644 index cb73e60..0000000 --- a/Dockerfile-base +++ /dev/null @@ -1,164 +0,0 @@ -FROM --platform=linux/amd64 python:3.13-slim-bullseye as compile-amd64 -ARG TARGETOS -ARG TARGETARCH -ARG TARGETVARIANT -RUN echo "I'm building for $TARGETOS/$TARGETARCH/$TARGETVARIANT" - - -COPY requirements.txt /opt/kcc/ -ENV PATH="/opt/venv/bin:$PATH" -RUN DEBIAN_FRONTEND=noninteractive apt-get update -y && apt-get -yq upgrade && \ - apt-get install -y libpng-dev libjpeg-dev p7zip-full unrar-free libgl1 && \ - python -m pip install --upgrade pip && \ - python -m venv /opt/venv && \ - python -m pip install -r /opt/kcc/requirements.txt - - -###################################################################################### - -FROM --platform=linux/arm64 python:3.13-slim-bullseye as compile-arm64 -ARG TARGETOS -ARG TARGETARCH -ARG TARGETVARIANT -RUN echo "I'm building for $TARGETOS/$TARGETARCH/$TARGETVARIANT" - -ENV LC_ALL=C.UTF-8 \ - LANG=C.UTF-8 \ - LANGUAGE=en_US:en - -SHELL ["/bin/bash", "-o", "pipefail", "-c"] - -COPY requirements.txt /opt/kcc/ -ENV PATH="/opt/venv/bin:$PATH" - -RUN set -x && \ - TEMP_PACKAGES=() && \ - KEPT_PACKAGES=() && \ - # Packages only required during build - TEMP_PACKAGES+=(build-essential) && \ - TEMP_PACKAGES+=(cmake) && \ - TEMP_PACKAGES+=(libfreetype6-dev) && \ - TEMP_PACKAGES+=(libfontconfig1-dev) && \ - TEMP_PACKAGES+=(libpng-dev) && \ - TEMP_PACKAGES+=(libjpeg-dev) && \ - TEMP_PACKAGES+=(libssl-dev) && \ - TEMP_PACKAGES+=(libxft-dev) && \ - TEMP_PACKAGES+=(make) && \ - TEMP_PACKAGES+=(python3-dev) && \ - TEMP_PACKAGES+=(python3-setuptools) && \ - TEMP_PACKAGES+=(python3-wheel) && \ - # Packages kept in the image - KEPT_PACKAGES+=(bash) && \ - KEPT_PACKAGES+=(ca-certificates) && \ - KEPT_PACKAGES+=(chrpath) && \ - KEPT_PACKAGES+=(locales) && \ - KEPT_PACKAGES+=(locales-all) && \ - KEPT_PACKAGES+=(libfreetype6) && \ - KEPT_PACKAGES+=(libfontconfig1) && \ - KEPT_PACKAGES+=(p7zip-full) && \ - KEPT_PACKAGES+=(python3) && \ - KEPT_PACKAGES+=(python3-pip) && \ - KEPT_PACKAGES+=(unrar-free) && \ - # Install packages - DEBIAN_FRONTEND=noninteractive apt-get update -y && apt-get -yq upgrade && \ - DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \ - ${KEPT_PACKAGES[@]} \ - ${TEMP_PACKAGES[@]} \ - && \ - # Install required python modules - python -m pip install --upgrade pip && \ - python -m venv /opt/venv && \ - python -m pip install -r /opt/kcc/requirements.txt - - -###################################################################################### - -FROM --platform=linux/arm/v7 python:3.13-slim-bullseye as compile-armv7 -ARG TARGETOS -ARG TARGETARCH -ARG TARGETVARIANT -RUN echo "I'm building for $TARGETOS/$TARGETARCH/$TARGETVARIANT" - -ENV LC_ALL=C.UTF-8 \ - LANG=C.UTF-8 \ - LANGUAGE=en_US:en - -SHELL ["/bin/bash", "-o", "pipefail", "-c"] - -COPY requirements.txt /opt/kcc/ -ENV PATH="/opt/venv/bin:$PATH" - -RUN set -x && \ - TEMP_PACKAGES=() && \ - KEPT_PACKAGES=() && \ - # Packages only required during build - TEMP_PACKAGES+=(build-essential) && \ - TEMP_PACKAGES+=(cmake) && \ - TEMP_PACKAGES+=(libffi-dev) && \ - TEMP_PACKAGES+=(libfreetype6-dev) && \ - TEMP_PACKAGES+=(libfontconfig1-dev) && \ - TEMP_PACKAGES+=(libpng-dev) && \ - TEMP_PACKAGES+=(libjpeg-dev) && \ - TEMP_PACKAGES+=(libssl-dev) && \ - TEMP_PACKAGES+=(libxft-dev) && \ - TEMP_PACKAGES+=(make) && \ - TEMP_PACKAGES+=(python3-dev) && \ - TEMP_PACKAGES+=(python3-setuptools) && \ - TEMP_PACKAGES+=(python3-wheel) && \ - # Packages kept in the image - KEPT_PACKAGES+=(bash) && \ - KEPT_PACKAGES+=(ca-certificates) && \ - KEPT_PACKAGES+=(chrpath) && \ - KEPT_PACKAGES+=(locales) && \ - KEPT_PACKAGES+=(locales-all) && \ - KEPT_PACKAGES+=(libfreetype6) && \ - KEPT_PACKAGES+=(libfontconfig1) && \ - KEPT_PACKAGES+=(p7zip-full) && \ - KEPT_PACKAGES+=(python3) && \ - KEPT_PACKAGES+=(python3-pip) && \ - KEPT_PACKAGES+=(unrar-free) && \ - # Install packages - DEBIAN_FRONTEND=noninteractive apt-get update -y && apt-get -yq upgrade && \ - DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \ - ${KEPT_PACKAGES[@]} \ - ${TEMP_PACKAGES[@]} \ - && \ - # Install required python modules - python -m pip install --upgrade pip && \ - python -m venv /opt/venv && \ - python -m pip install --upgrade pillow psutil requests python-slugify raven packaging mozjpeg-lossless-optimization natsort distro numpy pymupdf - - -###################################################################################### -FROM --platform=linux/amd64 python:3.13-slim-bullseye as build-amd64 -COPY --from=compile-amd64 /opt/venv /opt/venv - -FROM --platform=linux/arm64 python:3.13-slim-bullseye as build-arm64 -COPY --from=compile-arm64 /opt/venv /opt/venv - -FROM --platform=linux/arm/v7 python:3.13-slim-bullseye as build-armv7 -COPY --from=compile-armv7 /opt/venv /opt/venv -###################################################################################### - -# Select final stage based on TARGETARCH ARG -FROM build-${TARGETARCH}${TARGETVARIANT} -LABEL com.kcc.name="Kindle Comic Converter base image" -LABEL com.kcc.author="Ciro Mattia Gonano, Paweł Jastrzębski and Darodi" -LABEL org.opencontainers.image.description='Kindle Comic Converter base image' -LABEL org.opencontainers.image.documentation='https://github.com/ciromattia/kcc' -LABEL org.opencontainers.image.source='https://github.com/ciromattia/kcc' -LABEL org.opencontainers.image.authors='darodi' -LABEL org.opencontainers.image.url='https://github.com/ciromattia/kcc' -LABEL org.opencontainers.image.documentation='https://github.com/ciromattia/kcc' -LABEL org.opencontainers.image.vendor='ciromattia' -LABEL org.opencontainers.image.licenses='ISC' -LABEL org.opencontainers.image.title="Kindle Comic Converter" - - -ENV PATH="/opt/venv/bin:$PATH" -WORKDIR /app -RUN DEBIAN_FRONTEND=noninteractive apt-get update -y && apt-get -yq upgrade && \ - apt-get install -y p7zip-full unrar-free && \ - ln -s /app/kindlegen /bin/kindlegen && \ - echo docker-base-20241116 > /IMAGE_VERSION - diff --git a/entrypoint.sh b/entrypoint.sh new file mode 100644 index 0000000..27aada1 --- /dev/null +++ b/entrypoint.sh @@ -0,0 +1,22 @@ +#!/bin/sh + +set -e + +MODE=${KCC_MODE:-c2e} + +case "$MODE" in + "c2e") + echo "Starting C2E..." + exec c2e "$@" + ;; + + "c2p") + echo "Starting C2P..." + exec c2p "$@" + ;; + + *) + echo "Error: Unknown mode '$MODE'" >&2 + exit 1 + ;; +esac \ No newline at end of file diff --git a/requirements-docker.txt b/requirements-docker.txt new file mode 100644 index 0000000..077a006 --- /dev/null +++ b/requirements-docker.txt @@ -0,0 +1,11 @@ +Pillow>=11.3.0 +psutil>=5.9.5 +requests>=2.31.0 +python-slugify>=1.2.1 +packaging>=23.2 +mozjpeg-lossless-optimization>=1.2.0 +natsort>=8.4.0 +distro>=1.8.0 +# Below requirements are compiled in Dockefile +# numpy==2.3.4 +# PyMuPDF==1.26.6 \ No newline at end of file