Jenkins + GitLab などで体験する『CI/CD入門』

Factory floor with yellow robotic arms on an assembly line; bold Japanese text advertises CI/CD intro with Jenkins and GitLab.

目次

はじめに

こんにちは、サイオステクノロジーの小沼 俊治です。

「理屈はいいから、まずは実際に CI/CD パイプラインというものを動かして体験してみたい」。 本記事は、そんな方々に向けて、ソフトウェア開発に不可欠な CI/CD の基礎を手を動かしながら学習できる、実践的な入門ガイドとして用意しました。

単なるビルドやデプロイの自動化にとどまらず、近年その重要性が叫ばれている「サプライチェーンセキュリティ(SBOM の活用)」や「脆弱性可視化」、さらには検証フェーズとして独立したジョブで実行する「動的セキュリティテスト(DAST)」までを包括したパイプライン環境を無料で体験できるハンズオンを提供します。
本ハンズオンでは、以下のオープンソース・プロダクトのみで構成された環境をコンテナを使って一括で立ち上げ、ソースコードのコミットからセキュリティチェック、そして本番デプロイに至るまでの一連の流れを体験していただきます。

  • Jenkins: パイプライン実行
  • GitLab: ソースコード管理
  • Dependency-Track: SBOM / 脆弱性可視化
  • Google OSV (Open Source Vulnerabilities): 脆弱性データベース
  • Artifactory: アーティファクト管理
  • Ansible: デプロイプロセス自動化
  • OWASP ZAP: 動的セキュリティテスト (DAST)

なお、本記事は「CI/CD のプロセスそのもの」を体感していただくことを主目的としています。そのため、複雑になりがちな環境構築の手順解説はあえて割愛しており、「まずは動かしてみたい」という方に最適です。もし環境構築の裏側に興味を持っていただいた場合は、ぜひ GitHub リポジトリの設定ファイルを解析してみてください。


構成概要

ハンズオン環境の構成

筆者が動かした際の主な構成要素は以下の通りです。

  • Windows 11 Professional
  • WSL 2.5.9.0
  • Ubuntu 24.04.3 LTS
  • Docker Engine 28.4.0
  • Jenkins
  • GitLab 18.2.4
  • Dependency-Track
  • JFrog Artifactory OSS
  • Ansible
  • OWASP ZAP

Windows (WSL) 以外のOSをご利用の方も、条件が満たしていれば以下の手順からハンズオンを進められます。

ハンズオンを構成する環境は以下の通りです。

  • CI/CD パイプラインを構成するツール群、およびデプロイ先となるサーバーをすべてコンテナとして構築します。
    • Jenkins:CI/CD の中核として、ジョブやパイプラインの実行を管理します。
    • GitLab:ビルド対象となるソースコードを管理します。本ハンズオンでは、ここでのマージがパイプラインを起動するトリガーとなります。
    • Dependency-Track:ビルド時にパッケージと一緒に生成したソフトウェア部品表(SBOM)を取り込み、脆弱性の有無を分析・可視化します。
    • Artifactory:Maven リポジトリのプロキシとして機能するほか、ビルドして生成された成果物(アーティファクト)をプロダクション環境(本番環境)へデプロイするために保管します。
    • Ansible:事前に定義された Playbook(インストール手順書)に従い、Artifactory にあるアーティファクトを利用してプロダクション環境へデプロイします。
    • OWASP ZAP:Jenkins の verify-dast-webapp ジョブから Docker-out-of-Docker (DooD) の仕組みを利用してコンテナを一時的に構築し、動的セキュリティテスト(DAST)を実施します。
    • Web アプリケーション(Ubuntu):デプロイ対象となるプロダクション環境のアプリケーションサーバーです。
  • Dependency-Track コンテナの構築には、OWASP Foundation が公開している docker-compose の YAML ファイルを取得して使用します。
  • Artifactory コンテナの構築には、JFrog 社が公開している docker-compose の YAML ファイルを取得して使用します。
  • デプロイ対象の Web アプリケーションは、プレゼンテーション層のフロントエンド、アプリケーション層の Web API、そしてデータ層のデータベースから成る三層アーキテクチャーで構成されています。
    • このうち「フロントエンド」と「Web API」を CI/CD パイプラインによるデプロイの対象とし、データベース(MySQL)については、コンテナ構築時に作成した環境をそのまま利用するためデプロイ対象になりません。
    • CI/CD の演習では、以下のリポジトリから Web アプリケーションのソースコードをダウンロードし、ハンズオン環境内に構築した GitLab のリポジトリへコミットすることで、CI/CD の一連の流れを体験します。
  • 単にツールを動かすだけでなく、シーンごとに以下の登場人物になりきって実際の開発現場を想定したロールプレイング形式で進めます。
    • 開発担当:ソースコードの実装や修正を行い、GitLab へコミットします。レビューアーへレビュー依頼として、マージリクエスト(プルリクエスト)を作成します 。
    • レビューアー:開発担当から起案されたマージリクエストを元にコードをレビューし、問題なければマージを行います 。
    • 運用担当:CI/CD パイプラインの実行状況を監視します。
    • ユーザー:プロダクション環境へデプロイされた Web アプリケーションを操作して楽しみます 。

環境構築や各種設定に使用するそれぞれのファイルは、以下の GitHub リポジトリで公開しています。

$ tree ~/handson/hands-on-jenkins/
hands-on-jenkins/
|-- container/ …… 「環境構築」章でコンテナ作成で使う素材
|   |-- docker-compose.yml
|   |-- docker-compose-webapp.yml
|   :
|
|-- setup/ …… 「環境構築」章でツール準備の環境準備に必要な素材
|   |-- SETUP_HANDS-ON.sh
|   :
|
`-- try-my-hand/  …… 「CI/CD の演習」章で CI/CD のハンズオンを進める環境
    |-- PREPARE_LOCAL_GIT_REPO_TO_PUSH.sh
    :

CI/CD の概要

ハンズオンで実施する CI/CD の流れを DevOps のライフサイクル(Infinity Loop)に当てはめると、以下の工程が該当します。

  • Code (GitLab):ソースコードの開発とレビューを実施し、バージョン管理ツールでソースコードを管理します。
  • Build (Jenkins):バージョン管理ツールから取得したソースコードをビルドしてローンチ候補のパッケージを生成します。
  • Test (Jenkins, Dependency-Track, OWASP ZAP):ローンチ候補のソースコードやパッケージを元にテストやセキュリティ検査を実施します。
  • Release (Artifactory):ローンチ対象のパッケージをアーティファクト管理ツールに保存・管理します。
  • Deploy (Ansible):アーティファクト管理ツールからパッケージを取得し、プロダクション環境へインストールします。
  • CI/CD のハンズオンでは、Operate(運用)、Monitor(監視)、Plan(計画)の工程は対象外となります。

開発者によるソースコードの開発から、プロダクション環境へデプロイするまでの一連の CI/CD フローを示します。

  1. GitLab:開発を終えたソースコードを開発者がプッシュし、レビューアーがソースコードをマージします。これを契機に、Webhook で Jenkins へ最新版のソースコードが登録されたことを通知します。
  2. Jenkins(ビルドジョブ):通知を受けると GitLab からソースコードを取得し、ビルドを行ってパッケージを生成してからテストを実行します。テストに成功するとパッケージを Artifactory に登録します。
  3. Artifactory:デプロイ対象のパッケージ(アーティファクト)を保管・管理します。
  4. Jenkins(デプロイジョブ):デプロイ実行の司令塔となり、Ansible と連携してプロダクション環境を最新の構成に更新します。
  5. Ansible:Artifactory にある最新のアーティファクトを利用し、人手を介さずにプロダクション環境へ自動的にデプロイします。
  • DASTは、本来ビルドジョブ内で自動実行するのが理想です。しかし、スキャン完了までに10分以上かかる場合があるため、本ハンズオンではスムーズな進行を優先し、専用ジョブ(verify-dast-webapp)として独立させています。

DevOps の Code 工程において、品質を担保しつつ効率的にソースコードの開発を進めるには、適切なソースコード管理(ブランチ戦略)が欠かせません。
本ハンズオンでは GitHub Flow をベースとした手法を用いて、プロダクション環境用のmainブランチと開発作業用のブランチを明確に分けることで、安全で効率的な開発フローを実現します。

  • 各ブランチの役割は以下の通りです。
    • mainブランチ:プロダクション環境と常に同じ状態を保つ「安定版」のブランチです。このブランチへのマージがプロダクション環境へのデプロイのトリガーとなります。
    • feature/*ブランチ:新しい機能の開発を行うためのブランチです。mainから枝分かれして作成し、開発とコードレビューが完了した後に、再びmainへマージします。
    • hotfix/*ブランチ:プロダクション環境で発生した緊急のバグ修正専用のブランチです。通常の開発とは別に、迅速な対応が求められる際に利用します。
  • 開発者はfeature/*やhotfix/*といった作業ブランチを作成して開発を進めます。直接mainブランチに開発した差分をコミットしません。
  • 開発が完了した作業ブランチは、必ずレビューアーの承認を経てからmainブランチにマージされます。

基礎環境の構築

WSL 環境の構築

Windows PC(社用標準 PC)の場合には、 以下手順を参考に WSL と Linux ディストリビューション(Ubuntu)環境を用意します。

Docker Engine 環境の構築

コンテナ環境を使うため、以下手順を参考に Ubuntu へ Docker Engine 環境を用意します。

ハンズオンに必要なコマンドの準備

本ハンズオンの実施には、以下のコマンドやランタイムが必要です。 これらは主に、環境構築やリポジトリ準備を行う際に使用します。

  • JDK 21:Jenkins の設定を操作する CLI ツール(jenkins-cli)の実行環境として必要です。 通信先となる Jenkins サーバーが JDK 21 で稼働しているため、クライアント側もバージョンを統一する必要があります。
  • jq コマンド:API のレスポンス(JSON 形式)から、特定の値を抽出・整形するために使用します。
  • unzip コマンド:GitHub から取得した Web アプリケーションのソースコード(Zip 形式)を展開するために使用します。

インストールされていない場合は、以下手順を参照して Ubuntu 環境へ用意します。


CI/CD 環境の構築

GitHub からハンズオン用のリポジトリ取得

ハンズオンを進めるための環境構築用の設定ファイルやスクリプトを含んだリポジトリを GitHub からダウンロードして取得します。

本章ではターミナルを使用してハンズオン用の作業ディレクトリを作成して作業を実施します。

$ mkdir -p ~/handson/
$ cd ~/handson/

「$ git clone」コマンドで本ハンズオン用のリポジトリを取得します。

$ git clone https://github.com/Toshiharu-Konuma-sti/hands-on-jenkins.git
$ cd hands-on-jenkins/

コンテナ構築スクリプトの実行

本章ではターミナルを用いて以下のディレクトリで作業を実施します。

$ cd ~/handson/hands-on-jenkins/container/

コンテナ構築用に用意してあるスクリプトを実行して、CI/CD 環境の各種コンテナを構築します。

$ ./CREATE_CONTAINER.sh

コンテナが構築されてから Jenkins と GitLab の初期パスワードの準備までに少々時間がかかるので、暫く待った後に info オプションを付けてスクリプトを実行すると、Jenkins および GitLab の初期パスワードと、後続の環境構築手順概要を表示することができます。

$ ./CREATE_CONTAINER.sh info

/************************************************************
 * Information:
 * - Navigate to Web ui tools with the URL below.
 *   - Jenkins:             http://localhost:8080
 *   - Artifactory:         http://localhost:8082
 *   - GitLab:              http://localhost:13000
 *   - Dependency-Track:    http://localhost:8981
 * - Navigate to the deployed webapp with the URL below.
 *   - webapp:              http://localhost:8181
 ***********************************************************/
- Password:
  - Jenkins Default: 66aa56faf61f47ddaed8c0f5777679a6
  - GitLab root user: fNvqnjyFC08DMXNov1X0z+zLrc2rxY7CbjMI1SZMFu4=
- Setup Instructions:
  1. Go to Jenkins and apply JCasC: /var/jenkins_home/my-config/jcasc/jenkins.yaml
  :

なお、コンテナ構築スクリプトで実行する内容は以下を参照してください。

Jenkins の基礎設定

本章ではブラウザを用いて作業を実施します。

初期セットアップ

Jenkins で推奨されているプラグインのインストールと Admin ユーザの作成を行います。

Jenkins へブラウザでアクセスし、初期パスワードを入力のうえ「Continue」ボタンをクリックしてセットアップを開始します。

  • Administrator password:テキストボックス上部に書かれている、Jenkins コンテナ内のファイルパスから取得して入力します。(「コンテナ構築スクリプトの実行」章を参照、もしくは、ターミナルで $ docker container exec jenkins cat /var/jenkins_home/secrets/initialAdminPassword コマンドを実行して取得できます)

「Install suggested plugins」を選び、推奨するプラグインをインストールします。

インストールの経過をしばらく待ちます。

Admin ユーザーを作ります。

  • ユーザー名:「admin」を入力します。
  • パスワード:「password」を入力します。(別の値を入力した場合は「variables.sh#L14 」の定義も変更します)
  • フルネーム:「admin」を入力します。
  • メールアドレス:「admin@example.com」を入力します。

URL はデフォルト値のままで変更せずに「Save and Finish」ボタンをクリックします。

「Restart」ボタンをクリックすれば、初期セットアップは完了です。

Artifactory のリポジトリ作成

本章ではブラウザを用いて作業を実施します。

ローカルリポジトリ作成

Jenkins のジョブでビルドしたアーティファクトを格納するリポジトリを用意します。

ブラウザで Artifactory へアクセスして、admin ユーザーで初期パスワードを入力してログインします。

  • Username:「admin」を入力します。
  • Password:初期パスワードの「password」を入力します。

Welcome 画面にて「Create a Repository」ボタンをクリックします。

画面右上の「Create a Repository > Local」のメニューを選択します。

パッケージタイプの一覧から「Gradle」を選択します。

New Local Repository 画面にて「Repository Key」にリポジトリ名を入力して「Create Local Repository」ボタンをクリックします。

  • Repository Key:「hands-on-rollingdice-webapp」を入力します。

表示されたポップアップウィンドウで「Add Users」は押さずに、ウィンドウの右上の×ボタンで閉じます。

リモートリポジトリ作成

ビルドする際に Maven Repository をプロキシしてキャッシュとして機能するリポジトリを用意します。

リポジトリ一覧画面で右上にある「Create a Repository」ボタンをクリックすると表示するメニューから「Remote」を選択します。

Select Package Type で「Gradle」を選択して New Remote Repository 画面に遷移します。画面内で「Repository Key」にリポジトリ名を入力して「Create Remote Repository」ボタンをクリックしてリポジトリーを作成ます。

  • Repository Key:「hands-on-remote」を入力します。
  • URL:デフォルトで入っている URL のままにします。

バーチャルリポジトリ作成

ここまでに作成したローカルリポジトリとリモートリポジトリを一つにまとめ、単一のアクセスポイントで機能するリポジトリを用意します。

リポジトリ一覧画面で右上にある「Create a Repository」ボタンをクリックすると表示するメニューから「Virtual」を選択します。

Select Package Type で「Gradle」を選択して New Remote Repository 画面に遷移します。画面内で「Repository Key」にリポジトリ名を入力したら「Repositories」セクションまで画面をスクロールします。

  • Repository Key:「hands-on-virtual」を入力します。

Repositories セクションで左側リストに表示されているここまでの手順で作成した Available Repositories(ローカルリポジトリと、リモートリポジトリを各1つずつ)を「>>」ボタンをクリックして、右側リストの Selected Repositories に移します。「Create Virtual Repository」ボタンをクリックしてリポジトリーを作成します。

ハンズオンで必要なローカルリポジトリ、リモートリポジトリ、およびバーチャルリポジトリが全て揃った状態のリポジトリ一覧画面は、以下の構成になります。

CI/CD 環境セットアップスクリプトの実行

Jenkins へのジョブ登録や GitLab のプロジェクト作成などを、スクリプトを使って一気に行います。これにより、複雑な連携設定を手動で行う手間を省きます。

本章ではターミナルを用いて以下のディレクトリで作業を実施します。

$ cd ~/handson/hands-on-jenkins/setup/

セットアップ用に用意してあるスクリプトを実行して、CI/CD 環境の各種設定を行います。コンテナ構築直後は GitLab が完全に起動していない場合があり、スクリプトは GitLab の Web API が応答するまで自動的にリトライを繰り返しますので、完了するまでそのままお待ちください。

$ ./SETUP_HANDS-ON.sh

CI/CD の演習

CI/CD workflow diagram showing stages from Code to Deploy with Jenkins, GitLab, Maven, JFrog and OSS repos.

環境構築が完了しましたので、いよいよここから実際の開発フローによる CI/CD を体験していきます。

「CI/CD の概要」章でも説明した CI/CD フローを、開発者、レビューアー、運用者などの役割を演じながら、コードの変更がどのようにパイプラインを通過し、プロダクション環境へデプロイされるかを確認しましょう。

GitLab ローカルリポジトリ準備

GitLab 上のリポジトリを確認し、ローカル環境にソースコードを準備します。まずは開発担当の視点から開始します。

初期状態のリモートリポジトリ確認

CI/CD の演習で使用するリポジトリが作成されているか確認します。

ブラウザで GitLab へアクセスして、root ユーザーでログインします。

  • ユーザー名:「root」を入力します。
  • パスワード:gitlab コンテナ内の「/etc/gitlab/initial_root_password」に書かれている初期パスワードを入力します。
    (「コンテナ構築スクリプトの実行」章を参照、もしくは $ docker container exec gitlab cat /etc/gitlab/initial_root_password コマンドで取得できます)

Web API のソースコードを管理する「webapp-webapi」リポジトリが存在していて、「README.md」ファイルのみが存在する初期状態であることを確認します。

同様にフロントエンドのソースコードを管理する「webapp-webui」リポジトリについても確認します。
なお、「webapp-webapi」と「webapp-webui」のリポジトリは、「CI/CD 連携設定スクリプトの実行」章で実行したスクリプトで作成しています。

ローカルリポジトリ準備スクリプトの実行

通常であれば、ここで初期状態の Git リポジトリを git clone してゼロから Web アプリケーションのソースコードを実装するところですが、本ハンズオンでは CI/CD の体験に集中するため、「実装済みのソースコード」を一括で適用するスクリプトを用意しています。これにより、面倒な準備なしで、すぐに CI/CD の演習(ハンズオン)を始められる状態を作ります。

本章ではターミナルを用いて以下のディレクトリで作業を実施します。

$ cd ~/handson/hands-on-jenkins/try-my-hand/

GitLab から初期状態のリモートリポジトリを取得して、実装された Web アプリケーションのソースコードをローカルリポジトリへ用意するスクリプトを実行して、リモートリポジトリへプッシュできる状態を準備します。

$ ./PREPARE_LOCAL_GIT_REPO_TO_PUSH.sh

本ハンズオンでは一からのコーディング作業を省略するため、以下のリポジトリから各種ハンズオン向けに用意してある Web アプリケーションのソースコードを取得し、実装が完了した状態を再現して進めます。

ローカルリポジトリ準備スクリプトで実行する内容は以下を参照してください。

GitLab リモートリポジトリ更新(webapi)

ローカルリポジトリに Web アプリケーションの実装が完了しました。 ここからは、この変更をリモートリポジトリへ反映し、CI/CD パイプラインを始動させるまでの流れを体験します。

ローカルからリモートリポジトリへプッシュ

ローカルリポジトリに実装した Web アプリケーションをリモートリポジトリへ反映して CI/CD の演習を本格的に開始します。

「webapp-webapi」リポジトリから開始するため、以下のディレクトリで作業を実施します。

$ cd ~/handson/hands-on-jenkins/try-my-hand/webapp-webapi/

既に Web アプリケーションが実装された状態を再現しているため、ローカルリポジトリにソースコードや設定ファイルの差分が生じていることが確認できます。

$ git status

ブランチ feature/sample
追跡されていないファイル:
  (use "git add <file>..." to include in what will be committed)
        .gitattributes
        .gitignore
        RUN.sh
        build.gradle
        :
nothing added to commit but untracked files present (use "git add" to track)

差分のファイルをコミット対象として登録します。

$ git add .

リモートリポジトリへプッシュするためにローカルリポジトリへ登録します。

$ git commit -m "implement the source code of the web app"

28 files changed, 2009 insertions(+)
create mode 100644 .gitattributes
  :
create mode 100644 src/test/java/jp/sios/apisl/handson/rollingdice/webapp/webapi/util/UtilEnvInfoTest.java

ローカルリポジトリで開発した開発用ブランチ (feature/sample) をリモートリポジトリへプッシュします。

$ git push --set-upstream origin feature/sample
 Username for 'http://localhost:13000': root
 Password for 'http://root@localhost:13000':

Enumerating objects: 63, done.
  :
branch 'feature/sample' set up to track 'origin/feature/sample'.
  • Username for ‘http://localhost:13000’:「root」を入力します。
  • Password for ‘http://localhost:13000’:gitlab コンテナ内の「/etc/gitlab/initial_root_password」に書かれている初期パスワードを入力します。
    (「コンテナ構築スクリプトの実行」章を参照、もしくは、ターミナルで $ docker container exec gitlab cat /etc/gitlab/initial_root_password コマンドを実行することで取得できます)

リモートリポジトリでマージリクエスト作成

ソースコードのプッシュが完了したら、GitLab 城で「マージリクエスト(プルリクエスト)」を作成してレビューを依頼します。

ブラウザで GitLab にアクセスし、トップページ、もしくはリポジトリページに「Create merge request」ボタンが掲示されている場合には、該当のボタンをクリックしてマージリクエストの作成を開始します。

「Create merge request」ボタンが掲示されていない場合には、左ペインのメニューから「Pinned > Merge requests」を選択し、画面中央部にある「New merge reuqest」ボタンを押下してマージリクエストの作成を開始します。

マージリクエストの対象となるマージしたいブランチを指定して、「Compare branches and continue」ボタンをクリックします。

  • Source branch:マージしたい開発した最新のソースコードを含む「feature/sample」ブランチを指定します。
  • Target branch:マージ先となるプロダクション環境と同じ状態を保っている「main」ブランチを指定します。

マージリクエストの情報を入力するフォームが表示されるので、Title、Description など必要な項目の入力を進めます。

情報の入力フォームの画面下部に存在する「Create merge request」ボタンをクリックしてマージリクエストを作成します。

出来上がったマージリクエストをレビューアーに提示して、開発担当からレビューアーにバトンタッチしてレビューフェーズに進みます。

GitLab でコードレビューとマージ

開発担当がコーディングしたソースコードや設定ファイルをレビューアーがレビューを実施し、品質に問題が無ければ承認、およびマージして、DevOps の Code 工程を完了します。この章はレビューアーの視点になります。

レビューアーとしてブラウザで GitLab にアクセスし、左ペインのメニュー一覧より「Merge requests」を選択してマージリクエストの一覧を表示します。一覧に開発担当が作成したレビュー待ちのマージリクエストがあるので、クリックしてレビューを開始します。

マージリクエストがアクティブになりましたので、「Change」タブをクリックして差分表示に切り替えます。

マージ前後の差分表示になっているので、こちらを利用してソースコードの変更点をレビューします。

レビューが問題なければ「Overview」タブをクリックして「Approve」ボタンをクリックして承認します。続けて「Merge」ボタンをクリックすると開発用の「feature/sample」ブランチが「main」ブランチへマージされレビューは完了です。

直後に GitLab から Jenkins へ Webhook で「main」ブランチにマージが発生したことの通知が飛び、Jenkins ではビルドジョブが自動的に開始します。次章でその様子を確認しましょう。

Jenkins ビルドジョブ実行(webapi)

GitLab で「main」ブランチへのマージが完了すると、Jenkins 側で自動的にビルドジョブが開始されます。 その様子と、実行されたセキュリティチェックの結果を確認しましょう。この章は開発担当がメインとなりますが、レビューアーと運用担当も関わりを持ちます。

ビルドジョブ実行確認

ビルドジョブが実行されるので確認します。

ジョブの一覧から自動的に実行開始された「build-webapp-webapi」ジョブをクリックして詳細情報に遷移します。

Stage View で、ビルドジョブを構成するステージが順に実行されていることと、各ステージの処理に掛かった時間も確認することができます。

順にステージの実行を繰り返し、「Declarative: Post Actions」ステージまで到達するとジョブも完了です。Stage View の最左列のジョブ番号(例:[#1])をクリックしてビルドジョブの結果詳細を見てみましょう。

ビルドジョブ結果確認

ビルドジョブの完了後、生成された各種レポートや成果物を確認してプロダクトの品質を評価します。 本ハンズオンのパイプラインには、「品質(Quality)」と「セキュリティ(Security)」の検証に加え、「仕様の可視化(Visibility)」を行うため、以下のプロセスが組み込まれています。
これらの結果から改善点を見つけ出し、コードを修正して再びプッシュする ―― このサイクルを回すことで、品質と安全性を継続的に向上させます。

  • SCA (Software Composition Analysis):Dependency-Track を使用し、利用している OSS ライブラリに既知の脆弱性がないかを分析します。
  • 単体テスト (Unit Testing):JUnit を使用し、プログラムの機能が正しく動作するかを検証します。
  • SAST (Static Application Security Testing):SpotBugs と PMD を使用し、ソースコード等の不具合やセキュリティホールの原因となる記述を検出します。
  • Linter:CheckStyle を使用し、コードの書き方(インデントや命名規則など)が規約に沿っているかをチェックします。
  • ドキュメント生成 (Documentation):ソースコードから Javadoc や OpenAPI 仕様書を自動生成し、実装と乖離のない最新の仕様を可視化します。

ビルドジョブの結果ページでは、脆弱性の解析や静的コード解析などの各種結果のサマリー表示と、結果の詳細情報へ遷移するリンクで構成されています。

Dependency-Track と連携した脆弱性解析の結果レポートです。一覧の各行で「Name」列の先頭にある「+」ボタンをクリックすると、展開表示で各脆弱問題に対する対処方法も確認できます。

JUnit による単体テストの実行結果のレポートです。アプリケーションを構成するパッケージごとに、単体テストの実行に掛かった所要時間、成功数や失敗数などが確認できます。

単体テストのカバレッジのレポートです。テストコードがプロダクションのソースコードをどれだけ網羅しているか確認することができます。

SpotBugs による静的な検証結果のレポートです。実行時エラーに繋がるバグの発見など、動かなくなるリスクの回避を手助けします。

PMD による静的な検証結果のレポートです。非効率や冗長なコードなどによる、保守しにくいリスクの回避を手助けします。

CheckStyle による静的な検証結果のレポートです。コーディング規約の違反など、読みにくいリスクの回避を手助けします。

ソースコードから生成された Javadoc 形式のプログラム仕様書を確認できます。

Web API を対象とした「build-webapp-webapi」ビルドジョブでは、ソースコードから生成された OpenAPI 形式の API 仕様書も確認できます。

GitLab リモートリポジトリ更新 ~ Jenkins ビルドジョブ実行(webui)

ここまでの手順で、Web API のソースコードを管理する「webapp-webapi」リポジトリのビルドまでが完了しました。次は、フロントエンドのソースコードを管理する「webapp-webui」リポジトリを対象に同じ手順を実行してビルドまで実施します。以下の各章内の説明で「webapi」を「webui」に読み替えて実行します。

  1. GitLab リモートリポジトリ更新(webapi)
    • 対象ディレクトリを webapp-webui に読み替えて、プッシュおよびマージリクエストの作成を行います。
  2. GitLab でコードレビューとマージ
    • 対象リポジトリを webapp-webui に読み替えて、コードレビューおよびマージを行います。
  3. Jenkins ビルドジョブ実行(webapi)
    • Jenkins 上で build-webapp-webui ジョブが実行されることを確認します。

Artifactory リポジトリ確認

Jenkins で「build-webapp-webapi」と「build-webapp-webui」の各ビルドジョブが完了すると、各ビルドジョブでリリースされたアーティファクトが Artifactory に登録されていることが確認できます。これがデプロイの原資となります。この章あたりから、運用担当がメインとなってきますが、開発担当とレビューアーも関わりを持ちます。

Artifactory の画面上部で「Platform」タブがアクティブな状態で、左ペインのメニューから「Artifactory > Artifacts」を選択するとリポジトリツリーが表示します。ツリーから事前に作成したローカルリポジトリをクリックしてツリーを展開すると、ローカルリポジトリに登録されたアーティファクトを表示することができます。

一覧で一つアーティファクトを選んでいる状態で、「Properties」タブをアクティブにするとビルド時の情報が確認できます。

「apisl.handson.rollingdice.webapp.webapi-0.0.1-SNAPSHOT.jar」と「apisl.handson.rollingdice.webapp.webui-0.0.1-SNAPSHOT.jar」のアーティファクトが登録されていることが確認できたら、アプリケーションレイヤーにデプロイする Jenkins のデプロイジョブの実行に進みます。

Jenkins デプロイジョブ実行

Jenkins のデプロイジョブから Ansible と連携して、Artifactory に登録されているアーティファクトをアプリケーションレイヤーのアプリケーションサーバーにデプロイし、Web アプリケーションを構築します。この章は運用担当の視点になります。

Jenkins のジョブ一覧から「deploy-webapp」デプロイジョブを選択します。

デプロイジョブは Jenkins 自身でジョブを開始するため、左ペインのメニューから「ビルド実行」をクリックしてジョブを実行します。

全てのタスクが完了すると Web アプリケーションの構築が完了しました。

このジョブの中で、Ansible が Playbook に従って「アーティファクトのダウンロード」「インストール」「サービスの再起動」を自動的に行っています。

Webアプリケーション実行

Jenkins のデプロイジョブで Web アプリケーションが構築されているので、アクセスしてアプリケーションが動いているか確認しましょう。この章はユーザーによる利用がメインとなりますが、サービス稼働の裏方として運用担当、開発担当とレビューアーも関わりを持ちます。

ブラウザで Web アプリケーションにアクセスしてデプロイ結果を確認します。

画面が表示され、サイコロを振るなどの操作ができれば成功です!CI/CD による開発からアプリケーションの稼働開始までの一連の流れは以上となります。

Web アプリケーションの稼働確認で改善点や改修点が見つかった場合には、GitLab のローカルリポジトリでソースコードや設定ファイルの改修を行って、再度「GitLab リモートリポジトリ更新(webapi)」章の手順から実行し直すことで、常に「コード」と「環境」が一致した状態を保ちながら、安全かつ高速に機能改善(継続的デリバリー)を行うことが可能になります。

Jenkins DAST(動的アプリケーションセキュリティテスト)ジョブ実行

診断ツール「OWASP ZAP」を利用した DAST ジョブを実行します。通常、DAST はビルドジョブの一環として自動化することが一般的ですが、スキャン完了までに時間を要する(10分以上)傾向があるため、本ハンズオンではパイプラインの即応性とハンズオンの円滑さを考慮し、ビルドジョブとは切り離した独立したジョブとして用意しています。

Jenkins のジョブ一覧から「verify-dast-webapp」検証ジョブを選択します。

検証ジョブは Jenkins 自身でジョブを開始するため、左ペインのメニューから「ビルド実行」をクリックしてジョブを実行します。

全てのタスクが完了すると DAST の検証が完了しました。左ペインのメニューで「DAST Scan Report (webapi)」および「DAST Scan Report (webui)」をクリックすると、DAST の検証結果が確認できます。

検出されたリスクがあれば、レベルや検出に至った経緯が掲載されているので、改善に向けた検討を試みてください。

GitLab CI/CD 実行

本ハンズオンでは Jenkins を利用した CI/CD の体験をメインとしているが、GitLab CI/CD による簡易な CI/CD も体験できます。

「webapp-webapi」リポジトリを選んでいる状態で左ペインのメニューから「Build > Pipelines」を選びます。GitLab CI/CD を実行するために画面右上にある「New pipeline」ボタンをクリックします。

Run new pipeline 画面に遷移してきたら「New pipeline」ボタンをクリックします。

パイプラインの「launchers」のボックス内で、「trigger-build-release」ジョブ名の右隣にある再生ボタンをクリックして、ビルドジョブを起動します。

ビルドジョブが走り出し、その配下にあるステップが順番に実行されている様子が確認できます。

「trigger-build-release」ジョブ配下の全てのステップが完了したら、左ペインのメニュー「Deploy > Pakage registry」より、アーティファクトが保存されているのを確認します。

続いて「Deploy > Pages」にて、「trigger-build-release」ジョブの実行中に生成されたテスト結果や仕様書が閲覧できます。

アーティファクトが出来上がったので、アプリケーションサーバーへデプロイします。左ペインのメニュー「Build > Pipelines」で遷移し、「trigger-build-release」ジョブを起動したパイプラインをアクティブにします。今度は「trigger-deploy」の右隣にある再生ボタンをクリックしてジョブを開始します。

「trigger-deploy」ジョブの全てのステップが完了するとアプリケーションサーバーにデプロイも完了しています。

説明は割愛しますが、「webapp-webui」リポジトリも同様にパイプラインでジョブを実行したら、Web アプリケーションにアクセスしてお試しください。

DevOps の演習(CI/CD + オブザーバビリティー)

前提条件

本章を進めるには、「Webアプリケーション実行」章までの手順がすべて完了していることが必須となります。以下の状態になっていることを確認してから開始してください。

  • コンテナ環境の稼働:Jenkins を含む CI/CD ハンズオン環境のコンテナ群が起動していること。
  • デプロイの実績:パイプラインを通じて、プロダクション環境へ一度はデプロイが成功し、Web アプリケーションが稼働していること。

DevOps 統合環境の概要

本ハンズオンの CI/CD 環境でアプリケーションレイヤーを軸に、「Grafana OSS LGTM スタックで体験する『オブザーバビリティー入門』」のオブザーバビリティー環境を追加構築することで、DevOps のハンズオン環境を用意します。

  • CI/CD 環境:アプリケーションレイヤーに最新のソースコードで実装された Web アプリケーションを提供します。また、オブザーバビリティーによって見つかった改善点を改修した Web アプリケーションも更新提供できます。
  • オブザーバビリティー環境:CI/CD 環境によって提供された Web アプリケーションを観測し、安定稼働していることの確認や、時によっては改善箇所の発見を行います。

CI/CD のハンズオン環境では、DevOps ライフサイクルの Code から Deploy までが範囲でしたが、オブザーバビリティー環境を足すことによって、DevOps ライフサイクルの循環を体験することが可能になります。

  • Code から Deploy:本ハンズオン「CI/CD の概要」の説明を参照してください。
  • Operate(Web アプリケーション):デプロイされたアプリケーションが稼働し、オブザーバビリティーに必要なテレメトリーデータ(ログ、メトリクス、トレース)を継続的に出力します。
  • Monitor(Grafana LGTM Stack):収集したデータをダッシュボードで可視化・分析し、アプリケーションの健全性やボトルネック、エラーの発生をリアルタイムに検知します。
  • Plan:監視データから得られた客観的な事実に基づいて改善点や修正方針を策定し、次の開発サイクル(Code)へとフィードバックします。

構築手順

ブラウザで Jenkins にアクセスし Web アプリケーションを Grafana へのメトリクス送信に対応したジョブ(「deploy-webapp-with-grafana」デプロイジョブ)でデプロイし直します。

ターミナルを使い、Web アプリケーションのメトリクス収集用として NodeExporter をサイドカーコンテナで立ち上げます。

$ cd ~/handson/hands-on-jenkins/container/
$ ./CREATE_CONTAINER.sh up-exporter

Grafana のハンズオン環境のリポジトリを GitHub から取得します。

$ cd ~/handson/
$ git clone https://github.com/Toshiharu-Konuma-sti/hands-on-grafana.git

CI/CD のハンズオン環境に対し、Web アプリケーションを除く Grafana 関連のコンテナ群を追加で立ち上げます。

$ cd ~/handson/hands-on-grafana/container/
$ ./CREATE_CONTAINER.sh up-to-jenkins

DevOps フィードバックループの体験

ブラウザで Web アプリケーションにアクセスし、サイコロを振ってアプリケーションを楽しみます。

Web アプリケーションを動かすことでテレメトリーデータが Grafana に送られますので、ブラウザで Grafana にアクセスします。

Grafana で各種テレメトリーデータを確認します。Grafana で確認する際の操作手順については、以下のハンズオン資料を確認してください。

Grafana で観測した結果から Web アプリケーションのソースコードを改修してます。以下のソースコード改修例は、観測結果から「タイトルの視認性を上げたい」などの改善点が見つかったと仮定してソースコードを改修しています。

$ cd ~/handson/hands-on-jenkins/try-my-hand/webapp-webui/
$ vim src/main/resources/templates/include/title.html
$ git diff src/main/resources/templates/include/title.html

diff --git a/src/main/resources/templates/include/title.html b/src/main/resources/templates/include/title.html
index 51f33eb..7fa53b1 100644
--- a/src/main/resources/templates/include/title.html
+++ b/src/main/resources/templates/include/title.html
@@ -1,3 +1,3 @@
 <div>
-       <h1>Let's pray for a good eye!!</h1>
+       <h1>Let's pray for a good eye!! v2</h1>
 </div>

改修が完了したらコミット・プッシュを行い、以下手順で再度 CI/CD を回します。これにより、改善されたアプリケーションがプロダクション環境へリリースされ、再び「Operate」→「Monitor」へと続く DevOps の無限ループが回り始めます。

以上で、DevOps を含めた CI/CD のハンズオンはすべて終了です。お疲れ様でした!

コードのコミットからデプロイ、そして稼働状況の観測から次の改善へ。この一連の「DevOps ループ」が実際に回る様子を通して、CI/CD とオブザーバビリティーが連携することでどのように継続的な改善が実現されるのか、その「手応え」を感じていただけたなら幸いです。


環境のクリーンアップ

CI/CD の演習、およびDevOps の演習が一通り終わったら、これまでに利用した環境をクリーンアップしてハンズオンを終了します。

コンテナ削除スクリプトの実行

ターミナルを用いて、以下のディレクトリへ移動します。

$ cd ~/handson/hands-on-jenkins/container/

環境構築時にも使用したスクリプトに down オプションを指定して実行して、CICD 環境の各種コンテナを停止・削除します。

$ ./CREATE_CONTAINER.sh down

スクリプトの実行が終わったら、list オプションを付けてスクリプトを実行し、起動しているコンテナが存在しない(一覧に表示されない)ことを確認します。

$ ./CREATE_CONTAINER.sh list
### START: Show a list of container ##########
CONTAINER ID   IMAGE     COMMAND   CREATED   STATUS    PORTS     NAMES

なお、「DevOps の演習(CI/CD + オブザーバビリティー)」も体験していた場合は、オブザーバビリティー環境のコンテナが残っているので次の章も実施します。

コンテナ削除スクリプトの実行(DevOps の演習を実施した場合)

ターミナルを用いて、以下のディレクトリへ移動します。

$ cd ~/handson/hands-on-grafana/container/

環境構築時にも使用したスクリプトに down オプションを指定して実行して、オブザーバビリティー環境の各種コンテナを停止・削除します。

$ ./CREATE_CONTAINER.sh down

スクリプトの実行が終わったら、list オプションを付けてスクリプトを実行し、起動しているコンテナが存在しない(一覧に表示されない)ことを確認します。

$ ./CREATE_CONTAINER.sh list
### START: Show a list of container ##########
CONTAINER ID   IMAGE     COMMAND   CREATED   STATUS    PORTS     NAMES

以上で環境のクリーンアップは完了です。お疲れ様でした。

続く Appendix では、このハンズオン環境を裏で支えている設定ファイルやスクリプトについて解説します。「どうやってこの環境を作ったのか詳しく知りたい!」という方は、ぜひこのままご覧ください。


Appendix

ハンズオン環境の構築や設定手順で利用した各種スクリプトや設定ファイルの実装内容について解説します。

docker-compose / Dockerfile の解説

jenkins/Dockerfile

「container/jenkins/Dockerfile#L3-L4」に記述した Jenkins CLI コマンドを実行して、「container/jenkins/my-config/ref/plugins.txt」で列記した以下のプラグインがインストールされたコンテナを用意します。

  • Configuration as Code:Jenkins Configuration as Code (JCasC)による設定ができるようにします。
  • SSH Credentials:SSH ノードや Git 接続に必要な SSH 認証情報(秘密鍵やパスワードなど)を暗号化して安全に管理できるようにします。
  • GitLab:GitLab でコミットやマージなどのイベント発生時に、WebHook を受信してジョブが実行できるようにします。
  • Pipeline: Stage View:ジョブのページで Stage View を表示できるようにします。
  • Coverage:単体テストのカバレッジを確認できるようにします。
  • Warnings:コーディングルール(CheckStyle、PMDなど)の結果を確認できるようにします。
  • Javadoc:ソースコードから Javadoc 形式で仕様書を生成できるようにします。
  • Generic Tool:JCasCで「tool:」セクションが使えるようにします。
  • OWASP Dependency-Track:ビルド時に生成した SBOM を Dependency-Track へ自動送信し、脆弱性解析結果を連携・確認できるようにします。
  • JFrog:ジョブから JFrog Platform(Artifactory)にアクセスしやすくします。

JCasC 適用内容の解説

「container/docker-compose.yml#L58 」で「CASC_JENKINS_CONFIG」に指定されている Jenkins Configuration as Code(JCasC)ファイル「jenkins.yaml」で適用される内容について解説します。

master ノードのラベル付与

「Jenkins の管理 > System Configuration > Nodes」のノード一覧にある「master」ノードに、デフォルトでは付与されていないラベルを付与します。JCasC ファイルでは「container/jenkins/my-config/jcasc/jenkins.yaml#L8」の定義が該当します。

  • ラベル:「master」を付与します。
ノード追加

「Jenkins の管理 > System Configuration > Nodes」でノードを追加します。JCasC ファイルでは「container/jenkins/my-config/jcasc/jenkins.yaml#L10-L32」の定義が該当します。
エージェントノードとしてあらかじめ登録しておくことで、Jenkins の起動時に jenkins-agent や ansible コンテナへ自動的に SSH 接続されます。これにより、デプロイジョブ側で個別に SSH 接続処理を実装することなく、直接 Ansible を操作してデプロイを実行できるようになります。

  • 追加するノード情報は以下の通りです。
    • ノード名「jenkins-agent-node」を追加します。
      • ラベル:「jenkins-agent」を入力します。
      • ホスト:「jenkins-agent」を入力します。
    • ノード名「ansible-node」を追加します。
      • ラベル:「ansible」を入力します。
      • ホスト:「ansible」を入力します。
    • 各ノード共通で以下情報を登録します。
      • リモートFSルート:「/root」を入力します。
      • 起動方法:「SSH経由でUnixマシンのスレーブエージェントを起動」を入力します。
      • 認証情報:「root/*******」を選択します。
      • Host Key Verification Strategy:「Non Verifying Verification Strategy」を選択します。
ツール(Plugin)設定

「Jenkins の管理 > System Configuration > Tools」でインストール済みの中から以下のプラグインを設定します。JCasC ファイルでは「container/jenkins/my-config/jcasc/jenkins.yaml#L34-L50」の定義が該当します。

  • Gradle(初期セットアップの Suggested Plugin でインストール)
  • JFrog(コンテナ作成時に Jenkins CLI でインストール)
  • Gradle に設定する内容は以下の通りです。
    • name:「my-gradle」を入力します。
    • 自動インストール:「On」でチェックを入れます。
    • アーカイブダウンロードURL:「https://services.gradle.org/distributions/gradle-9.6.0-bin.zip」を入力します。
    • バージョン:「Gradle 9.0.0」を選択します。
  • JFrog に設定する内容は以下の通りです。
    • name:「my-jfrog-cli」を入力します。
    • 自動インストール:「On」でチェックを入れます。
    • Version:最新版をインストールするため空欄のままにします。
外観設定

「Jenkins の管理 > System Configuration > Appearance」で外観を設定します。JCasC ファイルでは「container/jenkins/my-config/jcasc/jenkins.yaml#L52-L57」の定義が該当します。

  • 外観で設定する内容は以下の通りです。
    • Pipeline Stages
      • Show pipeline stages on job page:「On」にします。
      • Show stage names by default:「On」にします。
      • Show stage durations by default:「On」にします。
    • Pipeline Graph
      • Show pipeline graph on build page:「On」にします。
クレデンシャル追加

「Jenkins の管理 > Security > Credentials」で認証情報を登録します。JCasC ファイルでは「container/jenkins/my-config/jcasc/jenkins.yaml#L59-L81」の定義が該当します。

  1. 「Stores scoped to Jenkins」の表で Store = System 行の Domains 列で「(global)」をクリックしてグローバルドメイン画面に遷移します。
  2. 「+ Add Credentials」ボタンをクリックして「Jenkins-Agent SSH 接続用」、「Ansible SSH 接続用」、「Artifactory Push 用」と「Dependeny-Track SBOM 登録用 API Key」の4つの認証情報を作ります。
  3. 「Jenkins-Agent SSH 接続用」は以下の値を入力してから「Create」ボタンをクリックして作成します。
    • 種類:「ユーザー名とパスワード」を選択します。
    • スコープ:「グローバル」を選択します。
    • ユーザー名:「root」を入力します。
    • パスワード:「password」を入力します。
    • ID:「jenkins-agent-node-credential」を入力します。
  4. 「Ansible SSH 接続用」は以下の値を入力してから「Create」ボタンをクリックして作成します。
    • 種類:「ユーザー名とパスワード」を選択します。
    • スコープ:「グローバル」を選択します。
    • ユーザー名:「root」を入力します。
    • パスワード:「password」を入力します。
    • ID:「ansible-node-credential」を入力します。
  5. 「Artifactory Push 用」は以下の値を入力してから「Create」ボタンをクリックして作成します。
    • 種類:「ユーザー名とパスワード」を選択します。
    • スコープ:「グローバル」を選択します。
    • ユーザー名:「admin」を入力します。
    • パスワード:「password」を入力します。
    • ID:「artifactory-app-credential」を入力します。
  6. 「Dependeny-Track SBOM 登録用 API Key」は以下の値を入力してから「Create」ボタンをクリックして作成します。
    • 種類:「Secret Text」を選択します。
    • スコープ:「グローバル」を選択します。
    • シークレット:SETUP のスクリプトで埋めるので適当な文字をを入力します。
    • ID:「dependency-track-api-key」を入力します。
Artifactory 設定

「Jenkins の管理 > System Configuration > System」で JFrog のプラグイン情報を設定します。JCasC ファイルでは「container/jenkins/my-config/jcasc/jenkins.yaml#L90-L96」の定義が該当します

  • 「JFrog Plugin Configuration」セクションで以下の値を入力します。
    • Server ID:「my-artifactory」を入力します。
    • JFrog Platform URL:「http://artifactory:8081」を入力します。
    • Credentials:「admin/******」を選択します。
    • Allow HTTP Connections:On でチェックを入れます。

コンテナ構築スクリプトの解説

「コンテナ構築スクリプトの実行」章で使用する「container/CREATE_CONTAINER.sh」スクリプトの処理内容について解説します。

Artifactory 構築用の YAML ファイル取得

Artifactory コンテナを構築するための docker-compose YAML ファイルを取得します。JFrog 社が公開しているファイルを利用して構築するため、以下 OSS 版のダウンロードページより、Linux Installer で「Docker Compose」を選択した際に表示される Download URL から tar.gz ファイルを取得します。

取得した tar.gz ファイルを解凍すると artifactory-oss-{version}/templates/ ディレクトリ配下に、いくつか docker-compose YAML ファイルが存在しているが、その中から Artifactory と PostgerSQL コンテナを構築する「docker-compose-volumes.yaml」を利用します。

Web アプリ向け MySQL 設定ファイル取得

本ハンズオン、および、Grafana LGTM スタックのハンズオン向けに用意した Web アプリケーションのリポジトリから MySQL 設定用のファイルを取得します。Clone で取得するのではなく、リポジトリを zip 圧縮したファイルで取得します。

取得した zip ファイル解凍すると hands-on-webapp-rolling-dice-main/mysql/ ディレクトリ配下に、MySQL を設定するファイルが存在するので、これらファイルを Web アプリケーション構築用の docker-compose-webapp.yaml ファイルに定義した MySQL コンテナから volume 参照して利用します。

コンテナの構築

本ハンズオンで利用するコンテナは 3 種類の docker-compose YAML ファイルを利用して構築するため、これらのファイルを指定して docker-compose コマンドを実行します。

$ docker-compose \
  -f docker-compose.yml \
  -f docker-compose-webapp.yml \
  -f docker-compose-volumes.yaml \
  up -d -V --remove-orphans

ネットワークへ登録

Artifactory コンテナは JFrog 社で公開している docker-compose YAML ファイルで構築しているため、ハンズオン用に独自で運用している Docker ネットワークに後から追加します。

$ docker network connect hands-net artifactory
$ docker network connect intra-net artifactory
$ docker network connect intra-net postgresql

    CI/CD 環境セットアップスクリプトの解説

    「CI/CD 環境セットアップスクリプトの実行」章で使用する「SETUP_HANDS-ON.sh」スクリプトの処理内容について解説します。

    必須コマンドの存在確認

    CI/CD の連携をスクリプトで行う際に必要となるコマンドがインストールされているかどうかを確認します。コマンドの存在が確認できなかった場合には、スクリプトは停止しますので、手作業でコマンドのインストールをお願いします。詳細な実行内容は以下実装を確認してください。

    Jenkins ジョブ登録

    Jenkins CLI クライアントをダウンロードして、Jenkins CLI でジョブを登録します。

    $ wget -O jenkins-cli.jar http://localhost:8080/jnlpJars/jenkins-cli.jar
    
    $ java -jar jenkins-cli.jar -s http://localhost:8080/ -auth admin:password create-job build-webapp-webapi < ./jenkins/jobs/config-build-webapp-webapi.xml
    $ java -jar jenkins-cli.jar -s http://localhost:8080/ -auth admin:password create-job build-webapp-webui < ./jenkins/jobs/config-build-webapp-webui.xml
    $ java -jar jenkins-cli.jar -s http://localhost:8080/ -auth admin:password create-job deploy-webapp < ./jenkins/jobs/config-deploy-webapp.xml

    詳細な実行内容は以下実装を確認してください。

    Dependency-Track 設定

    Admin 初期パスワード変更

    Admin ユーザーの初期パスワードを変更します。詳細な実行内容は以下実装を確認してください。

    OSV 有効化

    Google 提供の OSV を脆弱性判定ソースとして有効化します。初期同期の時間を最小限に抑えるため、対象エコシステムを「Maven」のみに限定し、設定後は即座に同期を実行します。詳細な実行内容は以下実装を確認してください。

    Dependency-Track API Key の Jenkins 連携

    Jenkins ジョブと Dependency-Track 間の脆弱性スキャン連携における認証を設定します。Dependency-Track の「Administrators」チームで生成した API Key を、Jenkins の認証情報(Credentials)へ同期します。詳細な実行内容は以下実装を確認してください。

    GitLab Admin 設定

    Administrator 権限が必要な Admin area の GitLab 環境全般の各種設定を行います。詳細な実行内容は以下実装を確認してください。

    GitLab export からのインポート有効化
    1. GitLabトップページに移り左ペイン最下部から「Admin」ボタン押下
    2. 左ペインから「Settings > General」選択
    3. 「Import and Export settings」セクションを選択
    4. 「GitLab export」をOn
    Auto DevOps pipeline無効化
    1. GitLabトップページに移り左ペイン最下部から「Admin」ボタン押下
    2. 左ペインから「Settings > CI/CD」選択
    3. 「Continuous Integration and Deployment」セクションを選択
    4. 「Default to Auto DevOps pipeline for all projects」をOff
    Webhook 許可設定

    ローカルネットワーク内にWebhookを送信するには、ここでOn設定をする必要がある

    手順は以下の通り

    1. GitLabトップページに移り左ペイン最下部から「Admin」ボタン押下
    2. 左ペインから「Settings > Network」選択
    3. 「Outbound requests」セクションを選択
    4. 「Allow requests to the local network from webhooks and integrations」をOn
    5. 「Save changes」ボタン押下

    GitLab リポジトリ設定

    リポジトリ作成

    事前にエクスポートして用意してあるファイルをインポートして、初期状態のリポジトリを Web UI、Web API の2つ分を用意します。

    1. 「Create a project」→「Create a blank project」押下
    2. 以下入力して「Create project」押下
      • Project name = webapp-webapi
      • Project URLで「root」選択
      • Visibility levelで「Public」選択
      • 「Create project」押下
    3. 同様に「Project name = webapp-webui」も作成します。

    詳細な実行内容は以下実装を確認してください。

    リポジトリへ WebHook 登録

    「webapp-webapi」「webapp-webui」の各リポジトリでマージイベント発生時に、各リポジトリに対応する Jenkins のビルドジョブへ Webhook を送信するための設定を行います。

    1. GitLabトップページ移り「webapp-webui」プロジェクトをアクティブにする
    2. プロジェクト画面の左ペインより「Settings > Webhooks」を選択
    3. 「Add new webhook」押下
    4. 以下入力
      • Name = jenkins-build-webapi
      • URL = http://jenkins:8080/project/build-webapi
      • Secret tokne に Jenkins でジョブに発行したTokenを入力(1234567890abcdefghijklmnopqrstuvwxyz)
      • Trigger は「Merge request events」のみ「On」にする
      • Enable SSL verification = Off
      • 「Add webhook」押下
    5. 事前にプロジェクトに「マージリクエスト(=プルリク)」を作ったうえで、リストに移ったら登録したWebhookの右側にある「Test > Merge request events」でテストを実施し、画面上部に「Hook executed successfully: HTTP 200」で成功(マージリクエストが存在しない状態だと、いくらテスト実行してもエラーとなる)

    詳細な実行内容は以下実装を確認してください。

    GitLab CI/CD 向け設定

    Jenkins ではなく、GitLab CI/CD でビルドやデプロイを行うために必要な各種設定を行います。

    リポジトリへ CI/CD 変数登録

    GitLab CI/CD からデプロイする際に Ansible へアクセスするために必要な変数を設定します。詳細な実行内容は以下実装を確認してください。

    グループ Runner 紐付け用のグループ作成

    GitLab CI/CDの実行環境を一元管理するため、グループ Runner の紐付け対象となる専用グループを新規に作成します。詳細な実行内容は以下実装を確認してください。

    グループ Runner 作成

    先に作ったグループを紐づけてグループ Runner を作成します。詳細な実行内容は以下実装を確認してください。

    ローカルリポジトリ準備スクリプトの解説

    「ローカルリポジトリ準備スクリプトの実行」章で使用する「PREPARE_LOCAL_GIT_REPO_TO_PUSH.sh 」スクリプトの処理内容について解説します。

    リモートからローカルリポジトリ取得

    Web API のリモートリポジトリを取得して、開発作業を進めるためにローカルリポジトリへディレクトリを遷移します。

    $ git clone http://localhost:13000/admin/webapp-webapi.git
    $ cd webapp-webapi/
    • 手順説明では Web API を対象に進めますが、Web API が終わったら手順のコマンドに書かれている「webapp-webapi」を「webapp-webui」に差し替えて、フロントエンドも同様の流れで実施します。

    ローカルリポジトリへ開発ブランチ作成

    アプリケーションを開発を GitHub flow ベースのソースコード管理に準じて進めるために、開発用のブランチを作成して、該当のブランチがアクティブにします。

    $ git checkout -b feature/sample
    $ git branch -a
    
    * feature/sample
      main
      remotes/origin/HEAD -> origin/main
      remotes/origin/feature/sample
      remotes/origin/main

    ローカルリポジトリで Web アプリケーション開発

    本来であれば、Web アプリケーションをゼロから実装してリポジトリに登録するのが理想的な手順ではありますが、本ハンズオンでは Web アプリケーションの開発ではなく、CI/CD の実施を体験することが主な目的となるため、既に開発されている以下の Web アプリケーションのソースコードを利用して、開発したつもりで進めます。

    Web アプリケーションのリポジトリをダウンロードするディレクトリを作成します。

    $ mkdir ~/handson/hands-on-jenkins/download/

    圧縮形式のリポジトリをダウンロードします。

    $ curl -LO \
      --output-dir ~/handson/hands-on-jenkins/download/ \
      https://github.com/Toshiharu-Konuma-sti/hands-on-rollingdice-webapp/archive/refs/heads/main.zip

    圧縮しているリポジトリを展開します。

    $ unzip -o ~/handson/hands-on-jenkins/download/main.zip -d ~/handson/hands-on-jenkins/download/

    展開したリポジトリから Web アプリケーションのソースコードを、CI/CD 演習用のリポジトリに移動して持ってきます。「webapi」が終わったら「webui」に置き換えて実行します。

    $ mv -f \
      ~/handson/hands-on-jenkins/download/hands-on-rollingdice-webapp-main/webapi/* \
      ~/handson/hands-on-jenkins/try-my-hand/webapp-webapi/
    $ mv -f \
      ~/handson/hands-on-jenkins/download/hands-on-rollingdice-webapp-main/webapi/.git* \
      ~/handson/hands-on-jenkins/try-my-hand/webapp-webapi/

    GitLab CI/CD の各リポジトリ設定

    「webapp-webapi」「webapp-webui」の各リポジトリで、GitLab CI/CD を動かす設定ファイルは以下の通りです。

    まとめ

    Jenkins や GitLab をはじめとするすべてオープンソース(OSS)のプロダクトを組み合わせ、ソースコードのコミットからビルド、セキュリティ検査、デプロイ、そしてオブザーバビリティーと連携したフィードバックループに至るまで、CI/CD および DevOpsの一連の流れをハンズオン形式で体験していただきました。

    今回のハンズオンで体験・学習できる主なポイントは以下の通りです。

    • オール OSS で揃う DevSecOps 環境
      • Jenkins、GitLab、Dependency-Track、Artifactory OSS、Ansible、OWASP ZAP などのオープンソースのみをコンテナで一括構築し、手軽に実践的な CI/CD環境を用意できること。
    • シフトレフトを意識した多角的なセキュリティ&品質検証
      • 単体テストや静的解析(SAST: SpotBugs/PMD)だけでなく、SCA(Dependency-TrackによるSBOM・脆弱性可視化)やDAST(OWASP ZAP)まで組み込んだ、安全なサプライチェーンセキュリティのプロセス。
    • 仕様書自動生成とアーティファクト管理
      • JavaDoc や OpenAPI Spec 形式の仕様書自動生成による最新仕様の可視化と、Artifactory を用いた成果物の一元管理。
    • 継続的な改善を回す DevOps フィードバックループ
      • デプロイして終わりではなく、Grafana 等のオブザーバビリティー環境と連携することで、アプリケーションの稼働状況を観測し、次のコード改修(Plan/Code)へと循環させる「DevOpsの無限ループ」を体感できること。

    「CI/CD」や「DevSecOps」、「シフトレフト」といった概念は、言葉や図で理解しようとすると難しく感じられがちですが、実際に手元でコンテナを動かし、パイプラインが実行されてアプリが更新される様子を目の当たりにすることで、その本質やメリットを実感していただけたのではないでしょうか。

    本ハンズオンで使用したスクリプトや設定ファイルはすべてGitHubで公開していますので、環境構築の裏側の仕組みを解析してみたり、ご自身の開発アプリを載せてカスタマイズしてみたりと、CI/CD・DevOps 実践の第一歩としてぜひご活用ください。

    最後までお読みいただき、ありがとうございました

    ご覧いただきありがとうございます! この投稿はお役に立ちましたか?

    役に立った 役に立たなかった

    0人がこの投稿は役に立ったと言っています。
    エンジニア募集中!

    コメントを残す

    メールアドレスが公開されることはありません。 ※ が付いている欄は必須項目です