Jenkins & GitHub WebhooksでROS 2のビルド・テストを自動化する
海洋ロボコンをやってた人です。
今回はJenkinsを触ってROS 2パッケージのビルド・テストを自動化してみたので、その備忘録として記載していきます。
構成図は以下です。
JenkinsとはオープンソースのCI/CDツール
※1, 2 で、Javaで書かれたWebアプリケーションにてソフトウェアのビルド・テスト・デプロイメントなどのプロセスを自動化できます。
これにより、変更を本番環境に反映させるという手間の改善が期待されます。
※1 CI: Continuous Integration(継続的インテグレーション)
※2 CD: Continuous Deployment(継続的デプロイメント)
記事を書いた理由は以下です。
- CI/CDを触りながら学びたいため
- 後から使い方を自分で見直せるようにするため
CI/CDツールにはGitHub Actionsを始め、様々なツールがあると思います。
一方、Zenn: Github Actionsの「テンション上がるところ」と「注意点」にもあるように、Jenkinsと比べて管理しづらいところもあるそうなので、手始めにJenkinsを学ぶことにしたのが事の経緯です。
初学者なので、何かコメントあれば積極的に募集します。
使用機器と環境は以下です。
-
Jenkinsサーバー側: docker on Ubuntu 22.04 Laptop PC
- jenkins --version 2.401.2 (直でインストールする場合)
- Docker version 20.10.21, build 20.10.21-0ubuntu1~22.04.3
- docker-compose version 1.29.2, build unknown
-
リモートサーバー側: Ubuntu 20.04 Jetson Nano B01
- ROS 2 Foxy
※ 2023/8 GitHub ActionsとJenkinsどっちを使用するのが良いのか?という疑問に対しては、使用する際の環境と以下の相違点を踏まえて判断していただければと思います。
Jenkinsのインストール
この章ではJenkinsのインストール方法を2種類記載しますが、表題の自動化はDockerを使用しています。
お手元の使用環境に応じて、選択してください。
Jenkinsを直でインストール
まずは、Jenkinsを直でインストールする方法を記載します。
環境の再現性、拡張性、管理の容易性の観点から考えると、Docker上でJenkinsサーバーを動かす方が良いと思いますが、設定のシンプルさでは直インストールが楽かもしれません。
- Jenkinsに必要なJavaをインストール
sudo apt install default-jre
java -version
sudo apt install default-jdk
sudo apt install openjdk-17-jdk
javac -version
- 最新リポジトリの著名鍵:signing keysを取得
curl -fsSL https://pkg.jenkins.io/debian-stable/jenkins.io-2023.key | sudo tee \
/usr/share/keyrings/jenkins-keyring.asc > /dev/null
echo deb [signed-by=/usr/share/keyrings/jenkins-keyring.asc] \
https://pkg.jenkins.io/debian-stable binary/ | sudo tee \
/etc/apt/sources.list.d/jenkins.list > /dev/null
- Jenkinsのインストール
sudo apt update
sudo apt install jenkins
jenkins --version
- Jenkinsをインストール後、JenkinsサーバーがActiveかどうかを確認
sudo systemctl status jenkins
もしstatusがActive
でなければ、sudo systemctl start jenkins
でjenkins.serviceをActiveにします。
ファイアウォール有効の確認もしておきましょう。
sudo ufw enable
- Jenkinsサーバーの動作確認
Active後、以下をブラウザで入力するとJenkinsサーバにアクセスすることができます。
http://localhost:8080/
もしJenkinsサーバーにアクセスできない場合は、/etc/hosts
を確認します。
また、Jenkinsサーバーの初期パスワードは/var/lib/jenkins/secrets/initialAdminPassword
で確認できます。
sudo cat /etc/hosts
sudo cat /var/lib/jenkins/secrets/initialAdminPassword
Unlock Jenkins画面で初期パスワードを入力後、Customize Jenkins画面に遷移します。
こちらはコミュニティで最も必要だと知られているプラグインの設置:Install suggested plugins
を選択で良いと思います。
※ 調査中
http://localhost
でなく、マイコン等にJenkinsを直インストールし、マイコンのIPアドレスを使用してJenkinsサーバーにアクセスした際、プラグインインストールのGitでエラーになることがありました。
こちらは先にlocalhostでInstall suggested pluginsのGitHubをインストール後に、Jenkinsサーバーを再起動することで解決しましたが、原因が分かり次第追記します。
Create Admin User画面では、ユーザー名やパスワードの設定後、Save and Continue
で設定を保存します。
ユーザー名やメールアドレスはあとからダッシュボード>Jenkinsの管理>Users
から変更可能です。
これでログインできれば、Jenkinsで遊ぶ準備は完了です。
もしJenkinsサーバーの停止や、Jenkinsの削除するときは、以下を実行します。
sudo systemctl stop jenkins
sudo apt autoremove jenkins
Jenkins-dockerのインストール
続いて表題のビルド・テスト環境で使用した、Jenkins-dockerのインストール方法も記載します。
ディレクトリ構成は以下のとおりです。
jenkins-docker
├ Dockerfile
├ docker-compose.yaml
- docker-composeのインストール
複数のコンテナを使用するためにdocker-composeをインストールします。
sudo apt install docker-compose
docker-compose --version # docker-compose version 1.29.2, build unknown
- docker-compose.yaml等のファイル作成
jenkins-dockerというフォルダ下にDockerfileとdocker-compose.yamlを格納します。
mkdir -p jenkins-docker && cd ~/jenkins-docker/
sudo nano Dockerfile
sudo nano docker-compose.yaml
Dockerfileにて、jenkins/jenkins:lts-jdk11
のイメージをベースにDockerイメージを作成します。
FROM jenkins/jenkins:lts-jdk11
RUN jenkins-plugin-cli --plugins pipeline-model-definition github-branch-source:1.8
docker-compose.yamlにてjenkinsとssh-agentというコンテナを定義します。
services:
jenkins:
image: jenkins/jenkins:lts
ports:
- "8080:8080"
volumes:
- jenkins_home:/var/jenkins_home
ssh-agent:
image: jenkins/ssh-agent
volumes:
jenkins_home:
ports
はホストのポート8080をコンテナのポート8080にマッピングしています。
volumes
はJenkinsコンテナ内の/var/jenkins_home
ディレクトリに保存されるデータを、`jenkins_homeという名前の永続ボリュームに永続的に保存します。
Dockerはデフォルトで永続化ボリュームの名前を<プロジェクト名>
_<jenkins_home>として関連付けています。
- jenkins-dockerの起動を確認する
以下のコマンドでdocker-composeを起動します。
sudo docker-compose up
http://localhost:8080/
にアクセスし、JenkinsサーバーにアクセスできればOKです。
initialAdminPassword
はdocker-compose upするとターミナルに表示されているので、そちらを見つけて使用しましょう。
- docker関連のコマンド
docker-composeを触る上で、使用したdockerコマンドも併記しておきます。
sudo docker-compose ps
sudo docker-compose images
sudo docker-compose down
sudo docker volume ls
sudo docker volume prune # ボリュームをすべて削除
JenkinsでROS 2のビルトとテストを試す
Jenkinsサーバーの準備ができたら、本題のROS 2ビルド&テストを試していきます。
Jenkinsジョブの設定
Jenkinsサーバー側でGitHubのpushによりシェルスクリプトを実行するジョブを作成します。
- フリースタイル・プロジェクトの作成
Create a job > Enter an item name と進み、build_and_test
のようにジョブ名をつけてフリースタイル・プロジェクトとして作成します。
- GitHubの設定
ROS 2パッケージのビルドとテストを試すようにros2_topic_sampleを準備したので、このリポジトリのpushがトリガになるように以下3つを設定します。
・General > GitHub project > Project url
へgitのweb URLを記入します。
・ソースコード管理 > Git > リポジトリURL
にもgitのweb URLを記入します。
・ビルド・トリガ > GitHub hook trigger for GITScm polling にチェック
※ Jenkinsの管理 > Plugins > Available plugins > GitHub Pipeline for Blue Ocean
でGitHub用のプラグインを使用する方法もあるようです。
- シェルスクリプトの記入
Build Steps > シェルの実行(Execute shell)
を選び、Githubのpushに応じて実行されるシェルを記入します。
GitHubと紐付けると、対象のリポジトリが/var/jenkins_home/workspace/ジョブ名(ここではbuild_and_test)下にクローンされるので、その内容に対しての処理を行います。
流れとしてはros2_wsを作成 > リモートマイコンにscpでワークスペースごとコピー > リモートマイコン上でcolcon build & colcon testを実行
という形です。
また後述しますが、Jenkins側でssh接続等する場合はパスワード入力等ができないので、事前に公開鍵などを登録しておく必要があります。
#!/bin/bash
pwd
ls
mkdir -p ros2_ws/src/ros2_topic_sample
#! 現在のディレクトリのファイルを一時的に記録
files=$(ls -A)
#! 一時的なフォルダにファイルを移動
echo "file move"
for file in $files
do
if [ "$file" != "ros2_ws" ]; then
mv -f "$file" /var/jenkins_home/workspace/build_and_test/ros2_ws/src/ros2_topic_sample
fi
done
#! リモートマイコンのIPアドレスとユーザー名を設定
remote_ip="192.168.11.7"
remote_user="jetson"
remote_path="/home/jetson"
#! Jenkinsホームディレクトリのパス
jenkins_home="/var/jenkins_home"
#! マイコンにros2_wsディレクトリを送信
echo "---scp shellscript---"
scp -i "$jenkins_home/.ssh/id_rsa_new" -r "$jenkins_home/workspace/build_and_test/ros2_ws" "$remote_user@$remote_ip:$remote_path"
#! リモートマイコン上でcolcon buildを実行
echo "---ssh shellscript---"
ssh -i "$jenkins_home/.ssh/id_rsa_new" "$remote_user@$remote_ip" <<EOF
source /opt/ros/foxy/setup.bash
echo "---colcon build script---"
cd $remote_path/ros2_ws && colcon build
echo "---colcon test script---"
colcon test
colcon test-result
EOF
echo "---Finish---"
Jenkinsからssh接続するための設定
上記でも記載しましたが、Jenkinsのシェル実行でsshコマンドを記載しても、パスワードを求められるので、接続できません。
そこで、Jenkinsサーバーが起動しているdocker containerに入り、リモートマイコンとの公開鍵を設定する必要があります。
sudo docker container exec -it -u 0 jenkins-docker_jenkins_1 bash
dockerコンテナ内に入ったら、以下を実行し公開鍵の生成と表示確認します。
公開鍵ですが、管理者には全権限
を付与し、他ユーザーには書込+読込
の権限を付与するためにchmod 766
を設定しています。
公開鍵暗号方式での接続なので、書込+読込権限付与はセキュリティ面で良くないと思いますが、一旦はこちらで進めます。
ssh-keygen -t rsa -b 4096 -f /var/jenkins_home/.ssh/id_rsa_new -C "Jenkins SSH Key" -N ""
chmod 766 /var/jenkins_home/.ssh/id_rsa_new
# Jenkinsサーバー上の公開鍵を表示
cat /var/jenkins_home/.ssh/id_rsa_new.pub
公開鍵を確認できたら、リモートマイコン側に接続し、公開鍵の内容をauthorized_keys
にコピーしてください。ssh-copy-id 接続される側@接続するhost側
を使用しても公開鍵をコピーできます。
nano ~/.ssh/authorized_keys
上記が上手く設定できていれば、Jenkinsサーバーで以下を実行した際に接続ができるようになります。
ssh -i /var/jenkins_home/.ssh/id_rsa_new jetson@192.168.11.7
Jenkins URLの設定
JenkinsとGitHubを連携する際にはgithub-webhook
を使用します。
github-webhookですが、JenkinsサーバーのURLがhttp://localhost
から始まっていると使用できません。
方法としては
・Jenkinsの管理 > Jenkinsのユーザーデータベース > Setting > APIトークンを生成
・Jenkinsの管理 > System > Jenkinsの位置 > Jenkins URLの変更
などもありますが、
Youtube: Jenkins #6 | Auto Trigger Jenkins Jobs using GitHub Webhooksを参考にngrokでhttps経由でアクセスできるようにしました。
ngrokのインストールおよび起動は以下です。
snap install ngrok
ngrok http 8080
httpsに変換されたURLでJenkinsサーバーにアクセスできればOKです。
また、httpsに変換されたURLはgithub-webhookのPayload URL
で使用するので、コピーしておいてください。
GitHub側の設定
最後にGithub側で設定をしていきます。
対象のリポジトリで Setting > Left Panel: Webhooks >> Add webhook
と進み、5項目を以下のように設定します。
-
Payload URL:
ngrokで取得したhttpsのURL/github-webhook/
※ ex:https://abcdefg/github-webhook/
-
Content type:
application/x-www-form-urlencoded
-
SSL verification:
Enable SSL verification
-
Which events would you like to trigger this webhook?: Let me select individual events >
Pushes
-
Active:
check
上手く設定できていれば、以下のように✅マークが表示されます。
もし✅マークがつかず上手く接続できない場合は、「Edit」ではなくWebhooksを一度「Delete」後に再度Webhooksを追加してみてください。
GithubのpushイベントによってJenkinsのジョブが起動すればOKです。
以上、お疲れ様でした。
Reference
- Jenkins
How to install Jenkins on Ubuntu 22.04
The Construct: Jenkins Basics for Robotics | ROS2 Developers Open Class
TECH ART ONLINE: Jenkinsの使い方と環境構築方法、定期的にビルドする環境を作ろう!
- Jenkins-Docker
- Jenkins-ngrok
Discussion