0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Jenkins基礎と自動運転を題材にしたCI/CDパイプライン構築ハンズオン

0
Posted at

1. はじめに

本記事を書こうと思ったきっかけ

Jenkinという言葉はよく聞くのですが、これまで利用したことがなくJenkinを用いたCI/CD、パイプライン構築についてイメージがわかなかったため独自で調査し本記事を執筆しました。また自動運転(どちらかというとADAS寄り)に絡めてハンズオン形式にしていますので、自動運転開発やCI/CDに興味がある方は是非ご一読ください。

自動運転開発とCI/CDの親和性

自動運転システムの開発では、カメラやLiDARといったセンサーの入力データ処理や、車両の挙動を決定する制御ロジックなど、多岐にわたるコードが組み合わさっています。このような複雑なシステムでは、わずかなコード修正が意図しない挙動(例えばブレーキが効かない、急ブレーキを踏むなど)を引き起こすリスクがあります。

安全第一である自動運転開発において、コードを変更するたびに手動でビルドやテストを行うことは時間がかかるだけでなく、ヒューマンエラーの原因にもなります。そこで、変更されたコードを自動で検証するCI/CD(継続的インテグレーション/継続的デリバリー)が極めて重要な役割を果たします。

CI/CDとは

CI/CDとは、ソフトウェア開発におけるビルド、テスト、デプロイを自動化するための仕組みです。
大きくCI(Continuous Integration:継続的インテグレーション)とCD(Continuous Delivery/Deployment)からなります。CIではソースコードの変更を統合する、ビルド・テストを自動実行する、不具合を早期発見する役割があります。CDはテストを通過した成果物を自動で配布可能な状態にする、本番環境へのリリースを自動化する役割があります。

本記事で体験するハンズオンの全体像

本記事では、特別なシミュレータやハードウェアを必要とせず、Docker環境が動作するローカルPC(Windows/Mac/Linux)のみで手軽に実行できる環境を作ります。
題材として、Pythonで実装した簡易的な衝突被害軽減ブレーキ(AEB: Autonomous Emergency Braking)の制御コードを使用します。※ECU実装段階ではリアルタイム性、メモリ管理の観点からC/C++などの言語が利用されるかと思いますが今回はあくまで簡易版ということでPythonを採用しています。

本ハンズオンの前提条件として、以下の基礎知識があることを想定しています。

  • Pythonの基本文法: 制御ロジックやテストコードの理解に使用します。
  • Gitの基本操作: リポジトリの初期化、コミット、GitHubへのプッシュ等の操作を行います。
  • Dockerの基礎知識: Jenkinsサーバーの起動、および静的解析やテストを実行するためのカスタムイメージ作成時にDockerを使用します。

このコードに対し、Docker上のJenkinsを用いて以下の処理を自動で実行するパイプラインを構築します。

  1. 静的解析: コードの記述スタイルに問題がないかを自動チェックする。
  2. 単体テスト: 異なる走行条件(前方車両との距離や相対速度)において、ブレーキが設計通りに作動するかをテストする。
  3. ビルド成果物のパッケージング: テストを通過した制御モジュールをリリース用のzip形式にパッケージし、Jenkinsのビルド結果からダウンロードできるようにする。

本記事を通じて、Dockerを用いたJenkinsの基本的な使い方と、自動化パイプラインが開発プロセスをいかに効率化するかを体験できるかと思います。

2. 登場するツールたちの紹介

この章では、今回のハンズオンで使用する4つの開発ツールについて詳しく解説します。それぞれのツールの役割や、なぜ自動運転開発などの現場で広く使われているのかを理解しておきましょう。

Git

Gitはソースコードの変更履歴を記録・管理する分散型のバージョン管理システムです。

自動運転開発では、AIモデルの改善、制御ロジックの修正、シミュレータとの連携など、日々無数のプログラム更新が発生します。また、複数の開発者が同時に異なる機能の開発を進めることも日常茶飯事です。

Gitを使用することで、誰がいつどのような変更を加えたのか履歴を完全に残すことができます。万が一、自動ブレーキの挙動に不具合が発生した場合でも、過去の正常に動いていたバージョンへ即座に巻き戻すことが可能です。

Jenkins

Jenkinsは、ソフトウェア開発のビルド、テスト、およびデプロイを自動化するためのオープンソースのCI/CDエンジンです。

自動運転システムのように構成要素が多い開発プロセスでは、コードを変更するたびに手動でビルドし、テストを実行し、成果物をパッケージングするのは大変な作業です。

Jenkinsは、Gitへのコミットなどを検知してこれらの定型作業をあらかじめ定義した手順(パイプライン)に従って全自動で実行します。これにより、開発者は「コードを書くこと」に集中でき、検証漏れも防ぐことができます。
Jenkinsの詳細は次の章で見ていきます。

flake8

flake8は、Pythonのコードが標準的なコーディング規約であるPEP 8に準拠しているかをチェックする静的解析ツール(Linter)です。

プログラムを実行することなく、コードを走査して文法ミスや、使われていない変数の定義、スタイル上の不備(余分な空白や改行など)を検出します。

車載ソフトウェアの開発現場では、コードの品質と可読性を保つために厳格なコーディング標準が定められています。flake8を使用することで、チーム全体のソースコードの書き方を統一し、一目で理解しやすい綺麗な状態に維持できます。

pytest

pytestは、Pythonで書かれたプログラムの動作検証を簡単に行うための単体テストフレームワークです。

テスト用のコードを極めてシンプルに記述でき、検証結果の成否をわかりやすく出力します。

自動運転の制御ロジック開発においては、実車を動かす前にPC上であらゆる走行シナリオを想定したテストを行う必要があります。pytestを使用すれば、様々な入力データ(障害物との距離や車速など)を想定したテストケースを定義し、期待通りに出力(ブレーキの強さなど)が得られるかを自動で何度も検証できます。

3. Jenkinsの概要

簡単にJenkinsの特長および他のCI/CDエンジンとの比較, 基本概念を示します。

Jenkinsの強み

  • プラグインが非常に豊富: 利用できるプラグインは1000種類以上あり、GitHub、GitLab、Docker、AWS、Azureなど様々なツールと連携が可能。
  • あらゆる環境で動作可能: Jenkins自体はJavaアプリケーションであり、Windows、Linuxなど様々な環境で動作する。
  • Pipeline as Code: ビルド手順などパイプラインをコード化しGitで管理できるため、レビュー可能、履歴管理可能、再現性が高い。

Jenkinsの基本概念

Controller

Jenkins全体を管理するサーバです。ジョブ管理、スケジューリング、UI提供、エージェント管理を担っています。

Agent

実際にビルドやテストを実行するマシンです。一方のAgentをLinux、もう一方のAgentをWindowsとしておけば、OSごとのビルドも可能になります。

Node

Jenkinsから見た実行環境の総称です。Controller、Agentの両方を含みます。

Job

Jenkinsに登録されるPiplineの実行単位です。例えばAEBビルド、テスト、Dockerイメージ作成などがそれぞれJobになります。

Pipline

Job内の処理手順を定義したものです。コード取得⇒Lint⇒テスト⇒パッケージ化 のような手順のことで、Jenkinsfileで記述します。

Jenkinsを用いたパイプラインの下記に例を示します。
下記の例は開発者がgithubなどへpushしたコードをトリガーにCI/CDパイプライン実行し、
成果物DBへのデプロイまでを自動化するものです。

Pipelineの下にはさらにStageという概念があります。

Stage

Piplineを構成する作業そのものです。コード取得、Lint、テスト、パッケージ化がそれぞれStageに当たります。
下記のようなイメージです。

その他の代表的なCI/CDツール

GitHub Actions

GitHub公式のCI/CDツールです。GitHubリポジトリと統合でき、設定が簡単、SaaS利用可能な点が強みです。

GitLab CI/CD

GitLabに標準搭載されたCI/CD機能です。DevOps機能が統合されており、セキュリティスキャンが豊富です。

CircleCI

クラウドネイティブなCI/CDサービスです。セットアップが容易で実行速度が速いです。

他にも様々なツールがあり、ユースケースや実行環境に応じて使い分ける、組み合わせて利用する必要があります。

本ハンズオンにおける実行環境について
一般的な大規模開発では、管理を行う「Controller」と、ビルドを実行する複数の「Agent」を別々のサーバー(WindowsやLinux等)に分けて運用します。しかし本ハンズオンでは、簡略化のためDockerコンテナ(Linux環境)内にJenkins Controllerを立ち上げ、そのコンテナ内で直接すべての処理(Lint・テスト・パッケージ化)を実行するシンプルな構成をとります。

説明はここまでとして、いよいよ次章からハンズオンに入っていきます。

4. JenkinsをDockerで起動しよう

この章では、必要なツールがあらかじめインストールされたJenkins環境をDockerを用いて構築します。
今回は、静的解析ツール flake8、テストフレームワーク pytest、および成果物をまとめるための zip コマンドがあらかじめインストールされたカスタムDockerイメージを作成して使用します。

1. カスタムDockerイメージの作成

Jenkinsの公式イメージ(LTS版)をベースに、必要なパッケージをインストールしたカスタムイメージを作成します。

Dockerfileの作成

適当な作業用フォルダ(例:jenkins-setup)を作成し、その中に Dockerfile という名前のファイルを新規作成して以下の内容を記述します。

FROM jenkins/jenkins:lts

USER root

# Python、pip、zipをインストール
RUN apt-get update && \
    apt-get install -y \
        python3 \
        python3-pip \
        zip && \
    rm -rf /var/lib/apt/lists/*

# flake8 と pytest を pip でインストール
RUN pip3 install --break-system-packages \
        flake8 \
        pytest

USER jenkins

イメージのビルド

ターミナル(WindowsではPowerShellなど)を開き、Dockerfile を配置したフォルダに移動して、以下のコマンドを実行してイメージをビルドします。ビルドには数分かかる可能性がありますので気長に待ちましょう。

docker build -t jenkins-python .

「Successfully tagged jenkins-custom:latest」といったログが出力されれば、カスタムイメージのビルドは成功です。

2. Jenkinsコンテナの起動

ビルドしたカスタムイメージ jenkins-custom を使用して、Jenkinsコンテナを起動します。
以下のコマンドを実行します。

docker run -d -p 8080:8080 -p 50000:50000 --name jenkins-local -v jenkins_home:/var/jenkins_home jenkins-python

各オプションの役割は以下の通りです。

  • -d: バックグラウンドでコンテナを実行します。
  • -p 8080:8080: ブラウザからアクセスするためのポート(8080番)をホストPCとマッピングします。
  • -p 50000:50000: Jenkinsのエージェント接続用ポートを指定します。
  • --name jenkins-local: 起動するコンテナに jenkins-local という名前を付けます。
  • -v jenkins_home:/var/jenkins_home: ジョブの設定や実行履歴などのデータをホスト側のボリュームに保存して永続化します。これにより、コンテナを再起動・削除しても設定が失われません。

コマンドを実行し、少し待つとコンテナが起動します。

※コンテナを停止する場合は docker stop jenkins-local、再度起動する場合は docker start jenkins-local を実行します。

Jenkinsの初期セットアップ

Jenkinsが起動したら、Webブラウザを開き、http://localhost:8080 にアクセスします。下記のような画面が表示されればJenkinsの起動は成功です。
image.png

1. 管理者パスワードの入力

初回アクセス時、さきほどの Unlock Jenkins という画面が表示され、管理者パスワードの入力を求められます。

ターミナルで docker logs jenkins-local コマンドを実行し、出力された起動ログの中から数十桁の英数字のパスワードを見つけてコピーします。パスワードは下記のように表示されるはずで、<This is password> の箇所に該当するパスワードが表示されています。

*************************************************************
*************************************************************
*************************************************************

Jenkins initial setup is required. An admin user has been created and a password generated.
Please use the following password to proceed to installation:

<This is password>

This may also be found at: /var/jenkins_home/secrets/initialAdminPassword

*************************************************************
*************************************************************
*************************************************************

パスワードをブラウザの入力欄に貼り付け、Continue をクリックします。

2. プラグインのインストール

プラグインの選択画面が表示されます。ここでは「Install suggested plugins」を選択してください。自動運転のビルドや今回のパイプライン作成に必要な基本プラグイン(Git連携やパイプライン機能など)が自動的にインストールされます。完了するまで数分待ちます。

3. 管理者ユーザーの作成

プラグインのインストールが完了すると、最初の管理者ユーザー(Create First Admin User)を作成する画面が表示されます。

ユーザー名、パスワード、フルネーム、メールアドレスを入力し、Save and Continue をクリックします。
image.png

4. URLの確認と完了

最後にJenkinsのアクセスURLを確認する画面が出ます。そのまま http://localhost:8080/ で良ければ Save and Finish をクリックします。

「Jenkins is ready!」と表示されたら Start using Jenkins をクリックします。ダッシュボード画面が表示されたら初期設定はすべて完了です。
image.png

5. 題材とする自動運転制御コード(AEB)の準備

この章では、自動運転の制御ロジックとして簡易的な衝突被害軽減ブレーキ(AEB)のプログラムを作成し、それを検証するための単体テストコードを用意します。

自動ブレーキの制御ロジックを実装する

まずは、車両のセンサーから得られた前方車両との距離と相対速度を元に、ブレーキの強度を計算するプログラムを作成します。

aeb_control.py という名前で以下のコードを作成してください。

def calculate_brake_level(distance: float, relative_speed: float) -> float:
    """衝突被害軽減ブレーキ (AEB) のブレーキ強度を計算する

    Args:
        distance (float): 前方車両との距離 (m)。0以上。
        relative_speed (float): 自車と前方車両の相対速度 (m/s)。
            正の値は接近していることを示し、負の値は離れていっていることを示す。

    Returns:
        float: ブレーキ強度 (0.0 から 1.0)
            0.0: ブレーキなし
            1.0: 緊急フルブレーキ
    """

    # 距離が負、または相対速度が0以下の場合はブレーキ不要
    if distance < 0.0 or relative_speed <= 0.0:
        return 0.0

    # ゼロ除算防止
    distance = max(distance, 0.1)

    # 衝突予測時間 (TTC: Time-To-Collision)
    ttc = distance / relative_speed

    # 衝突回避に必要な減速度
    # v² = 2ad → a = v²/(2d)
    required_decel = (relative_speed ** 2) / (2.0 * distance)

    # ---- 緊急フルブレーキ判定 ----
    # TTCが極端に短い場合は躊躇せず最大制動
    if ttc < 0.8:
        return 1.0

    # ---- 危険度評価 ----
    # TTC危険度
    # TTC 3秒以上 → 0
    # TTC 0.8秒以下 → 1
    ttc_risk = max(0.0, min((3.0 - ttc) / (3.0 - 0.8), 1.0))

    # 必要減速度危険度
    # 1m/s²までは快適
    # 8m/s²以上は緊急レベル
    decel_risk = max(
        0.0,
        min((required_decel - 1.0) / (8.0 - 1.0), 1.0)
    )

    # TTCと必要減速度を組み合わせる
    risk = max(ttc_risk, decel_risk)

    # ---- 滑らかな立ち上がり ----
    # 線形ではなくSmoothstepを使用
    # 急な変化を抑えて自然なブレーキ感にする
    brake_level = risk * risk * (3.0 - 2.0 * risk)

    return round(brake_level, 2)

ポイント解説

  • calculate_brake_level 関数は、障害物までの距離と接近速度を受け取り、ブレーキの強さを決定します。
  • 衝突予測時間であるTTC(Time-To-Collision)を 距離 / 相対速度 によって計算し、停止するために必要な減速度(Required Deceleration)を相対速度² / (2 × 距離)によって計算します。
  • 必要減速度が大きいほど危険度を高く評価し、高速で接近しているケースでも適切にブレーキを強められるようにしています。
  • TTCから算出した危険度と、必要減速度から算出した危険度の両方を評価し、より危険な方を採用することで安全側の制御を行います。
  • ブレーキ強度は単純な線形計算ではなく Smoothstep 関数を用いて算出し、危険度の変化に対して滑らかに立ち上がるようにしています。この処理により、閾値付近でブレーキ強度が急激に変化することを抑え、より自然な減速特性を実現しています。

※実際の車両ではさらにジャーク(加速度の変化率)制限を加えることで、乗員が不快に感じにくい滑らかなブレーキ制御を行うのが一般的ですがコードがさらに複雑になるためここでは割愛します。


pytestで単体テストコードを記述する

次に、作成した制御ロジックが安全要件を満たしているかを検証するためのテストコードを作成します。

test_aeb_control.py という名前で以下のコードを作成してください。

import pytest

from aeb_control import calculate_brake_level


def test_safe_distance():
    # 安全な距離(TTC = 10m / 2m/s = 5s)
    # ブレーキは不要であること
    assert calculate_brake_level(10.0, 2.0) == 0.0


def test_warning_brake():
    # 警告域(TTC = 3m / 2m/s = 1.5s)
    # 緊急ブレーキではないが、一定以上のブレーキがかかること
    level = calculate_brake_level(3.0, 2.0)
    assert level == pytest.approx(0.77, abs=0.02)


def test_emergency_brake():
    # 緊急ブレーキ(TTC = 1m / 2m/s = 0.5s)
    # 緊急ブレーキが発動すること
    assert calculate_brake_level(1.0, 2.0) == 1.0


def test_negative_distance():
    # 不正な距離(負の値)ではブレーキがかからないこと
    assert calculate_brake_level(-5.0, 2.0) == 0.0


def test_moving_away():
    # 離れていく場合はブレーキがかからないこと(相対速度が負)
    assert calculate_brake_level(5.0, -2.0) == 0.0
    # 相対速度が0(並走状態)でもふれーきを書けないこと
    assert calculate_brake_level(5.0, 0.0) == 0.0


def test_high_speed_approach():
    # TTCは2sと比較的長いが、高速で接近しているため危険と判断し強いブレーキがかかること
    level = calculate_brake_level(40.0, 20.0)

    assert level == pytest.approx(0.61, abs=0.02)


def test_brake_level_range():
    # ブレーキ強度は常に0.0~1.0の範囲内であること
    level = calculate_brake_level(5.0, 3.0)

    assert 0.0 <= level <= 1.0


def test_ttc_boundary():
    # TTC = 0.8sでは緊急ブレーキ(1.0)にはならないこと
    assert calculate_brake_level(1.6, 2.0) == 1.0

    # TTCが0.8s未満になると、緊急ブレーキになること
    assert calculate_brake_level(2.0, 2.0) < 1.0
    

ポイント解説

  • pytest は、test_ で始まる関数を自動的にテストケースとして認識して実行します。
  • assert ステートメントを使用し、実際の計算結果が期待されるブレーキ強度と一致しているかを評価します。
  • 警告や緊急ブレーキのような通常時の制御パターンだけでなく、距離や速度に異常な値が入った場合の異常系の動作も検証しています。
  • 浮動小数点演算によるわずかな誤差を考慮するため、一部のテストでは pytest.approx() を使用して許容誤差の範囲内であることを検証しています。

ローカル環境でテストと静的解析を手動実行してみる

Jenkinsのパイプラインに載せる前に、まずはローカルのターミナルで動作確認を行います。

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

以下のコマンドをターミナルで実行して、flake8pytest をインストールします。

pip install flake8 pytest

2. 静的解析(Lint)の実行

コードのスタイルチェックを行います。

flake8 aeb_control.py test_aeb_control.py

このコマンドを実行し、何もエラーメッセージが表示されなければ、コードがPEP 8規約に正しく準拠していることを示しています。

3. 単体テストの実行

続いて、制御ロジックの動作検証を行います。

pytest

テストを実行すると、「5 passed」と出力され、作成したすべてのシナリオでテストが成功したことが確認できます。

手動でのテストと静的解析が成功したことを確認できたら、いよいよこれらの手順をJenkinsで自動化していきます。

6. Jenkinsパイプラインの構築と実行

この章では、静的解析、単体テスト、パッケージングの一連の流れを自動で実行するパイプラインスクリプト(Jenkinsfile)を作成し、Jenkins上で実行する方法を解説します。

事前準備:GitHubへのソースコード登録とJenkinsfileの作成

Jenkinsがビルドやテストを実行するためには、対象となるソースコードを取得する必要があります。今回はローカルPCで作成したコードをGitHubリポジトリへ登録し、Jenkinsから取得する構成にします。

まずGitHubリポジトリ上で新しいリポジトリ(例:aeb-jenkins-handson)を作成してください。

続いて、aeb_control.pytest_aeb_control.pyJenkinsfileを同じディレクトリに配置し、以下のような構成にします。

aeb-jenkins-handson/
├── Jenkinsfile
├── aeb_control.py
└── test_aeb_control.py

JenkinsfileはJenkinsにどのような手順で自動処理を行わせるかを記述するファイルです。下記の内容で作成してください。

pipeline {
    agent any

    stages {
        stage('Lint') {
            steps {
                echo 'Running flake8...'
                sh 'flake8 aeb_control.py test_aeb_control.py'
            }
        }
  
        stage('Test') {
            steps {
                echo 'Running pytest...'
                sh 'pytest --junitxml=reports/test-results.xml'
            }
            post {
                always {
                    junit 'reports/test-results.xml'
                }
            }
        }
  
        stage('Package') {
            steps {
                echo 'Packaging artifacts...'
                sh 'zip release.zip aeb_control.py'
            }
            post {
                success {
                    archiveArtifacts artifacts: 'release.zip', followSymlinks: false
                }
            }
        }
    }
}

ポイント解説

  • pipeline ブロックで囲むことで、JenkinsのDeclarative Pipelineという推奨される形式でパイプラインを記述しています。
  • agent any は、利用可能な任意の実行環境(エージェント)でこのパイプラインを走らせることを指定します。今回はDockerコンテナ(Linux)環境のJenkins自身で実行されます。
  • Dockerコンテナ(Linux環境)で実行するため、シェル実行コマンドに sh ステップを使用しています。これにより標準的なLinuxシェルコマンドが呼び出されます。
  • Test ステージ内の post ブロックでは、テスト成否に関わらず always (常に)JUnit形式のテスト結果XMLを収集し、Jenkinsの画面上に綺麗なグラフやレポートとして表示するように指示しています。
  • Package ステージでは、テストが成功した場合のみ archiveArtifacts を用いて、生成された release.zip をビルド成果物としてJenkinsサーバーに保存します。Linux環境にプレインストールされている zip コマンドを使用して圧縮を行います。

最後に下記のコマンドを実行して、GitHubリポジトリへpushします。

git init
git add .
git commit -m "Initial commit"
git branch -M main
git remote add origin https://github.com/<ユーザー名>/aeb-jenkins-handson.git
git push -u origin main

これでJenkinsからGitHub上のソースコードを取得する準備が整いました。


Jenkins上での「Pipeline」ジョブの作成手順

Jenkinsの管理画面から、パイプラインを実行するための設定を行います。

  1. 新規ジョブの作成:
    Jenkinsのダッシュボード左側メニューにある「新規ジョブ作成」をクリックします。
    image.png

  2. ジョブ名と種類の指定:
    ジョブの入力欄に aeb-pipeline と入力し、一覧から「Pipeline」を選択して、画面下部の OK をクリックします。
    image.png

  3. パイプラインスクリプトの登録:
    設定画面が表示されたら、一番下にある「Pipeline」セクションまでスクロールします。

    • Definition(定義)で 「Pipeline script from SCM」 を選択します。
    • SCMで 「Git」 を選択します。
    • Repository URL にGitHubリポジトリのURLを入力します。
      例:
      https://github.com/<ユーザー名>/aeb-jenkins-handson.git
      
    • Branch Specifier には */main を入力します。
    • Script Path は Jenkinsfile のままにします。(リポジトリ直下に配置しているため)
    • リポジトリがプライベートの場合は、CredentialsでGitHubの認証情報を設定してください。

    image.png

    ※パイプラインを実行すると、JenkinsはまずGitHubからリポジトリを取得し、その中にある Jenkinsfile を読み込んでパイプラインを開始します。その後、LintTestPackage の各ステージを順番に実行します。

  4. 保存:
    画面下の 保存(Save) をクリックします。


パイプラインを実行して結果を確認する

いよいよパイプラインを実行します。

  1. 実行:
    ジョブのトップ画面で、左側メニューにある「ビルド実行(Build Now)」をクリックします。

  2. 進捗の確認:
    実行が始まると、画面中央に Stage View という表が表示され Lint -> Test -> Package と順に各ステージが緑色に変わっていきます。すべてのステージが緑色になれば成功です。
    image.png

  3. テスト結果の確認:
    ジョブの実行結果画面(Build #1など)を開くと、「テスト結果」というリンクが出現します。ここをクリックすると、pytestによって実行された5つのテストケースがすべて正常に通過したかどうかの詳細レポートをブラウザ上で視覚的に確認できます。

  4. ビルド成果物のダウンロード:
    ビルドが成功すると、成果物(Build Artifacts)として release.zip が画面上に表示されます。リンクをクリックすることで、テスト済みの成果物をローカルPCへダウンロードできます。
    image.png

不具合検出のシミュレーション

CI/CDの真価は、不具合があるコードがコミットされた際に即座に検知できることにあります。

試しに、aeb_control.py の緊急ブレーキ条件などを変更して、TTCが0.5秒のときに緊急ブレーキが作動しないようにロジックを書き換えてみてください。

その状態で再度「ビルド実行」を行うと、Test ステージが赤くなり、パイプラインが自動的にストップします。テスト結果画面には「どのテストが何行目で期待と異なったか」が明記されるため、自動運転ロジックに潜むデグレーション(先祖返り・不具合の混入)を開発の超初期段階で防ぐことができる様子が実感できます。

7. おわりに

本記事では、自動運転開発における衝突被害軽減ブレーキ(AEB)の制御ロジックを題材とし、Docker上でJenkinsを用いた自動化パイプラインを構築する手順を解説しました。

自動化パイプラインがもたらす価値のまとめ

手動で静的解析やテストを実行するのは、開発者にとって手間な作業です。しかし、Jenkinsによるパイプラインを導入することで、コードの取得、構文チェック、制御ロジックの動作検証、さらには配布パッケージの生成までが、常に同じ品質で自動実行されるようになります。

このような継続的インテグレーション(CI)環境を整えておくことで、不具合を素早く発見し、安全性の高いソフトウェアを継続的にリリースできます。特に、安全性が何よりも重視される自動運転や車載ソフトウェアの開発現場において、CI/CDは欠かすことのできない必須の技術となっています。

次のステップ

今回はローカルPC上のDockerでJenkinsを起動し、GitHubリポジトリからソースコードを取得して手動でビルド実行する基本的な仕組みを構築しました。

さらに実用的なCI/CD環境として、以下のステップへの挑戦をおすすめします。

  1. 自動ビルドトリガー(Webhook)の設定:
    GitHubのWebHook機能などを活用し、リポジトリにコードがプッシュされたことを検知してJenkinsのビルドが全自動で走り出すように設定します(ローカル環境で試す場合は、ngrokなどのトンネリングツールを利用して外部からアクセス可能にするか、ローカルにGitサーバーを建てるなどの工夫が必要です)。
  2. 動的コンテナエージェント(Docker Agent)の利用:
    現在はJenkins Controllerのコンテナ内で直接すべての処理(Lint・テスト・パッケージ化)を実行していますが、ビルドの実行ごとに別のクリーンなコンテナを動的に起動し、その中で実行させる構成(Docker Pipelineプラグイン等の活用)もあります。これにより、より安全でスケーラブルなCI環境になります。
  3. ツールの拡張:
    今回はPythonのシンプルなロジックを対象としましたが、C++によるROSパッケージのビルドや、より高度なシミュレータ環境の連動など、ご自身のプロジェクトに必要なツールやステージをパイプラインに追加してみてください。

最後に

Jenkinsについて初学者ながらハンズオン形式にまとめてみましたらいかがでしたでしょうか?これからCI/CDに携わる、Jenkinsを触るという方の参考になれば幸いです。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?