Создание Linux-контейнера Self Hosted GitHub runner на базе Docker


Обзор

Весь код, используемый в этом руководстве, можно найти в моем проекте на GitHub: docker-github-runner-linux.

Добро пожаловать во вторую часть моего цикла статей: Самостоятельное размещение контейнеров GitHub Runner на Azure.

В первой части этой серии мы рассмотрели, как создать образ контейнера windows с помощью docker, а затем запустить наши саморазмещаемые GitHub runner в качестве контейнеров. В этой части мы сосредоточимся на создании образа Ubuntu на базе Linux.

В последующих частях мы рассмотрим, как использовать Azure для хранения и запуска наших контейнеров в облаке с помощью Azure Container Registry (ACR), Azure Container Instances (ACI) и Azure Container Apps (ACA) для запуска и масштабирования наших саморазмещающихся бегунов GitHub, вместо того чтобы использовать подход на базе ВМ с запуском docker внутри ВМ.

Настройка среды

Как было описано в первой части, перед созданием и запуском образов docker нам нужно сначала настроить несколько вещей. Для моей среды я буду использовать виртуальную машину Windows 11 под управлением WSL2. Вот дополнительная информация о запуске docker на Windows Server. На нашей виртуальной машине нам понадобятся следующие вещи:

  • Установите редактор кода, например VSCode

  • Установите и включите WSL2 (более подробную информацию см. в разделе: как включить WSL2):

Откройте PowerShell от имени администратора и запустите:

wsl --install
Войти в полноэкранный режим Выйти из полноэкранного режима

После установки WSL запустите:

Enable-WindowsOptionalFeature -Online -FeatureName $("Microsoft-Hyper-V", "Containers") -All
Войти в полноэкранный режим Выйти из полноэкранного режима

ПРИМЕЧАНИЕ: Вам потребуется перезагрузить систему после добавления соответствующих функций, указанных выше.

  • Загрузите и установите Docker Desktop для Windows (при этом автоматически будет установлен Docker-Compose)

  • После установки Docker Desktop For Windows необходимо переключиться на контейнеры Linux. Используйте элемент Docker в системном трее Windows:

ПРИМЕЧАНИЕ: Linux-контейнеры — это настройка по умолчанию, поэтому если вы пропустили первую часть этой серии, Docker Desktop For Windows уже будет настроен на использование Linux-контейнеров по умолчанию.

Подготовка сценариев Bash, используемых при создании образа

Теперь, когда Docker-Desktop, а также Docker-Compose установлены и настроены на использование Linux-контейнеров, мы можем приступить к созданию docker-образа для самостоятельного запуска на GitHub.

Откройте VSCode, вы можете клонировать репозиторий, найденный на моем проекте GitHub docker-github-runner-linux, который содержит все файлы, или просто выполнить следующие шаги. Мы подготовим скрипт, который будет необходим для создания образа docker.

Создайте папку root под названием docker-github-runner-linux, а затем еще одну папку под названием scripts. Внутри папки scripts вы можете создать следующий скрипт:

start.sh

Этот скрипт будет использоваться как наш 'ENTRYPOINT' скрипт и будет использоваться для загрузки нашего контейнера docker, когда мы запускаем контейнер из образа, который мы создаем. Основная цель этого скрипта — зарегистрировать новый экземпляр GitHub runner на репозитории, которую мы передаем в среду docker каждый раз, когда новый контейнер запускается или масштабируется из образа.

#!/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. Перейдите в корневую папку и создайте файл с именем: 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}
Вход в полноэкранный режим Выход из полноэкранного режима

Мы определяем входной аргумент с помощью 'ARG'. Это нужно для того, чтобы мы могли указать команде docker build загрузить определенную версию агента GitHub runner в образ при сборке образа. Поскольку мы используем контейнер linux, '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
Вход в полноэкранный режим Выйти из полноэкранного режима

Первая команда 'RUN' обновит базовые пакеты на образе Ubuntu 20.04 и добавит пользователя docker без права доступа.

Второй 'RUN' установит пакеты и зависимости, такие как git, Azure-CLI, python вместе с jq, чтобы мы могли разобрать JSON для токена в нашем сценарии ENTRYPOINT.

ПРИМЕЧАНИЕ: Вы можете добавлять дополнительные пакеты по мере необходимости на этом этапе, но старайтесь не устанавливать слишком много пакетов во время сборки, чтобы сохранить образ как можно более компактным, компактным и пригодным для повторного использования. Вы всегда можете использовать GitHub Action позже в рабочем процессе при запуске контейнера и использовать действия для установки дополнительных инструментов.

Я покажу, как мы можем добавить дополнительное программное обеспечение и инструменты, например Terraform, позже при запуске нашего контейнера, используя действие GitHub Action.

# 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 и загрузит и извлечет определенную версию двоичных файлов GitHub runner на основе аргумента сборки 'ARG', переданного в процесс сборки контейнера, который устанавливает переменную окружения: $RUNNER_VERSION, как описано ранее. Несколько дополнительных зависимостей также устанавливаются из извлеченных файлов 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"]
Вход в полноэкранный режим Выход из полноэкранного режима

Последний раздел 'ADD' добавит к образу 'ENTRYPOINT' скрипт start.sh. Сценарий точки входа будет запускаться каждый раз при создании нового контейнера. Он действует как бутстраппер, который на основе определенных переменных окружения, которые мы передаем в команду Docker Run, таких как $GH_OWNER, $GH_REPOSITORY и $GH_TOKEN, зарегистрирует агент runner, самостоятельно размещенный в контейнере, в определенном репозитории в указанной нами организации GitHub.

Теперь, когда у нас готовы наши скрипты, а также наш dockerfile, мы можем собрать наш образ.

ПРИМЕЧАНИЕ: Мы можем собирать и запускать образы контейнеров linux с помощью docker-desktop или docker-compose, далее я покажу оба метода.

Сборка образа Docker — Docker Desktop (Linux)

В терминале VSCode или в сессии PowerShell перейдите в корневую папку, содержащую файл docker, и выполните следующую команду. Помните, что нам нужно передать аргумент build, чтобы указать 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 для Windows в разделе images:

Запуск образа Docker — Docker Desktop (Linux)

Для запуска и инициализации нового контейнера GitHub runner linux из только что созданного образа выполните следующую команду. Мы должны передать некоторые переменные окружения с помощью опции '-e', чтобы указать PAT (Personal Access Token), организацию GitHub и репозиторий для регистрации runner.

#Run container from image:
docker run -e GH_TOKEN='myPatToken' -e GH_OWNER='orgName' -e GH_REPOSITORY='repoName' -d image-name
Вход в полноэкранный режим Выход из полноэкранного режима

О том, как создать токен PAT на GitHub, см. в разделе Создание персонального маркера доступа. PAT-токены отображаются только один раз и являются конфиденциальными, поэтому позаботьтесь об их сохранности.

Для регистрации саморазмещаемого бегуна в токене PAT требуются следующие минимальные диапазоны разрешений: "repo", "read:org":

Совет: Я рекомендую использовать только токены PAT с коротким сроком действия и генерировать новые токены каждый раз, когда требуется регистрация новых бегунов-агентов.

После выполнения этой команды в настройках репозитория GitHub вы увидите новый саморазмещающийся GitHub runner. (Это наш контейнер docker):

Вы также сможете увидеть запущенный контейнер в Docker Desktop для Windows в разделе Containers:

Давайте протестируем наш новый контейнер docker с саморазмещаемым GitHub runner, создав рабочий процесс GitHub для запуска нескольких GitHub Actions с помощью установки Terraform на запущенный контейнер.

Вы можете использовать этот тестовый рабочий процесс из моего проекта на GitHub: docker-github-runner-linux.

Создайте новый рабочий процесс в репозитории GitHub, где вы развернули саморазмещаемый бегун, и запустите его:

name: Local runner test

on:
  workflow_dispatch:

jobs:
  testRunner:
    runs-on: [self-hosted]
    steps:
      - uses: actions/checkout@v2
      - 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 runners (контейнеры), просто повторно выполните команду docker, которую мы запустили ранее (каждый запуск будет создавать дополнительный экземпляр runner/контейнер):

#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)
Войти в полноэкранный режим Выйти из полноэкранного режима

Вы заметите, что все запущенные контейнеры под Docker Desktop для Windows больше не существуют, а также регистрация узлов docker в нашем репозитории GitHub также была очищена и удалена:

Причина, по которой наши регистрации бегунов на GitHub также удаляются, заключается в коде очистки в нашем сценарии 'ENTRYPOINT' start.sh, который автоматически запускает очистку регистрации бегуна, когда докер-контейнер останавливается и уничтожается:

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, и создайте новый файл 'YAML' под названием docker-compose.yml:

---
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, а также переменные окружения.

Обратите внимание, что мы должны установить эти переменные окружения на нашем хосте, машине windows 11, чтобы docker compose смог интерпретировать значения, указанные в файле 'YAML' внутри символов '${}'. Это можно легко сделать, выполнив следующие команды PowerShell на хосте windows 11:

#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, используя файл docker-compose.yml, как показано ниже:

---
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 для 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 file, 'services:', который в нашем случае называется 'runner':

services:
  runner:
Войти в полноэкранный режим Выйти из полноэкранного режима

Чтобы уменьшить масштаб до одного бегуна, мы можем просто повторно выполнить команду следующим образом:

docker-compose up --scale runner=1 -d
Войти в полноэкранный режим Выйти из полноэкранного режима

Чтобы остановить и удалить все запущенные контейнеры, просто выполните команду:

docker-compose stop
docker rm $(docker ps -aq)
Enter fullscreen mode Выйти из полноэкранного режима

Как было описано ранее, вы заметите, что все запущенные контейнеры в Docker Desktop for Windows больше не существуют, также как и регистрации в нашем репозитории GitHub были очищены:

В этой части серии мы рассказали о том, как можно создавать и запускать саморазмещаемые GitHub runners как linux-контейнеры с помощью docker-desktop и docker-compose. В следующей части этой серии блогов мы рассмотрим размещение/хранение образов контейнеров GitHub runner в удаленном реестре Azure с помощью Azure Container Registry (ACR).

Надеюсь, вам понравилась эта статья и вы узнали что-то новое. Примеры кода, использованные в этой статье, вы можете найти на моей странице GitHub. ❤️

Автор

Like, share, follow me on: 🐙 GitHub | 🐧 Twitter | 👾 LinkedIn

Marcel.L

Microsoft DevOps MVP | Cloud Solutions & DevOps Architect | Технический спикер, специализирующийся на технологиях Microsoft, IaC и автоматизации в Azure. Найдите меня на GitHub: https://github.com/Pwd9000-ML

Оцените статью
Procodings.ru
Добавить комментарий