This is an automated email from the ASF dual-hosted git repository. shahar1 pushed a commit to branch gha-arc-rebase in repository https://gitbox.apache.org/repos/asf/airflow-ci-infra.git
commit 1c102e60982faee3b12421329dcff505c66f9251 Author: Hussein Awala <[email protected]> AuthorDate: Sun Aug 13 13:49:21 2023 +0200 Simplfy the runner docker image by extending the official docker image --- README.rst | 13 +- docker/Dockerfile | 159 ----------------------- docker/docker-shim.sh | 36 ------ docker/entrypoint.sh | 49 ------- docker/graceful-stop.sh | 118 ----------------- docker/hooks/job-completed.d/update-status | 24 ---- docker/hooks/job-completed.sh | 32 ----- docker/hooks/job-started.d/update-status | 24 ---- docker/hooks/job-started.sh | 32 ----- docker/logger.sh | 92 ------------- docker/startup.sh | 199 ----------------------------- docker/update-status | 71 ---------- runner/Dockerfile | 25 ++++ 13 files changed, 30 insertions(+), 844 deletions(-) diff --git a/README.rst b/README.rst index 1491270..6d3bff2 100644 --- a/README.rst +++ b/README.rst @@ -95,15 +95,12 @@ To build docker image, you can run the following command: .. code-block:: bash - TARGETPLATFORM=linux/arm64 - RUNNER_OWNER=ashb - RUNNER_VERSION=2.304.0-airflow8 + export TARGETPLATFORM=linux/arm64 + export AIRFLOW_RUNNER_VERSION=2.304.0-airflow8 docker build --platform $TARGETPLATFORM \ - --build-arg TARGETPLATFORM=$TARGETPLATFORM \ - --build-arg RUNNER_VERSION=$RUNNER_VERSION \ - --build-arg RUNNER_OWNER=$RUNNER_OWNER \ - -t public.ecr.aws/u9s5q9f7/airflow-gha-runner:$RUNNER_VERSION \ - docker --push + --build-arg AIRFLOW_RUNNER_VERSION=$AIRFLOW_RUNNER_VERSION \ + -t public.ecr.aws/u9s5q9f7/airflow-gha-runner:$AIRFLOW_RUNNER_VERSION \ + runner --push .. _Dockerfiles: https://github.com/actions/actions-runner-controller/tree/master/runner diff --git a/docker/Dockerfile b/docker/Dockerfile deleted file mode 100644 index cebd9b5..0000000 --- a/docker/Dockerfile +++ /dev/null @@ -1,159 +0,0 @@ -# -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you 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. -# - -FROM ubuntu:20.04 - -ARG TARGETPLATFORM=linux/arm64 -ARG RUNNER_VERSION=2.304.0-airflow8 -ARG RUNNER_CONTAINER_HOOKS_VERSION=0.3.2 -ARG RUNNER_OWNER=ashb -# Docker and Docker Compose arguments -ARG CHANNEL=stable -ARG DOCKER_VERSION=20.10.23 -ARG DOCKER_COMPOSE_VERSION=v2.16.0 -ARG DUMB_INIT_VERSION=1.2.5 - -# Use 1001 and 121 for compatibility with GitHub-hosted runners -ARG RUNNER_UID=1000 -ARG DOCKER_GID=1001 - -ENV DEBIAN_FRONTEND=noninteractive -RUN apt-get update -y \ - && apt-get install -y software-properties-common \ - && add-apt-repository -y ppa:git-core/ppa \ - && apt-get update -y \ - && apt-get install -y --no-install-recommends \ - build-essential \ - curl \ - ca-certificates \ - dnsutils \ - ftp \ - git \ - git-lfs \ - iproute2 \ - iputils-ping \ - jq \ - libunwind8 \ - locales \ - netcat \ - openssh-client \ - parallel \ - python3-pip \ - rsync \ - shellcheck \ - sudo \ - telnet \ - time \ - tzdata \ - unzip \ - upx \ - wget \ - zip \ - zstd \ - && ln -sf /usr/bin/python3 /usr/bin/python \ - && ln -sf /usr/bin/pip3 /usr/bin/pip \ - && rm -rf /var/lib/apt/lists/* - -RUN adduser --disabled-password --gecos "" --uid $RUNNER_UID runner \ - && groupadd docker --gid $DOCKER_GID \ - && 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 - -ENV HOME=/home/runner - -RUN export ARCH=$(echo ${TARGETPLATFORM} | cut -d / -f2) \ - && if [ "$ARCH" = "arm64" ]; then export ARCH=aarch64 ; fi \ - && if [ "$ARCH" = "amd64" ] || [ "$ARCH" = "i386" ]; then export ARCH=x86_64 ; fi \ - && curl -fLo /usr/bin/dumb-init https://github.com/Yelp/dumb-init/releases/download/v${DUMB_INIT_VERSION}/dumb-init_${DUMB_INIT_VERSION}_${ARCH} \ - && chmod +x /usr/bin/dumb-init - -ENV RUNNER_ASSETS_DIR=/runnertmp -RUN export ARCH=$(echo ${TARGETPLATFORM} | cut -d / -f2) \ - && if [ "$ARCH" = "amd64" ] || [ "$ARCH" = "x86_64" ] || [ "$ARCH" = "i386" ]; then export ARCH=x64 ; fi \ - && mkdir -p "$RUNNER_ASSETS_DIR" \ - && cd "$RUNNER_ASSETS_DIR" \ - && curl -fLo runner.tar.gz https://github.com/${RUNNER_OWNER}/runner/releases/download/v${RUNNER_VERSION}/actions-runner-linux-${ARCH}-${RUNNER_VERSION}.tar.gz \ - && tar xzf ./runner.tar.gz \ - && rm runner.tar.gz \ - && ./bin/installdependencies.sh \ - && mv ./externals ./externalstmp \ - # libyaml-dev is required for ruby/setup-ruby action. - # It is installed after installdependencies.sh and before removing /var/lib/apt/lists - # to avoid rerunning apt-update on its own. - && apt-get install -y libyaml-dev \ - && rm -rf /var/lib/apt/lists/* - -ENV RUNNER_TOOL_CACHE=/opt/hostedtoolcache -RUN mkdir /opt/hostedtoolcache \ - && chgrp docker /opt/hostedtoolcache \ - && chmod g+rwx /opt/hostedtoolcache - -RUN cd "$RUNNER_ASSETS_DIR" \ - && curl -fLo 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 -f runner-container-hooks.zip - -RUN set -vx; \ - export ARCH=$(echo ${TARGETPLATFORM} | cut -d / -f2) \ - && if [ "$ARCH" = "arm64" ]; then export ARCH=aarch64 ; fi \ - && if [ "$ARCH" = "amd64" ] || [ "$ARCH" = "i386" ]; then export ARCH=x86_64 ; fi \ - && curl -fLo docker.tgz https://download.docker.com/linux/static/${CHANNEL}/${ARCH}/docker-${DOCKER_VERSION}.tgz \ - && tar zxvf docker.tgz \ - && install -o root -g root -m 755 docker/docker /usr/bin/docker \ - && rm -rf docker docker.tgz - -RUN export ARCH=$(echo ${TARGETPLATFORM} | cut -d / -f2) \ - && if [ "$ARCH" = "arm64" ]; then export ARCH=aarch64 ; fi \ - && if [ "$ARCH" = "amd64" ] || [ "$ARCH" = "i386" ]; then export ARCH=x86_64 ; fi \ - && mkdir -p /usr/libexec/docker/cli-plugins \ - && curl -fLo /usr/libexec/docker/cli-plugins/docker-compose https://github.com/docker/compose/releases/download/${DOCKER_COMPOSE_VERSION}/docker-compose-linux-${ARCH} \ - && chmod +x /usr/libexec/docker/cli-plugins/docker-compose \ - && ln -s /usr/libexec/docker/cli-plugins/docker-compose /usr/bin/docker-compose \ - && which docker-compose \ - && docker compose version - -# We place the scripts in `/usr/bin` so that users who extend this image can -# override them with scripts of the same name placed in `/usr/local/bin`. -COPY entrypoint.sh startup.sh logger.sh graceful-stop.sh update-status /usr/bin/ - -# Copy the docker shim which propagates the docker MTU to underlying networks -# to replace the docker binary in the PATH. -COPY docker-shim.sh /usr/local/bin/docker - -# Configure hooks folder structure. -COPY hooks /etc/arc/hooks/ - -# Add the Python "User Script Directory" to the PATH -ENV PATH="${PATH}:${HOME}/.local/bin/" -ENV ImageOS=ubuntu20 - -RUN echo "PATH=${PATH}" > /etc/environment \ - && echo "ImageOS=${ImageOS}" >> /etc/environment - -# TODO: Remove this once https://github.com/actions/setup-python/issues/705 is solved -RUN apt-get update && \ - apt-get install -y --no-install-recommends \ - curl nodejs wget unzip vim git jq build-essential libssl-dev libffi-dev python3 python3-venv python3-dev python3-pip - -USER runner - -ENTRYPOINT ["/bin/bash", "-c"] -CMD ["entrypoint.sh"] \ No newline at end of file diff --git a/docker/docker-shim.sh b/docker/docker-shim.sh deleted file mode 100755 index f522f8f..0000000 --- a/docker/docker-shim.sh +++ /dev/null @@ -1,36 +0,0 @@ -#!/usr/bin/env bash - -# -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you 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. -# - -set -Eeuo pipefail - -DOCKER=/usr/bin/docker -if [ ! -e $DOCKER ]; then - DOCKER=/home/runner/bin/docker -fi - -if [[ ${ARC_DOCKER_MTU_PROPAGATION:-false} == true ]] && - (($# >= 2)) && [[ $1 == network && $2 == create ]] && - mtu=$($DOCKER network inspect bridge --format '{{index .Options "com.docker.network.driver.mtu"}}' 2>/dev/null); then - shift 2 - set -- network create --opt com.docker.network.driver.mtu="$mtu" "$@" -fi - -exec $DOCKER "$@" diff --git a/docker/entrypoint.sh b/docker/entrypoint.sh deleted file mode 100755 index 5decfde..0000000 --- a/docker/entrypoint.sh +++ /dev/null @@ -1,49 +0,0 @@ -#!/bin/bash -# -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you 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. -# - -source logger.sh -source graceful-stop.sh -trap graceful_stop TERM - -dumb-init bash <<'SCRIPT' & -source logger.sh - -startup.sh -SCRIPT - -RUNNER_INIT_PID=$! -log.notice "Runner init started with pid $RUNNER_INIT_PID" -wait $RUNNER_INIT_PID -log.notice "Runner init exited. Exiting this process with code 0 so that the container and the pod is GC'ed Kubernetes soon." - -if [ -f /runner/.runner ]; then -# If the runner failed with the following error: -# √ Connected to GitHub -# Failed to create a session. The runner registration has been deleted from the server, please re-configure. -# Runner listener exit with terminated error, stop the service, no retry needed. -# Exiting runner... -# It might have failed to delete the .runner file. -# We use the existence of the .runner file as the indicator that the runner agent has not stopped yet. -# Remove it by ourselves now, so that the dockerd sidecar prestop won't hang waiting for the .runner file to appear. - echo "Removing the .runner file" - rm -f /runner/.runner -fi - -trap - TERM diff --git a/docker/graceful-stop.sh b/docker/graceful-stop.sh deleted file mode 100755 index 36431f0..0000000 --- a/docker/graceful-stop.sh +++ /dev/null @@ -1,118 +0,0 @@ -#!/bin/bash - -# -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you 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. -# - -# This should be shorter enough than the terminationGracePeriodSeconds, -# so that the job is cancelled immediately, instead of hanging for 10 minutes or so and failing without any error message. -RUNNER_GRACEFUL_STOP_TIMEOUT=${RUNNER_GRACEFUL_STOP_TIMEOUT:-15} - -graceful_stop() { - log.notice "Executing actions-runner-controller's SIGTERM handler." - log.notice "Note that if this takes more time than terminationGracePeriodSeconds, the runner will be forcefully terminated by Kubernetes, which may result in the in-progress workflow job, if any, to fail." - - log.notice "Ensuring dockerd is still running." - if ! docker ps -a; then - log.warning "Detected configuration error: dockerd should be running but is already nowhere. This is wrong. Ensure that your init system to NOT pass SIGTERM directly to dockerd!" - fi - - # The below procedure atomically removes the runner from GitHub Actions service, - # to ensure that the runner is not running any job. - # This is required to not terminate the actions runner agent while running the job. - # If we didn't do this atomically, we might end up with a rare race where - # the runner agent is terminated while it was about to start a job. - - # `pushd`` is needed to run the config.sh successfully. - # Without this the author of this script ended up with errors like the below: - # Cannot connect to server, because config files are missing. Skipping removing runner from the server. - # Does not exist. Skipping Removing .credentials - # Does not exist. Skipping Removing .runner - if ! pushd /runner; then - log.error "Failed to pushd ${RUNNER_HOME}" - exit 1 - fi - - # We need to wait for the registration first. - # Otherwise a direct runner pod deletion triggered while the runner entrypoint.sh is about to register itself with - # config.sh can result in this graceful stop process to get skipped. - # In that case, the pod is eventually and forcefully terminated by ARC and K8s, resulting - # in the possible running workflow job after this graceful stop process failed might get cancelled prematurely. - log.notice "Waiting for the runner to register first." - while ! [ -f /runner/.runner ]; do - sleep 1 - done - log.notice "Observed that the runner has been registered." - - if ! /runner/config.sh remove --token "$RUNNER_TOKEN"; then - i=0 - log.notice "Waiting for RUNNER_GRACEFUL_STOP_TIMEOUT=$RUNNER_GRACEFUL_STOP_TIMEOUT seconds until the runner agent to stop by itself." - while [[ $i -lt $RUNNER_GRACEFUL_STOP_TIMEOUT ]]; do - sleep 1 - if ! pgrep Runner.Listener > /dev/null; then - log.notice "The runner agent stopped before RUNNER_GRACEFUL_STOP_TIMEOUT=$RUNNER_GRACEFUL_STOP_TIMEOUT" - break - fi - i=$((i+1)) - done - fi - - if ! popd; then - log.error "Failed to popd from ${RUNNER_HOME}" - exit 1 - fi - - if pgrep Runner.Listener > /dev/null; then - # The below procedure fixes the runner to correctly notify the Actions service for the cancellation of this runner. - # It enables you to see `Error: The operation was canceled.` in the worklow job log, in case a job was still running on this runner when the - # termination is requested. - # - # Note though, due to how Actions work, no all job steps gets `Error: The operation was canceled.` in the job step logs. - # Jobs that were still in the first `Stet up job` step` seem to get `Error: A task was canceled.`, - # - # Anyway, without this, a runer pod is "forcefully" killed by any other controller (like cluster-autoscaler) can result in the workflow job to - # hang for 10 minutes or so. - # After 10 minutes, the Actions UI just shows the failure icon for the step, without `Error: The operation was canceled.`, - # not even showing `Error: The operation was canceled.`, which is confusing. - runner_listener_pid=$(pgrep Runner.Listener) - log.notice "Sending SIGTERM to the actions runner agent ($runner_listener_pid)." - kill -TERM "$runner_listener_pid" - - log.notice "SIGTERM sent. If the runner is still running a job, you'll probably see \"Error: The operation was canceled.\" in its log." - log.notice "Waiting for the actions runner agent to stop." - while pgrep Runner.Listener > /dev/null; do - sleep 1 - done - fi - - # This message is supposed to be output only after the runner agent output: - # 2022-08-27 02:04:37Z: Job test3 completed with result: Canceled - # because this graceful stopping logic is basically intended to let the runner agent have some time - # needed to "Cancel" it. - # At the times we didn't have this logic, the runner agent was even unable to output the Cancelled message hence - # unable to gracefully stop, hence the workflow job hanged like forever. - log.notice "The actions runner process exited." - - if [ "$RUNNER_INIT_PID" != "" ]; then - log.notice "Holding on until runner init (pid $RUNNER_INIT_PID) exits, so that there will hopefully be no zombie processes remaining." - # We don't need to kill -TERM $RUNNER_INIT_PID as the init is supposed to exit by itself once the foreground process(=the runner agent) exists. - wait "$RUNNER_INIT_PID" || : - fi - - log.notice "Graceful stop completed." -} diff --git a/docker/hooks/job-completed.d/update-status b/docker/hooks/job-completed.d/update-status deleted file mode 100755 index fd01665..0000000 --- a/docker/hooks/job-completed.d/update-status +++ /dev/null @@ -1,24 +0,0 @@ -#!/usr/bin/env bash - -# -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you 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. -# - -set -u - -exec update-status Idle diff --git a/docker/hooks/job-completed.sh b/docker/hooks/job-completed.sh deleted file mode 100755 index 0fd2abe..0000000 --- a/docker/hooks/job-completed.sh +++ /dev/null @@ -1,32 +0,0 @@ -#!/usr/bin/env bash - -# -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you 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. -# - -set -Eeuo pipefail - -# shellcheck source=runner/logger.sh -source logger.sh - -log.debug "Running ARC Job Completed Hooks" - -for hook in /etc/arc/hooks/job-completed.d/*; do - log.debug "Running hook: $hook" - "$hook" "$@" -done diff --git a/docker/hooks/job-started.d/update-status b/docker/hooks/job-started.d/update-status deleted file mode 100755 index 17d2d08..0000000 --- a/docker/hooks/job-started.d/update-status +++ /dev/null @@ -1,24 +0,0 @@ -#!/usr/bin/env bash - -# -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you 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. -# - -set -u - -exec update-status Running "Run $GITHUB_RUN_ID from $GITHUB_REPOSITORY" diff --git a/docker/hooks/job-started.sh b/docker/hooks/job-started.sh deleted file mode 100644 index 3e08e74..0000000 --- a/docker/hooks/job-started.sh +++ /dev/null @@ -1,32 +0,0 @@ -#!/usr/bin/env bash - -# -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you 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. -# - -set -Eeuo pipefail - -# shellcheck source=runner/logger.sh -source logger.sh - -log.debug "Running ARC Job Started Hooks" - -for hook in /etc/arc/hooks/job-started.d/*; do - log.debug "Running hook: $hook" - "$hook" "$@" -done diff --git a/docker/logger.sh b/docker/logger.sh deleted file mode 100755 index 08c0283..0000000 --- a/docker/logger.sh +++ /dev/null @@ -1,92 +0,0 @@ -#!/usr/bin/env bash -# -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you 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. -# - -# We are not using `set -Eeuo pipefail` here because this file is sourced by -# other scripts that might not be ready for a strict Bash setup. The functions -# in this file do not require it, because they are not handling signals, have -# no external calls that can fail (printf as well as date failures are ignored), -# are not using any variables that need to be set, and are not using any pipes. - -# This logger implementation can be replaced with another logger implementation -# by placing a script called `logger.sh` in `/usr/local/bin` of the image. The -# only requirement for the script is that it defines the following functions: -# -# - `log.debug` -# - `log.notice` -# - `log.warning` -# - `log.error` -# - `log.success` -# -# Each function **MUST** accept an arbitrary amount of arguments that make up -# the (unstructured) logging message. -# -# Additionally the following environment variables **SHOULD** be supported to -# disable their corresponding log entries, the value of the variables **MUST** -# not matter the mere fact that they are set is all that matters: -# -# - `LOG_DEBUG_DISABLED` -# - `LOG_NOTICE_DISABLED` -# - `LOG_WARNING_DISABLED` -# - `LOG_ERROR_DISABLED` -# - `LOG_SUCCESS_DISABLED` - -# The log format is constructed in a way that it can easily be parsed with -# standard tools and simple string manipulations; pattern and example: -# -# YYYY-MM-DD hh:mm:ss.SSS $level --- $message -# 2022-03-19 10:01:23.172 NOTICE --- example message -# -# This function is an implementation detail and **MUST NOT** be called from -# outside this script (which is possible if the file is sourced). -__log() { - local color instant level - - color=${1:?missing required <color> argument} - shift - - level=${FUNCNAME[1]} # `main` if called from top-level - level=${level#log.} # substring after `log.` - level=${level^^} # UPPERCASE - - if [[ ! -v "LOG_${level}_DISABLED" ]]; then - instant=$(date '+%F %T.%-3N' 2>/dev/null || :) - - # https://no-color.org/ - if [[ -v NO_COLOR ]]; then - printf -- '%s %s --- %s\n' "$instant" "$level" "$*" 1>&2 || : - else - printf -- '\033[0;%dm%s %s --- %s\033[0m\n' "$color" "$instant" "$level" "$*" 1>&2 || : - fi - fi -} - -# To log with a dynamic level use standard Bash capabilities: -# -# level=notice -# command || level=error -# "log.$level" message -# -# @formatter:off -log.debug () { __log 37 "$@"; } # white -log.notice () { __log 34 "$@"; } # blue -log.warning () { __log 33 "$@"; } # yellow -log.error () { __log 31 "$@"; } # red -log.success () { __log 32 "$@"; } # green -# @formatter:on diff --git a/docker/startup.sh b/docker/startup.sh deleted file mode 100755 index a955127..0000000 --- a/docker/startup.sh +++ /dev/null @@ -1,199 +0,0 @@ -#!/bin/bash -# -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you 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. -# - -source logger.sh - -RUNNER_ASSETS_DIR=${RUNNER_ASSETS_DIR:-/runnertmp} -RUNNER_HOME=${RUNNER_HOME:-/runner} - -# Let GitHub runner execute these hooks. These environment variables are used by GitHub's Runner as described here -# https://github.com/actions/runner/blob/main/docs/adrs/1751-runner-job-hooks.md -# Scripts referenced in the ACTIONS_RUNNER_HOOK_ environment variables must end in .sh or .ps1 -# for it to become a valid hook script, otherwise GitHub will fail to run the hook -export ACTIONS_RUNNER_HOOK_JOB_STARTED=/etc/arc/hooks/job-started.sh -export ACTIONS_RUNNER_HOOK_JOB_COMPLETED=/etc/arc/hooks/job-completed.sh - -if [ -n "${STARTUP_DELAY_IN_SECONDS}" ]; then - log.notice "Delaying startup by ${STARTUP_DELAY_IN_SECONDS} seconds" - sleep "${STARTUP_DELAY_IN_SECONDS}" -fi - -if [ -z "${GITHUB_URL}" ]; then - log.debug 'Working with public GitHub' - GITHUB_URL="https://github.com/" -else - length=${#GITHUB_URL} - last_char=${GITHUB_URL:length-1:1} - - [[ $last_char != "/" ]] && GITHUB_URL="$GITHUB_URL/"; : - log.debug "Github endpoint URL ${GITHUB_URL}" -fi - -if [ -z "${RUNNER_NAME}" ]; then - log.error 'RUNNER_NAME must be set' - exit 1 -fi - -if [ -n "${RUNNER_ORG}" ] && [ -n "${RUNNER_REPO}" ] && [ -n "${RUNNER_ENTERPRISE}" ]; then - ATTACH="${RUNNER_ORG}/${RUNNER_REPO}" -elif [ -n "${RUNNER_ORG}" ]; then - ATTACH="${RUNNER_ORG}" -elif [ -n "${RUNNER_REPO}" ]; then - ATTACH="${RUNNER_REPO}" -elif [ -n "${RUNNER_ENTERPRISE}" ]; then - ATTACH="enterprises/${RUNNER_ENTERPRISE}" -else - log.error 'At least one of RUNNER_ORG, RUNNER_REPO, or RUNNER_ENTERPRISE must be set' - exit 1 -fi - -if [ -z "${RUNNER_TOKEN}" ]; then - log.error 'RUNNER_TOKEN must be set' - exit 1 -fi - -if [ -z "${RUNNER_REPO}" ] && [ -n "${RUNNER_GROUP}" ];then - RUNNER_GROUPS=${RUNNER_GROUP} -fi - -# Hack due to https://github.com/actions/actions-runner-controller/issues/252#issuecomment-758338483 -if [ ! -d "${RUNNER_HOME}" ]; then - log.error "$RUNNER_HOME should be an emptyDir mount. Please fix the pod spec." - exit 1 -fi - -# if this is not a testing environment -if [[ "${UNITTEST:-}" == '' ]]; then - sudo chown -R runner:docker "$RUNNER_HOME" - # enable dotglob so we can copy a ".env" file to load in env vars as part of the service startup if one is provided - # loading a .env from the root of the service is part of the actions/runner logic - shopt -s dotglob - # use cp instead of mv to avoid issues when src and dst are on different devices - cp -r "$RUNNER_ASSETS_DIR"/* "$RUNNER_HOME"/ - shopt -u dotglob -fi - -if ! cd "${RUNNER_HOME}"; then - log.error "Failed to cd into ${RUNNER_HOME}" - exit 1 -fi - -# past that point, it's all relative pathes from /runner - -config_args=() -if [ "${RUNNER_FEATURE_FLAG_ONCE:-}" != "true" ] && [ "${RUNNER_EPHEMERAL}" == "true" ]; then - config_args+=(--ephemeral) - log.debug 'Passing --ephemeral to config.sh to enable the ephemeral runner.' -fi -if [ "${DISABLE_RUNNER_UPDATE:-}" == "true" ]; then - config_args+=(--disableupdate) - log.debug 'Passing --disableupdate to config.sh to disable automatic runner updates.' -fi - -update-status "Registering" - -retries_left=10 -while [[ ${retries_left} -gt 0 ]]; do - log.debug 'Configuring the runner.' - ./config.sh --unattended --replace \ - --name "${RUNNER_NAME}" \ - --url "${GITHUB_URL}${ATTACH}" \ - --token "${RUNNER_TOKEN}" \ - --runnergroup "${RUNNER_GROUPS}" \ - --labels "${RUNNER_LABELS}" \ - --work "${RUNNER_WORKDIR}" "${config_args[@]}" - - if [ -f .runner ]; then - log.debug 'Runner successfully configured.' - break - fi - - log.debug 'Configuration failed. Retrying' - retries_left=$((retries_left - 1)) - sleep 1 -done - -if [ ! -f .runner ]; then - # we couldn't configure and register the runner; no point continuing - log.error 'Configuration failed!' - exit 2 -fi - -cat .runner -# Note: the `.runner` file's content should be something like the below: -# -# $ cat /runner/.runner -# { -# "agentId": 117, #=> corresponds to the ID of the runner -# "agentName": "THE_RUNNER_POD_NAME", -# "poolId": 1, -# "poolName": "Default", -# "serverUrl": "https://pipelines.actions.githubusercontent.com/SOME_RANDOM_ID", -# "gitHubUrl": "https://github.com/USER/REPO", -# "workFolder": "/some/work/dir" #=> corresponds to Runner.Spec.WorkDir -# } -# -# Especially `agentId` is important, as other than listing all the runners in the repo, -# this is the only change we could get the exact runnner ID which can be useful for further -# GitHub API call like the below. Note that 171 is the agentId seen above. -# curl \ -# -H "Accept: application/vnd.github.v3+json" \ -# -H "Authorization: bearer ${GITHUB_TOKEN}" -# https://api.github.com/repos/USER/REPO/actions/runners/171 - -# Hack due to the DinD volumes -if [ -z "${UNITTEST:-}" ] && [ -e ./externalstmp ]; then - mkdir -p ./externals - mv ./externalstmp/* ./externals/ -fi - -WAIT_FOR_DOCKER_SECONDS=${WAIT_FOR_DOCKER_SECONDS:-120} -if [[ "${DISABLE_WAIT_FOR_DOCKER}" != "true" ]] && [[ "${DOCKER_ENABLED}" == "true" ]]; then - log.debug 'Docker enabled runner detected and Docker daemon wait is enabled' - log.debug "Waiting until Docker is available or the timeout of ${WAIT_FOR_DOCKER_SECONDS} seconds is reached" - if ! timeout "${WAIT_FOR_DOCKER_SECONDS}s" bash -c 'until docker ps ;do sleep 1; done'; then - log.notice "Docker has not become available within ${WAIT_FOR_DOCKER_SECONDS} seconds. Exiting with status 1." - exit 1 - fi -else - log.notice 'Docker wait check skipped. Either Docker is disabled or the wait is disabled, continuing with entrypoint' -fi - -# Unset entrypoint environment variables so they don't leak into the runner environment -unset RUNNER_NAME RUNNER_REPO RUNNER_TOKEN STARTUP_DELAY_IN_SECONDS DISABLE_WAIT_FOR_DOCKER - -# Docker ignores PAM and thus never loads the system environment variables that -# are meant to be set in every environment of every user. We emulate the PAM -# behavior by reading the environment variables without interpreting them. -# -# https://github.com/actions/actions-runner-controller/issues/1135 -# https://github.com/actions/runner/issues/1703 - -# /etc/environment may not exist when running unit tests depending on the platform being used -# (e.g. Mac OS) so we just skip the mapping entirely -if [ -z "${UNITTEST:-}" ]; then - mapfile -t env </etc/environment -fi - -log.notice "WARNING LATEST TAG HAS BEEN DEPRECATED. SEE GITHUB ISSUE FOR DETAILS:" -log.notice "https://github.com/actions/actions-runner-controller/issues/2056" - -update-status "Idle" -exec env -- "${env[@]}" ./run.sh diff --git a/docker/update-status b/docker/update-status deleted file mode 100755 index 40e8bd9..0000000 --- a/docker/update-status +++ /dev/null @@ -1,71 +0,0 @@ -#!/usr/bin/env bash -# -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you 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. -# - -set -Eeuo pipefail - -if [[ ${1:-} == '' ]]; then - # shellcheck source=runner/logger.sh - source logger.sh - log.error "Missing required argument -- '<phase>'" - exit 64 -fi - -if [[ ${RUNNER_STATUS_UPDATE_HOOK:-false} == true ]]; then - - apiserver=https://${KUBERNETES_SERVICE_HOST}:${KUBERNETES_SERVICE_PORT_HTTPS} - serviceaccount=/var/run/secrets/kubernetes.io/serviceaccount - namespace=$(cat ${serviceaccount}/namespace) - token=$(cat ${serviceaccount}/token) - phase=$1 - message=${2:-} - - data=$(jq -n --arg phase "$phase" \ - --arg message "$message" \ - --arg workflow_repository "${GITHUB_REPOSITORY:-}" \ - --arg workflow_repository_owner "${GITHUB_REPOSITORY_OWNER:-}" \ - --arg workflow_name "${GITHUB_WORKFLOW:-}" \ - --arg workflow_run_id "${GITHUB_RUN_ID:-}" \ - --arg workflow_run_number "${GITHUB_RUN_NUMBER:-}" \ - --arg workflow_job "${GITHUB_JOB:-}" \ - --arg workflow_action "${GITHUB_ACTION:-}" \ - ' - .status.phase = $phase - | .status.message = $message - | .status.workflow.name = $workflow_name - | .status.workflow.runID = $workflow_run_id - | .status.workflow.runNumber = $workflow_run_number - | .status.workflow.repository = $workflow_repository - | .status.workflow.repositoryOwner = $workflow_repository_owner - | .status.workflow.job = $workflow_job - | .status.workflow.action = $workflow_action - ') - - echo "$data" | curl \ - --cacert ${serviceaccount}/ca.crt \ - --data @- \ - --noproxy '*' \ - --header "Content-Type: application/merge-patch+json" \ - --header "Authorization: Bearer ${token}" \ - --show-error \ - --silent \ - --request PATCH \ - "${apiserver}/apis/actions.summerwind.dev/v1alpha1/namespaces/${namespace}/runners/${HOSTNAME}/status" \ - 1>/dev/null -fi \ No newline at end of file diff --git a/runner/Dockerfile b/runner/Dockerfile new file mode 100644 index 0000000..d720480 --- /dev/null +++ b/runner/Dockerfile @@ -0,0 +1,25 @@ +ARG ACTIONS_RUNNER_VERSION=v2.307.1-ubuntu-22.04-dcb64f0 + +FROM summerwind/actions-runner:${ACTIONS_RUNNER_VERSION} + +USER root + +ARG AIRFLOW_RUNNER_VERSION + +RUN rm -rf $RUNNER_ASSETS_DIR/* \ + && export ARCH=$(arch) \ + && if [ "$ARCH" = "amd64" ] || [ "$ARCH" = "x86_64" ] || [ "$ARCH" = "i386" ]; then export ARCH=x64 ; fi \ + && if [ "$ARCH" = "aarch64" ]; then export ARCH=arm64 ; fi \ + && cd "$RUNNER_ASSETS_DIR" \ + && curl -fLo runner.tar.gz "https://github.com/ashb/runner/releases/download/v${AIRFLOW_RUNNER_VERSION}/actions-runner-linux-${ARCH}-${AIRFLOW_RUNNER_VERSION}.tar.gz" \ + && tar xzf ./runner.tar.gz \ + && rm runner.tar.gz \ + && ./bin/installdependencies.sh \ + && mv ./externals ./externalstmp + +# TODO: Remove this once https://github.com/actions/setup-python/issues/705 is solved +RUN apt-get update && \ + apt-get install -y --no-install-recommends \ + curl nodejs wget unzip vim git jq build-essential libssl-dev libffi-dev python3 python3-venv python3-dev python3-pip + +USER runner \ No newline at end of file
