【GitHub Actions】self-hosted runnerでsetup-pythonアクションを使用したらエラーでハマった話

未解決(setup-pythonのissue対応待ち)に終わったので代替案を次回以降に試したいと思います。
2020.06.11

こんにちは、CX事業本部の若槻です。

GitHub Actionsには、CIのジョブ実行をGitHub上ではなく任意のサーバー上で行えるようにするself-hosted runnersという機能があります。

Self-hosted runners offer more control of hardware, operating system, and software tools than GitHub-hosted runners provide. With self-hosted runners, you can choose to create a custom hardware configuration with more processing power or memory to run larger jobs, install software available on your local network, and choose an operating system not offered by GitHub-hosted runners. Self-hosted runners can be physical, virtual, in a container, on-premises, or in a cloud.

今回は、このself-hosted runnerでsetup-pythonアクションを使用しようとした際にエラーとなりハマった話をご紹介します。

setup-pythonアクションとは

setup-pythonアクションとは、GitHubが公式提供しているGitHub Actionsで利用可能なアクションの一つです。GitHubマーケットプレイスでは現在最新版として「setup-python V2」が公開されています。

This action sets up a Python environment for use in actions by:
- optionally installing and adding to PATH a version of Python that is already installed in the tools cache
- downloading, installing and adding to PATH an available version of Python from GitHub Releases (actions/python-versions) if a specific version is not available in the tools cache
- failing if a specific version of Python is not preinstalled or available for download
- registering problem matchers for error output

上記要約すると、setup-pythonアクションは次の方法でジョブ実行時に使用するPython環境をセットアップするとのことです。

  • オプションで、tools cacheに既にインストールされているバージョンのPythonをインストールしてPATHに追加する
  • tools cacheで特定のバージョンが利用できない場合、GitHubリリース(actions/python-versions)から利用可能なバージョンのPythonをダウンロード、インストール、およびPATHに追加する
  • 特定のバージョンのPythonがプレインストールされていないかダウンロードできない場合は失敗する

使い方は、「setup-python V2」を使いたい場合はGitHub Actionsのコンフィグの中でuses: actions/setup-python@v2と指定することにより使用できます。

.github/workflows/action.yml

steps:
- uses: actions/checkout@v2
- uses: actions/setup-python@v2
  with:
    python-version: '3.x' # Version range or exact version of a Python version to use, using SemVer's version range syntax
    architecture: 'x64' # optional x64 or x86. Defaults to x64 if not specified
- run: python my_script.py

setup-pythonアクションをself-hosted runnerで使用してみる

前提環境

self-hosted runnerを実行させる環境にはAWS Cloud9を利用しました。Cloud9のsettingは下記のようになります。

  • Environment type:EC2
  • Platform:Amazon Linux

ドキュメントを読む

GitHubのドキュメントを読むと、setup-pythonアクションをself-hosted runnerで使用する際の必要な設定事項について記載がありました。

少々長いですが、原文と和訳を次に記載します。

原文

If you would like to use setup-python and a self-hosted runner, there are a few extra things you need to make sure are set up so that new versions of Python can be downloaded and configured on your runner.

Linux

  • The Python packages that are downloaded from actions/python-versions are originally compiled from source in /opt/hostedtoolcache/ with the --enable-shared flag, which makes them non-relocatable.
  • Create an environment variable called AGENT_TOOLSDIRECTORY and set it to /opt/hostedtoolcache. This controls where the runner downloads and installs tools.
    • In the same shell that your runner is using, type export AGENT_TOOLSDIRECTORY=/opt/hostedtoolcache
    • A more permanent way of setting the environment variable is to create a .env file in the same directory as your runner and to add AGENT_TOOLSDIRECTORY=/opt/hostedtoolcache. This ensures the variable is always set if your runner is configured as a service.
  • Create a directory called hostedtoolcache inside /opt.
  • The user starting the runner must have write permission to the /opt/hostedtoolcache directory. It is not possible to start the Linux runner with sudo and the /opt directory usually requires root privileges to write to. Check the current user and group that the runner belongs to by typing ls -l inside the runners root directory.
  • The runner can be granted write access to the /opt/hostedtoolcache directory using a few techniques:
    • The user starting the runner is the owner, and the owner has write permission
    • The user starting the runner is in the owning group, and the owning group has write permission
    • All users have write permission
  • One quick way to grant access is to change the user and group of /opt/hostedtoolcache to be the same as the runners using chown
    • sudo chown runner-user:runner-group opt/hostedtoolcache/
  • If your runner is configured as a service and you run into problems, make sure the user that the service is running as is correct. For more information, you can check the status of your self-hosted runner.

和訳

setup-pythonとセルフホストランナーを使用したい場合は、新しいバージョンのPythonをダウンロードしてランナーに構成できるように設定する必要がある追加の事項がいくつかあります。

  • actions/python-versionsからダウンロードされたPythonパッケージは、元々ソースから/opt/hostedtoolcache/に--enable-sharedフラグを付けてコンパイルされているため、再配置できません。
  • AGENT_TOOLSDIRECTORYという環境変数を作成し、それを/opt/hostedtoolcacheに設定します。これは、ランナーがツールをダウンロードしてインストールする場所を制御します。
    • ランナーが使用しているのと同じシェルで、export AGENT_TOOLSDIRECTORY=/opt/hostedtoolcacheと入力します
    • 環境変数を設定するより永続的な方法は、ランナーと同じディレクトリに.envファイルを作成し、AGENT_TOOLSDIRECTORY=/opt/hostedtoolcacheを追加することです。これにより、ランナーがサービスとして構成されている場合、変数が常に設定されます。
  • /opt内にhostedtoolcacheというディレクトリを作成します。
  • ランナーを開始するユーザーには、 /opt/hostedtoolcacheディレクトリへの書き込み権限が必要です。 Linuxランナーを sudoで起動することはできません。/optディレクトリには通常、書き込みにroot権限が必要です。ランナーのルートディレクトリにls -lと入力して、ランナーが属する現在のユーザーとグループを確認します。
    • ランナーを開始したユーザーが所有者であり、所有者に書き込み権限がある
    • ランナーを開始したユーザーは所有グループに属しており、所有グループには書き込み権限があります
    • すべてのユーザーに書き込み権限があります
  • アクセスを許可する簡単な方法の1つは、/opt/hostedtoolcacheのユーザーとグループを、ランナーと同じになるように chownを使用して変更することです。
    • sudo chown runner-user:runner-group opt/hostedtoolcache/
  • ランナーがサービスとして構成されているときに問題が発生した場合は、サービスが正しく実行されていることをユーザーに確認してください。詳細については、セルフホストランナーのステータスを確認できます。

今回行うこととしたsetup-pythonアクション向けの設定

以上の記載を参考に、self-hosted runnerを実行する環境でsetup-pythonアクション向けに今回は次の設定を行うことにします。

  • ランナーと同じディレクトリに.envファイルを作成し、AGENT_TOOLSDIRECTORY=/opt/hostedtoolcacheを追加する
  • /opt内にhostedtoolcacheディレクトリを作成する
  • /opt/hostedtoolcacheのユーザーとグループを、ランナーと同じになるように chownを使用して変更する

設定をする

self-hosted runner自体の設定

まずCloud9上でself-hosted runner自体の設定をします。

GitHub Actionsを利用したいRepositoryのページで、[Settings]タブ - [Actions]で[Add runner]をクリックします。 image.png

表示される[Download]と[Configure]のコマンドを控えます。 image.png

AWS Cloud9のコンソールを開き、控えたコマンドを実行していきます。

まずactions runnerのツールをダウンロードして展開します。

$ mkdir actions-runner && cd actions-runner
$ curl -O -L https://github.com/actions/runner/releases/download/v2.262.1/actions-runner-linux-x64-2.262.1.tar.gz
$ tar xzf ./actions-runner-linux-x64-2.262.1.tar.gz

./config.shを実行してRunnerのGitHubへの登録を行います。

$ ./config.sh --url https://github.com/{user}/{repo} --token XXXXXXXXXXXXXXXX

setup-pythonアクション向けの設定

次に同環境でsetup-pythonアクション向けの設定を行います。

actions-runner/.envファイルにAGENT_TOOLSDIRECTORY=/opt/hostedtoolcacheを追記します。

actions-runner/.env

LANG=en_US.UTF-8
JAVA_HOME=/usr/lib/jvm/java
NVM_BIN=/home/ec2-user/.nvm/versions/node/v10.16.0/bin
NVM_PATH=/home/ec2-user/.nvm/versions/node/v10.16.0/lib/node
AGENT_TOOLSDIRECTORY=/opt/hostedtoolcache

/opt配下にhostedtoolcacheディレクトリを作成します。

$ mkdir /opt/hostedtoolcache

/opt/hostedtoolcacheのユーザーとグループを、ランナーと同じになるように chownを使用して変更します。

$ ls -l actions-runner/run.sh
-rwxr-xr-x 1 ec2-user ec2-user 1666 May 21 20:37 actions-runner/run.sh
$ sudo chown ec2-user:ec2-user /opt/hostedtoolcache/

self-hosted runnerでsetup-pythonアクションを実行するとエラーとなった

それではここまでで設定した環境でself-hosted runnerによりsetup-pythonアクションを実行してみます。

まずランナーを起動させます。./run.shを実行し、プロンプトにListening for Jobsと表示されれば、self-hosted runnersがアクティブになり、CIが実行可能な状態となっています。

$ actions-runner/run.sh

√ Connected to GitHub

2020-06-10 11:22:59Z: Listening for Jobs

ソースコードのGitHub Actionsのコンフィグは次のようになります。setup-pythonアクションを使用してPython環境を作成するだけのworkflowとなります。

.github/workflows/action.yml

name: Workflow

on:
  push:

jobs:
  cicd:
    runs-on: self-hosted

    steps:
    - uses: actions/setup-python@v2

ソースコードのcommitをGitHubにpushします。するとGitHub ActionsのWorkflow画面でジョブ実行が開始されます。 image.png

少し経つとactions/setup-python@v2の実行でエラーとなりジョブが失敗しました。 image.png

エラーの出力は以下のようになりました。

Run actions/setup-python@v2
  with:
    python-version: 3.x
    token: ***
Version 3.x was not found in the local cache
##[error]Version 3.x with arch x64 not found
The list of all available versions can be found here: https://raw.githubusercontent.com/actions/python-versions/master/versions-manifest.json

切り分け

切り分けとして、Actionsのコンフィグを編集していくつかのパターンでCIを実行させてみます。

GitHub-hosted runnerで実行した場合

以下のようにjobのruns-onubuntu-latestに変更してGitHub-hosted runnerで実行されるようにしてみます。

.github/workflows/action.yml

name: Workflow

on:
  push:

jobs:
  cicd:
    runs-on: ubuntu-latest

    steps:
    - uses: actions/setup-python@v2

この場合はCI実行は成功しました。

image.png

self-hosted runnerでsetup-goアクションを実行した場合

次に、以下のようにjobで実行するstepをuses: actions/setup-go@v2に変更して、go環境の作成がself-hosted runnerで実行されるようにしてみます。

.github/workflows/action.yml

name: Workflow

on:
  push:

jobs:
  cicd:
    runs-on: self-hosted

    steps:
    - uses: actions/setup-go@v2

この場合もCI実行は成功しました。 image.png

以上の切り分けにより、self-hosted runnerとsetup-pythonアクションの組み合わせの時に何かしらの問題が発生しているようです。(もちろん他の条件が影響している可能性もあります)

類似の事象が報告されている

出力されたエラーログVersion 3.x was not found in the local cacheなどでググってみると、actions/setup-python Repositoryで前月(2020/5)に以下のissueがopenされていました。

内容は今回遭遇した事象と状況もエラー内容も類似しています。ただし、issue内ではいくつかのユーザーが「/opt/hostedtoolcache配下にPythonがインストールされているにも関わらずCI実行が失敗する」と報告していますが、私の環境ではエラー発生後にも/opt/hostedtoolcache配下にはPythonのインストールはされておらず空のままでした。

ただし今回と類似の事象のissueであるのには変わりないため、こちらの対応を待ってみたいと思います。

代替案

今回のエラーを回避する代替案はいくつか考えられますが、CIの要件によって取りうる方法は違ってくるかと思います。

  • Python環境の作成にsetup-pythonアクションを使用する必要性がない場合

job内でsetup-pythonアクションを使用しなければ、self-hosted runnerの実行環境にすでにインストールされているPythonがjob実行に使用されます。

ただし、複数種類のバージョンのPythonを利用する場合はjob実行ごとのバージョン切り替えを工夫する必要があるかと思います。

また、ドキュメント[Using Python without setup-python]にある通り、GitHubとしてはPython環境が必要な場合はsetup-pythonアクションを使用するのが推奨とのことです。

  • Self-hosted runnerを使用する必要性がない場合

Amazon Linuxなど、GitHub-hosted runnerで用意されていないOS環境(現在用意されているのはUbuntu、Mac、Windowsのみ)でjobを実行したい場合は、job内で任意のDockerイメージから起動したコンテナ上でCIを実施するという方法が考えられます。

おわりに

GitHub Actionsのself-hosted runnerでsetup-pythonアクションを使用しようとした際にエラーとなりハマった話でした。

ハードウェア的な制約や要件などが特になければ、代替案でも示した「job内で任意のDockerイメージから起動したコンテナ上でCIを実施する」方法が個人的にはスマートではないかと思っています。次回以降にこの方法を検証した結果をご紹介したいと思います。

以上