mirror of
https://github.com/apache/airflow.git
synced 2026-11-04 07:12:48 +00:00
* Refresh the hardened base image mirror every six hours Docker rebuilds the hardened images in place and moves the dhi.io apt repository on at the same time. With a weekly mirror, the base images Airflow builds on lag the repository by up to a week, and any apt install whose dependencies were rebuilt in between fails: build-essential currently cannot be installed because the mirrored base has an older libbz2 than the bzip2 the repository offers (docker-hardened-images/catalog#689). Mirroring copies manifests between registries without pulling layers, so running it several times a day is cheap. Generated-by: Claude Opus 5 * Pin the hardened base images to digests the CI has passed on Building on the mirror's moving tags made CI non-reproducible: any refresh of the mirror changed the image every build started from, without a change in the repository and without the full CI having run on it. A CI run could pass or fail depending only on when it ran, and rebuilding the same commit later gave a different image. The images now build on a digest, and only the upgrade check moves it, in a PR that must pass the full CI before the new base is used. The mirror refreshes every six hours and triggers that upgrade check when it moves a tag past its pin, so the pins follow Docker's rebuilds - and the dhi.io apt repository moving with them - within hours rather than drift behind it. Every pinned and mirrored digest keeps a tag of its own, so a pinned image never becomes untagged. The hardened images keep stock Debian's apt sources beside dhi.io, and apt took whichever offered the higher version, mixing Debian builds into an image whose dependencies were built by Docker. dhi.io is now preferred whenever it publishes the package. Generated-by: Claude Opus 5 * Let dhi.io's package versions win over the image's own Docker renumbered its builds ("1.0.8-6+dhi2" became "1.0.8-6+deb13u0+dhi2", which sorts lower) and its apt repository moved to the new numbers before its images did. Every package depending on a renumbered build - bzip2, libffi-dev, libgpg-error-dev among them - is then uninstallable, because apt will not replace the image's higher-numbered copy with the repository's lower-numbered one, and the CI image build fails (docker-hardened-images/catalog#689). Every package in the image comes from dhi.io, so letting its repository decide their versions is safe, and it keeps the build working through such a renumbering. Generated-by: Claude Opus 5 * Move the base images to Docker's current Python patch releases Docker stops rebuilding a Python patch release once it publishes the next, so the 3.11.17, 3.12.15 and 3.13.16 images still carry the old package numbering that the dhi.io apt repository has moved past, and installing packages on them fails (docker-hardened-images/catalog#689). Docker fixed it in the images of the current patch releases. Generated with the Python part of the upgrade check, which also pins the new images to the digests the mirror serves for them. Generated-by: Claude Opus 5 * Compare the registry host exactly in the mirror test Generated-by: Claude Opus 5 * Lower the dhi.io apt pin below 1000 so dependencies can resolve At priority 1001 the Package:* dhi.io preference forces dhi.io's build even as a downgrade, so apt keeps dhi.io's libpq5 17.11 and postgresql-client-18 (which needs libpq5 >= 18.6 from PGDG) cannot be installed. Below 1000 the preference still favours dhi.io for the packages it publishes but lets apt take a newer version from another repository to satisfy a dependency. The forced "downgrade" the >1000 priority handled no longer arises now the base image is pinned to a digest CI has passed on. * Rank the PostgreSQL apt repository above the dhi.io preference install_postgres adds the PGDG repository, but the hardened image's Package:* dhi.io preference outranks Debian's default, so apt kept dhi.io's libpq and postgresql-client-18 (which needs a newer libpq5 than dhi.io carries) failed with held broken packages. Pinning the PostgreSQL origin above the dhi.io preference lets apt take libpq from PGDG to satisfy the client. * Use US spelling favors to pass the docs spellcheck The docker-stack docs spellcheck rejects the British spelling favours in build.rst; use the US spelling there and in the matching install-script comments. --------- Co-authored-by: Rahul Vats <43964496+vatsrahul1001@users.noreply.github.com>
141 lines
6.5 KiB
YAML
141 lines
6.5 KiB
YAML
# Licensed to the Apache Software Foundation (ASF) under one
|
|
# or more contributor license agreements. See the NOTICE file
|
|
# distributed with this work for additional information
|
|
# regarding copyright ownership. The ASF licenses this file
|
|
# to you under the Apache License, Version 2.0 (the
|
|
# "License"); you may not use this file except in compliance
|
|
# with the License. You may obtain a copy of the License at
|
|
#
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
#
|
|
# Unless required by applicable law or agreed to in writing,
|
|
# software distributed under the License is distributed on an
|
|
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
# KIND, either express or implied. See the License for the
|
|
# specific language governing permissions and limitations
|
|
# under the License.
|
|
#
|
|
---
|
|
name: Mirror hardened base images
|
|
# Copies the Docker Hardened Image (https://dhi.io) tags that Airflow images are built on into a
|
|
# public ghcr.io repository owned by the project.
|
|
#
|
|
# Pulling from dhi.io requires a Docker Hub login. Requiring one to build an Airflow image would
|
|
# mean every contributor and every CI job needs Docker Hub credentials, so the tags are mirrored
|
|
# instead and `BASE_IMAGE` defaults to the mirror. The images are Apache-2.0 licensed, so
|
|
# redistributing them is allowed.
|
|
#
|
|
# `docker buildx imagetools create` copies the multi-platform manifest between registries without
|
|
# pulling the layers into the runner, so a refresh of all Python versions is cheap.
|
|
#
|
|
# The builds do not use these moving tags: they are pinned to digests that only "breeze ci upgrade"
|
|
# moves, in a PR that has to pass the full CI. Docker rebuilds the images in place and moves the
|
|
# dhi.io apt repository on together with them, so a pin left behind soon stops matching what apt
|
|
# installs. A run that moves a tag past its pin therefore triggers that upgrade check, and the pins
|
|
# follow Docker's rebuilds within hours.
|
|
on: # yamllint disable-line rule:truthy
|
|
workflow_dispatch:
|
|
inputs:
|
|
trigger-upgrade-check:
|
|
description: >-
|
|
Run the main upgrade check when a tag moves past its pin. "breeze ci upgrade" for main turns
|
|
it off, as it is the upgrade that pins the images.
|
|
type: boolean
|
|
default: true
|
|
schedule:
|
|
- cron: '27 */6 * * *'
|
|
permissions:
|
|
contents: read
|
|
concurrency:
|
|
group: mirror-hardened-base-images
|
|
cancel-in-progress: false
|
|
jobs:
|
|
# Picks the runner the way CI does: RunsOn in apache/airflow, public runners when the repository
|
|
# variable USE_PUBLIC_RUNNERS is "true".
|
|
build-info:
|
|
name: "Build info"
|
|
runs-on: ["ubuntu-slim"]
|
|
timeout-minutes: 10
|
|
if: github.repository == 'apache/airflow' && github.ref == 'refs/heads/main'
|
|
permissions:
|
|
contents: read
|
|
outputs:
|
|
runner-type: ${{ steps.selective-checks.outputs.runner-type }}
|
|
steps:
|
|
- name: "Checkout ${{ github.ref }} ( ${{ github.sha }} )"
|
|
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
with:
|
|
fetch-depth: 2
|
|
persist-credentials: false
|
|
- name: "Install Breeze"
|
|
uses: ./.github/actions/breeze
|
|
with:
|
|
free-space: "false"
|
|
- name: "Save github context to file"
|
|
# Same as in ci-amd.yml: a scheduled or dispatched run has no attacker-controlled context, and
|
|
# the single-quoted heredoc disables every shell expansion of the JSON anyway.
|
|
shell: bash
|
|
run: | # zizmor: ignore[template-injection]
|
|
cat > "${RUNNER_TEMP}/github_context.json" << '__GITHUB_CONTEXT_END__'
|
|
${{ toJson(github) }}
|
|
__GITHUB_CONTEXT_END__
|
|
- name: "Selective checks"
|
|
id: selective-checks
|
|
env:
|
|
COMMIT_REF: "${{ github.sha }}"
|
|
VERBOSE: "false"
|
|
GITHUB_CONTEXT_INPUT: "${{ runner.temp }}/github_context.json"
|
|
PLATFORM: "linux/amd64"
|
|
USE_PUBLIC_RUNNERS: "${{ vars.USE_PUBLIC_RUNNERS }}"
|
|
run: breeze ci selective-check 2>> ${GITHUB_OUTPUT}
|
|
mirror:
|
|
name: "Mirror hardened base images"
|
|
needs: [build-info]
|
|
# Copies manifests registry-to-registry without pulling layers, so the smallest class is enough.
|
|
runs-on: ${{ format(fromJSON(needs.build-info.outputs.runner-type)[0], '2+4', '8+16') }}
|
|
timeout-minutes: 30
|
|
# Never runs on forks - they have neither the credentials nor the package to push to. Only main
|
|
# pushes: the mirror is the default BASE_IMAGE of every build, so a manual dispatch from any other
|
|
# branch must not be able to replace it. Main mirrors every Python version an active release
|
|
# branch still builds on, so the release branches need no runs of their own.
|
|
if: github.repository == 'apache/airflow' && github.ref == 'refs/heads/main'
|
|
permissions:
|
|
actions: write
|
|
contents: read
|
|
packages: write
|
|
steps:
|
|
- name: "Cleanup repo"
|
|
shell: bash
|
|
run: sudo rm -rf ${GITHUB_WORKSPACE}/*
|
|
- name: "Checkout ${{ github.ref }} ( ${{ github.sha }} )"
|
|
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
with:
|
|
persist-credentials: false
|
|
- name: "Install Breeze"
|
|
uses: ./.github/actions/breeze
|
|
# dhi.io accepts any Docker Hub account - the free tier covers the images we mirror - so this
|
|
# reuses the credentials the DockerHub release workflows already use.
|
|
- name: "Login to dhi.io"
|
|
env:
|
|
DOCKERHUB_USER: ${{ secrets.DOCKERHUB_USER }}
|
|
DOCKERHUB_TOKEN: ${{ secrets.DOCKERHUB_TOKEN }}
|
|
run: echo "${DOCKERHUB_TOKEN}" | docker login dhi.io -u "${DOCKERHUB_USER}" --password-stdin
|
|
- name: "Login to ghcr.io"
|
|
env:
|
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
ACTOR: ${{ github.actor }}
|
|
run: echo "${GITHUB_TOKEN}" | docker login ghcr.io -u "${ACTOR}" --password-stdin
|
|
- name: "Mirror base images"
|
|
id: mirror
|
|
run: breeze release-management mirror-base-images
|
|
# Only main's pins: release branches move theirs on their own upgrade schedule. Also after a
|
|
# failed mirror step: a tag it moved before failing stays moved, so a re-run would not see it
|
|
# move again.
|
|
- name: "Trigger the upgrade check to move the pinned base images"
|
|
if: >-
|
|
!cancelled() && steps.mirror.outputs.moved-past-pins == 'true' &&
|
|
(github.event_name == 'schedule' || inputs.trigger-upgrade-check)
|
|
env:
|
|
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
run: gh workflow run scheduled-upgrade-check-main.yml --repo "${GITHUB_REPOSITORY}" --ref main
|