diff --git a/.github/workflows/flow-pull-request-checks.yaml b/.github/workflows/flow-pull-request-checks.yaml index b6be462..d2e621d 100644 --- a/.github/workflows/flow-pull-request-checks.yaml +++ b/.github/workflows/flow-pull-request-checks.yaml @@ -51,3 +51,18 @@ jobs: docker-version: 24.0.9 platforms: linux/amd64 dry-run-enabled: true + + scaleset-images: + name: ScaleSet Images + uses: ./.github/workflows/zxc-build-scaleset-images.yaml + needs: + - versions + with: + base-os-image: ubuntu-22.04 + runner-version: ${{ needs.versions.outputs.runner }} + runner-container-hooks-version: ${{ needs.versions.outputs.hooks }} + docker-version: 25.0.5 + docker-buildx-version: 0.16.2 + gh-cli-version: 2.54.0 + platforms: linux/amd64 + dry-run-enabled: true diff --git a/.github/workflows/flow-release-scaleset-images.yaml b/.github/workflows/flow-release-scaleset-images.yaml new file mode 100644 index 0000000..3116624 --- /dev/null +++ b/.github/workflows/flow-release-scaleset-images.yaml @@ -0,0 +1,226 @@ +## +# Copyright (C) 2024 Hedera Hashgraph, LLC +# +# Licensed 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: "Release ScaleSet Images" +on: + workflow_dispatch: + inputs: + runner-version: + description: "Runner Version:" + type: string + required: true + + ## Upstream Github Action Runner Container Hooks Version + runner-container-hooks-version: + description: "Container Hooks Version:" + type: string + required: false + default: "0.6.1" + + ## Upstream Docker Version + docker-version: + description: "Docker Version:" + type: string + required: false + default: "25.0.5" + + ## Upstream Docker Buildx Version + docker-buildx-version: + description: "Docker Buildx Version:" + type: string + required: false + default: "0.16.2" + + ## Upstream Github CLI Version + gh-cli-version: + description: "GitHub CLI Version:" + type: string + required: false + default: "2.54.0" + + ## Linux Architectures for Multi-Arch Builds + platforms: + description: "Platforms:" + type: string + required: false + default: "linux/amd64" + + dry-run-enabled: + description: "Perform Dry Run" + type: boolean + required: false + default: true + +defaults: + run: + shell: bash + +permissions: + id-token: write + contents: read + packages: write + +jobs: + versions: + name: Upstream Versions + uses: ./.github/workflows/zxc-retrieve-upstream-versions.yaml + with: + explicit-runner-version: ${{ github.event.inputs.runner-version }} + explicit-hooks-version: ${{ github.event.inputs.runner-container-hooks-version }} + + safety-checks: + name: Safety Checks + runs-on: ubuntu-22.04 + needs: + - versions + steps: + - name: Harden Runner + uses: step-security/harden-runner@5c7944e73c4c2a096b17a9cb74d65b6c2bbafbde # v2.9.1 + with: + egress-policy: audit + + - name: Checkout Code + uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 + + - name: Install GH CLI + uses: sersoft-gmbh/setup-gh-cli-action@2d02c06e284b7d55e954d6d6406e7a886f45a818 # v2.0.1 + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + + - name: Authorize GH CLI + run: echo "${{ secrets.GITHUB_TOKEN }}" | gh auth login --with-token + + - name: Check for Existing Releases + run: | + if gh release view scaleset-v${{ needs.versions.outputs.runner }} --json id >/dev/null 2>&1; then + echo "::error title=Release Version::Release scaleset-v${{ needs.versions.outputs.runner }} already exists and may not be redeployed." + exit 1 + fi + + scaleset-image: + name: ScaleSet Image + uses: ./.github/workflows/zxc-build-scaleset-images.yaml + needs: + - versions + - safety-checks + strategy: + matrix: + base-os-image: + - ubuntu-22.04 + with: + custom-job-label: "Release" + base-os-image: ${{ matrix.base-os-image }} + runner-version: ${{ needs.versions.outputs.runner }} + runner-container-hooks-version: ${{ needs.versions.outputs.hooks }} + docker-version: ${{ github.event.inputs.docker-version || '25.0.5' }} + docker-buildx-version: ${{ github.event.inputs.docker-buildx-version || '0.16.2' }} + gh-cli-version: ${{ github.event.inputs.gh-cli-version || '2.54.0' }} + platforms: ${{ github.event.inputs.platforms || 'linux/amd64' }} + dry-run-enabled: ${{ github.event.inputs.dry-run-enabled == 'true' || github.ref_name != 'main' }} + + update-version: + name: Update Version + runs-on: ubuntu-22.04 + needs: + - versions + - scaleset-image + if: ${{ github.event.inputs.dry-run-enabled != 'true' && github.ref_name == 'main' }} + steps: + - name: Harden Runner + uses: step-security/harden-runner@5c7944e73c4c2a096b17a9cb74d65b6c2bbafbde # v2.9.1 + with: + egress-policy: audit + + - name: Checkout Code + uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 + with: + fetch-depth: 0 + token: ${{ secrets.GH_ACCESS_TOKEN }} + + - name: Import GPG key + id: gpg_key + uses: crazy-max/ghaction-import-gpg@01dd5d3ca463c7f10f7f4f7b4f177225ac661ee4 # v6.1.0 + with: + gpg_private_key: ${{ secrets.GPG_KEY_CONTENTS }} + passphrase: ${{ secrets.GPG_KEY_PASSPHRASE }} + git_config_global: true + git_user_signingkey: true + git_commit_gpgsign: true + git_tag_gpgsign: false + + - name: Update Version Descriptor + working-directory: legacy/runner + run: printf "RUNNER_VERSION=%s\nRUNNER_CONTAINER_HOOKS_VERSION=%s\n" "${{ needs.versions.outputs.runner }}" "${{ needs.versions.outputs.hooks }}" >VERSION + + - name: Commit Changes + uses: actions-js/push@5a7cbd780d82c0c937b5977586e641b2fd94acc5 # v1.5 + with: + github_token: ${{ secrets.GH_ACCESS_TOKEN }} + author_name: ${{ vars.GIT_USER_NAME }} + author_email: ${{ vars.GIT_USER_EMAIL }} + message: "chore(release): scaleset-v${{ needs.versions.outputs.runner }} [skip ci]" + + finalize-release: + name: Finalize Release + runs-on: ubuntu-22.04 + needs: + - versions + - update-version + steps: + - name: Harden Runner + uses: step-security/harden-runner@5c7944e73c4c2a096b17a9cb74d65b6c2bbafbde # v2.9.1 + with: + egress-policy: audit + + - name: Checkout Code + uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 + with: + ref: ${{ github.ref_name }} + fetch-depth: 0 + token: ${{ secrets.GH_ACCESS_TOKEN }} + + - name: Import GPG key + id: gpg_key + uses: crazy-max/ghaction-import-gpg@01dd5d3ca463c7f10f7f4f7b4f177225ac661ee4 # v6.1.0 + with: + gpg_private_key: ${{ secrets.GPG_KEY_CONTENTS }} + passphrase: ${{ secrets.GPG_KEY_PASSPHRASE }} + git_config_global: true + git_user_signingkey: true + git_commit_gpgsign: true + git_tag_gpgsign: true + + - name: Install GH CLI + uses: sersoft-gmbh/setup-gh-cli-action@2d02c06e284b7d55e954d6d6406e7a886f45a818 # v2.0.1 + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + + - name: Authorize GH CLI + run: echo "${{ secrets.GITHUB_TOKEN }}" | gh auth login --with-token + + - name: Fetch Upstream Release Info + run: | + RELEASE_URL="$(gh release view v${{ needs.versions.outputs.runner }} --json url -R actions/runner | jq -r '.url')" + gh release view v${{ needs.versions.outputs.runner }} --json body -R actions/runner | jq -r '.body' > .github/RELEASE_BODY.md + printf "\n\n### _Release Notes have been imported from the [%s](%s) release in the upstream repository._\n\n" "v${{ needs.versions.outputs.runner }}" "${RELEASE_URL}" >> .github/RELEASE_BODY.md + + - name: Create Release + uses: ncipollo/release-action@2c591bcc8ecdcd2db72b97d6147f871fcd833ba5 # v1.14.0 + with: + token: ${{ secrets.GH_ACCESS_TOKEN }} + commit: ${{ github.ref_name }} + tag: scaleset-v${{ needs.versions.outputs.runner }} + bodyFile: .github/RELEASE_BODY.md diff --git a/.github/workflows/zxc-build-scaleset-images.yaml b/.github/workflows/zxc-build-scaleset-images.yaml new file mode 100644 index 0000000..0adfdae --- /dev/null +++ b/.github/workflows/zxc-build-scaleset-images.yaml @@ -0,0 +1,264 @@ +## +# Copyright (C) 2024 Hedera Hashgraph, LLC +# +# Licensed 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: "ZXC: Build ScaleSet Images" +# This reusable component is called by the following workflows: +# - .github/workflows/flow-pull-request-checks.yaml +# - .github/workflows/flow-build-application.yaml + +on: + workflow_call: + inputs: + ## Base Operating System Image + ## Options include: + ## - ubuntu-22.04 + base-os-image: + description: "Operating System Image:" + type: string + required: true + + ## Upstream Github Action Runner Version + runner-version: + description: "Runner Version:" + type: string + required: true + + ## Upstream Github Action Runner Container Hooks Version + runner-container-hooks-version: + description: "Container Hooks Version:" + type: string + required: false + default: "0.6.1" + + ## Upstream Docker Version + docker-version: + description: "Docker Version:" + type: string + required: false + default: "25.0.5" + + ## Upstream Docker Buildx Version + docker-buildx-version: + description: "Docker Buildx Version:" + type: string + required: false + default: "0.16.2" + + # Upstream Github CLI Version + gh-cli-version: + description: "Github CLI Version:" + type: string + required: false + default: "2.54.0" + + ## Linux Architectures for Multi-Arch Builds + platforms: + description: "Platforms:" + type: string + required: false + default: "linux/amd64" + + dry-run-enabled: + description: "Perform Dry Run" + type: boolean + required: false + default: false + + custom-job-label: + description: "Custom Job Label:" + type: string + required: false + default: "Build" + +defaults: + run: + shell: bash + +env: + TOOL_CACHE_ARTIFACT_NAME: "tool-cache.tar.gz" + +permissions: + id-token: write + contents: read + packages: write + +jobs: + create-tool-cache: + name: Create Tool Cache + runs-on: ubuntu-22.04 + steps: + - name: Harden Runner + uses: step-security/harden-runner@5c7944e73c4c2a096b17a9cb74d65b6c2bbafbde # v2.9.1 + with: + egress-policy: audit + + - name: Checkout Code + uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 + + - name: Install WGet + run: sudo apt update && sudo apt install -y --no-install-recommends wget + + - name: Clear Hosted Tool Cache + run: rm -rvf "${{ runner.tool_cache }}"/* + + - name: Setup Python + uses: actions/setup-python@39cd14951b08e74b54015e9e001cdefcf80e669f # v5.1.1 + with: + python-version: '3.10' + + - name: Setup Google Cloud SDK + uses: google-github-actions/setup-gcloud@f0990588f1e5b5af6827153b93673613abdc6ec7 # v2.1.1 + + - name: Setup Java + uses: actions/setup-java@6a0805fcefea3d4657a47ac4c165951e33482018 # v4.2.2 + with: + distribution: temurin + java-version: 21 + + - name: Setup NodeJS 16 + uses: actions/setup-node@1e60f620b9541d16bece96c5465dc8ee9832be0b # v4.0.3 + with: + node-version: 16 + + - name: Setup NodeJS 18 + uses: actions/setup-node@1e60f620b9541d16bece96c5465dc8ee9832be0b # v4.0.3 + with: + node-version: 18 + + - name: Setup NodeJS 20 + uses: actions/setup-node@1e60f620b9541d16bece96c5465dc8ee9832be0b # v4.0.3 + with: + node-version: 20 + + - name: Setup NodeJS 22 + uses: actions/setup-node@1e60f620b9541d16bece96c5465dc8ee9832be0b # v4.0.3 + with: + node-version: 22 + + - name: Setup Kind + uses: helm/kind-action@0025e74a8c7512023d06dc019c617aa3cf561fde # v1.10.0 + with: + install_only: true + + - name: Setup Helm v3.12.3 + uses: azure/setup-helm@fe7b79cd5ee1e45176fcad797de68ecaf3ca4814 # v4.2.0 + with: + version: "v3.12.3" # helm version + + - name: Setup Helm Latest + uses: azure/setup-helm@fe7b79cd5ee1e45176fcad797de68ecaf3ca4814 # v4.2.0 + + - name: Setup QEmu Support + uses: docker/setup-qemu-action@49b3bc8e6bdd4a60e6116a5414239cba5943d3cf # v3.2.0 + + - name: Setup Docker Buildx Support + uses: docker/setup-buildx-action@988b5a0280414f521da01fcc63a27aeeb4b104db # v3.6.1 + with: + version: v0.16.2 + driver-opts: network=host + + - name: Archive Tool Cache + working-directory: ${{ runner.tool_cache }} + run: tar -czf ${{ env.TOOL_CACHE_ARTIFACT_NAME }} * + + - name: Upload Tool Cache + uses: actions/upload-artifact@834a144ee995460fba8ed112a2fc961b36a5ec5a # v4.3.6 + with: + name: "Tools (${{ inputs.base-os-image }})" + retention-days: 1 + path: ${{ runner.tool_cache }}/${{ env.TOOL_CACHE_ARTIFACT_NAME }} + + build-legacy-images: + name: ${{ inputs.custom-job-label || 'Build' }} + runs-on: ubuntu-22.04 + needs: + - create-tool-cache + steps: + - name: Harden Runner + uses: step-security/harden-runner@5c7944e73c4c2a096b17a9cb74d65b6c2bbafbde # v2.9.1 + with: + egress-policy: audit + + - name: Checkout Code + uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 + + - name: Download Tool Cache + uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 # v4.1.8 + with: + name: "Tools (${{ inputs.base-os-image }})" + path: ${{ github.workspace }}/scaleset/runner/tools + + - name: Unpack Tool Cache + run: | + tar -xzf ${{ github.workspace }}/scaleset/runner/tools/${{ env.TOOL_CACHE_ARTIFACT_NAME }} -C ${{ github.workspace }}/scaleset/runner/tools/ + rm -f ${{ github.workspace }}/scaleset/runner/tools/${{ env.TOOL_CACHE_ARTIFACT_NAME }} + + - name: Setup QEmu Support + uses: docker/setup-qemu-action@49b3bc8e6bdd4a60e6116a5414239cba5943d3cf # v3.2.0 + + - name: Setup Docker Buildx Support + uses: docker/setup-buildx-action@988b5a0280414f521da01fcc63a27aeeb4b104db # v3.6.1 + with: + version: v0.16.2 + driver-opts: network=host + + - name: Show Docker Version + run: docker version + + - name: Show Docker Info + run: docker info + + - name: Docker Login (Github) + uses: docker/login-action@9780b0c442fbb1117ed29e0efdff1e18412f7567 # v3.3.0 + if: ${{ inputs.dry-run-enabled != true }} + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Calculate Docker Registry + id: registry + run: | + DOCKER_REGISTRY_PREFIX="ghcr.io/${{ github.repository }}" + IMG_RESULT="push" + + if [[ "${{ inputs.dry-run-enabled }}" == "true" ]]; then + DOCKER_REGISTRY_PREFIX="local" + IMG_RESULT="load" + fi + + echo "prefix=${DOCKER_REGISTRY_PREFIX}" >>"${GITHUB_OUTPUT}" + echo "operation=${IMG_RESULT}" >>"${GITHUB_OUTPUT}" + + - name: Build Image + uses: docker/build-push-action@5cd11c3a4ced054e52742c5fd54dca954e0edd85 # v6.7.0 + with: + context: ${{ github.workspace }}/scaleset/runner + platforms: ${{ inputs.platforms }} + push: ${{ steps.registry.outputs.operation == 'push' }} + load: ${{ steps.registry.outputs.operation == 'load' }} + tags: | + ${{ steps.registry.outputs.prefix }}/scaleset-runner:${{ inputs.base-os-image }} + ${{ steps.registry.outputs.prefix }}/scaleset-runner:v${{ inputs.runner-version }}-${{ inputs.base-os-image }} + build-args: | + TARGETOS=linux + TARGETARCH=amd64 + RUNNER_VERSION=${{ inputs.runner-version }} + RUNNER_CONTAINER_HOOKS_VERSION=${{ inputs.runner-container-hooks-version }} + DOCKER_VERSION=${{ inputs.docker-version }} + BUILDX_VERSION=${{ inputs.docker-buildx-version }} + GH_CLI_VERSION=${{ inputs.gh-cli-version }} + diff --git a/scaleset/runner/Dockerfile b/scaleset/runner/Dockerfile new file mode 100644 index 0000000..ff792fe --- /dev/null +++ b/scaleset/runner/Dockerfile @@ -0,0 +1,107 @@ +# Source: https://github.com/dotnet/dotnet-docker +FROM mcr.microsoft.com/dotnet/runtime-deps:6.0-jammy as build + +ARG TARGETOS +ARG TARGETARCH +ARG RUNNER_VERSION +ARG RUNNER_CONTAINER_HOOKS_VERSION=0.6.1 +ARG DOCKER_VERSION=25.0.5 +ARG BUILDX_VERSION=0.16.2 + +RUN apt update -y && apt install curl unzip -y + +WORKDIR /actions-runner +RUN export RUNNER_ARCH=${TARGETARCH} \ + && if [ "$RUNNER_ARCH" = "amd64" ]; then export RUNNER_ARCH=x64 ; fi \ + && curl -f -L -o runner.tar.gz https://github.com/actions/runner/releases/download/v${RUNNER_VERSION}/actions-runner-${TARGETOS}-${RUNNER_ARCH}-${RUNNER_VERSION}.tar.gz \ + && tar xzf ./runner.tar.gz \ + && rm runner.tar.gz + +RUN curl -f -L -o runner-container-hooks.zip https://github.com/actions/runner-container-hooks/releases/download/v${RUNNER_CONTAINER_HOOKS_VERSION}/actions-runner-hooks-k8s-${RUNNER_CONTAINER_HOOKS_VERSION}.zip \ + && unzip ./runner-container-hooks.zip -d ./k8s \ + && rm runner-container-hooks.zip + +RUN export RUNNER_ARCH=${TARGETARCH} \ + && if [ "$RUNNER_ARCH" = "amd64" ]; then export DOCKER_ARCH=x86_64 ; fi \ + && if [ "$RUNNER_ARCH" = "arm64" ]; then export DOCKER_ARCH=aarch64 ; fi \ + && curl -fLo docker.tgz https://download.docker.com/${TARGETOS}/static/stable/${DOCKER_ARCH}/docker-${DOCKER_VERSION}.tgz \ + && tar zxvf docker.tgz \ + && rm -rf docker.tgz \ + && mkdir -p /usr/local/lib/docker/cli-plugins \ + && curl -fLo /usr/local/lib/docker/cli-plugins/docker-buildx \ + "https://github.com/docker/buildx/releases/download/v${BUILDX_VERSION}/buildx-v${BUILDX_VERSION}.linux-${TARGETARCH}" \ + && chmod +x /usr/local/lib/docker/cli-plugins/docker-buildx + +FROM mcr.microsoft.com/dotnet/runtime-deps:6.0-jammy + +ENV DEBIAN_FRONTEND=noninteractive +ENV RUNNER_MANUALLY_TRAP_SIG=1 +ENV ACTIONS_RUNNER_PRINT_LOG_TO_STDOUT=1 +ENV ImageOS=ubuntu22 + +# 'gpg-agent' and 'software-properties-common' are needed for the 'add-apt-repository' command that follows +RUN apt update -y \ + && apt install -y --no-install-recommends sudo lsb-release gpg-agent software-properties-common \ + && rm -rf /var/lib/apt/lists/* + +# Configure git-core/ppa based on guidance here: https://git-scm.com/download/linux +RUN add-apt-repository ppa:git-core/ppa \ + && apt update -y + +RUN adduser --disabled-password --gecos "" --uid 1001 runner \ + && groupadd docker --gid 123 \ + && usermod -aG sudo runner \ + && usermod -aG docker runner \ + && echo "%sudo ALL=(ALL:ALL) NOPASSWD:ALL" > /etc/sudoers \ + && echo "Defaults env_keep += \"DEBIAN_FRONTEND\"" >> /etc/sudoers + +WORKDIR /home/runner + +COPY --chown=runner:docker --from=build /actions-runner . +COPY --from=build /usr/local/lib/docker/cli-plugins/docker-buildx /usr/local/lib/docker/cli-plugins/docker-buildx + +RUN install -o root -g root -m 755 docker/* /usr/bin/ && rm -rf docker + +######################################### +## Begin Tool Cache Customization ## +######################################### +COPY --link --chown=1001:123 --chmod=777 tools /home/runner/_work/_tool +######################################### +## End Tool Cache Customization ## +######################################### + +######################################### +## Begin OS Software Customizations ## +######################################### +RUN apt-get update -y \ + && apt-get install -y --no-install-recommends \ + git \ + make \ + wget \ + gnupg2 \ + tree \ + curl \ + unzip \ + zip \ + gzip \ + jq \ + && apt-get clean \ + && rm -rf /var/lib/apt/lists/* + +RUN curl -fL https://install-cli.jfrog.io | sh \ + && sh -c "$(curl --location https://taskfile.dev/install.sh)" -- -d -b /usr/local/bin \ + && curl -L -o /usr/local/bin/semver https://raw.githubusercontent.com/fsaintjacques/semver-tool/master/src/semver \ + && chmod +x /usr/local/bin/semver + +ARG TARGETARCH +ARG GH_CLI_VERSION=2.54.0 +RUN export ARCH=${TARGETARCH} \ + && if [ "${ARCH}" = "i386" ]; then export ARCH=386 ; fi \ + && curl -sL https://github.com/cli/cli/releases/download/v${GH_CLI_VERSION}/gh_${GH_CLI_VERSION}_linux_${ARCH}.tar.gz \ + | tar -xz --wildcards --strip-components=2 -C /usr/local/bin "*/bin/gh" \ + && chmod +x /usr/local/bin/gh +######################################### +## End OS Software Customizations ## +######################################### + +USER runner