diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 1e467cd3..24dd1177 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -20,42 +20,3 @@ jobs: uses: actions/checkout@v4 - name: Run shellcheck run: find . -type f \( -name "*.sh" -o -path "*/bin/*" \) ! -name '*.jq' | xargs -t shellcheck - build-stack: - runs-on: ubuntu-22.04 - needs: - - shellcheck - env: - STACK: heroku-${{ matrix.stack-version }} - STACK_VERSION: "${{ matrix.stack-version }}" - DOCKER_HUB_TOKEN: "${{ secrets.DOCKER_HUB_TOKEN }}" - DOCKER_HUB_USERNAME: "${{ secrets.DOCKER_HUB_USERNAME }}" - MANIFEST_APP_TOKEN: "${{ secrets.MANIFEST_APP_TOKEN }}" - MANIFEST_APP_URL: "${{ secrets.MANIFEST_APP_URL }}" - strategy: - fail-fast: false - matrix: - stack-version: ["20", "22", "24"] - steps: - - name: Checkout - uses: actions/checkout@v4 - - name: Build images - run: bin/build.sh $STACK_VERSION - - name: Check that the generated files are in sync - run: |- - status="$(git status --porcelain)" - if [[ -n "$status" ]]; then - echo "Generated files differ from checked-in versions! Run bin/build.sh to regenerate them locally." - echo -e "\nChanged files:\n${status}\n" - git diff - exit 1 - fi - - name: Publish to image registries - run: |- - docker buildx create --use - bin/publish-to-registries.sh - if: success() && (github.ref_name == 'main' || github.ref_type == 'tag') - - name: Unpublish temp tags from this run - run: bin/unpublish-tags.sh - if: always() && (github.ref_name == 'main' || github.ref_type == 'tag') - - name: Convert docker image and for Git tags release to Heroku staging - run: bin/convert-and-publish-to-heroku.sh diff --git a/.github/workflows/docker-publish.yml b/.github/workflows/docker-publish.yml new file mode 100644 index 00000000..744bb218 --- /dev/null +++ b/.github/workflows/docker-publish.yml @@ -0,0 +1,28 @@ +name: Docker + +on: + push: + # Publish `multiarch-push-robuust` branch to Container Registry + branches: 'multiarch-push-robuust' + +jobs: + # Push image to GitHub Packages. + # See also https://docs.docker.com/docker-hub/builds/ + push: + runs-on: ubuntu-latest + if: github.event_name == 'push' + + steps: + - uses: actions/checkout@v4 + + - name: Set up QEMU + uses: docker/setup-qemu-action@v3 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Log into GitHub Container Registry + run: echo "${{ secrets.CR_PAT }}" | docker login https://ghcr.io -u ${{ github.actor }} --password-stdin + + - name: Build & push image to GitHub Container Registry + run: bin/build.sh 22 diff --git a/bin/build.sh b/bin/build.sh index c229d7dc..c16fbcd7 100755 --- a/bin/build.sh +++ b/bin/build.sh @@ -1,11 +1,12 @@ #!/usr/bin/env bash +# shellcheck disable=SC2034 set -euo pipefail cd "$(dirname "${BASH_SOURCE[0]}")/.." . bin/stack-helpers.sh -REPO="heroku/heroku" +REPO="ghcr.io/robuust/heroku" STACK_VERSION=${1:-"NAN"} PUBLISH_SUFFIX=${2:-} BASE_NAME=$(basename "${BASH_SOURCE[0]}") @@ -40,59 +41,50 @@ print_usage(){ EOF } +# Create buildx driver +docker buildx create --use + [[ $STACK_VERSION =~ ^[0-9]+$ ]] || (>&2 print_usage && abort "fatal: invalid STACK_VERSION") -have_docker_container_driver= -if (docker buildx inspect; true) | grep -q 'Driver:\s*docker-container$'; then - have_docker_container_driver=1 -fi +have_docker_container_driver=1 have_containerd_snapshotter= if docker info -f "{{ .DriverStatus }}" | grep -qF "io.containerd.snapshotter."; then have_containerd_snapshotter=1; fi if (( STACK_VERSION <= 22 )); then - # heroku/heroku:22 and prior images do not support multiple chip - # architectures or multi-arch images. Instead, they are amd64 only. - DOCKER_ARGS=("build" "--platform=linux/amd64") # heroku/heroku:22 and prior images need separate *cnb* variants that # add compatibility for Cloud Native Buildpacks. VARIANTS=("-build:" "-cnb:" "-cnb-build:-build") else - # heroku/heroku:24 images and beyond are multi-arch (amd64+arm64) images. - # Due to weak feature support parity between Docker on Linux and Docker - # Desktop building and publishing across platforms has caveats (see the - # top of this file). - if [[ $have_containerd_snapshotter ]] || { [[ $PUBLISH_SUFFIX ]] && [[ $have_docker_container_driver ]]; }; then - DOCKER_ARGS=("buildx" "build" "--platform=linux/amd64,linux/arm64") - elif [[ ! $PUBLISH_SUFFIX ]] && [[ ! $have_docker_container_driver ]]; then - DOCKER_ARGS=("buildx" "build" "--platform=linux/amd64") - >&2 echo "WARNING: heroku-24 and newer images are multi-arch images," \ - "but this script is building single architecture images" \ - "due to limitations of the current platform." \ - "To build a multi-arch image, enable the 'containerd'" \ - "snapshotter in Docker Desktop and/or use a 'docker-container'" \ - "Docker BuildKit driver." - else - >&2 echo "ERROR: Can't build images with this configuration. Enable" \ - "the 'containerd' snapshotter in Docker Desktop, enable" \ - "the 'docker-container' driver in Docker, or use this script" \ - "in build-only mode (don't provide PUBLISH_SUFFIX argument)." - abort 1 - fi # heroku/heroku:24 and beyond images include CNB specific # modifications, so separate *cnb* variants are not created. VARIANTS=("-build:") fi -if [[ $PUBLISH_SUFFIX ]]; then - # If there is a tag suffix, this script is pushing to a remote registry. - DOCKER_ARGS+=("--push") +# Due to weak feature support parity between Docker on Linux and Docker +# Desktop building and publishing across platforms has caveats (see the +# top of this file). +if [[ $have_containerd_snapshotter ]] || [[ $have_docker_container_driver ]]; then + DOCKER_ARGS=("buildx" "build" "--platform=linux/amd64,linux/arm64") +elif [[ ! $PUBLISH_SUFFIX ]] && [[ ! $have_docker_container_driver ]]; then + DOCKER_ARGS=("buildx" "build" "--platform=linux/amd64") + >&2 echo "WARNING: heroku-24 and newer images are multi-arch images," \ + "but this script is building single architecture images" \ + "due to limitations of the current platform." \ + "To build a multi-arch image, enable the 'containerd'" \ + "snapshotter in Docker Desktop and/or use a 'docker-container'" \ + "Docker BuildKit driver." else - # Otherwise, load the image into the local image store. - DOCKER_ARGS+=("--load") + >&2 echo "ERROR: Can't build images with this configuration. Enable" \ + "the 'containerd' snapshotter in Docker Desktop, enable" \ + "the 'docker-container' driver in Docker, or use this script" \ + "in build-only mode (don't provide PUBLISH_SUFFIX argument)." + abort 1 fi +DOCKER_ARGS+=("--push") + write_package_list() { local image_tag="$1" local dockerfile_dir="$2" @@ -102,24 +94,18 @@ write_package_list() { stack_version=$(echo "$dockerfile_dir" | sed -n 's/^heroku-\([0-9]*\).*$/\1/p') local archs=("amd64") - # heroku-24 and newer are multiarch. If containerd is available, + # If containerd is available, # the package list for each architecture can be generated. - if (( stack_version >= 24 )); then - if [[ $have_containerd_snapshotter ]]; then - archs+=(arm64) - else - >&2 echo "WARNING: Generating package list for single architecture." \ - "Use the 'containerd' snapshotter to generate package lists" \ - "for all architectures." - fi + if [[ $have_containerd_snapshotter ]]; then + archs+=(arm64) + else + >&2 echo "WARNING: Generating package list for single architecture." \ + "Use the 'containerd' snapshotter to generate package lists" \ + "for all architectures." fi local output_file="" for arch in "${archs[@]}"; do - if (( stack_version >= 24 )); then - output_file="${dockerfile_dir}/installed-packages-${arch}.txt" - else - output_file="${dockerfile_dir}/installed-packages.txt" - fi + output_file="${dockerfile_dir}/installed-packages-${arch}.txt" display "Generating package list: ${output_file}" echo "# List of packages present in the final image. Regenerate using bin/build.sh" > "$output_file" # We include the package status in the output so we can differentiate between fully installed diff --git a/bin/publish-to-registries.sh b/bin/publish-to-registries.sh index f2b2e38d..d4e207fe 100755 --- a/bin/publish-to-registries.sh +++ b/bin/publish-to-registries.sh @@ -11,6 +11,8 @@ set -x echo "${DOCKER_HUB_TOKEN}" | docker login -u "${DOCKER_HUB_USERNAME}" --password-stdin ) +bin/build.sh "${STACK_VERSION}" + push_group() { local tagBase="$1" local sourceTagSuffix="$2" @@ -22,7 +24,7 @@ push_group() { for variant in "${variants[@]}"; do source="${tagBase}${variant}${sourceTagSuffix}" target="${tagBase}${variant}${targetTagSuffix}" - if (( STACK_VERSION < 24 )); then + if (( STACK_VERSION < 22 )); then # Re-tag amd64-only images docker tag "${source}" "${target}" docker push "${target}" diff --git a/heroku-20-build/installed-packages.txt b/heroku-20-build/installed-packages.txt index 0a72fe41..48d4360e 100644 --- a/heroku-20-build/installed-packages.txt +++ b/heroku-20-build/installed-packages.txt @@ -610,7 +610,7 @@ shared-mime-info socat ssl-cert stunnel4 -syslinux +syslinux-common sysvinit-utils tar telnet diff --git a/heroku-20/installed-packages.txt b/heroku-20/installed-packages.txt index 1f832b61..c9901886 100644 --- a/heroku-20/installed-packages.txt +++ b/heroku-20/installed-packages.txt @@ -384,7 +384,7 @@ sensible-utils shared-mime-info socat stunnel4 -syslinux +syslinux-common sysvinit-utils tar telnet diff --git a/heroku-20/setup.sh b/heroku-20/setup.sh index 629b8363..58e65857 100755 --- a/heroku-20/setup.sh +++ b/heroku-20/setup.sh @@ -6,9 +6,12 @@ export DEBIAN_FRONTEND=noninteractive # The default sources list minus backports, restricted and multiverse. cat >/etc/apt/sources.list </etc/apt/sources.list <