├── .github └── workflows │ ├── link_check.yml │ └── update_images.yml ├── README.md ├── base ├── Containerfile ├── README.md ├── entrypoint.sh ├── get-runner-release.sh ├── get_github_app_token.sh ├── register.sh └── uid.sh ├── build-images.sh ├── buildah ├── Containerfile └── README.md ├── docs ├── github-app-authentication.md └── runner-token.md ├── dotnet-6.0 ├── Containerfile └── README.md ├── java ├── Containerfile └── README.md ├── k8s-tools ├── Containerfile ├── README.md └── install-tools.sh ├── node ├── Containerfile └── README.md └── pat-creation.png /.github/workflows/link_check.yml: -------------------------------------------------------------------------------- 1 | name: Link checker 2 | on: 3 | push: 4 | paths: 5 | - '**.md' 6 | pull_request: 7 | paths: 8 | -'**.md' 9 | 10 | jobs: 11 | markdown-link-check: 12 | name: Check links in markdown 13 | runs-on: ubuntu-20.04 14 | steps: 15 | - uses: actions/checkout@v2 16 | - uses: gaurav-nelson/github-action-markdown-link-check@v1 17 | with: 18 | use-verbose-mode: true 19 | -------------------------------------------------------------------------------- /.github/workflows/update_images.yml: -------------------------------------------------------------------------------- 1 | name: Update Runner Images 2 | on: 3 | push: 4 | pull_request: 5 | workflow_dispatch: 6 | 7 | 8 | env: 9 | REGISTRY_URL: quay.io/redhat-github-actions 10 | 11 | BASE_IMG_NAME: runner 12 | BASE_IMG_DIR: base 13 | 14 | BUILDAH_IMG_NAME: buildah-runner 15 | BUILDAH_IMG_DIR: buildah 16 | 17 | K8S_TOOLS_IMG_NAME: k8s-tools-runner 18 | K8S_TOOLS_IMG_DIR: k8s-tools 19 | 20 | NODE_IMG_NAME: node-runner-14 21 | NODE_IMG_DIR: node 22 | 23 | JAVA_IMG_NAME: java-runner-11 24 | JAVA_IMG_DIR: java 25 | 26 | jobs: 27 | update_images: 28 | name: Update images 29 | runs-on: ubuntu-20.04 30 | 31 | steps: 32 | - uses: actions/checkout@v2 33 | 34 | - uses: redhat-actions/common/commit-data@v1 35 | id: commit_data 36 | 37 | - uses: lots0logs/gh-action-get-changed-files@2.1.4 38 | id: get_changed_files 39 | with: 40 | token: ${{ secrets.GITHUB_TOKEN }} 41 | 42 | - name: Determine changed directories 43 | id: is_dir_changed 44 | uses: actions/github-script@v4 45 | with: 46 | script: | 47 | const changedFiles = ${{ steps.get_changed_files.outputs.all }}; 48 | console.log(`Changed files: ${JSON.stringify(changedFiles)}`); 49 | 50 | // console.log(`payload ${JSON.stringify(context.payload)}`); 51 | // console.log(`eventName ${JSON.stringify(context.eventName)}`); 52 | 53 | const BASE = "base"; 54 | const dirsChanged = { 55 | [BASE]: false, 56 | buildah: false, 57 | "k8s-tools": false, 58 | java: false, 59 | node: false, 60 | }; 61 | 62 | Object.keys(dirsChanged).forEach((dir) => { 63 | const changed = changedFiles.find((changedFile) => changedFile.startsWith(dir + "/")) != null; 64 | dirsChanged[dir] = changed; 65 | }); 66 | 67 | let rebuildAll = false; 68 | if (context.ref.startsWith("refs/tags/")) { 69 | console.log(`Tag build; all images will be rebuilt.`); 70 | rebuildAll = true; 71 | } 72 | else if (context.eventName === "workflow_dispatch") { 73 | console.log(`Workflow triggered by workflow_dispatch; all images will be rebuilt`); 74 | rebuildAll = true; 75 | } 76 | else if (dirsChanged[BASE]) { 77 | console.log("Base image changed; all images will be rebuilt."); 78 | rebuildAll = true; 79 | } 80 | 81 | Object.keys(dirsChanged).forEach((dir) => { 82 | const changed = rebuildAll || dirsChanged[dir]; 83 | 84 | const outputName = (dir + "_changed").toUpperCase(); 85 | console.log(`${outputName}=${changed}`) 86 | core.exportVariable(outputName, changed); 87 | }); 88 | 89 | // const anyChanged = Object.entries(dirsChanged).find(([k, v] => dirsChanged[k])); 90 | return dirsChanged; 91 | 92 | - name: Determine image tag 93 | shell: bash 94 | run: | 95 | export IMG_TAGS=latest 96 | export GIT_TAG="${{ steps.commit_data.outputs.tag }}" 97 | export BRANCH="${{ steps.commit_data.outputs.branch }}" 98 | 99 | if [[ -n "$GIT_TAG" ]]; then 100 | IMG_TAGS="$GIT_TAG" 101 | elif [[ -n "$BRANCH" ]]; then 102 | if [[ "$BRANCH" == "main" ]]; then 103 | IMG_TAGS="latest" 104 | else 105 | IMG_TAGS=$BRANCH 106 | fi 107 | else 108 | IMG_TAGS="${{ steps.commit_data.outputs.short_sha }}" 109 | fi 110 | 111 | echo "IMG_TAGS=$IMG_TAGS" >> $GITHUB_ENV 112 | echo "BRANCH=$BRANCH" >> $GITHUB_ENV 113 | echo "Tagging images with '$IMG_TAGS'" 114 | 115 | # The child image builds are done on the same machine so that 116 | # it doesn't have to pull the updated base image; it's already there locally. 117 | - name: Determine parent image name and tag 118 | shell: bash 119 | run: | 120 | export FIRST_TAG=$(echo "${{ env.IMG_TAGS }}" | awk '{ print $1 }') 121 | 122 | # export BASE_IMG=${{ env.REGISTRY_URL }}/${{ env.BASE_IMG_NAME }}:$FIRST_TAG 123 | export BASE_IMG=${{ env.BASE_IMG_NAME }}:$FIRST_TAG 124 | echo "Base image is '$BASE_IMG'" 125 | echo BASE_IMG=$BASE_IMG >> $GITHUB_ENV 126 | 127 | - name: Build base image 128 | if: env.BASE_CHANGED == 'true' 129 | uses: redhat-actions/buildah-build@v2 130 | id: build_base_img 131 | with: 132 | image: ${{ env.BASE_IMG_NAME }} 133 | tags: ${{ env.IMG_TAGS }} 134 | oci: true 135 | context: 136 | ${{ env.BASE_IMG_DIR }} 137 | dockerfiles: 138 | ${{ env.BASE_IMG_DIR }}/Containerfile 139 | 140 | - name: Push base image 141 | if: steps.commit_data.outputs.is_pr == 'false' && env.BASE_CHANGED == 'true' 142 | uses: redhat-actions/push-to-registry@v2 143 | with: 144 | image: ${{ env.BASE_IMG_NAME }} 145 | tags: ${{ env.IMG_TAGS }} 146 | registry: ${{ env.REGISTRY_URL }} 147 | username: ${{ secrets.REGISTRY_USER }} 148 | password: ${{ secrets.REGISTRY_PASSWORD }} 149 | 150 | - name: Determine if child images should be built 151 | run: | 152 | export BUILD_BASE_OUTCOME="${{ steps.build_base_img.outcome }}" 153 | 154 | if [[ $BUILD_BASE_OUTCOME == "success" ]] || [[ $BUILD_BASE_OUTCOME == "skipped" ]]; then 155 | echo "Base image was built or did not need to be built" 156 | echo "Child images will be built" 157 | export BUILD_CHILDREN=true 158 | else 159 | export BUILD_CHILDREN=false 160 | echo "Base image build failed" 161 | echo "Child image builds will be skipped." 162 | fi 163 | echo "BUILD_CHILDREN=$BUILD_CHILDREN" >> $GITHUB_ENV 164 | 165 | - name: Build buildah image 166 | if: | 167 | always() && 168 | env.BUILDAH_CHANGED == 'true' && 169 | env.BUILD_CHILDREN == 'true' 170 | id: build_buildah 171 | uses: redhat-actions/buildah-build@v2 172 | with: 173 | image: ${{ env.BUILDAH_IMG_NAME }} 174 | tags: ${{ env.IMG_TAGS }} 175 | oci: true 176 | context: 177 | ${{ env.BUILDAH_IMG_DIR }} 178 | dockerfiles: 179 | ${{ env.BUILDAH_IMG_DIR }}/Containerfile 180 | build-args: | 181 | BASE_IMG=${{ env.BASE_IMG }} 182 | 183 | - name: Push buildah image 184 | if: | 185 | steps.build_buildah.outcome == 'success' && 186 | steps.commit_data.outputs.is_pr == 'false' 187 | uses: redhat-actions/push-to-registry@v2 188 | with: 189 | image: ${{ env.BUILDAH_IMG_NAME }} 190 | tags: ${{ env.IMG_TAGS }} 191 | registry: ${{ env.REGISTRY_URL }} 192 | username: ${{ secrets.REGISTRY_USER }} 193 | password: ${{ secrets.REGISTRY_PASSWORD }} 194 | 195 | - name: Build K8s tools image 196 | if: | 197 | always() && 198 | env.K8S-TOOLS_CHANGED == 'true' && 199 | env.BUILD_CHILDREN == 'true' 200 | uses: redhat-actions/buildah-build@v2 201 | id: build_k8s 202 | with: 203 | image: ${{ env.K8S_TOOLS_IMG_NAME }} 204 | tags: ${{ env.IMG_TAGS }} 205 | oci: true 206 | context: 207 | ${{ env.K8S_TOOLS_IMG_DIR }} 208 | dockerfiles: 209 | ${{ env.K8S_TOOLS_IMG_DIR }}/Containerfile 210 | build-args: | 211 | BASE_IMG=${{ env.BASE_IMG }} 212 | 213 | - name: Push K8s tools image 214 | if: | 215 | steps.build_k8s.outcome == 'success' && 216 | steps.commit_data.outputs.is_pr == 'false' 217 | uses: redhat-actions/push-to-registry@v2 218 | with: 219 | image: ${{ env.K8S_TOOLS_IMG_NAME }} 220 | tags: ${{ env.IMG_TAGS }} 221 | registry: ${{ env.REGISTRY_URL }} 222 | username: ${{ secrets.REGISTRY_USER }} 223 | password: ${{ secrets.REGISTRY_PASSWORD }} 224 | 225 | - name: Build Node image 226 | if: | 227 | always() && 228 | env.NODE_CHANGED == 'true' && 229 | env.BUILD_CHILDREN == 'true' 230 | id: build_node 231 | uses: redhat-actions/buildah-build@v2 232 | with: 233 | image: ${{ env.NODE_IMG_NAME }} 234 | tags: ${{ env.IMG_TAGS }} 235 | oci: true 236 | context: 237 | ${{ env.NODE_IMG_DIR }} 238 | dockerfiles: 239 | ${{ env.NODE_IMG_DIR }}/Containerfile 240 | build-args: | 241 | BASE_IMG=${{ env.BASE_IMG }} 242 | 243 | - name: Push Node image 244 | if: | 245 | steps.build_node.outcome == 'success' && 246 | steps.commit_data.outputs.is_pr == 'false' 247 | uses: redhat-actions/push-to-registry@v2 248 | with: 249 | image: ${{ env.NODE_IMG_NAME }} 250 | tags: ${{ env.IMG_TAGS }} 251 | registry: ${{ env.REGISTRY_URL }} 252 | username: ${{ secrets.REGISTRY_USER }} 253 | password: ${{ secrets.REGISTRY_PASSWORD }} 254 | 255 | - name: Build Java image 256 | if: | 257 | always() && 258 | env.JAVA_CHANGED == 'true' && 259 | env.BUILD_CHILDREN == 'true' 260 | id: build_java 261 | uses: redhat-actions/buildah-build@v2 262 | with: 263 | image: ${{ env.JAVA_IMG_NAME }} 264 | tags: ${{ env.IMG_TAGS }} 265 | oci: true 266 | context: 267 | ${{ env.JAVA_IMG_DIR }} 268 | dockerfiles: 269 | ${{ env.JAVA_IMG_DIR }}/Containerfile 270 | build-args: | 271 | BASE_IMG=${{ env.BASE_IMG }} 272 | 273 | - name: Push Java image 274 | if: | 275 | steps.build_java.outcome == 'success' && 276 | steps.commit_data.outputs.is_pr == 'false' 277 | uses: redhat-actions/push-to-registry@v2 278 | with: 279 | image: ${{ env.JAVA_IMG_NAME }} 280 | tags: ${{ env.IMG_TAGS }} 281 | registry: ${{ env.REGISTRY_URL }} 282 | username: ${{ secrets.REGISTRY_USER }} 283 | password: ${{ secrets.REGISTRY_PASSWORD }} 284 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # OpenShift GitHub Actions Runners 2 | 3 | [![Update Runner Images](https://github.com/redhat-actions/openshift-actions-runner/actions/workflows/update_images.yml/badge.svg)](https://github.com/redhat-actions/openshift-actions-runner/actions/workflows/update_images.yml) 4 | [![Link checker](https://github.com/redhat-actions/openshift-actions-runner/actions/workflows/link_check.yml/badge.svg)](https://github.com/redhat-actions/openshift-actions-runner/actions/workflows/link_check.yml) 5 | 6 | [![Tag](https://img.shields.io/github/v/tag/redhat-actions/openshift-actions-runner)](https://github.com/redhat-actions/openshift-actions-runner/tags) 7 | [![Quay org](https://img.shields.io/badge/quay-redhat--github--actions-red)](https://quay.io/organization/redhat-github-actions) 8 | 9 | This repository contains Containerfiles for building container images that act as [self-hosted GitHub Action runners](https://docs.github.com/en/free-pro-team@latest/actions/hosting-your-own-runners/about-self-hosted-runners) that work on OpenShift. 10 | 11 | The [**OpenShift Actions Runner Chart**](https://github.com/redhat-actions/openshift-actions-runner-chart) is used to deploy these images into a cluster, and the [**OpenShift Actions Runner Installer**](https://github.com/redhat-actions/openshift-actions-runner-installer) is an Action to automate the chart install. 12 | 13 | ## Runners 14 | 1. The [**base runner**](./base) is based on Fedora. It is intended to have a fairly minimal tool set to keep the image size as small as possible. It has all the GitHub Actions Runner needs, plus a limited number of popular Unix command-line tools. 15 | 2. The [**buildah runner**](./buildah) extends the base runner to add `buildah` and `podman`. This runner requires permissions that are disabled for by default on OpenShift. See [the buildah image README](./buildah/#README.md) for details. 16 | 3. The [**K8s tools runner**](./k8s-tools) installs a set of CLIs used to work with Kubernetes. 17 | 4. The [**Node.js runner**](./node) includes a Node.js runtime. 18 | 5. The [**Java runner**](./java) includes a JDK and JRE. 19 | 20 | The idea is that the base runner can be extended to build larger, more complex images that have additional capabilities. Refer to [Creating your own runner image](./base#creating-your-own-runner-image). 21 | 22 | The images are hosted at [quay.io/redhat-github-actions](https://quay.io/redhat-github-actions/). 23 | 24 | While these images are developed for and tested on OpenShift, they do not contain any OpenShift specific code and should be compatible with any Kubernetes platform. 25 | 26 | ## Installing into a cluster 27 | Use the [**OpenShift Actions Runner Chart**](https://github.com/redhat-actions/openshift-actions-runner-chart) to deploy these runners into your cluster. 28 | 29 | 30 | ## Creating a Personal Access Token 31 | To register themselves with GitHub, the runners require a [GitHub Personal Access Token](https://docs.github.com/en/free-pro-team@latest/github/authenticating-to-github/creating-a-personal-access-token) (PAT) which has the `repo` permission scope. This is provided to the container through the `GITHUB_PAT` environment variable. 32 | - The user who created the token must have administrator permission on the organization/repository the runner will be added to. 33 | - If the runner will be for an organization, the token must also have the `admin:org` permission scope. 34 | - [See an example](./pat-creation.png). 35 | 36 | ## Building your own runner image 37 | See the [base image README](./base/#own-image). 38 | 39 | ## Running Locally 40 | You can run the images locally to test and develop. 41 | 42 | To launch and connect a runner to `redhat-actions/openshift-actions-runner` with the labels `local` and `podman`: 43 | ```sh 44 | podman run \ 45 | --env GITHUB_PAT=$GITHUB_PAT \ 46 | --env GITHUB_OWNER=redhat-actions \ 47 | --env GITHUB_REPOSITORY=openshift-actions-runner \ 48 | --env RUNNER_LABELS="local,podman" \ 49 | quay.io/redhat-github-actions/runner:latest 50 | ``` 51 | 52 | Or, to run a shell for debugging: 53 | ```sh 54 | podman run -it --entrypoint=/bin/bash quay.io/redhat-github-actions/runner:latest 55 | ``` 56 | 57 | ## Authenticating with a Runner Token 58 | A Runner Token can be used as an alternative to PAT or GitHub App authentication. 59 | 60 | Refer to [Authenticating with a Runner Token](./docs/runner-token.md). 61 | 62 | ## Running with Github App Authentication 63 | 64 | If you are able to use a GitHub App it is highly recommended over the PAT because you have greater control of the API permissions granted to it and you do not need a bot or service account. 65 | 66 | Refer to [Authenticating with GitHub App Authentication](./docs/github-app-authentication.md). 67 | 68 | 69 | 70 | ## GitHub Enterprise Support 71 | You can use any of the runners on your GitHub Enterprise server by overriding `GITHUB_DOMAIN` in the environment, using `podman run --env` or using the [chart](https://github.com/redhat-actions/openshift-actions-runner-chart). 72 | 73 | For example, if you set: 74 | ``` 75 | GITHUB_DOMAIN=github.mycompany.com 76 | ``` 77 | 78 | the runner entrypoint will then try and register itself with 79 | 80 | ``` 81 | https://github.mycompany.com/$GITHUB_OWNER/$GITHUB_REPOSITORY 82 | ``` 83 | 84 | and use the GitHub API at 85 | 86 | ``` 87 | https://github.mycompany.com/api/v3/ 88 | ``` 89 | 90 | ## Troubleshooting 91 | If the containers crash on startup, it is usually because one of the environment variables is missing or misconfigured. Make sure to read the container logs carefully to make sure the variables' values are set as expected. 92 | 93 | - If the container crashes with an HTTP 403 error, the `GITHUB_PAT` does not have the appropriate permissions. Refer to the [PAT guidelines](#pat-guidelines). 94 | - If the container crashes with an HTTP 404 error, the `GITHUB_OWNER` or `GITHUB_REPOSITORY` is incorrect or misspelled. 95 | - This will also happen if a private repository is selected which the `GITHUB_PAT` does not have permission to view. 96 | 97 | If you encounter any other issues, please [open an issue](https://github.com/redhat-actions/openshift-actions-runner/issues) and we will help you work through it. 98 | 99 | ## Credits 100 | This repository builds on the work done in [bbrowning/github-runner](https://github.com/bbrowning/github-runner), which is forked from [SanderKnape/github-runner](https://github.com/SanderKnape/github-runner). 101 | 102 | The Github App creation tutorial is heavily based on the excellent README in [actions-runner-controller/actions-runner-controller](https://github.com/actions-runner-controller/actions-runner-controller) 103 | -------------------------------------------------------------------------------- /base/Containerfile: -------------------------------------------------------------------------------- 1 | FROM fedora:35 2 | 3 | # Adapted from https://github.com/bbrowning/github-runner/blob/master/Dockerfile 4 | RUN dnf -y upgrade --security && \ 5 | dnf -y --setopt=skip_missing_names_on_install=False install \ 6 | curl git jq hostname procps findutils which openssl && \ 7 | dnf clean all 8 | 9 | # The UID env var should be used in child Containerfile. 10 | ENV UID=1000 11 | ENV GID=0 12 | ENV USERNAME="runner" 13 | 14 | # Create our user and their home directory 15 | RUN useradd -m $USERNAME -u $UID 16 | # This is to mimic the OpenShift behaviour of adding the dynamic user to group 0. 17 | RUN usermod -G 0 $USERNAME 18 | ENV HOME /home/${USERNAME} 19 | WORKDIR /home/${USERNAME} 20 | 21 | # Override these when creating the container. 22 | ENV GITHUB_PAT "" 23 | ENV GITHUB_APP_ID "" 24 | ENV GITHUB_APP_INSTALL_ID "" 25 | ENV GITHUB_APP_PEM "" 26 | ENV GITHUB_OWNER "" 27 | ENV GITHUB_REPOSITORY "" 28 | ENV RUNNER_WORKDIR /home/${USERNAME}/_work 29 | ENV RUNNER_GROUP "" 30 | ENV RUNNER_LABELS "" 31 | ENV EPHEMERAL "" 32 | 33 | # Allow group 0 to modify these /etc/ files since on openshift, the dynamically-assigned user is always part of group 0. 34 | # Also see ./uid.sh for the usage of these permissions. 35 | RUN chmod g+w /etc/passwd && \ 36 | touch /etc/sub{g,u}id && \ 37 | chmod -v ug+rw /etc/sub{g,u}id 38 | 39 | COPY --chown=${USERNAME}:0 get-runner-release.sh ./ 40 | RUN ./get-runner-release.sh 41 | RUN ./bin/installdependencies.sh 42 | 43 | # Set permissions so that we can allow the openshift-generated container user to access home. 44 | # https://docs.openshift.com/container-platform/3.3/creating_images/guidelines.html#openshift-container-platform-specific-guidelines 45 | RUN chown -R ${USERNAME}:0 /home/${USERNAME}/ && \ 46 | chgrp -R 0 /home/${USERNAME}/ && \ 47 | chmod -R g=u /home/${USERNAME}/ 48 | 49 | COPY --chown=${USERNAME}:0 entrypoint.sh uid.sh register.sh get_github_app_token.sh ./ 50 | 51 | USER $UID 52 | 53 | ENTRYPOINT ./entrypoint.sh 54 | 55 | # Test comment 56 | -------------------------------------------------------------------------------- /base/README.md: -------------------------------------------------------------------------------- 1 | # Base Actions Runner 2 | 3 | [![Quay org](https://img.shields.io/badge/quay-redhat--github--actions%2Frunner-red)](https://quay.io/repository/redhat-github-actions/runner) 4 | 5 | The base actions runner is meant to be minimal. It is build from [`fedora:35`](https://hub.docker.com/_/fedora), and contains the [GitHub Actions Runner](https://github.com/actions/runner/) and all its dependencies. At image build time, the latest runner version [is downloaded](./get-runner-release.sh), and the runner self-updates when it is connected to GitHub. 6 | 7 | On OpenShift, containers run as a dynamically assigned user ID You can read about this on [the OpenShift blog](https://www.openshift.com/blog/a-guide-to-openshift-and-uids). This image contains logic to assign that user ID to the `runner` user and make sure the home directory and other required files are have the necessary permissions. 8 | 9 | The [`entrypoint.sh`](./entrypoint.sh) acquires a GitHub Self Hosted Runner token using your GitHub PAT. The token is used to register the runner with GitHub, and connect to start listening for jobs on the organization or repository you specify. 10 | 11 | Some basic CLI tools are installed in addition to what's in the parent Fedora image. 12 | 13 | - `curl` 14 | - `findutils` (`find`) 15 | - `git` 16 | - `hostname` 17 | - `jq` 18 | - `openssl` 19 | - `procps` (`ps`, `pgrep`) 20 | - `which` 21 | 22 | 23 | ## Building your own runner image 24 | 25 | You can create your own runner image based on this one, and install any runtimes and tools your workflows need. 26 | 27 | 1. Create your own Containerfile, with `FROM quay.io/redhat-github-actions/runner:`. 28 | 2. Edit the Containerfile to install and set up your tools, environment, etc. 29 | - If you have to use root in your Containerfile, use `USER root` and convert back to `USER $UID` before the end of the Containerfile. 30 | - The `UID` environment variable is set in the base Containerfile. 31 | - Do not override the `ENTRYPOINT`. 32 | 3. Build and push your new runner image. 33 | 4. Install the [OpenShift Action Runner Chart](https://github.com/redhat-actions/openshift-actions-runner-chart). Set the value `runnerImage` to your image, and `runnerTag` to your tag. 34 | 35 | Remember to pull the base image before running the container build to make sure you are building from an up-to-date image. 36 | 37 | For example, one could build a runner image that includes a Node runtime in just four lines. 38 | ```Dockerfile 39 | FROM quay.io/redhat-github-actions/runner:latest as runner 40 | 41 | USER root 42 | RUN dnf module install -y nodejs:14/default 43 | USER $UID 44 | ``` 45 | 46 | Just like that, we have created the [Node runner image](../node/). 47 | -------------------------------------------------------------------------------- /base/entrypoint.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # Based on https://github.com/bbrowning/github-runner/blob/master/entrypoint.sh 3 | 4 | ./uid.sh > /tmp/uid.sh.log 5 | 6 | set -eE 7 | 8 | CREDS_FILE="${PWD}/.credentials" 9 | 10 | # Assume registration artifacts have been persisted from a previous start 11 | # if no PAT or TOKEN is provided, and simply attempt to start. 12 | if [ -n "${GITHUB_PAT:-}" ] || [ -n "${RUNNER_TOKEN:-}" ] || [ -n "${GITHUB_APP_ID:-}" ]; then 13 | source ./register.sh 14 | elif [ -e "${CREDS_FILE}" ]; then 15 | echo "No GITHUB_PAT or RUNNER_TOKEN provided. Using existing credentials file ${CREDS_FILE}." 16 | else 17 | echo "No saved credentials found in ${CREDS_FILE}." 18 | echo "Fatal: GITHUB_PAT or RUNNER_TOKEN must be set in the environment." 19 | exit 1 20 | fi 21 | 22 | if [ -n "${GITHUB_PAT:-}" ]; then 23 | trap 'remove; exit 130' INT 24 | trap 'remove; exit 143' TERM 25 | elif [ -n "${GITHUB_APP_ID:-}" ]; then 26 | trap 'remove_github_app; exit 130' INT 27 | trap 'remove_github_app; exit 143' TERM 28 | else 29 | trap 'exit 130' INT 30 | trap 'exit 143' TERM 31 | fi 32 | 33 | set -x 34 | ./bin/runsvc.sh --once & 35 | svc_pid=$! 36 | 37 | wait $svc_pid 38 | -------------------------------------------------------------------------------- /base/get-runner-release.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # Use the GitHub API to find the latest release of the GitHub Action runner, 4 | # then download and extract the tarball for that release. 5 | 6 | set -eE -o pipefail 7 | 8 | release_file=/tmp/latest-runner-release.json 9 | releases_api=https://api.github.com/repos/actions/runner/releases/latest 10 | 11 | echo "Fetching latest release from $releases_api" 12 | 13 | if [ ! $GITHUB_PAT = '' ]; then 14 | # Set this to work around rate-limiting issues 15 | echo "GITHUB_PAT is set; using for GitHub API" 16 | auth_header="Authorization: token $GITHUB_PAT" 17 | fi 18 | 19 | curl -sSLf -H "$auth_header" -H 'Accept: application/json' -o $release_file $releases_api 20 | 21 | latest_tag=$(jq -r '.tag_name' $release_file) 22 | echo "Latest runner is ${latest_tag}" 23 | echo $latest_tag >> ".RUNNER_VERSION" 24 | rm $release_file 25 | 26 | tag_without_v=$(echo $latest_tag | cut -c 2-) 27 | 28 | os="linux" # could be "win" or "osx" 29 | arch="x64" # for linux os, could be "arm" or "arm64" 30 | 31 | runner_tar="actions-runner-${os}-${arch}-${tag_without_v}.tar.gz" 32 | runner_url="https://github.com/actions/runner/releases/download/${latest_tag}/${runner_tar}" 33 | 34 | set -x 35 | curl -sSLf -O ${runner_url} 36 | tar fxzp ${runner_tar} 37 | rm ${runner_tar} 38 | -------------------------------------------------------------------------------- /base/get_github_app_token.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # Adapted from https://stackoverflow.com/a/62646786 and 3 | # Github's docs: https://docs.github.com/en/developers/apps/building-github-apps/authenticating-with-github-apps#authenticating-as-a-github-app 4 | 5 | get_github_app_token() { 6 | NOW=$( date +%s ) 7 | IAT=$((${NOW} - 60)) 8 | EXP=$((${NOW} + 540)) 9 | HEADER_RAW='{"alg":"RS256"}' 10 | HEADER=$( echo -n "${HEADER_RAW}" | openssl base64 | tr -d '=' | tr '/+' '_-' | tr -d '\n' ) 11 | PAYLOAD_RAW='{"iat":'"${IAT}"',"exp":'"${EXP}"',"iss":'"${GITHUB_APP_ID}"'}' 12 | PAYLOAD=$( echo -n "${PAYLOAD_RAW}" | openssl base64 | tr -d '=' | tr '/+' '_-' | tr -d '\n' ) 13 | HEADER_PAYLOAD="${HEADER}"."${PAYLOAD}" 14 | 15 | # Making a tmp directory here because /bin/sh doesn't support process redirection <() 16 | tmp_dir=/tmp/github_app_tmp 17 | mkdir "${tmp_dir}" 18 | echo -n "${GITHUB_APP_PEM}" > "${tmp_dir}/github.pem" 19 | echo -n "${HEADER_PAYLOAD}" > "${tmp_dir}/header" 20 | SIGNATURE=$( openssl dgst -sha256 -sign "${tmp_dir}/github.pem" "${tmp_dir}/header" | openssl base64 | tr -d '=' | tr '/+' '_-' | tr -d '\n' ) 21 | rm -rf "${tmp_dir}" 22 | 23 | JWT="${HEADER_PAYLOAD}"."${SIGNATURE}" 24 | INSTALL_URL="https://${GITHUB_API_SERVER}/app/installations/${GITHUB_APP_INSTALL_ID}/access_tokens" 25 | INSTALL_TOKEN_PAYLOAD=$(curl -sSfLX POST -H "Authorization: Bearer ${JWT}" -H "Accept: application/vnd.github.v3+json" "${INSTALL_URL}") 26 | INSTALL_TOKEN=$(echo ${INSTALL_TOKEN_PAYLOAD} | jq .token --raw-output) 27 | 28 | echo "${INSTALL_TOKEN}" 29 | } -------------------------------------------------------------------------------- /base/register.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # Based on https://github.com/bbrowning/github-runner/blob/master/entrypoint.sh 3 | 4 | set -eE 5 | 6 | # Load Github app authentication helper function 7 | source ./get_github_app_token.sh 8 | 9 | if [ -z "${GITHUB_OWNER:-}" ]; then 10 | echo "Fatal: \$GITHUB_OWNER must be set in the environment" 11 | exit 1 12 | fi 13 | 14 | if [ -z "${GITHUB_DOMAIN:-}" ]; then 15 | echo "Connecting to public GitHub" 16 | GITHUB_DOMAIN="github.com" 17 | GITHUB_API_SERVER="api.github.com" 18 | else 19 | echo "Connecting to GitHub server at '$GITHUB_DOMAIN'" 20 | GITHUB_API_SERVER="${GITHUB_DOMAIN}/api/v3" 21 | fi 22 | 23 | echo "GitHub API server is '$GITHUB_API_SERVER'" 24 | 25 | if [ -z "${GITHUB_REPOSITORY:-}" ] && [ -n "${GITHUB_REPO:-}" ]; then 26 | GITHUB_REPOSITORY=$GITHUB_REPO 27 | fi 28 | 29 | # https://docs.github.com/en/free-pro-team@latest/rest/reference/actions#create-a-registration-token-for-an-organization 30 | 31 | registration_url="https://${GITHUB_DOMAIN}/${GITHUB_OWNER}${GITHUB_REPOSITORY:+/$GITHUB_REPOSITORY}" 32 | 33 | if [ -z "${GITHUB_PAT:-}" ] && [ -z "${GITHUB_APP_ID:-}" ]; then 34 | echo "Neither GITHUB_PAT nor the GITHUB_APP variables are set in the environment. Automatic runner removal will be disabled." 35 | echo "Visit ${registration_url}/settings/actions/runners to manually force removal of runner." 36 | fi 37 | 38 | if [ -z "${RUNNER_TOKEN:-}" ]; then 39 | if [ -z "${GITHUB_REPOSITORY:-}" ]; then 40 | echo "Runner is scoped to organization '${GITHUB_OWNER}'" 41 | echo "View runner status at https://${GITHUB_DOMAIN}/organizations/${GITHUB_OWNER}/settings/actions" 42 | 43 | token_url="https://${GITHUB_API_SERVER}/orgs/${GITHUB_OWNER}/actions/runners/registration-token" 44 | else 45 | echo "Runner is scoped to repository '${GITHUB_OWNER}/${GITHUB_REPOSITORY}'" 46 | echo "View runner status at https://${GITHUB_DOMAIN}/${GITHUB_OWNER}/${GITHUB_REPOSITORY}/settings/actions" 47 | 48 | token_url="https://${GITHUB_API_SERVER}/repos/${GITHUB_OWNER}/${GITHUB_REPOSITORY}/actions/runners/registration-token" 49 | fi 50 | echo "Obtaining runner token from ${token_url}" 51 | 52 | if [ -n "${GITHUB_APP_ID:-}" ] && [ -n "${GITHUB_APP_INSTALL_ID:-}" ] && [ -n "${GITHUB_APP_PEM:-}" ]; then 53 | echo "GITHUB_APP environment variables are set. Using GitHub App authentication." 54 | app_token=$(get_github_app_token) 55 | payload=$(curl -sSfLX POST -H "Authorization: token ${app_token}" ${token_url}) 56 | else 57 | echo "Using GITHUB_PAT for authentication." 58 | payload=$(curl -sSfLX POST -H "Authorization: token ${GITHUB_PAT}" ${token_url}) 59 | fi 60 | 61 | export RUNNER_TOKEN=$(echo $payload | jq .token --raw-output) 62 | echo "Obtained registration token" 63 | else 64 | echo "Using RUNNER_TOKEN from environment" 65 | fi 66 | 67 | labels_arg="" 68 | if [ -n "${RUNNER_LABELS:-}" ]; then 69 | labels_arg="--labels $RUNNER_LABELS" 70 | else 71 | echo "No labels provided" 72 | fi 73 | 74 | runner_group_arg="" 75 | # Runner groups are only valid for organization-wide runners 76 | if [ -n "${RUNNER_GROUP:-}" ]; then 77 | if [ -z "${GITHUB_REPOSITORY:-}" ]; then 78 | runner_group_arg="--runnergroup $RUNNER_GROUP" 79 | else 80 | echo "Not applying runner group '${RUNNER_GROUP}' - Runner groups are not valid for repository-scoped runners." 81 | fi 82 | else 83 | echo "No runner group provided" 84 | fi 85 | 86 | ephemeral_arg="" 87 | if [ -n "${EPHEMERAL:-}" ]; then 88 | ephemeral_arg="--ephemeral" 89 | fi 90 | 91 | if [ -n "${RUNNER_TOKEN:-}" ]; then 92 | set -x 93 | ./config.sh \ 94 | --name $(hostname) \ 95 | --token ${RUNNER_TOKEN} \ 96 | --url ${registration_url} \ 97 | --work ${RUNNER_WORKDIR} \ 98 | ${labels_arg} \ 99 | ${runner_group_arg} \ 100 | ${ephemeral_arg} \ 101 | --unattended \ 102 | --replace 103 | set +x 104 | fi 105 | 106 | remove() { 107 | payload=$(curl -sSfLX POST -H "Authorization: token ${GITHUB_PAT}" ${token_url%/registration-token}/remove-token) 108 | export REMOVE_TOKEN=$(echo $payload | jq .token --raw-output) 109 | 110 | ./config.sh remove --unattended --token "${REMOVE_TOKEN}" 111 | } 112 | 113 | remove_github_app() { 114 | app_token=$(get_github_app_token) 115 | payload=$(curl -sSfLX POST -H "Authorization: token ${app_token}" ${token_url%/registration-token}/remove-token) 116 | export REMOVE_TOKEN=$(echo $payload | jq .token --raw-output) 117 | 118 | ./config.sh remove --unattended --token "${REMOVE_TOKEN}" 119 | } -------------------------------------------------------------------------------- /base/uid.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # Ensure that dynamically-assigned uid has an entry in /etc/passwd on container startup. 4 | 5 | # https://docs.openshift.com/container-platform/3.3/creating_images/guidelines.html#openshift-container-platform-specific-guidelines 6 | # https://www.openshift.com/blog/jupyter-on-openshift-part-6-running-as-an-assigned-user-id 7 | 8 | set -eEu 9 | 10 | uid=$(id -u) 11 | gid=$(id -g) 12 | username=${USERNAME:-default} 13 | 14 | echo "Current user has ID ${uid} and GID ${gid}" 15 | 16 | if ! whoami &> /dev/null; then 17 | if [ -w /etc/passwd ]; then 18 | echo "Creating passwd entry for $username" 19 | echo "${username}:x:${uid}:0:${username} user:${HOME}:/sbin/nologin" >> /etc/passwd 20 | echo -n "New passwd entry: " 21 | tail -n 1 /etc/passwd 22 | else 23 | echo "No write permission to /etc/passwd!" 1>&2 24 | fi 25 | else 26 | echo "User already has passwd entry" 27 | fi 28 | 29 | echo "whoami=$(whoami)" 30 | echo "groups=$(groups 2>/dev/null)" 31 | 32 | set +x 33 | echo "Creating sub{u,g}id entries for $username" 34 | subuids_start=$(expr $uid + 1000) 35 | subgids_start=$(expr $gid + 1000) 36 | 37 | # Do not allocate too many. 38 | # https://github.com/containers/buildah/issues/3053 39 | no_subids=50000 40 | 41 | echo "${username}:${subuids_start}:${no_subids}" | tee /etc/subuid 42 | echo "${username}:${subgids_start}:${no_subids}" | tee /etc/subgid 43 | 44 | # set -x 45 | # tail -n +1 /etc/sub{u,g}id 46 | -------------------------------------------------------------------------------- /build-images.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -eEu -o pipefail 4 | 5 | # Replace with your username. Don't push your dev images to redhat-github-actions. 6 | REGISTRY=${RUNNERS_REGISTRY:-quay.io/tetchell} 7 | TAG=${RUNNERS_TAG:-latest} 8 | 9 | BASE_IMG=${REGISTRY}/runner:${TAG} 10 | BUILDAH_IMG=${REGISTRY}/buildah-runner:${TAG} 11 | K8S_TOOLS_IMG=${REGISTRY}/k8s-tools-runner:${TAG} 12 | 13 | echo "Base img tag $BASE_IMG" 14 | 15 | enabled() { 16 | [[ $1 == *$2* ]] 17 | } 18 | 19 | cd $(dirname $0) 20 | 21 | if enabled "$*" base; then 22 | echo "Building base image..." 23 | docker build -f ./base/Containerfile -t $BASE_IMG ./base 24 | fi 25 | 26 | if enabled "$*" buildah; then 27 | echo "Building buildah image..." 28 | docker build -f ./buildah/Containerfile -t $BUILDAH_IMG ./buildah 29 | fi 30 | if enabled "$*" k8s; then 31 | echo "Building K8s image..." 32 | docker build -f ./k8s-tools/Containerfile -t $K8S_TOOLS_IMG ./k8s-tools 33 | fi 34 | 35 | if enabled "$*" push; then 36 | echo "Pushing..." 37 | docker push $BASE_IMG 38 | 39 | if enabled "$*" buildah; then 40 | docker push $BUILDAH_IMG 41 | fi 42 | if enabled "$*" k8s; then 43 | docker push $K8S_TOOLS_IMG 44 | fi 45 | else 46 | echo "Not pushing. Pass 'push' to push" 47 | fi 48 | 49 | echo "$BASE_IMG" 50 | if enabled "$*" buildah; then 51 | echo "$BUILDAH_IMG" 52 | fi 53 | if enabled "$*" k8s; then 54 | echo "$K8S_TOOLS_IMG" 55 | fi 56 | 57 | cd - > /dev/null 58 | -------------------------------------------------------------------------------- /buildah/Containerfile: -------------------------------------------------------------------------------- 1 | ARG BASE_IMG=quay.io/redhat-github-actions/runner:latest 2 | FROM $BASE_IMG AS buildah-runner 3 | 4 | USER root 5 | 6 | # https://github.com/containers/buildah/blob/main/docs/tutorials/05-openshift-rootless-build.md 7 | # https://github.com/containers/buildah/blob/master/contrib/buildahimage/stable/Dockerfile 8 | # https://github.com/containers/buildah/issues/1011 9 | # https://github.com/containers/buildah/issues/3053 10 | 11 | RUN dnf -y update && \ 12 | dnf -y install xz slirp4netns buildah podman fuse-overlayfs shadow-utils --exclude container-selinux && \ 13 | dnf -y reinstall shadow-utils && \ 14 | dnf clean all 15 | 16 | ARG OC_VERSION=4.7.4 17 | RUN curl -sSLf https://mirror.openshift.com/pub/openshift-v4/x86_64/clients/ocp/${OC_VERSION}/openshift-client-linux.tar.gz \ 18 | | tar --exclude=README.md -xzvf - &&\ 19 | mv kubectl oc /usr/local/bin/ 20 | 21 | ENV BUILDAH_ISOLATION=chroot 22 | ENV BUILDAH_LAYERS=true 23 | 24 | ADD https://raw.githubusercontent.com/containers/buildah/master/contrib/buildahimage/stable/containers.conf /etc/containers/ 25 | 26 | RUN chgrp -R 0 /etc/containers/ && \ 27 | chmod -R a+r /etc/containers/ && \ 28 | chmod -R g+w /etc/containers/ 29 | 30 | # Use VFS since fuse does not work 31 | # https://github.com/containers/buildah/blob/master/vendor/github.com/containers/storage/storage.conf 32 | RUN mkdir -vp /home/${USERNAME}/.config/containers && \ 33 | printf '[storage]\ndriver = "vfs"\n' > /home/${USERNAME}/.config/containers/storage.conf && \ 34 | chown -Rv ${USERNAME} /home/${USERNAME}/.config/ 35 | 36 | USER $UID 37 | -------------------------------------------------------------------------------- /buildah/README.md: -------------------------------------------------------------------------------- 1 | ## Buildah/Podman Actions Runner 2 | 3 | [![Quay org](https://img.shields.io/badge/quay-redhat--github--actions%2Fbuildah--runner-red)](https://quay.io/repository/redhat-github-actions/buildah-runner) 4 | 5 | The Buildah/Podman Actions Runner extends the [base runner](../base) to include Buildah, Podman, and the dependencies they need to run in a rootless, containerized environment. 6 | 7 | In order for OpenShift containers to run Buildah and Podman, the user or ServiceAccount that deploys the pod must have permission to deploy using the `anyuid` SecurityContextConstraint (SCC). 8 | 9 | Buildah has a [very good tutorial](https://github.com/containers/buildah/blob/main/docs/tutorials/05-openshift-rootless-build.md) detailing how to run buildah in OpenShift. 10 | 11 | You can also refer to the OpenShift documentation [Managing Security Context Constraints](https://docs.openshift.com/container-platform/4.6/authentication/managing-security-context-constraints.html), and [this blog post](https://www.openshift.com/blog/managing-sccs-in-openshift). 12 | 13 | ## Deploying the buildah pod 14 | 15 | It is recommended to deploy the pod using a ServiceAccount specifically configured to have the required permissions. An administrator must run: 16 | 17 | ```bash 18 | # Create the ServiceAccount (if needed) 19 | $ oc create -f - < 37 | ``` 38 | 39 | ## Podman run 40 | `podman run` doesn't work unless the pod is created with the `privileged` SCC. 41 | 42 | If you need to use `podman run`, run the `oc adm policy` commands as above, but substitute `privileged` for `anyuid`. 43 | -------------------------------------------------------------------------------- /docs/github-app-authentication.md: -------------------------------------------------------------------------------- 1 | ## Setting up a GitHub App for Runner Registration 2 | 3 | You can create a GitHub App for your user account, or any organization. 4 | 5 | The following app permissions are required for each supported type of runner: 6 | 7 | _Note: Links are provided further down to create an app for your logged in user account or an organization with the permissions for all runner types set in each link's query string_ 8 | 9 | **Required Permissions for Repository Runners:**
10 | **Repository Permissions** 11 | 12 | * Actions (read) 13 | * Administration (read / write) 14 | * Metadata (read) 15 | 16 | **Required Permissions for Organization Runners:**
17 | **Repository Permissions** 18 | 19 | * Actions (read) 20 | * Metadata (read) 21 | 22 | **Organization Permissions** 23 | * Self-hosted runners (read / write) 24 | 25 | 26 | _Note: All API routes mapped to their permissions can be found [here](https://docs.github.com/en/rest/reference/permissions-required-for-github-apps) if you wish to review_ 27 | 28 | --- 29 | 30 | **Setup Steps** 31 | 32 | If you want to create a GitHub App for your account, open the following link to the creation page, enter any unique name in the "GitHub App name" field, and hit the "Create GitHub App" button at the bottom of the page. 33 | 34 | 35 | - [Create GitHub Apps on your account](https://github.com/settings/apps/new?url=https://github.com/redhat-actions/openshift-actions-runners&webhook_active=false&public=false&administration=write&actions=read) 36 | 37 | If you want to create a GitHub App for your organization, replace the `:org` part of the following URL with your organization name before opening it. Then enter any unique name in the "GitHub App name" field, and hit the "Create GitHub App" button at the bottom of the page to create a GitHub App. 38 | 39 | 40 | - [Create GitHub Apps on your organization](https://github.com/organizations/:org/settings/apps/new?url=https://github.com/redhat-actions/openshift-actions-runners&webhook_active=false&public=false&administration=write&organization_self_hosted_runners=write&actions=read) 41 | 42 | You will see an *App ID* on the page of the GitHub App you created. You will need the value of this App ID later. 43 | 44 | Download the private key file by pushing the "Generate a private key" button at the bottom of the GitHub App page. This file will also be used later. 45 | 46 | Go to the "Install App" tab on the left side of the page and install the GitHub App that you created for your account or organization. 47 | 48 | When the installation is complete, you will be taken to a URL in one of the following formats. The number at the end of the URL will be used as the Installation ID later. 49 | 50 | For example, if the URL ends in `settings/installations/12345`, then the Installation ID is `12345`. 51 | 52 | - `https://github.com/settings/installations/${INSTALLATION_ID}` 53 | - `https://github.com/organizations/eventreactor/settings/installations/${INSTALLATION_ID}` 54 | 55 | ### Running Locally with GitHub App Authentication 56 | 57 | You need to set the `GITHUB_APP_ID`, `GITHUB_APP_INSTALL_ID`, and `GITHUB_APP_PEM` env variables and pass them to your container. 58 | 59 | The easiest way to get the private key in the correct form is to copy paste it into the environment variable. Newlines must be preserved. 60 | 61 | To launch and connect a runner to `redhat-actions/openshift-actions-runner` with the labels `local` and `podman`: 62 | 63 | ```sh 64 | podman run \ 65 | --env GITHUB_APP_ID \ 66 | --env GITHUB_APP_INSTALL_ID \ 67 | --env GITHUB_APP_PEM \ 68 | --env GITHUB_OWNER=redhat-actions \ 69 | --env GITHUB_REPOSITORY=openshift-actions-runner \ 70 | --env RUNNER_LABELS="local,podman" \ 71 | quay.io/redhat-github-actions/runner:latest 72 | ``` 73 | -------------------------------------------------------------------------------- /docs/runner-token.md: -------------------------------------------------------------------------------- 1 | ## Authenticating with a Runner Token 2 | 3 | If you're not comfortable persisting a PAT with access to all of your repositories, it is possible to manually generate a runner registration token and use that. 4 | 5 | You can create a runner token with [the GitHub API](https://docs.github.com/en/rest/reference/actions#create-a-registration-token-for-an-organization) or through the repository or organization's Settings. Navigate to `Settings` > `Actions` > `Runners`, click `Add Runner`, and copy out the `--token` argument from the `config.sh` call. 6 | 7 | Note that these tokens are only good for 60 minutes, so you must keep the local files created upon registration (after running `config.sh`) in order to be able to restart your runner. A similar process may be especially useful in Kubernetes, so that Pods can be recreated without manual intervention. 8 | 9 | ```sh 10 | # Create volume to persist authentication and configuration 11 | podman volume create runner 12 | # Perform registration, and copy artifacts to volume 13 | podman run \ 14 | --env RUNNER_TOKEN=$RUNNER_TOKEN \ 15 | --env GITHUB_OWNER=redhat-actions \ 16 | --env GITHUB_REPOSITORY=openshift-actions-runner \ 17 | --env RUNNER_LABELS="local,podman" \ 18 | --rm -v runner:/persistence \ 19 | --entrypoint='' \ 20 | quay.io/redhat-github-actions/runner:latest \ 21 | bash -c "./register.sh && cp -rT . /persistence" 22 | # Run container with volume mounted over runner home directory 23 | podman run \ 24 | --rm -v runner:/home/runner \ 25 | quay.io/redhat-github-actions/runner:latest 26 | ``` 27 | -------------------------------------------------------------------------------- /dotnet-6.0/Containerfile: -------------------------------------------------------------------------------- 1 | ARG BASE_IMG=quay.io/redhat-github-actions/runner:latest 2 | FROM $BASE_IMG AS dotnet-6.0-runner 3 | 4 | USER root 5 | 6 | RUN dnf install -y dotnet-sdk-6.0 7 | 8 | USER $UID 9 | -------------------------------------------------------------------------------- /dotnet-6.0/README.md: -------------------------------------------------------------------------------- 1 | # .NET 6.0 Runner 2 | 3 | This runner is the [base runner](../base/) extended to include the .NET 6.0 SDK for building .NET 6 applications. 4 | 5 | .NET 6 is only supported on Fedora 34 and higher. [More info from Microsoft](https://docs.microsoft.com/en-us/dotnet/core/install/linux-fedora) 6 | -------------------------------------------------------------------------------- /java/Containerfile: -------------------------------------------------------------------------------- 1 | ARG BASE_IMG=quay.io/redhat-github-actions/runner:latest 2 | FROM $BASE_IMG AS java-runner 3 | 4 | USER root 5 | 6 | RUN dnf install -y java-11-openjdk-devel.x86_64 7 | 8 | USER $UID 9 | -------------------------------------------------------------------------------- /java/README.md: -------------------------------------------------------------------------------- 1 | # Java Runner 2 | 3 | [![Quay org](https://img.shields.io/badge/quay-redhat--github--actions%2Fjava--11--runner-red)](https://quay.io/repository/redhat-github-actions/java-11-runner) 4 | 5 | This runner is the [base runner](../base) extended to include a OpenJDK and JRE for building and running your Java projects. 6 | 7 | This image includes Java 11, as the newer of the two current LTS versions. 8 | -------------------------------------------------------------------------------- /k8s-tools/Containerfile: -------------------------------------------------------------------------------- 1 | ARG BASE_IMG=quay.io/redhat-github-actions/runner:latest 2 | FROM $BASE_IMG AS k8s-tools-runner 3 | 4 | USER root 5 | 6 | ARG HELM_VERSION="3.5.0" 7 | ENV HELM_VERSION=${HELM_VERSION} 8 | 9 | ARG KN_VERSION="0.19.1" 10 | ENV KN_VERSION=${KN_VERSION} 11 | 12 | ARG OC_VERSION="4.6.18" 13 | ENV OC_VERSION=${OC_VERSION} 14 | 15 | ARG TKN_VERSION="0.15.0" 16 | ENV TKN_VERSION=${TKN_VERSION} 17 | 18 | ARG YQ_VERSION="4.6.0" 19 | ENV YQ_VERSION=${YQ_VERSION} 20 | 21 | COPY ./install-tools.sh . 22 | 23 | RUN ./install-tools.sh 24 | RUN rm ./install-tools.sh 25 | 26 | USER $UID 27 | -------------------------------------------------------------------------------- /k8s-tools/README.md: -------------------------------------------------------------------------------- 1 | # Kubernetes Tools Runner 2 | 3 | [![Quay org](https://img.shields.io/badge/quay-redhat--github--actions%2Fk8s--tools--runner-red)](https://quay.io/repository/redhat-github-actions/k8s-tools-runner) 4 | 5 | 6 | The Kubernetes tools runner is the [base runner](../base) plus a set of CLIs used to work with OpenShift/Kubernetes clusters. 7 | 8 | The version of each tool to install can be edited using a Docker `--build-arg`. View the [Containerfile](./Containerfile) to see the build args to use. 9 | 10 | Since most tools are installed from the [OpenShift V4 mirror](https://mirror.openshift.com/pub/openshift-v4/clients/), make sure the desired version is available there first. Refer to the [install-tools](./install-tools.sh) script to see where each CLI is fetched from. 11 | 12 | Note that `kubectl` is packaged together with `oc`. 13 | 14 | | Tool | Version | 15 | | ---- | ------- | 16 | | helm | 3.5.0 | 17 | | kn | 0.19.1 | 18 | | oc | 4.6.18 | 19 | | tkn | 0.15.0 | 20 | | yq | 4.6.0 | 21 | -------------------------------------------------------------------------------- /k8s-tools/install-tools.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | INSTALLER_TMP=/tmp/tool-installer/ 4 | INSTALL_TARGET_DIR=/usr/local/bin/ 5 | 6 | if [[ -n $DEV_INSTALL_TARGET_DIR ]]; then 7 | # Use this for testing the script without installing into your system dirs 8 | echo "Using override install target $DEV_INSTALL_TARGET_DIR" 9 | INSTALL_TARGET_DIR=$DEV_INSTALL_TARGET_DIR 10 | fi 11 | 12 | die() { 13 | echo >&2 "Error: $1" 14 | exit 1 15 | } 16 | 17 | assert_env_var() { 18 | local var=$1 19 | local value=$(eval echo "\$$var") 20 | echo "${var}=${value}" 21 | if [[ -z $value ]]; then 22 | die "$var not specified in environment" 23 | fi 24 | } 25 | 26 | extract() { 27 | extract_result="" 28 | 29 | local archive_name=$1 30 | local executable_name=$2 31 | local extract_dir=${INSTALLER_TMP}${executable_name} 32 | 33 | mkdir -vp $extract_dir 34 | 35 | if [[ $archive_name == *.tar* ]]; then 36 | echo "Extracting $archive_name" 37 | # -o is required due to https://discuss.circleci.com/t/tar-cannot-change-ownership/28766 38 | tar -axvof $archive_name -C $extract_dir 39 | elif [[ $archive_name =~ *\.zip ]]; then 40 | echo "Extracting $archive_name" 41 | unzip $archive_name -d $extract_dir 42 | else 43 | die "Unrecognized zip file '$archive_name'" 44 | exit 1 45 | fi 46 | 47 | # Return using global var 48 | extract_result=$(find $extract_dir -type f -iname "$executable_name*") 49 | 50 | if [[ -z $extract_result ]]; then 51 | die "Could not find $executable_name in $extract_dir after extraction" 52 | fi 53 | } 54 | 55 | move_executable() { 56 | local executable_path=$1 57 | local executable_name=$2 58 | chmod a+x $executable_path 59 | mv -v $executable_path $INSTALL_TARGET_DIR$executable_name 60 | 61 | echo "Installed $executable_name to $INSTALL_TARGET_DIR" 62 | } 63 | 64 | install() { 65 | local executable_name=$1 66 | local url=$2 67 | local download_filename=$(basename $url) 68 | echo "Downloading $2 to $download_filename ..." 69 | curl -fLsSO $url 70 | 71 | local extname=${download_filename#*.} 72 | 73 | if [[ $extname == $download_filename ]]; then 74 | # if extname == download_filename then there is no extension, we got just the executable 75 | if [[ $download_filename != $executable_name ]]; then 76 | mv -v $download_filename $executable_name 77 | fi 78 | local executable_path=$executable_name 79 | else 80 | # otherwise, we have to extract it 81 | extract $download_filename $executable_name 82 | 83 | # Global extract_result is the set in extract 84 | local executable_path=$extract_result 85 | 86 | if [[ $executable_name == "oc" ]]; then 87 | # special case for oc targz which also contains kubectl 88 | local oc_path=$extract_result 89 | 90 | extract $download_filename "kubectl" 91 | local kubectl_path=$extract_result 92 | move_executable $kubectl_path "kubectl" 93 | 94 | # Reset 95 | extract_result=$oc_path 96 | fi 97 | fi 98 | 99 | move_executable $executable_path $executable_name 100 | rm -fv $download_filename 101 | 102 | echo 103 | echo "========================================" 104 | } 105 | 106 | # set -x 107 | set -eEu -o pipefail 108 | 109 | MIRROR="https://mirror.openshift.com/pub/openshift-v4/x86_64/clients" 110 | 111 | mkdir -vp $INSTALLER_TMP 112 | 113 | assert_env_var "HELM_VERSION" 114 | install helm ${MIRROR}/helm/${HELM_VERSION}/helm-linux-amd64.tar.gz 115 | 116 | assert_env_var "KN_VERSION" 117 | install kn ${MIRROR}/serverless/${KN_VERSION}/kn-linux-amd64-${KN_VERSION}.tar.gz 118 | 119 | assert_env_var "OC_VERSION" 120 | install oc ${MIRROR}/ocp/${OC_VERSION}/openshift-client-linux.tar.gz 121 | 122 | assert_env_var "TKN_VERSION" 123 | install tkn ${MIRROR}/pipeline/${TKN_VERSION}/tkn-linux-amd64-${TKN_VERSION}.tar.gz 124 | 125 | assert_env_var "YQ_VERSION" 126 | install yq https://github.com/mikefarah/yq/releases/download/v${YQ_VERSION}/yq_linux_amd64.tar.gz 127 | 128 | echo "Removing $INSTALLER_TMP" 129 | rm -rf $INSTALLER_TMP 130 | -------------------------------------------------------------------------------- /node/Containerfile: -------------------------------------------------------------------------------- 1 | ARG BASE_IMG=quay.io/redhat-github-actions/runner:latest 2 | FROM $BASE_IMG AS node-runner 3 | 4 | USER root 5 | 6 | # https://nodejs.org/en/download/package-manager/#centos-fedora-and-red-hat-enterprise-linux 7 | # 14 is LTS 8 | RUN dnf module install -y nodejs:14 9 | 10 | USER $UID 11 | -------------------------------------------------------------------------------- /node/README.md: -------------------------------------------------------------------------------- 1 | # Node.js Runner 2 | 3 | [![Quay org](https://img.shields.io/badge/quay-redhat--github--actions%2Fnode--14--runner-red)](https://quay.io/repository/redhat-github-actions/node-14-runner) 4 | 5 | This runner is the [base runner](../base/) extended to include a Node.js runtime for building and running your Node.js projects. 6 | 7 | This image includes Node.js 14, as the newest current LTS version. 8 | -------------------------------------------------------------------------------- /pat-creation.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/redhat-actions/openshift-actions-runners/ce6d8a6548637d2e190ae56162530888a1258bf3/pat-creation.png --------------------------------------------------------------------------------