Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 1 addition & 4 deletions .github/CODEOWNERS
Original file line number Diff line number Diff line change
@@ -1,4 +1 @@
#ECCN:Open Source
#GUSINFO:Languages,Heroku Stacks & Images
* @heroku/languages

* @ninech/platform-team
170 changes: 34 additions & 136 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ on:

permissions:
contents: read
id-token: write
packages: write

jobs:
shellcheck:
Expand All @@ -34,10 +34,9 @@ jobs:
fail-fast: false
matrix:
arch: ["amd64", "arm64"]
stack-version: ["22", "24"]
exclude:
- arch: "arm64"
stack-version: "22"
stack-version: ["24"]
env:
DOCKER_IMAGE_NAME: ghcr.io/${{ github.repository_owner }}/deploio-heroku
steps:
- name: Checkout
uses: actions/checkout@v6
Expand All @@ -52,51 +51,16 @@ jobs:
git diff
exit 1
fi
- name: Generate Heroku runtime image files
if: matrix.arch == 'amd64'
run: |
bin/generate-runtime-images.sh ${{ matrix.stack-version }}
- name: Export base images from the Docker daemon
if: github.ref_name == 'main' || github.ref_type == 'tag'
run: |
docker save $(docker images --format '{{.Repository}}:{{.Tag}}' | grep "heroku/heroku:${{ matrix.stack-version }}") | zstd -T0 --long=31 -o images.tar.zst
docker save $(docker images --format '{{.Repository}}:{{.Tag}}' | grep "${DOCKER_IMAGE_NAME}:${{ matrix.stack-version }}") | zstd -T0 --long=31 -o images.tar.zst
- name: Save OCI base image exports to the cache
if: github.ref_name == 'main' || github.ref_type == 'tag'
uses: actions/cache/save@v5
with:
key: ${{ github.run_id}}-${{ matrix.stack-version }}-${{ matrix.arch }}
path: images.tar.zst
- name: Save Heroku runtime image files to the cache
if: matrix.arch == 'amd64' && github.ref_type == 'tag'
uses: actions/cache/save@v5
with:
key: runtime-images-${{ github.run_id}}-${{ matrix.stack-version }}
path: /tmp/heroku-${{ matrix.stack-version }}*

upload-runtime-images:
if: github.ref_type == 'tag'
name: "Upload heroku-${{ matrix.stack-version }} runtime images"
needs:
- build
runs-on: ubuntu-24.04
strategy:
fail-fast: false
matrix:
stack-version: ["22", "24"]
steps:
- name: Checkout
uses: actions/checkout@v6
- name: Restore heroku runtime images from the cache
uses: actions/cache/restore@v5
with:
fail-on-cache-miss: true
key: runtime-images-${{ github.run_id}}-${{ matrix.stack-version }}
path: /tmp/heroku-${{ matrix.stack-version }}*
- name: Upload heroku runtime images to staging
run: bin/upload-runtime-images.sh ${{ matrix.stack-version }} ${{ github.sha }}
env:
MANIFEST_APP_TOKEN: "${{ secrets.MANIFEST_APP_TOKEN }}"
MANIFEST_APP_URL: "${{ secrets.MANIFEST_APP_URL }}"

publish-images:
if: github.ref_name == 'main' || github.ref_type == 'tag'
Expand All @@ -106,14 +70,12 @@ jobs:
runs-on: ${{ matrix.arch == 'arm64' && 'ubuntu-24.04-arm' || 'ubuntu-24.04' }}
env:
TAG_SUFFIX: ".${{ github.ref_type == 'tag' && github.ref_name || 'nightly' }}"
DOCKER_IMAGE_NAME: ghcr.io/${{ github.repository_owner }}/deploio-heroku
strategy:
fail-fast: false
matrix:
arch: ["amd64", "arm64"]
stack-version: ["22", "24"]
exclude:
- arch: "arm64"
stack-version: "22"
stack-version: ["24"]
steps:
- name: Restore base images from the cache
uses: actions/cache/restore@v5
Expand All @@ -125,34 +87,15 @@ jobs:
SEGMENT_DOWNLOAD_TIMEOUT_MINS: 1
- name: Load Docker images into the Docker daemon
run: zstd -dc --long=31 images.tar.zst | docker load
- name: Log in to Docker Hub
run: echo '${{ secrets.DOCKER_HUB_TOKEN }}' | docker login -u '${{ secrets.DOCKER_HUB_USERNAME }}' --password-stdin
- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@61815dcd50bd041e203e49132bacad1fd04d2708 # v5.1.1
with:
role-to-assume: arn:aws:iam::${{ secrets.AWS_ACCOUNT_ID }}:role/${{ secrets.AWS_ECR_ROLE }}
aws-region: ${{ vars.AWS_REGION }}
- name: Log in to Amazon ECR Public
id: login-ecr-public
uses: aws-actions/amazon-ecr-login@062b18b96a7aff071d4dc91bc00c4c1a7945b076 # v2.0.1
with:
registry-type: public
- name: Publish base images to registries
- name: Log in to GitHub Container Registry
run: echo '${{ secrets.GITHUB_TOKEN }}' | docker login ghcr.io -u '${{ github.actor }}' --password-stdin
- name: Publish base images to registry
run: |
variants=("" "-build")
platformSuffix=""
if (( ${{ matrix.stack-version }} >= 24 )); then
platformSuffix="_linux-${{ matrix.arch }}"
else
variants+=("-cnb" "-cnb-build")
fi
for variant in "${variants[@]}"; do
srcTag="heroku/heroku:${{ matrix.stack-version}}${variant}"
destTag="${srcTag}${platformSuffix}${TAG_SUFFIX}"
for host in "docker.io" "public.ecr.aws"; do
docker tag "${srcTag}" "${host}/${destTag}"
docker push "${host}/${destTag}"
done
for variant in "" "-build"; do
srcTag="${DOCKER_IMAGE_NAME}:${{ matrix.stack-version }}${variant}"
destTag="${srcTag}_linux-${{ matrix.arch }}${TAG_SUFFIX}"
docker tag "${srcTag}" "${destTag}"
docker push "${destTag}"
done

publish-indices:
Expand All @@ -163,99 +106,54 @@ jobs:
runs-on: ubuntu-24.04
env:
TAG_SUFFIX: ".${{ github.ref_type == 'tag' && github.ref_name || 'nightly' }}"
DOCKER_IMAGE_NAME: ghcr.io/${{ github.repository_owner }}/deploio-heroku
strategy:
fail-fast: false
matrix:
stack-version: ["24"]
steps:
- name: Log in to Docker Hub
run: echo '${{ secrets.DOCKER_HUB_TOKEN }}' | docker login -u '${{ secrets.DOCKER_HUB_USERNAME }}' --password-stdin
- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@61815dcd50bd041e203e49132bacad1fd04d2708 # v5.1.1
with:
role-to-assume: arn:aws:iam::${{ secrets.AWS_ACCOUNT_ID }}:role/${{ secrets.AWS_ECR_ROLE }}
aws-region: ${{ vars.AWS_REGION }}
- name: Log in to Amazon ECR Public
id: login-ecr-public
uses: aws-actions/amazon-ecr-login@062b18b96a7aff071d4dc91bc00c4c1a7945b076 # v2.0.1
with:
registry-type: public
- name: Log in to GitHub Container Registry
run: echo '${{ secrets.GITHUB_TOKEN }}' | docker login ghcr.io -u '${{ github.actor }}' --password-stdin
- name: Publish multi-arch image index
run: |
for variant in '' '-build'; do
indexTag="heroku/heroku:${{ matrix.stack-version }}${variant}${TAG_SUFFIX}"
armTag="heroku/heroku:${{ matrix.stack-version }}${variant}_linux-arm64${TAG_SUFFIX}"
amdTag="heroku/heroku:${{ matrix.stack-version }}${variant}_linux-amd64${TAG_SUFFIX}"
for host in 'docker.io' 'public.ecr.aws'; do
docker buildx imagetools create \
--tag "${host}/${indexTag}" \
"${host}/${amdTag}" \
"${host}/${armTag}"
done
indexTag="${DOCKER_IMAGE_NAME}:${{ matrix.stack-version }}${variant}${TAG_SUFFIX}"
armTag="${DOCKER_IMAGE_NAME}:${{ matrix.stack-version }}${variant}_linux-arm64${TAG_SUFFIX}"
amdTag="${DOCKER_IMAGE_NAME}:${{ matrix.stack-version }}${variant}_linux-amd64${TAG_SUFFIX}"
docker manifest create "${indexTag}" "${amdTag}" "${armTag}"
docker manifest push "${indexTag}"
done

ctc-check:
name: Obtain CTC Lock
if: github.ref_type == 'tag'
runs-on: ubuntu-24.04
steps:
- name: Obtain CTC Lock via TPS API
run: |
curl -sS --connect-timeout 5 --fail-with-body --retry-connrefused --retry 5 \
-X PUT \
-H "ACCEPT: application/json" \
-H "Content-Type: application/json" \
-H "Authorization: Token ${{ secrets.TPS_TOKEN }}" \
-d '{"lock": {"sha": "${{ github.sha }}", "component_slug": "${{ vars.tps_component }}"}}' \
"${{ secrets.TPS_CTC_API_URL }}"

promote-tags:
if: github.ref_type == 'tag'
name: "Promote heroku-${{ matrix.stack-version }} tags"
needs:
- ctc-check
- publish-images
- publish-indices
runs-on: ubuntu-24.04
strategy:
fail-fast: false
matrix:
stack-version: ["22", "24"]
stack-version: ["24"]
env:
DOCKER_IMAGE_NAME: ghcr.io/${{ github.repository_owner }}/deploio-heroku
steps:
- name: Checkout
uses: actions/checkout@v6
- name: Log in to Docker Hub
run: echo '${{ secrets.DOCKER_HUB_TOKEN }}' | docker login -u '${{ secrets.DOCKER_HUB_USERNAME }}' --password-stdin
- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@61815dcd50bd041e203e49132bacad1fd04d2708 # v5.1.1
with:
role-to-assume: arn:aws:iam::${{ secrets.AWS_ACCOUNT_ID }}:role/${{ secrets.AWS_ECR_ROLE }}
aws-region: ${{ vars.AWS_REGION }}
- name: Log in to Amazon ECR Public
id: login-ecr-public
uses: aws-actions/amazon-ecr-login@062b18b96a7aff071d4dc91bc00c4c1a7945b076 # v2.0.1
with:
registry-type: public
- name: Log in to GitHub Container Registry
run: echo '${{ secrets.GITHUB_TOKEN }}' | docker login ghcr.io -u '${{ github.actor }}' --password-stdin
- name: Install crane
uses: buildpacks/github-actions/setup-tools@f3ec16c6d708761c6e87bbc8fe7f97375f80e7cd # v5.10.1
- name: Promote images to stable tag
run: |
destTags=( )
if (( ${{ matrix.stack-version }} >= 24 )); then
for variant in '' '-build'; do
for arch in 'amd64' 'arm64'; do
destTags+=("heroku/heroku:${{ matrix.stack-version }}${variant}_linux-${arch}")
done
destTags+=("heroku/heroku:${{ matrix.stack-version }}${variant}")
done
else
for variant in '' '-build' '-cnb' '-cnb-build'; do
destTags+=("heroku/heroku:${{ matrix.stack-version }}${variant}")
for variant in '' '-build'; do
for arch in 'amd64' 'arm64'; do
destTags+=("${DOCKER_IMAGE_NAME}:${{ matrix.stack-version }}${variant}_linux-${arch}")
done
fi
destTags+=("${DOCKER_IMAGE_NAME}:${{ matrix.stack-version }}${variant}")
done
for destTag in "${destTags[@]}"; do
srcTag="${destTag}.${{ github.ref_name }}"
for host in "docker.io" "public.ecr.aws"; do
crane copy "${host}/${srcTag}" "${host}/${destTag}"
done
crane copy "${srcTag}" "${destTag}"
done
27 changes: 6 additions & 21 deletions BUILD.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,29 +26,14 @@ Add the package you want to the appropriate `setup.sh` for example `heroku-24/se
+ libc6-dev
```

Once done, run `bin/build.sh` locally to generate the corresponding `installed-packages*` files. Multi-arch base images (heroku-24 and beyond) will produce an `installed-packages-$ARCH.txt` for each architecture, while single architecture images will produce a singular `installed-packages.txt`.
Once done, run `bin/build.sh` locally to generate the corresponding `installed-packages*` files. Multi-arch base images (heroku-24 and beyond) will produce an `installed-packages-$ARCH.txt` for each architecture.

The `*-build` variants include all the packages from the non-build variant by default. This means that if you're adding a package to both, you only need to add them to the non-build variant. The example above will add `libc6-dev` to both `heroku-24` and `heroku-24-build`.

The `*cnb*` variants (which only exist for heroku-22 and prior) inherit the installed packages from the non-`*cnb*` variant. Add packages to a non-`*cnb*` variant to add them to the `*cnb*` variant.
# Releasing Base Images

# Releasing Heroku Base Images
We use GitHub Actions to build and release the base images:

We use GitHub Actions to build and release Heroku Base Images:

* Any push to `main` will build the images and push the nightly Docker tag variants (such as `heroku/heroku:24-build.nightly`).
* Any new Git tag will build the image and push the latest Docker tag (such as `heroku/heroku:24-build`),
as well as a versioned tag (such as `heroku/heroku:24-build.v123`). The `amd64` images will then also be
converted to a Heroku-specific `.img` format and uploaded to S3 for consumption by the runtime hosts.

# Generating `.img` format Base Images locally

To test the generation of the Heroku-specific `.img` file:

1. Build the Docker images for your chosen stack as normal above.
2. `docker buildx build --platform "linux/amd64,linux/arm64" -t heroku-image-tools ./tools`
3. `docker run -it --rm --privileged -v /var/run/docker.sock:/var/run/docker.sock heroku-image-tools STACK_VERSION` (where `STACK_VERSION` is a integer version like `24`)

You can also pass `--platform linux/amd64` or `--platform linux/arm64` to the `docker run` call above to test the generation for a specific architecture instead of using the same architecture as the host.

To get the resulting `.img.gz` and `.img.sha256` files written to a local output directory on the host machine, pass `-v <localoutdir>:/output` to the `docker run` call.
* Any push to `main` will build the images and push the nightly GitHub Container Registry tag variants (such as `ghcr.io/ninech/deploio-heroku:24-build.nightly`).
* Any new Git tag will build the image and push the latest GitHub Container Registry tag (such as `ghcr.io/ninech/deploio-heroku:24-build`),
as well as a versioned tag (such as `ghcr.io/ninech/deploio-heroku:24-build.v123`).
39 changes: 14 additions & 25 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,31 +1,20 @@
## Heroku Base Images

[![CI](https://github.com/heroku/base-images/actions/workflows/ci.yml/badge.svg)](https://github.com/heroku/base-images/actions/workflows/ci.yml)

This repository holds recipes for building the base images for [Heroku stacks](https://devcenter.heroku.com/articles/stack).
The recipes are also rendered into Docker images that are available on Docker Hub:

| Image | Type | OS | Supported Architectures | Default `USER` | Status |
|-------------------------------------------|------------------------|--------------|-------------------------|----------------| -------------|
| [heroku/heroku:20][heroku-tags] | Heroku Run Image | Ubuntu 20.04 | AMD64 | `root` | End-of-life |
| [heroku/heroku:20-build][heroku-tags] | Heroku Build Image | Ubuntu 20.04 | AMD64 | `root` | End-of-life |
| [heroku/heroku:20-cnb][heroku-tags] | CNB Run Image | Ubuntu 20.04 | AMD64 | `heroku` | End-of-life |
| [heroku/heroku:20-cnb-build][heroku-tags] | CNB Build Image | Ubuntu 20.04 | AMD64 | `heroku` | End-of-life |
| [heroku/heroku:22][heroku-tags] | Heroku Run Image | Ubuntu 22.04 | AMD64 | `root` | Available |
| [heroku/heroku:22-build][heroku-tags] | Heroku Build Image | Ubuntu 22.04 | AMD64 | `root` | Available |
| [heroku/heroku:22-cnb][heroku-tags] | CNB Run Image | Ubuntu 22.04 | AMD64 | `heroku` | Available |
| [heroku/heroku:22-cnb-build][heroku-tags] | CNB Build Image | Ubuntu 22.04 | AMD64 | `heroku` | Available |
| [heroku/heroku:24][heroku-tags] | Heroku/CNB Run Image | Ubuntu 24.04 | AMD64 + ARM64 | `heroku` | Recommended |
| [heroku/heroku:24-build][heroku-tags] | Heroku/CNB Build Image | Ubuntu 24.04 | AMD64 + ARM64 | `heroku` | Recommended |
## ninech/deploio-heroku Base Images

[![CI](https://github.com/ninech/heroku-stack-base-images/actions/workflows/ci.yml/badge.svg)](https://github.com/ninech/heroku-stack-base-images/actions/workflows/ci.yml)

This is a ninech fork of [heroku/base-images](https://github.com/heroku/base-images), adapted for use with [deplo.io](https://deplo.io).
The recipes are rendered into Docker images available on the GitHub Container Registry:

| Image | Type | OS | Supported Architectures | Default `USER` | Status |
|----------------------------------------------------|----------------|--------------|-------------------------|----------------|-------------|
| [ghcr.io/ninech/deploio-heroku:24][ninech-tags] | Run Image | Ubuntu 24.04 | AMD64 + ARM64 | `deploio` | Recommended |
| [ghcr.io/ninech/deploio-heroku:24-build][ninech-tags] | Build Image | Ubuntu 24.04 | AMD64 + ARM64 | `deploio` | Recommended |

The build image variants use the run images as their base, but include additional packages needed
at build time such as development headers and compilation toolchains.

The CNB image variants contain additional metadata and changes required to make them compatible with
Heroku's Cloud Native Buildpacks [builder images](https://github.com/heroku/cnb-builder-images).

For images where the default `USER` is `heroku`, you will need to switch back to the `root` user when
modifying locations other then `/home/heroku` and `/tmp`. You can do this by adding `USER root` to
For images where the default `USER` is `deploio`, you will need to switch back to the `root` user when
modifying locations other than `/home/deploio` and `/tmp`. You can do this by adding `USER root` to
your `Dockerfile` when building images, or by passing `--user root` to any `docker run` invocations.

### Learn more
Expand All @@ -35,5 +24,5 @@ your `Dockerfile` when building images, or by passing `--user root` to any `dock

See [BUILD.md](BUILD.md) for instructions on how to build the images yourself.

[heroku-tags]: https://hub.docker.com/r/heroku/heroku/tags
[ninech-tags]: https://github.com/ninech/heroku-stack-base-images/pkgs/container/deploio-heroku
[ubuntu-tags]: https://hub.docker.com/_/ubuntu?tab=tags
Loading