From 5c11a6cf4486e052b33bd4f7973934c79ea729ed Mon Sep 17 00:00:00 2001 From: Jose Henrique Date: Wed, 8 Jul 2026 19:57:15 -0300 Subject: [PATCH] feat: reusable build-and-push and deploy-restart composite actions - build-and-push: multi-arch Docker build via remote Buildx builder over SSH - deploy-restart: kubectl rollout restart with kubeconfig validation - README with usage examples and required secrets --- README.md | 81 ++++++++++++++++++++++++++++++++++ build-and-push/action.yaml | 89 ++++++++++++++++++++++++++++++++++++++ deploy-restart/action.yaml | 67 ++++++++++++++++++++++++++++ 3 files changed, 237 insertions(+) create mode 100644 README.md create mode 100644 build-and-push/action.yaml create mode 100644 deploy-restart/action.yaml diff --git a/README.md b/README.md new file mode 100644 index 0000000..0f2df47 --- /dev/null +++ b/README.md @@ -0,0 +1,81 @@ +# pipeline-actions + +Reusable composite actions for Gitea Actions CI/CD pipelines in the homelab. + +## Actions + +### `build-and-push` + +Builds and pushes a multi-architecture Docker image using a remote Buildx builder over SSH. + +```yaml +jobs: + build: + runs-on: ubuntu-amd64 + steps: + - uses: actions/checkout@v4 + - uses: ivanch/pipeline-actions/build-and-push@main + with: + image: git.ivanch.me/ivanch/my-app + registry_password: ${{ secrets.REGISTRY_PASSWORD }} + ssh_key: ${{ secrets.SSH_KEY_DOCKERBUILD }} + # optional — these have sensible defaults: + # registry_host: git.ivanch.me + # registry_username: ivanch + # platforms: linux/amd64,linux/arm64 + # build_context: . + # build_dockerfile: Dockerfile + # docker_host: docker-build.haven + # docker_user: root +``` + +| Input | Required | Default | Description | +|---|---|---|---| +| `image` | ✅ | — | Full image reference without tag (`:latest` is appended) | +| `registry_password` | ✅ | — | Registry password/token (use secrets) | +| `ssh_key` | ✅ | — | SSH private key for the remote builder (use secrets) | +| `registry_host` | ❌ | `git.ivanch.me` | Container registry hostname | +| `registry_username` | ❌ | `ivanch` | Registry username | +| `platforms` | ❌ | `linux/amd64,linux/arm64` | Target build platforms | +| `build_context` | ❌ | `.` | Docker build context | +| `build_dockerfile` | ❌ | `Dockerfile` | Dockerfile path | +| `docker_host` | ❌ | `docker-build.haven` | Remote builder hostname | +| `docker_user` | ❌ | `root` | SSH user for remote builder | + +--- + +### `deploy-restart` + +Validates a kubeconfig, installs kubectl, and performs a `rollout restart` of a Kubernetes Deployment. + +```yaml +jobs: + deploy: + runs-on: ubuntu-amd64 + needs: build + steps: + - uses: ivanch/pipeline-actions/deploy-restart@main + with: + kube_config: ${{ secrets.KUBE_CONFIG }} + deployment_name: my-app + # optional: + # namespace: default + # kube_version: stable +``` + +| Input | Required | Default | Description | +|---|---|---|---| +| `kube_config` | ✅ | — | Full kubeconfig YAML (use secrets) | +| `deployment_name` | ✅ | — | Deployment name to restart | +| `namespace` | ❌ | `default` | Kubernetes namespace | +| `kube_version` | ❌ | `stable` | kubectl version (`stable` or e.g. `v1.31.0`) | + +## Required Secrets + +Consumer repositories need these secrets configured in Gitea: + +| Secret | Used by | Purpose | +|---|---|---| +| `REGISTRY_PASSWORD` | `build-and-push` | Container registry password/token | +| `SSH_KEY_DOCKERBUILD` | `build-and-push` | SSH private key for `docker-build.haven` | +| `KUBE_CONFIG` | `deploy-restart` | Full kubeconfig YAML for cluster access | diff --git a/build-and-push/action.yaml b/build-and-push/action.yaml new file mode 100644 index 0000000..a1fa8c8 --- /dev/null +++ b/build-and-push/action.yaml @@ -0,0 +1,89 @@ +name: Build and Push Multi-Arch Image +description: Log in to a container registry, set up a remote Docker Buildx builder over SSH, and build + push a multi-arch image. + +inputs: + registry_host: + description: Hostname of the container registry + required: true + default: git.ivanch.me + registry_username: + description: Username for the container registry + required: true + default: ivanch + registry_password: + description: Password / token for the container registry (pass via secrets) + required: true + image: + description: Full image reference (host/path/name) without tag — :latest is appended + required: true + platforms: + description: Comma-separated list of target platforms + required: false + default: linux/amd64,linux/arm64 + build_context: + description: Docker build context path + required: false + default: . + build_dockerfile: + description: Path to the Dockerfile (relative to context) + required: false + default: Dockerfile + ssh_key: + description: SSH private key for the remote Docker builder host (pass via secrets) + required: true + docker_host: + description: Hostname of the remote Docker Buildx builder + required: false + default: docker-build.haven + docker_user: + description: SSH user for the remote Docker builder + required: false + default: root + +runs: + using: composite + steps: + - name: Log in to Container Registry + shell: bash + env: + REGISTRY_HOST: ${{ inputs.registry_host }} + REGISTRY_USERNAME: ${{ inputs.registry_username }} + REGISTRY_PASSWORD: ${{ inputs.registry_password }} + run: | + echo "${REGISTRY_PASSWORD}" \ + | docker login "${REGISTRY_HOST}" \ + -u "${REGISTRY_USERNAME}" \ + --password-stdin + + - name: Set up SSH key for remote builder + shell: bash + env: + SSH_KEY: ${{ inputs.ssh_key }} + DOCKER_HOST: ${{ inputs.docker_host }} + run: | + mkdir -p ~/.ssh + echo "${SSH_KEY}" > ~/.ssh/id_ed25519 + chmod 600 ~/.ssh/id_ed25519 + ssh-keyscan "${DOCKER_HOST}" >> ~/.ssh/known_hosts + + - name: Set up remote Docker Buildx builder + shell: bash + env: + DOCKER_HOST: ${{ inputs.docker_host }} + DOCKER_USER: ${{ inputs.docker_user }} + run: | + docker context create remote-builder \ + --docker "host=ssh://${DOCKER_USER}@${DOCKER_HOST}" + docker context use remote-builder + docker buildx inspect --bootstrap + + - name: Build and Push Multi-Arch Image + uses: docker/build-push-action@v6 + with: + push: true + context: ${{ inputs.build_context }} + file: ${{ inputs.build_dockerfile }} + builder: remote-builder + platforms: ${{ inputs.platforms }} + tags: | + ${{ inputs.image }}:latest diff --git a/deploy-restart/action.yaml b/deploy-restart/action.yaml new file mode 100644 index 0000000..e44e338 --- /dev/null +++ b/deploy-restart/action.yaml @@ -0,0 +1,67 @@ +name: Deploy Restart (kubectl rollout) +description: Validate KUBE_CONFIG, install kubectl, and perform a rollout restart of a Kubernetes deployment. + +inputs: + kube_config: + description: Full kubeconfig YAML content (pass via secrets) + required: true + deployment_name: + description: Name of the Kubernetes Deployment to restart + required: true + namespace: + description: Kubernetes namespace of the deployment + required: false + default: default + kube_version: + description: Kubernetes version to download (stable, or a specific version like v1.31.0) + required: false + default: stable + +runs: + using: composite + steps: + - name: Check KUBE_CONFIG validity + shell: bash + env: + KUBE_CONFIG: ${{ inputs.kube_config }} + run: | + if [ -z "${KUBE_CONFIG}" ] || [ "${KUBE_CONFIG}" = "" ] || [ "${KUBE_CONFIG// }" = "" ]; then + echo "KUBE_CONFIG is not set or is empty." + exit 1 + fi + + - name: Check out repository + uses: actions/checkout@v4 + + - name: Download and install kubectl + shell: bash + env: + KUBE_VERSION: ${{ inputs.kube_version }} + run: | + apt-get update -y + apt-get install -y curl + if [ "${KUBE_VERSION}" = "stable" ]; then + KUBE_VER="$(curl -L -s https://dl.k8s.io/release/stable.txt)" + else + KUBE_VER="${KUBE_VERSION}" + fi + curl -LO "https://dl.k8s.io/release/${KUBE_VER}/bin/linux/amd64/kubectl" + install -m 0755 kubectl /usr/local/bin/kubectl + kubectl version --client + + - name: Set up kubeconfig + shell: bash + env: + KUBE_CONFIG: ${{ inputs.kube_config }} + run: | + echo "${KUBE_CONFIG}" > kubeconfig.yaml + kubectl --kubeconfig=kubeconfig.yaml cluster-info + + - name: Rollout restart + shell: bash + env: + DEPLOYMENT_NAME: ${{ inputs.deployment_name }} + NAMESPACE: ${{ inputs.namespace }} + run: | + kubectl --kubeconfig=kubeconfig.yaml rollout restart \ + deployment "${DEPLOYMENT_NAME}" -n "${NAMESPACE}"