Skip to content
Open
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
83 changes: 83 additions & 0 deletions .github/workflows/ci-base-images.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
name: CI Base Images

on:
pull_request:
branches:
- release-1.x
paths:
- 'build/ci-images/**'
- '.github/workflows/ci-base-images.yaml'
workflow_dispatch:
inputs:
image_tag:
description: 'Immutable tag to publish for the pre-baked CI base images'
required: true
type: string
push:
description: 'Push images to GHCR'
required: true
default: true
type: boolean

permissions:
contents: read
packages: write

jobs:
build:
runs-on: ubuntu-24.04
strategy:
fail-fast: false
matrix:
image:
- name: backup-manager-base
package: tidb-operator%2Fbackup-manager-base
context: build/ci-images/backup-manager-base
- name: e2e-base
package: tidb-operator%2Fe2e-base
context: build/ci-images/e2e-base
steps:
- name: Check out code
uses: actions/checkout@v6

- name: Set up QEMU
uses: docker/setup-qemu-action@v3

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3

- name: Log in to GHCR
if: ${{ github.event_name == 'workflow_dispatch' && inputs.push }}
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}

- name: Compute image tag
id: meta
run: |
if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then
echo "tag=${{ inputs.image_tag }}" >> "$GITHUB_OUTPUT"
else
echo "tag=${{ github.sha }}" >> "$GITHUB_OUTPUT"
fi

- name: Build image
uses: docker/build-push-action@v6
with:
context: ${{ matrix.image.context }}
platforms: linux/amd64,linux/arm64
push: ${{ github.event_name == 'workflow_dispatch' && inputs.push }}
tags: ghcr.io/pingcap/tidb-operator/${{ matrix.image.name }}:${{ steps.meta.outputs.tag }}

- name: Try to make package public
if: ${{ github.event_name == 'workflow_dispatch' && inputs.push }}
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
gh api \
--method PUT \
"/orgs/${{ github.repository_owner }}/packages/container/${{ matrix.image.package }}/visibility" \
-f visibility=public || \
echo "::warning::Could not make GHCR package public automatically. If anonymous pulls fail, make ghcr.io/${{ github.repository_owner }}/tidb-operator/${{ matrix.image.name }} public in the package settings before using it from Prow."
64 changes: 64 additions & 0 deletions build/ci-images/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
# TiDB Operator CI base images

This directory contains Dockerfiles for pre-baked images used by `release-1.x` CI/CD.

The goal is to move flaky external binary downloads out of normal PR and release Docker builds. These images are built and pushed explicitly by `.github/workflows/ci-base-images.yaml`; normal CI should consume a pinned tag/digest instead of downloading tools during `make docker` or `make e2e-docker`.

## Images

### `backup-manager-base`

Base image for `images/tidb-backup-manager/Dockerfile` and `images/tidb-backup-manager/Dockerfile.e2e`.

Includes:

- `ghcr.io/pingcap-qe/bases/pingcap-base:v1.11.1`
- `ca-certificates`, `bind-utils`, `wget`, `nc`, `unzip`
- `rclone v1.71.2`
- `shush v1.5.5`

### `e2e-base`

Base image for `tests/images/e2e/Dockerfile`.

Includes:

- `debian:bookworm-slim`
- `ca-certificates`, `curl`, `git`, `openssl`, `default-mysql-client`, `unzip`, `python3`
- `kubectl v1.28.5`
- `helm v3.11.0`
- AWS CLI v2
- `/cert-manager.yaml` from cert-manager `v1.15.1`

## Publishing

Run the **CI Base Images** workflow manually with an immutable tag, for example:

```text
release-1.x-20260629
```

The workflow publishes:

```text
ghcr.io/pingcap/tidb-operator/backup-manager-base:<tag>
ghcr.io/pingcap/tidb-operator/e2e-base:<tag>
```

The workflow also attempts to mark the generated GHCR packages public so GitHub Actions and Prow can pull them without registry credentials. Depending on GitHub package permissions, this may need to be completed manually in the package settings.

Before updating consuming Dockerfiles, verify the images are pullable by CI/Prow and record the resulting digest.

## Update policy

Only rebuild these images when one of the pinned inputs changes:

- base image or OS package set
- `rclone` version
- `shush` version
- `kubectl` version
- `helm` version
- AWS CLI installer behavior/version
- cert-manager manifest version

Do not use mutable `latest` tags in consuming Dockerfiles.
23 changes: 23 additions & 0 deletions build/ci-images/backup-manager-base/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
FROM ghcr.io/pingcap-qe/bases/pingcap-base:v1.11.1@sha256:24ecefceae6b114e11f6ae675232af3fa4942c53011f807983ac5bff7a62e3d9

ARG TARGETARCH
ARG RCLONE_VERSION=v1.71.2
ARG SHUSH_VERSION=v1.5.5

RUN dnf install -y ca-certificates bind-utils wget nc unzip && dnf clean all

RUN set -eux; \
wget -nv "https://github.com/ncw/rclone/releases/download/${RCLONE_VERSION}/rclone-${RCLONE_VERSION}-linux-${TARGETARCH}.zip"; \
unzip "rclone-${RCLONE_VERSION}-linux-${TARGETARCH}.zip"; \
mv "rclone-${RCLONE_VERSION}-linux-${TARGETARCH}/rclone" /usr/local/bin/rclone; \
chmod 755 /usr/local/bin/rclone; \
rm -rf "rclone-${RCLONE_VERSION}-linux-${TARGETARCH}.zip" "rclone-${RCLONE_VERSION}-linux-${TARGETARCH}"

RUN set -eux; \
wget -nv "https://github.com/realestate-com-au/shush/releases/download/${SHUSH_VERSION}/shush_linux_${TARGETARCH}"; \
mv "shush_linux_${TARGETARCH}" /usr/local/bin/shush; \
chmod 755 /usr/local/bin/shush

RUN set -eux; \
env -u RCLONE_VERSION rclone version; \
command -v shush
40 changes: 40 additions & 0 deletions build/ci-images/e2e-base/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
FROM debian:bookworm-slim

ENV KUBECTL_VERSION=v1.28.5
ENV HELM_VERSION=v3.11.0
ENV CERT_MANAGER_VERSION=v1.15.1

ARG TARGETARCH

RUN apt-get update && \
apt-get install -y ca-certificates curl git openssl default-mysql-client unzip python3 && \
apt-get autoremove -y && \
apt-get clean -y && \
rm -rf /var/lib/apt/lists/*

RUN set -eux; \
curl -fsSL "https://storage.googleapis.com/kubernetes-release/release/${KUBECTL_VERSION}/bin/linux/${TARGETARCH}/kubectl" -o /usr/local/bin/kubectl; \
chmod +x /usr/local/bin/kubectl; \
curl -fsSL "https://get.helm.sh/helm-${HELM_VERSION}-linux-${TARGETARCH}.tar.gz" -o "helm-${HELM_VERSION}-linux-${TARGETARCH}.tar.gz"; \
tar -zxvf "helm-${HELM_VERSION}-linux-${TARGETARCH}.tar.gz"; \
mv "linux-${TARGETARCH}/helm" /usr/local/bin/helm; \
rm -rf "linux-${TARGETARCH}" "helm-${HELM_VERSION}-linux-${TARGETARCH}.tar.gz"

RUN set -eux; \
case "${TARGETARCH}" in \
amd64) aws_arch=x86_64 ;; \
arm64) aws_arch=aarch64 ;; \
*) echo "unsupported TARGETARCH=${TARGETARCH}" >&2; exit 1 ;; \
esac; \
curl -fsSL "https://awscli.amazonaws.com/awscli-exe-linux-${aws_arch}.zip" -o awscliv2.zip; \
unzip awscliv2.zip; \
./aws/install; \
rm -rf aws awscliv2.zip

RUN curl -fsSL "https://github.com/jetstack/cert-manager/releases/download/${CERT_MANAGER_VERSION}/cert-manager.yaml" -o /cert-manager.yaml

RUN set -eux; \
kubectl version --client=true --output=yaml; \
helm version --short; \
aws --version; \
test -s /cert-manager.yaml
Loading