diff --git a/.github/workflows/build-pr.yml b/.github/workflows/build-pr.yml index c98b310..9423875 100644 --- a/.github/workflows/build-pr.yml +++ b/.github/workflows/build-pr.yml @@ -3,13 +3,16 @@ name: Build PR on: pull_request: +env: + IMAGE_BASE: "ghcr.io/${{ github.repository_owner }}/github-actions-runner" + jobs: generate_infos: uses: fullstack-devops/actions/.github/workflows/generate-build-infos.yml@main secrets: token: ${{ secrets.GITHUB_TOKEN }} - build: + build_base: runs-on: ubuntu-latest needs: generate_infos steps: @@ -28,11 +31,18 @@ jobs: - name: Set up Docker Buildx uses: docker/setup-buildx-action@v1 - - name: Build github-runner-base + - name: Build github-actions-runner:base + uses: docker/build-push-action@v2 + with: + context: ./images/base + push: true + tags: | + ${{ env.IMAGE_BASE }}:base-pr-${{ github.event.pull_request.number }} + + - name: Build github-actions-runner:kaniko-sidecar uses: docker/build-push-action@v2 with: - context: ./ - push: false + context: ./images/kaniko-sidecar + push: true tags: | - ghcr.io/${{ github.repository_owner }}/github-runner-base:latest - ghcr.io/${{ github.repository_owner }}/github-runner-base:${{needs.generate_infos.outputs.version}} + ${{ env.IMAGE_BASE }}:kaniko-sidecar-pr-${{ github.event.pull_request.number }} diff --git a/.github/workflows/cleanup-pr.yml b/.github/workflows/cleanup-pr.yml new file mode 100644 index 0000000..edeafe2 --- /dev/null +++ b/.github/workflows/cleanup-pr.yml @@ -0,0 +1,25 @@ +name: Cleanup PR + +on: + pull_request: + types: [closed] + +jobs: + purge-image: + name: Delete image from ghcr.io + runs-on: ubuntu-latest + steps: + - name: Delete base image + uses: bots-house/ghcr-delete-image-action@v1 + with: + owner: ${{ github.repository_owner }} + name: github-actions-runner + token: ${{ secrets.GITHUB_TOKEN }} + tag: base-pr-${{ github.event.pull_request.number }} + - name: Delete kaniko-sidecar image + uses: bots-house/ghcr-delete-image-action@v1 + with: + owner: ${{ github.repository_owner }} + name: github-actions-runner + token: ${{ secrets.GITHUB_TOKEN }} + tag: kaniko-sidecar-pr-${{ github.event.pull_request.number }} \ No newline at end of file diff --git a/.github/workflows/create-release.yml b/.github/workflows/create-release.yml index 4fd84d1..ea62bb7 100644 --- a/.github/workflows/create-release.yml +++ b/.github/workflows/create-release.yml @@ -9,6 +9,9 @@ on: branches: - "main" +env: + IMAGE_BASE: "ghcr.io/${{ github.repository_owner }}/github-actions-runner" + jobs: create_release: uses: fullstack-devops/actions/.github/workflows/create-release.yml@main @@ -34,14 +37,23 @@ jobs: - name: Set up Docker Buildx uses: docker/setup-buildx-action@v1 - - name: Build and push github-runner-base + - name: Build github-actions-runner:base + uses: docker/build-push-action@v2 + with: + context: ./images/base + push: true + tags: | + ${IMAGE_BASE}:latest + ${IMAGE_BASE}:base-latest + ${IMAGE_BASE}:base-${{needs.create_release.outputs.version}} + + - name: Build github-actions-runner:kaniko-sidecar uses: docker/build-push-action@v2 with: - context: ./ + context: ./images/kaniko-sidecar push: true tags: | - ghcr.io/${{ github.repository_owner }}/github-runner-base:latest - ghcr.io/${{ github.repository_owner }}/github-runner-base:${{needs.create_release.outputs.version}} + ${IMAGE_BASE}:kaniko-sidecar-${{needs.create_release.outputs.version}} publish_release: runs-on: ubuntu-latest diff --git a/README.md b/README.md index ab74734..5100f19 100644 --- a/README.md +++ b/README.md @@ -9,14 +9,81 @@ Base Image for github runner images in repo @fullstack-devops/github-runner. Can | Variable | Type | Description | |-------------------|--------|-------------------------------------------------------------------------------------------------------------------| -| `GH_ORGANIZATION` | string | Points to the GitHub Organisation where the runner should be installed | +| `GH_ORG` | string | Points to the GitHub Organisation where the runner should be installed | | `GH_ACCESS_TOKEN` | string | Developer Token vor the GitHub Organisation
This Token can be personal and is onlv needed during installation | ### Optional environmental variables For the helm values see the [values.yaml](helm/values.yaml), section `envValues` -| Variable | Type | Default | Description | -|--------------|--------|--------------------------|----------------------------------------------------------------------| -| `GH_URL` | string | `https://github.com` | For GitHub Enterprise support | -| `GH_API_URL` | string | `https://api.github.com` | For GitHub Enterprise support eg.: `https://git.example.com/api/v3/` | +| Variable | Type | Default | Description | +|-------------------|--------|--------------------------|----------------------------------------------------------------------| +| `GH_URL` | string | `https://github.com` | For GitHub Enterprise support | +| `GH_API_ENDPOINT` | string | `https://api.github.com` | For GitHub Enterprise support eg.: `https://git.example.com/api/v3/` | +| `GH_REPO` | string | | installing a runner to a spezific repository | +| `KANIKO_ENABLED` | bool | `false` | enable builds with kaniko (works only with kaniko-sidecar) | + +--- + +## Examples + +### docker or podman + +If you are using `docker` or `podman` the options and commands are basically the same. + +Run registerd to an Organisation: +```bash +podman run -e GH_ORG=fullstack-devops -e GH_ACCESS_TOKEN=ghp_**** github-runner-base:latest +``` + +Run registerd to an Organisation and Repo: +```bash +podman run -e GH_ORG=fullstack-devops -e GH_REPO=github-runner-testing -e GH_ACCESS_TOKEN=ghp_**** github-runner-base:latest +``` + +> Replace the `ghp_****` with your own valid personal access token + +### docker-compose + +```yaml +version: "3" + +services: + github-runner: + image: github-runner-base:latest + environment: + GH_ORG: fullstack-devops + GH_ACCESS_TOKEN: ghp_**** +``` + +Build images with kaniko: +```yaml +version: "3" + +volumes: + kaniko_workspace: + driver: local + +services: + github-action-runner: + image: github-action-runner:base-latest + environment: + GH_ORG: fullstack-devops + GH_ACCESS_TOKEN: ghp_**** + KANIKO_ENABLED: "true" + volumes: + - kaniko_workspace:/kaniko/workspace + + github-action-runner-kaniko: + image: github-action-runner:kaniko-sidecar-latest + volumes: + - kaniko_workspace:/kaniko/workspace +``` + +### kubernetes pod + +tbd + +### helm + +tbd \ No newline at end of file diff --git a/gh-entrypoint.sh b/gh-entrypoint.sh deleted file mode 100755 index 4c44f3b..0000000 --- a/gh-entrypoint.sh +++ /dev/null @@ -1,70 +0,0 @@ -#!/bin/bash - -if [ -z ${GH_ACCESS_TOKEN} ]; -then - echo "Environment variable 'GH_ACCESS_TOKEN' is not set" - exit 1 -fi - -if [ -z ${GH_URL} ]; -then - echo "Environment variable 'GH_URL' is not set" - echo "Using public github.com!" - GH_URL="https://github.com/" -fi -### Add trailing slash to GH_URL if needed -last_char="${GH_URL: -1}" -[[ $last_char != "/" ]] && GH_URL="$GH_URL/"; : - -if [ -z ${GH_API_URL} ]; -then - echo "Environment variable 'GH_API_URL' is not set" - echo "Using public github.com!" - GH_API_URL="https://api.github.com/" -fi -### Add trailing slash to GH_API_URL if needed -last_char="${GH_API_URL: -1}" -[[ $last_char != "/" ]] && GH_API_URL="$GH_API_URL/"; : - -ACCESS_TOKEN=$GH_ACCESS_TOKEN -unset GH_ACCESS_TOKEN - -if [ -z ${GH_ORGANIZATION} ]; -then - echo "Environment variable 'GH_ORGANIZATION' is not set" - exit 1 -fi - -if [ -z ${RUNNER_HOME} ]; -then - echo "Environment variable 'RUNNER_HOME' is not set" - exit 1 -fi - -REG_TOKEN=$(curl -s -X POST -H "Accept: application/vnd.github.v3+json" -H "Authorization: token $ACCESS_TOKEN" ${GH_API_URL}orgs/${GH_ORGANIZATION}/actions/runners/registration-token | jq .token --raw-output) - -echo "Individual Runner Name: $HOSTNAME" -echo "Runner Home: $RUNNER_HOME" - -${RUNNER_HOME}/config.sh \ - --name ${HOSTNAME} \ - --token ${REG_TOKEN} \ - --work ${GH_WORKDIR} \ - --url "${GH_URL}${GH_ORGANIZATION}" \ - --labels ${GH_RUNNER_LABELS} \ - --unattended \ - --replace -echo "Runner configured" - -cleanup() { - echo "Removing runner..." - REG_TOKEN=$(curl -s -X POST -H "Accept: application/vnd.github.v3+json" -H "Authorization: token ${ACCESS_TOKEN}" ${GH_API_URL}orgs/${GH_ORGANIZATION}/actions/runners/registration-token | jq .token --raw-output) - ${RUNNER_HOME}/config.sh remove --token ${REG_TOKEN} - exit 1 -} - -trap cleanup 0 -${RUNNER_HOME}/run.sh & - -echo $! > /tmp/runner_pid -wait $! \ No newline at end of file diff --git a/Dockerfile b/images/base/Dockerfile similarity index 64% rename from Dockerfile rename to images/base/Dockerfile index 4aa8eb3..f7a548a 100644 --- a/Dockerfile +++ b/images/base/Dockerfile @@ -1,13 +1,13 @@ FROM ubuntu:20.04 -COPY export-aarch-infos.sh /export-aarch-infos.sh -RUN chmod +x /export-aarch-infos.sh - ARG DEBIAN_FRONTEND=noninteractive +ARG PACKAGES="libffi-dev libicu-dev build-essential libssl-dev ca-certificates jq sed grep git curl wget zip" ENV USERNAME="runner" ENV RUNNER_HOME="/home/${USERNAME}/runner" -ENV GH_WORKDIR="/home/${USERNAME}" + +ENV GH_RUNNER_WORKDIR="/home/${USERNAME}" +ENV GH_KANIKO_WORKDIR="/kaniko/workspace" # https://github.com/actions/runner/releases ENV GH_RUNNER_VERSION=2.289.1 @@ -15,18 +15,27 @@ ENV GH_RUNNER_LABELS=ubuntu-20.04 ENV AWESOME_CI_VERSION 0.11.1 +# making nessecarry directories +RUN mkdir /helper-scripts \ + && mkdir -p /kaniko/workspace + +# Copy image helper scripts +COPY ./helper-scripts/gh-entrypoint.sh /helper-scripts/gh-entrypoint.sh +COPY ./helper-scripts/kaniko-wrapper.sh /helper-scripts/kaniko-wrapper.sh +COPY ./helper-scripts/translate-aarch.sh /helper-scripts/translate-aarch.sh + +RUN chmod -R 755 /helper-scripts + # install packages along with jq so we can parse JSON # add additional packages as necessary -ARG PACKAGES="libffi-dev libicu-dev build-essential libssl-dev ca-certificates jq sed grep git curl wget zip" - RUN apt-get update \ && apt-get install -y ${PACKAGES} \ && rm -rf /var/lib/apt/lists/* \ && apt-get clean # install awesoeme ci -RUN export ARCH=$(/export-aarch-infos.sh a-short) \ - && curl -L -O https://github.com/eksrvb/awesome-ci/releases/download/${AWESOME_CI_VERSION}/awesome-ci_${AWESOME_CI_VERSION}_${ARCH} \ +RUN export ARCH=$(/helper-scripts/translate-aarch.sh a-short) \ + && curl -L -O https://github.com/fullstack-devops/awesome-ci/releases/download/${AWESOME_CI_VERSION}/awesome-ci_${AWESOME_CI_VERSION}_${ARCH} \ && mv awesome-ci_${AWESOME_CI_VERSION}_${ARCH} /usr/local/src/awesome-ci_${AWESOME_CI_VERSION}_${ARCH} \ && chmod +x /usr/local/src/awesome-ci_${AWESOME_CI_VERSION}_${ARCH} \ && ln -s /usr/local/src/awesome-ci_${AWESOME_CI_VERSION}_${ARCH} /usr/local/bin/ @@ -40,7 +49,7 @@ RUN useradd -m $USERNAME \ && mkdir -p ${RUNNER_HOME} # Install github runner -RUN export ARCH=$(/export-aarch-infos.sh x-short) \ +RUN export ARCH=$(/helper-scripts/translate-aarch.sh x-short) \ && curl -L -O https://github.com/actions/runner/releases/download/v${GH_RUNNER_VERSION}/actions-runner-linux-${ARCH}-${GH_RUNNER_VERSION}.tar.gz \ && tar -zxf actions-runner-linux-x64-${GH_RUNNER_VERSION}.tar.gz \ && rm -f actions-runner-linux-x64-${GH_RUNNER_VERSION}.tar.gz \ @@ -48,15 +57,9 @@ RUN export ARCH=$(/export-aarch-infos.sh x-short) \ && cd ./bin \ && apt-get clean -# copy over the start script -COPY gh-entrypoint.sh /gh-entrypoint.sh -# make the script executable -RUN chmod +x /gh-entrypoint.sh - RUN chown -R $USERNAME /home/${USERNAME} -RUN chown -R $USERNAME /gh-entrypoint.sh # set the entrypoint to the entrypoint.sh script -ENTRYPOINT ["/gh-entrypoint.sh"] +ENTRYPOINT ["/helper-scripts/gh-entrypoint.sh"] USER $USERNAME \ No newline at end of file diff --git a/images/base/helper-scripts/gh-entrypoint.sh b/images/base/helper-scripts/gh-entrypoint.sh new file mode 100755 index 0000000..c2f97a0 --- /dev/null +++ b/images/base/helper-scripts/gh-entrypoint.sh @@ -0,0 +1,75 @@ +#!/bin/bash + +# connection details +last_char="${GH_URL: -1}" +[[ $last_char == "/" ]] && GH_URL="${GH_URL::-1}" +readonly _GH_URL="${GH_URL:-https://github.com}" + +last_char="${GH_API_ENDPOINT: -1}" +[[ $last_char == "/" ]] && GH_API_ENDPOINT="${GH_API_ENDPOINT::-1}" +readonly _GH_API_ENDPOINT="${GH_API_ENDPOINT:-https://api.github.com}" + +# Org/ Repo details +if [ -z "$GH_ORG" ]; then + echo "Please provide Organisation detail by setting GH_ORG" + exit 255 +fi +if [ -z "$GH_REPO" ]; then + readonly RUNNER_URL="${_GH_URL}/${GH_ORG}" + readonly RUNNER_REG_TOKEN_URL="${_GH_API_ENDPOINT}/orgs/${GH_ORG}/actions/runners/registration-token" +else + readonly RUNNER_URL="${_GH_URL}/${GH_ORG}/${GH_REPO}" + readonly RUNNER_REG_TOKEN_URL="${_GH_API_ENDPOINT}/repos/${GH_ORG}/${GH_REPO}/actions/runners/registration-token" +fi + +# access details +if [ ! -z "$RUNNER_TOKEN" ]; then + readonly REG_TOKEN=$RUNNER_TOKEN + unset RUNNER_TOKEN +elif [ ! -z $GH_ACCESS_TOKEN ]; then + readonly REG_TOKEN=$(curl -s -X POST -H "Accept: application/vnd.github.v3+json" -H "Authorization: token $GH_ACCESS_TOKEN" $RUNNER_REG_TOKEN_URL | jq .token --raw-output) + unset GH_ACCESS_TOKEN +else + echo "Please provide one of the Environment Variables:" + echo "GH_ACCESS_TOKEN, RUNNER_TOKEN" + exit 255 +fi + +if [ -z ${RUNNER_HOME} ]; then + echo "Environment variable 'RUNNER_HOME' is not set" + exit 1 +fi + +if [ "$KANIKO_ENABLED" == "true" ]; then + readonly GH_WORKDIR=$GH_KANIKO_WORKDIR + echo "Build container via Kaniko: enabled" +else + readonly GH_WORKDIR=$GH_RUNNER_WORKDIR + echo "Build container via Kaniko: disabled" +fi + +echo "Connecting runner to: $RUNNER_URL" +echo "Individual Runner Name: $HOSTNAME" +echo "Runner Home: $RUNNER_HOME" + +${RUNNER_HOME}/config.sh \ + --name $HOSTNAME \ + --token $REG_TOKEN \ + --work $GH_WORKDIR \ + --url "$RUNNER_URL" \ + --labels $GH_RUNNER_LABELS \ + --unattended \ + --replace +echo "Runner configured" + +cleanup() { + echo "Removing runner..." + ${RUNNER_HOME}/config.sh remove --token ${REG_TOKEN} + exit 1 +} + +trap cleanup 0 +${RUNNER_HOME}/run.sh $RUNNER_ARGS & + +echo $! >/tmp/runner_pid +wait $! diff --git a/images/base/helper-scripts/kaniko-wrapper.sh b/images/base/helper-scripts/kaniko-wrapper.sh new file mode 100755 index 0000000..69b049b --- /dev/null +++ b/images/base/helper-scripts/kaniko-wrapper.sh @@ -0,0 +1,23 @@ +#!/bin/sh +logpipe=/kaniko/workspace/log +returnpipe=/kaniko/workspace/returncode +if [ -p $logpipe ]; then + cat 0<> "$logpipe" <"$logpipe" + rm $logpipe + echo "Warning: removed stale communication file with kaniko" +fi +if [ -p $returnpipe ]; then + cat 0<> "$returnpipe" <"$returnpipe" + rm $returnpipe + echo "Warning: removed stale communication returncode file with kaniko" +fi +echo "cd ${PWD}" > /kaniko/workspace/start.sh +echo "/kaniko/executor --cleanup $@" >> /kaniko/workspace/start.sh +mkfifo $returnpipe +mkfifo $logpipe +cat $logpipe +rm $logpipe +returncode=`cat $returnpipe | tr -d "\n"` +rm $returnpipe +echo ${returncode} +exit ${returncode} \ No newline at end of file diff --git a/export-aarch-infos.sh b/images/base/helper-scripts/translate-aarch.sh similarity index 100% rename from export-aarch-infos.sh rename to images/base/helper-scripts/translate-aarch.sh diff --git a/images/kaniko-sidecar/Dockerfile b/images/kaniko-sidecar/Dockerfile new file mode 100644 index 0000000..9cf242c --- /dev/null +++ b/images/kaniko-sidecar/Dockerfile @@ -0,0 +1,5 @@ +FROM gcr.io/kaniko-project/executor:v1.8.0-debug + +COPY kaniko-entrypoint.sh /kaniko/kaniko-entrypoint.sh +WORKDIR / +ENTRYPOINT ["/kaniko/kaniko-entrypoint.sh"] diff --git a/images/kaniko-sidecar/kaniko-entrypoint.sh b/images/kaniko-sidecar/kaniko-entrypoint.sh new file mode 100755 index 0000000..fd0dc9a --- /dev/null +++ b/images/kaniko-sidecar/kaniko-entrypoint.sh @@ -0,0 +1,15 @@ +#!/busybox/sh +while [ true ] +do + echo "kaniko container waiting for pipe" + while [ ! -p /kaniko/workspace/log ]; do sleep 1; done + echo "kaniko container executing" + /busybox/sh /kaniko/workspace/start.sh > /kaniko/workspace/log 2>&1 + echo $? > /kaniko/workspace/returncode + if [ ! -f "/busybox/sh" ]; then + echo "kaniko self destructed. restarting container" + exit 1 + fi + echo "kaniko container end" + sleep 5 +done \ No newline at end of file