创建一个基于 Docker 的自托管 GitHub 运行器 Linux 容器
概述
本教程中使用的所有代码都可以在我的 GitHub 项目中找到:docker-github-runner-linux。
欢迎来到我的系列文章的第二部分:Azure 上的自托管 GitHub Runner 容器。
在本系列的第一部分中,我们探讨了如何使用 Docker 创建Windows 容器镜像,然后将自托管的GitHub Runner作为容器运行。在这一部分中,我们将重点介绍如何构建基于 Linux 的 Ubuntu 镜像。
在后续部分中,我们将探讨如何利用Azure容器注册表 (ACR)、Azure 容器实例 (ACI)和Azure 容器应用 (ACA)在云中存储和运行容器,以运行和扩展我们自托管的 GitHub 运行器,而不是使用基于 VM 的方法在 VM 内运行 Docker。
设置环境
如第一部分所述,在构建和运行 Docker 镜像之前,我们需要先进行一些设置。我的环境将使用运行WSL2 的Windows 11虚拟机。有关在Windows Server上运行 Docker 的更多信息,请参阅此处。我们的虚拟机需要以下组件:
以管理员身份打开 PowerShell 并运行:
wsl --install
WSL 安装完成后,运行:
Enable-WindowsOptionalFeature -Online -FeatureName $("Microsoft-Hyper-V", "Containers") -All
注意:添加上述相关功能后,您需要重启系统。
-
下载并安装适用于 Windows 的 Docker Desktop(这将自动安装Docker-Compose)
-
安装好适用于 Windows 的 Docker Desktop后,您需要切换到 Linux 容器。使用 Windows 系统托盘中的 Docker 图标:
注意: Linux 容器是默认设置,因此如果您跳过了本系列的第一部分,Docker Desktop For Windows默认将设置为使用Linux 容器。
准备用于镜像创建的 Bash 脚本
现在我们已经安装并设置了Docker-Desktop和Docker-Compose来使用Linux 容器,我们可以开始构建我们自己的 GitHub 运行器 docker 镜像了。
打开 VSCode,您可以克隆我的 GitHub 项目docker-github-runner-linux中的仓库(其中包含所有文件),或者直接按照以下步骤操作。我们将准备一个脚本,该脚本将在创建 Docker 镜像时用到。
创建一个root名为 `scripts` 的文件夹docker-github-runner-linux,然后在 `scripts` 文件夹中创建一个名为 `.scripts` 的子文件夹scripts。在`scripts`文件夹中,您可以创建以下脚本:
开始脚本
我们将使用此脚本作为引导'ENTRYPOINT'脚本,在从我们创建的镜像启动/运行容器时,用于引导我们的 Docker 容器。此脚本的主要目的是在每次从镜像启动或扩展新容器时,在我们传递给 Docker 环境的仓库上注册一个新的自托管 GitHub Runner 实例。
#!/bin/bash
GH_OWNER=$GH_OWNER
GH_REPOSITORY=$GH_REPOSITORY
GH_TOKEN=$GH_TOKEN
RUNNER_SUFFIX=$(cat /dev/urandom | tr -dc 'a-z0-9' | fold -w 5 | head -n 1)
RUNNER_NAME="dockerNode-${RUNNER_SUFFIX}"
REG_TOKEN=$(curl -sX POST -H "Accept: application/vnd.github.v3+json" -H "Authorization: token ${GH_TOKEN}" https://api.github.com/repos/${GH_OWNER}/${GH_REPOSITORY}/actions/runners/registration-token | jq .token --raw-output)
cd /home/docker/actions-runner
./config.sh --unattended --url https://github.com/${GH_OWNER}/${GH_REPOSITORY} --token ${REG_TOKEN} --name ${RUNNER_NAME}
cleanup() {
echo "Removing runner..."
./config.sh remove --unattended --token ${REG_TOKEN}
}
trap 'cleanup; exit 130' INT
trap 'cleanup; exit 143' TERM
./run.sh & wait $!
准备用于构建镜像的 Dockerfile(Linux)
现在脚本已经准备就绪,我们可以开始有趣的部分了……构建Linux Docker 镜像。返回根文件夹并创建一个名为 `docker-compose.yml` 的文件dockerfile:
Dockerfile
此 Dockerfile 包含构建容器镜像的指令。
# base image
FROM ubuntu:20.04
#input GitHub runner version argument
ARG RUNNER_VERSION
ENV DEBIAN_FRONTEND=noninteractive
LABEL Author="Marcel L"
LABEL Email="pwd9000@hotmail.co.uk"
LABEL GitHub="https://github.com/Pwd9000-ML"
LABEL BaseImage="ubuntu:20.04"
LABEL RunnerVersion=${RUNNER_VERSION}
# update the base packages + add a non-sudo user
RUN apt-get update -y && apt-get upgrade -y && useradd -m docker
# install the packages and dependencies along with jq so we can parse JSON (add additional packages as necessary)
RUN apt-get install -y --no-install-recommends \
curl nodejs wget unzip vim git azure-cli jq build-essential libssl-dev libffi-dev python3 python3-venv python3-dev python3-pip
# cd into the user directory, download and unzip the github actions runner
RUN cd /home/docker && mkdir actions-runner && cd actions-runner \
&& curl -O -L https://github.com/actions/runner/releases/download/v${RUNNER_VERSION}/actions-runner-linux-x64-${RUNNER_VERSION}.tar.gz \
&& tar xzf ./actions-runner-linux-x64-${RUNNER_VERSION}.tar.gz
# install some additional dependencies
RUN chown -R docker ~docker && /home/docker/actions-runner/bin/installdependencies.sh
# add over the start.sh script
ADD scripts/start.sh start.sh
# make the script executable
RUN chmod +x start.sh
# set the user to "docker" so all subsequent commands are run as the docker user
USER docker
# set the entrypoint to the start.sh script
ENTRYPOINT ["./start.sh"]
让我们仔细看看这个 Docker 构建文件究竟会执行哪些操作,一步一步来:
# base image
FROM ubuntu:20.04
该'FROM'指令将指示我们的 Docker 构建程序获取并使用 Ubuntu 20.04 操作系统基础镜像。接下来,我们将向该基础镜像添加其他配置。
#input GitHub runner version argument
ARG RUNNER_VERSION
ENV DEBIAN_FRONTEND=noninteractive
LABEL Author="Marcel L"
LABEL Email="pwd9000@hotmail.co.uk"
LABEL GitHub="https://github.com/Pwd9000-ML"
LABEL BaseImage="ubuntu:20.04"
LABEL RunnerVersion=${RUNNER_VERSION}
我们使用 `docker build` 定义一个输入参数'ARG'。这样我们就可以指示 `docker build` 命令在构建镜像时将特定版本的GitHub Runner Agent 加载到镜像中。由于我们使用的是Linux 容器, `docker build`'ARG'将创建一个系统变量`$RUNNER_VERSION`,容器内的 Bash 可以访问该变量。
我们还设置了一个名为DEBIAN_FRONTEND的环境变量,使其不与系统交互,这样我们以后就可以在无人值守模式下运行命令。'ENV'
此外,我们还可以使用元数据'LABEL'为图像添加标签,以便提供更多关于图像的信息。您可以根据需要更改这些值。
注意: 'LABEL RunnerVersion=${RUNNER_VERSION}'此标签会根据我们稍后将传递给 docker 构建命令的构建参数动态更新。
# update the base packages + add a non-sudo user
RUN apt-get update -y && apt-get upgrade -y && useradd -m docker
# install the packages and dependencies along with jq so we can parse JSON (add additional packages as necessary)
RUN apt-get install -y --no-install-recommends \
curl nodejs wget unzip vim git azure-cli jq build-essential libssl-dev libffi-dev python3 python3-venv python3-dev python3-pip
第一条指令将更新 Ubuntu 20.04 镜像上的基础软件包,并添加一个名为docker'RUN'的非 sudo 用户。
第二个步骤将安装git、Azure-CLI、python和jq'RUN'等软件包和依赖项,以便我们可以在ENTRYPOINT脚本中解析 JSON 以获取令牌。
注意:您可以在此阶段根据需要添加其他软件包,但请尽量不要在构建时安装过多软件包,以保持镜像尽可能精简、紧凑且易于重用。您始终可以在运行容器的工作流中使用GitHub Action,并通过 Action 安装更多工具。
稍后在运行容器时,我将演示如何使用 GitHub Action 添加更多软件和工具,例如Terraform 。
# cd into the user directory, download and unzip the github actions runner
RUN cd /home/docker && mkdir actions-runner && cd actions-runner \
&& curl -O -L https://github.com/actions/runner/releases/download/v${RUNNER_VERSION}/actions-runner-linux-x64-${RUNNER_VERSION}.tar.gz \
&& tar xzf ./actions-runner-linux-x64-${RUNNER_VERSION}.tar.gz
# install some additional dependencies
RUN chown -R docker ~docker && /home/docker/actions-runner/bin/installdependencies.sh
下一'RUN'条指令将创建一个名为actions-runner 的新文件夹,并根据'ARG'传递给容器构建过程的构建参数值(该参数值会设置环境变量$RUNNER_VERSION,如前所述)下载并提取特定版本的 GitHub Runner 二进制文件。此外,还会从提取的 GitHub Runner 文件中安装一些其他依赖项。
# add over the start.sh script
ADD scripts/start.sh start.sh
# make the script executable
RUN chmod +x start.sh
# set the user to "docker" so all subsequent commands are run as the docker user
USER docker
# set the entrypoint to the start.sh script
ENTRYPOINT ["./start.sh"]
最后一部分会将名为start.sh 的'ADD'脚本添加到镜像中。该入口脚本会在每次创建新容器时运行。它充当引导程序,根据我们传递给Docker Run命令的特定环境变量(例如$GH_OWNER、$GH_REPOSITORY和$GH_TOKEN),将容器的自托管运行器代理注册到我们指定的GitHub 组织中的特定仓库。'ENTRYPOINT'
现在我们的脚本和 Dockerfile 都已准备就绪,我们可以构建镜像了。
注意:我们可以使用docker-desktop或docker-compose构建和运行 linux 容器镜像,接下来我将展示这两种方法。
构建 Docker 镜像 - Docker Desktop(Linux)
在 VSCode 终端或 PowerShell 会话中,导航到包含 Dockerfile 的根文件夹并运行以下命令。请记住,我们需要传递一个构建参数,以告知 Docker 在创建镜像时要使用的 GitHub Runner 代理版本。GitHub Runner 版本
#Build container: docker build [OPTIONS] PATH
docker build --build-arg RUNNER_VERSION=2.292.0 --tag docker-github-runner-lin .
建造过程可能需要一些时间才能完成:
流程完成后,您将在Docker Desktop for Windows 的images 目录下看到新镜像:
运行 Docker 镜像 - Docker Desktop(Linux)
要从我们刚刚创建的镜像运行并配置一个新的自托管 GitHub Runner Linux 容器,请运行以下命令。我们需要使用选项传入一些环境变量,以'-e'指定PAT(个人访问令牌)、GitHub 组织和要注册 Runner 的仓库。
#Run container from image:
docker run -e GH_TOKEN='myPatToken' -e GH_OWNER='orgName' -e GH_REPOSITORY='repoName' -d image-name
请参阅“创建个人访问令牌”了解如何创建 GitHub PAT 令牌。PAT 令牌仅显示一次,且非常敏感,请务必妥善保管。
注册自托管运行器所需的 PAT 令牌的最低权限范围为:"repo","read:org":
提示:我建议只使用有效期较短的 PAT 令牌,并在需要注册新的代理程序时生成新的令牌。
运行此命令后,在 GitHub 仓库设置中,您将看到一个新的自托管 GitHub 运行器。(这就是我们的 Docker 容器):
您还可以在 Windows 版 Docker Desktop 的“容器”下看到正在运行的容器:
让我们通过在运行的容器上安装Terraform来创建一个GitHub 工作流,从而运行一些GitHub Actions,以此来测试我们新的自托管 docker 容器 GitHub runner 。
您可以使用我的 GitHub 项目中的此测试工作流程: docker-github-runner-linux。
在部署了自托管运行器的 GitHub 仓库下创建一个新的工作流:
name: Local runner test
on:
workflow_dispatch:
jobs:
testRunner:
runs-on: [self-hosted]
steps:
- uses: actions/checkout@v3.6.0
- name: Install Terraform
uses: hashicorp/setup-terraform@v2
- name: Display Terraform Version
run: terraform --version
- name: Display Azure-CLI Version
run: az --version
请注意工作流程'runs-on: [self-hosted]'。现在我们可以使用以下步骤安装Terraform:
steps:
- name: Install Terraform
uses: hashicorp/setup-terraform@v2
- name: Display Terraform Version
run: terraform --version
要添加额外的 Docker 运行器(容器),我们只需重新运行之前运行的 Docker 命令(每次运行都会创建一个额外的运行器实例/容器):
#Run container from image:
docker run -e GH_TOKEN='myPatToken' -e GH_OWNER='orgName' -e GH_REPOSITORY='repoName' -d image-name
接下来,我们将研究如何停止/销毁正在运行的 Docker 实例,并清理所有已注册到我们 GitHub 存储库的自托管运行器的注册信息。
要停止并移除所有正在运行的容器,只需运行:
docker stop $(docker ps -aq) && docker rm $(docker ps -aq)
您会注意到,所有在Windows 版 Docker Desktop下运行的容器都已消失,同时,我们 GitHub 仓库的 Docker 节点注册信息也已被清理和删除:
'ENTRYPOINT'GitHub runner 注册信息被移除的原因是,我们的脚本start.sh中包含清理代码,该代码会在 docker 容器停止并销毁时自动触发 runner 注册信息的清理:
cleanup() {
echo "Removing runner..."
./config.sh remove --unattended --token ${REG_TOKEN}
}
trap 'cleanup; exit 130' INT
trap 'cleanup; exit 143' TERM
接下来我们将了解如何构建镜像,以及如何使用docker-compose大规模运行镜像。
构建 Docker 镜像 - Docker Compose(Linux)
正如我们之前看到的,使用 Docker 命令构建镜像非常容易,但我们也可以使用带有配置文件的docker-compose来简化操作。接下来,再次导航到包含我们之前创建的Dockerfile 的根文件夹,并创建一个名为docker-compose.yml的新'YAML'文件:
---
version: '3.8'
services:
runner:
image: pwd9000-github-runner-lin:latest
build:
context: .
args:
RUNNER_VERSION: '2.292.0'
environment:
GH_TOKEN: ${GH_TOKEN}
GH_OWNER: ${GH_OWNER}
GH_REPOSITORY: ${GH_REPOSITORY}
在 docker compose 配置文件中,我们可以通过指定镜像名称、GitHub runner 版本以及环境变量等内容来设置 docker 镜像的参数。
请注意,我们需要在主机(Windows 11 系统)上设置这些环境变量,以便Docker Compose能够解析'YAML'文件中'${}'符号指定的值。这可以通过在 Windows 11 主机上运行以下 PowerShell 命令轻松完成:
#set system environment with $env: (or use .env file to pass GH_TOKEN, GH_OWNER, GH_REPOSITORY)
$env:GH_OWNER='Org/Owner'
$env:GH_REPOSITORY='Repository'
$env:GH_TOKEN='myPatToken'
注意:您也可以使用环境变量文件,通过类似这样的docker-compose.yml文件将环境变量传递给 docker compose 构建过程:
---
version: '3.8'
services:
runner:
image: pwd9000-github-runner-lin:latest
build:
context: .
args:
RUNNER_VERSION: '2.292.0'
env_file:
- ./variables.env
然而,这种方法需要我们在工作文件夹的根目录下创建一个名为./variables.env的文件,并像这样用我们的环境变量填充该文件:
GH_OWNER=orgName
GH_REPOSITORY=repoName
GH_TOKEN=myPatToken
重要提示:如果您使用敏感值并将代码存储在远程源代码控制仓库中,请勿使用此方法,也不要将此文件提交到源代码控制系统。'.gitignore'如有需要,请将此环境文件添加到您的文件中,以防止其被推送到源代码控制系统。
无论你决定使用哪种方法,创建好docker-compose.yml文件后,都可以运行以下 PowerShell 命令来启动构建过程:
docker-compose build
流程完成后,您将在Docker Desktop for Windows 的images 目录下看到新镜像:
运行和扩展 Docker 镜像 - Docker Compose(Windows)
使用docker-compose的好处在于,我们可以通过运行以下命令轻松扩展要使用的运行器数量:
docker-compose up --scale runner=3 -d
由于我们所有的配置和细节都保存在环境变量和docker-compose 'YAML'文件中,我们不必像以前那样运行冗长的 docker 命令,只需指定'--scale'参数即可扩展所需的运行器数量。
注意:该'--scale runner=3 -d'参数基于 docker compose 文件中的'services:'设置,在本例中名为'runner':
services:
runner:
要将规模缩小到单个运行器,我们可以简单地重新运行该命令,如下所示:
docker-compose up --scale runner=1 -d
要停止并移除所有正在运行的容器,只需运行:
docker-compose stop
docker rm $(docker ps -aq)
如前所述,您会注意到所有在Windows 版 Docker Desktop下运行的容器都已不存在,并且我们 GitHub 存储库的注册信息也已被清除:
在本系列文章的这一部分,我们介绍了如何使用docker-desktop和docker-compose构建和运行自托管的GitHub Runner,并将其作为Linux 容器运行。在本系列博客的下一部分中,我们将探讨如何使用Azure 容器注册表 (ACR)在 Azure 的远程注册表中托管/存储GitHub Runner容器镜像。
希望您喜欢这篇文章,并且有所收获。您可以在我的GitHub页面上找到本文中使用的代码示例。❤️
作者
请点赞、分享并关注我的社交媒体账号:🐙 GitHub | 🐧 X | 👾 LinkedIn
文章来源:https://dev.to/pwd9000/create-a-docker-based-self-hosted-github-runner-linux-container-48dh














