はじめに

モノづくりの現場において、さまざまな面でデジタル化が進んできました。精密機器や洋服のデザインは紙から CAD(コンピュータ支援設計: Computer-Aided Design)へ、建築業であれば CAD から BIM(建物情報モデル: Building Information Modeling)、実験やテストにおいても、現物ベースのテストからシミュレータの活用など、新規データの作成から、過去データの活用まで、さまざまな形でデジタルデータが活用されています。

ただし、ソフトウェアの側から見ると、必ずしも入力される一次情報が全てデジタル由来というわけではなく、カメラやマイク、さらには人間の五感では捉えきれない情報がセンサーを通じて入力されているのも、一方では事実です。

ソフトウェアテストという観点からは、そういった非デジタルに由来する入力のテストをどう扱うか、単体レベルではスタブやドライバ、モックでソフトウェア的に代替しつつも、システムレベルでは実機テスト、実環境テストを適用したい場合があります。従来、「ハードウェア」のカテゴリで扱われていた製品であっても、ソフトウェアのバージョンアップによって、新たな機能が加わる(テスラの車がまさにそうですね)、つまり、ハードウェアであっても powered by software な時代に、CI/CD はどういった貢献ができるのか。CircleCI ランナー や Arm ベースの Machine Executor など、組み込みソフトウェア開発への CI/CD の適用について、ご紹介していきます。

取り上げる内容

具体的な話に移りましょう。今回のターゲットデバイスは、Raspberry Pi(ラズベリーパイ、ラズパイ)です。Raspberry Pi にSeeed 社Groveシステムが提供するさまざまなセンサーやアクチュエータ、出力デバイスを(はんだ付けすることなく)つなげて、ハードウェアとソフトウェアの開発、およびテストをしていきます。

全4回で、次のような内容をご紹介します。

  1. Raspberry Pi 上での CircleCI ランナーの設定(本ブログ)
  2. Raspberry Pi 上での GrovePI+ 実行環境の設定
  3. CircleCI ランナーを使ったセンサー使用ソフトウェアのテスト
  4. Arm ベースの Machine Executor を使ったソフトウェアのビルド

2021-04-02-masahiko-hello-runner-on-raspberrypi.jpeg

なお、本ブログの記述時(2021 年 4 月現在)、CircleCI ランナーに関わる 1, 3 をご自身で実際に試すには、CircleCI の Scale プランをご契約いただく必要があります。一方、Arm ベースの Machine Executor に関わる 4 をご自身でお試しいただくには、こちらのアクセス申請フォームよりお申し込みをいただく必要があります(Free プランを含む全てのプランで利用可能です)。

CircleCI ランナー のインストール

CircleCI ランナーのインストールの方法は、オンラインの CircleCI ドキュメントにもステップを追って詳しく書かれていますが、本ブログでは、「Raspberry Pi にインストールする」という観点から、詳しく説明していきます。

なお、インストール作業は、大きく2つに分けられます。

  1. 認証(名前空間と認証トークンの作成) - macOS、または Linux(x64)上
  2. CircleCI ランナーのインストール - Raspberry Pi 上

説明内容を実行するための前提条件

  • 認証を行うために、CircleCI CLIをインストールし、動作する環境(具体的には、Mac または Linux(x86)が動作する環境。Windows の場合は WSL 上の Linux にインストール可能)。
  • 64bit 版のUbuntu Desktop 20.10をインストールし、動作する Raspberry Pi 環境(具体的には、Raspberry Pi 4、または Raspberry Pi 400)。なお、Raspberry Pi では Ubuntu Server も動作可能ですが、32bit 版では CircleCI ランナーは動作しません(詳しくは、サポート対象プラットフォームをご覧ください)。
  • Raspberry Pi は外部(CircleCI)からアクセスできる環境に設置しておく必要はありませんが(インバウンド接続は不要ですが)、以下の3アドレスへのアウトバウンド HTTPS 接続が可能であること。
    • runner.circleci.com
    • circleci-binary-release.s3.amazonaws.com
    • circle-production-customer-artifacts.s3.amazonaws.com

認証(名前空間と認証トークンの作成)

認証で説明の際に使用している番号に合わせて、説明していきます。

1. CircleCI コマンドラインツールのインストール

macOS 環境、または Linux(x64)環境にCircleCI コマンドラインツールをインストールし、CLI の構成までの手順(つまり、circleci setupを実行してのパーソナル API トークンの設定)までを完了しておきます。

2. 名前空間の作成

CircleCI Scale プランを契約している組織のランナー リソース用の名前空間を作成します。すでに組織で Orbs を作成したことがあれば、その際に名前空間も作成してあるので、このステップを飛ばして、次に進みます。

circleci namespace create <名前空間> <vcs種別> <組織名>

筆者の場合は、

circleci namespace create mayoct github Mayoct

を実行しました。

3. ランナー用リソースクラスの作成

名前空間内にランナー用のリソースクラスを作成します。

circleci runner resource-class create <リソースクラス名> <説明>

筆者の場合は、

circleci runner resource-class create mayoct/arm-runner "Arm Runner"

を実行しました。

4. 認証用トークンの作成

ランナーが認証のために使用する(後述)、トークンを作成します。

circleci runner token create <リソースクラス名> <ニックネーム>

筆者の場合は、

circleci runner token create mayoct/arm-runner "Arm Runner"

を実行すると、auth_token として英小文字+数字を組み合わせた 80 文字が通知されました。 後で参照する方法はないので、手元に大事に保管しておくとともに、外部に漏洩することのないようにします。

CircleCI ランナーのインストール

オンラインドキュメントのインストールに必要なツールジョブ実行の要件インストールにて紹介されている順番を踏まえて、Raspberry Pi 上の Ubuntu でのインストール方法をご紹介していきます。

1. 必要なツールのインストール

ここから Raspberry Pi 上での作業に入ります。Raspberry Pi にディスプレイ、キーボード、マウス等を接続するか、Raspberry Pi に対して、SSH 接続、または VNC 接続や X サーバ接続した上で、以下の操作を行なっていきます。

まずは、前述したインストールに必要なツールで紹介されているツール、およびジョブ実行の要件で紹介されているツールをインストールします。

sudo apt-get install curl sha256sum coreutils git

2. ローンチ エージェント バイナリのダウンロード、インストール

ランナーの操作でも説明されているように、CircleCI ランナーは、

  • ローンチ エージェント (root ユーザーとして実行)
  • タスク エージェント (circleci ユーザーとして実行)

の2つのエージェントから構成されています。最初にローンチ エージェントをインストールします。

インストール手順はスクリプトとして提示されていますが、問題発生時の切り分けが容易になるよう、初めて実行するのであれば、1行ごとにコピー&ペーストしながら実行されることをお勧めします。なお、下に示した例では、例示されているスクリプトの1行目の前に、platform=linux/arm64でインストール対象を指定するための変数を設定していることにご注意ください。

platform=linux/arm64
prefix=/opt/circleci
sudo mkdir -p "$prefix/workdir"
base_url="https://circleci-binary-releases.s3.amazonaws.com/circleci-launch-agent"
echo "Determining latest version of CircleCI Launch Agent"
agent_version=$(curl "$base_url/release.txt")
echo "Using CircleCI Launch Agent version $agent_version"

筆者環境では、次のようなメッセージが出力されました。

Using CircleCI Launch Agent version 1.0.8765-4fbd4ff

さらに続きます。

echo "Downloading and verifying CircleCI Launch Agent Binary"
curl -sSL "$base_url/$agent_version/checksums.txt" -o checksums.txt
file="$(grep -F "$platform" checksums.txt | cut -d ' ' -f 2)"
file="${file:1}"
mkdir -p "$platform"
echo "Downloading CircleCI Launch Agent: $file"

筆者環境では、次のようなメッセージが出力されました。

Downloading CircleCI Launch Agent: linux/arm64/circleci-launch-agent

さらに続きます。

curl --compressed -L "$base_url/$agent_version/$file" -o "$file"
echo "Verifying CircleCI Launch Agent download"
sha256sum --check --ignore-missing checksums.txt && chmod +x "$file"; sudo cp "$file" "$prefix/circleci-launch-agent" || echo "Invalid checksum for CircleCI Launch Agent, please try download again"

筆者環境では、次のようなメッセージが出力されました。

linux/arm64/circleci-launch-agent: OK

3. Ubuntu on Raspberry Pi への CircleCI ランナーのインストール方法

Linux への CircleCI ランナーのインストール方法に沿って説明していきます。

まずは、CircleCI ランナー設定ファイルを作成するで説明されているように、CircleCI ランナー設定ファイル(/opt/circleci/launch-agent-config.yaml)を作成し、以下の内容を保存します。

api:
  auth_token: <認証トークン>
runner:
  name: <ランナー名>
  command_prefix: ["/opt/circleci/launch-task"]
  working_directory: /opt/circleci/workdir/%s
  cleanup_working_directory: true

なお、<認証トークン>には前述の認証トークンを、<ランナー名>には名前空間を含めないランナー名(筆者の例ではmayoct/を含めないでarm-runnerのみ)を指定する様、注意します。

次に、CircleCI ランナー設定ファイルをインストールするで説明されているように、このランナー設定ファイル(launch-agent-config.yaml)に適切な所有者(root)、および必要最低限のパーミッション(600)を設定します。

sudo chown root: /opt/circleci/launch-agent-config.yaml
sudo chmod 600 /opt/circleci/launch-agent-config.yaml

次に、CircleCI ユーザーと作業ディレクトリを作成するで説明されているように、タスクエージェントを実行するユーザー(circleci)と作業ディレクトリ(/opt/circleci/workdir)を作成します。

id -u circleci &>/dev/null || sudo adduser --uid 1500 --disabled-password --gecos GECOS circleci

mkdir -p /opt/circleci/workdir
sudo chown -R circleci /opt/circleci/workdir

上記の例は、オンラインドキュメントにあるスクリプト例に対して、1行目途中のadd userにはsudo、最終行のchownも同様にsudo権限で実行するように変更を加えていることに注意してください。

次に、タスク起動用スクリプトを作成するで説明されているように、タスク起動用スクリプト(/opt/circleci/launch-task)を用意します。

#!/bin/bash

set -euo pipefail

## このスクリプトでは、終了時に子プロセスすべてを適切にクリーンアップするため、
## systemd-run を使用して build-agent を起動し、
## これらの子プロセスがすべて所属する cgroup を作成します。

# build-agent の実行ユーザーは数値で指定する必要があります
USER_ID=$(id -u circleci)

# 一時的な systemd ユニットにわかりやすい名前をつけます
unit="circleci-$CIRCLECI_LAUNCH_ID"

# プロセスの終了時に systemd ユニットをシャットダウンします
abort() {
  if systemctl is-active --quiet "$unit"; then
    systemctl stop "$unit"
  fi
}
trap abort EXIT

systemd-run \
    --pipe --collect --quiet --wait \
    --uid "$USER_ID" --unit "$unit" -- "$@"

そして、先ほどと同様の方法で、/opt/circleci/launch-taskファイルの所有者(root)とパーミッション(755)を設定します。

sudo chown root: /opt/circleci/launch-task
sudo chmod 755 /opt/circleci/launch-task

次に、systemd ユニットを有効にするで説明されているように、circleci.serviceとして実行する内容を、/opt/circleci/circleci.serviceとして定義します。

[Unit]
Description=CircleCI Runner
After=network.target
[Service]
ExecStart=/opt/circleci/circleci-launch-agent --config /opt/circleci/launch-agent-config.yaml
Restart=always
User=root
NotifyAccess=exec
TimeoutStopSec=18300
[Install]
WantedBy = multi-user.target

そして、先ほどと同様の方法で、/opt/circleci/circleci.serviceファイルの所有者(root)とパーミッション(755)を設定します。

sudo chown root: /opt/circleci/circleci.service
sudo chmod 755 /opt/circleci/circleci.service

設定が完了したら、サービスを有効化します。

prefix=/opt/circleci
systemctl enable $prefix/circleci.service

有効化した circleci.service サービスを起動します。

systemctl start circleci.service

サービスを起動したら、サービスの実行状態を確認するに書かれているように、systemctlコマンドで または journalctl コマンドで、サービスが正しく実行されているかを確認してください。

筆者の環境では、systemctlコマンドの実行結果は次の通りでした(合わせてfileコマンドでcircleci-launch-agentバイナリの属性を出力しており、ARM aarch64 アーキテクチャで動作する Linux バイナリ形式であることが分かります)。

2021-04-02-masahiko-runner-systemctl-img02.jpeg

また、journalctlコマンドの実行結果は次の通りでした。

 4月 07 17:11:28 MAYOCT-RP01 systemd[1]: Started CircleCI Runner.
 4月 07 17:11:28 MAYOCT-RP01 circleci-launch-agent[3515]: time="2021-04-07T17:11:28+09:00" level=info msg="CircleCI launcher starting" config=/opt/circleci/launch-agent-config.yaml
 4月 07 17:11:28 MAYOCT-RP01 circleci-launch-agent[3515]: time="2021-04-07T17:11:28+09:00" level=info msg="loaded config" name=arm-runner url="https://runner.circleci.com"
 4月 07 17:11:30 MAYOCT-RP01 circleci-launch-agent[3515]: time="2021-04-07T17:11:30+09:00" level=info msg="no task found"

おわりに

今回のブログでは、Raspberry Pi の Ubuntu 環境上で Arm 版の CircleCI Runner が動作可能な環境を構築することができました。次回のブログでは、Raspberry Pi にセンサーを接続し、センサーの値を読み取るプログラムが動作しているかテストするワークフローをご紹介いたします。

リファレンス

CircleCI ドキュメント

CircleCI ブログ(日本語)

その他 関連情報