Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
Jenkins PipelineでのShared Librariesの活用
Search
Hisashi.Iguchi
March 23, 2022
Technology
1.2k
0
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
Jenkins PipelineでのShared Librariesの活用
Hisashi.Iguchi
March 23, 2022
More Decks by Hisashi.Iguchi
See All by Hisashi.Iguchi
EC2 Mac インスタンスに入門してみた
hisa9chi
0
1.6k
20200805_Server版を見捨てないで_Cloud版の機能欲しいんです_.pdf
hisa9chi
0
410
Jenkins環境運用に関するSWETとしての取り組み
hisa9chi
0
1.3k
MacStadium使ってみた
hisa9chi
1
2.8k
サポートは強力な味方
hisa9chi
2
520
Bitriseの社内提供へ
hisa9chi
6
6.6k
CircleCI first-step
hisa9chi
2
1.8k
Other Decks in Technology
See All in Technology
JEP 522 Deep Dive - G1 GC同期コスト削減によるスループット向上を徹底検証&解説
tabatad
1
850
AI駆動開発が変える、大規模開発の前提 ーHuman in the Loop から Human on the Loop へ / AIE2026
visional_engineering_and_design
7
4.8k
Chart.js が簡単に使えるようになっていたので OGP 画像生成に使った話
kamekyame
0
160
そのPoC、何を検証したつもりでしたか? AIプロダクトの価値検証で陥った落とし穴
techtekt
PRO
0
150
データ基盤をDataformで整えた話 〜 開発環境を添えて 〜
takapy
0
110
サイバーセキュリティ概論 / Introduction to Cybersecurity
ks91
PRO
0
150
ブロックチェーン / Blockchain
ks91
PRO
0
110
正解のないAIプロダクトをどう導くか?dodaが挑む、ユーザーの『本音』を構造化する評価設計と検証のリアル
techtekt
PRO
0
180
イベントストーミングとKiroの仕様駆動開発で実現する要件の認識合わせプロセス
syobochim
7
1.2k
実装は速くなった、レビューはどうする? ― 自身のレビューをAIで再現させるサーヴァントエンジニアリングのすゝめ / Implementation got faster. So what about reviews? — An invitation to Servant Engineering: Recreating your own code reviews with AI
nrslib
6
3.8k
新規事業を牽引する技術選定 〜フルスタックTypeScript開発の実践事例〜
nullnull
3
350
Claude Code×Terraform IaC テンプレート駆動開発
itouhi
1
290
Featured
See All Featured
First, design no harm
axbom
PRO
2
1.2k
Max Prin - Stacking Signals: How International SEO Comes Together (And Falls Apart)
techseoconnect
PRO
0
170
How Fast Is Fast Enough? [PerfNow 2025]
tammyeverts
3
600
The Anti-SEO Checklist Checklist. Pubcon Cyber Week
ryanjones
0
150
Learning to Love Humans: Emotional Interface Design
aarron
275
41k
Stop Working from a Prison Cell
hatefulcrawdad
274
21k
Dealing with People You Can't Stand - Big Design 2015
cassininazir
367
27k
The agentic SEO stack - context over prompts
schlessera
0
790
Testing 201, or: Great Expectations
jmmastey
46
8.2k
The MySQL Ecosystem @ GitHub 2015
samlambert
251
13k
The Myth of the Modular Monolith - Day 2 Keynote - Rails World 2024
eileencodes
28
3.5k
Site-Speed That Sticks
csswizardry
13
1.2k
Transcript
Jenkins Pipelineでの Shared Librariesの活用 @Jenkins Day Japan 2021 [2021/12/10] 井口
恒志 <Hisashi Iguchi> システム本部 品質統括部 品質管理部 SWET第二グループ 株式会社ディー・エヌ・エー @ DeNA Co.,Ltd.
2 自己紹介 井口 恒志 (Hisashi Iguchi) 自動テストの開発・導入サポート CI/CDの活用促進や関連技術の調査
プロジェクトの状態可視化基盤などの整備 CircleCI のJapanユーザコミュニティでも活動中 バスケ好きで試合観戦や週1, 2でプレイもしてます DeNA システム本部 SWET第二グループ @hisa9chi
3 目次 SWETとは Shared Libraries 活用事例 まとめ 1 2 3
4
4 本発表に関して • 弊社チームのTesting Blogへ投 稿した内容を発表形式にまとめ ています https://swet.dena.com/entry/2021/01/18/200000
5 本発表での前提 • Jenkins controllerのversionは2.x系 • Jenkinsのジョブの種類は“Pipeline” ◦ ジョブの定義はJenkinsfileにしてリポジトリへ登録
◦ Pipeline Syntaxは“Declarative Pipeline”
6 1. SWETとは SWETのビジョンや役割などを紹介
7 SoftWare Engineer in Test c.f.> Google SET 「テストから見えてくるグーグルのソフトウェア開発」
https://www.nikkeibp.co.jp/atclpubmkt/book/13/P85120/
8 MISSION 1 ソフトウェアを起点とした ◦ DeNAサービス全般の品質向上 ◦ DeNAエンジニアの開発生産性向上
により、価値あるものを素早く提供できるようにする
9 Vision: Make Testing Fun, Smart and Delighting End-Users 2
• Fun ◦ テスティングを楽しくクリエイティブなものにする • Smart ◦ 定型的なテストを人の手を煩わせず実現する ◦ テストによるフィードバックを上手に活用して、素早い開発サイクルを実現す る • Delighting End-Users ◦ テストにより事業の成功を後押しするため、エンドユーザをデライトさせる 様々な品質を計測し改善する
10 SWETメンバーのプロジェクトへの関わり 3 • ソフトウェアテスト技術分野ごとのチーム ◦ アーキテクチャ ◦ 自動テスト
◦ プロセス(CI/CD) • それぞれのチームが様々な技術領域の案件をサポート ◦ QAによるテスト工程よりも前の工程で品質・生産性の向上 ◦ デバッグの効率化・工数削減などテスト技術の蓄積 ◦ テスト全般の実行環境・プロセスサポート・サービス化
11 プロセスチームのJenkinsに関する取り組み 4 • チームではJenkinsの運用コストを削減するための取り組みを実施
https://speakerdeck.com/dena_tech/mohairukemukai-fa-niokerujenkinskurautoshi-dai-falsejenkinsgou-zhu-toguan-li-tekunituk
12 2 SWETの取り組みなどを ブログで定期的に投稿中 https://swet.dena.com もしくは SWET
Testing Blog で検索
13 2. Shared Libraries 利用方法や特徴などを紹介
Pipeline 1 • PipelineのJenkinsfileをリポジトリ に登録・管理 14 sample-01.jenkinsfile pipeline { agent
{ label 'ubuntu' } stages { stage ( 'pre-build' ) { .... } stage ( ‘build’ ) { .... } } }
Pipeline 1 • PipelineのJenkinsfileをリポジトリ に登録・管理 • ジョブの数だけJenkinsfileは増加 15 sample-01.jenkinsfile
pipeline { agent { label 'ubuntu' } stages { stage ( 'pre-build' ) { .... } stage ( ‘build’ ) { .... } } } sample-02.jenkinsfile pipeline { agent { label 'ubuntu' } stages { stage ( 'pre-build' ) { .... } stage ( ‘build’ ) { .... } } } sample-03.jenkinsfile pipeline { agent { label 'ubuntu' } stages { stage ( 'pre-build' ) { .... } stage ( ‘build’ ) { .... } } }
Pipeline 1 • PipelineのJenkinsfileをリポジトリ に登録・管理 • ジョブの数だけJenkinsfileは増加 • 時にはメソッドも定義
16 sample-01.jenkinsfile pipeline { agent { label 'ubuntu' } stages { stage ( 'pre-build' ) { .... } stage ( ‘build’ ) { .... } } } sample-02.jenkinsfile pipeline { agent { label 'ubuntu' } stages { stage ( 'pre-build' ) { .... } stage ( ‘build’ ) { .... } } } sample-03.jenkinsfile pipeline { agent { label 'ubuntu' } stages { stage ( 'pre-build' ) { .... } stage ( ‘build’ ) { .... } } } sample-04.jenkinsfile pipeline { agent { label 'ubuntu' } stages { stage ( 'pre-build' ) { .... } stage ( ‘build’ ) { .... } } } def myFunc() { …. }
Pipeline 1 • PipelineのJenkinsfileをリポジトリ に登録・管理 • ジョブの数だけJenkinsfileは増加 • 時にはメソッドも定義
• コードの重複発生 17 sample-01.jenkinsfile pipeline { agent { label 'ubuntu' } stages { stage ( 'pre-build' ) { .... } stage ( ‘build’ ) { .... } } } sample-02.jenkinsfile pipeline { agent { label 'ubuntu' } stages { stage ( 'pre-build' ) { .... } stage ( ‘build’ ) { .... } } } sample-03.jenkinsfile pipeline { agent { label 'ubuntu' } stages { stage ( 'pre-build' ) { .... } stage ( ‘build’ ) { .... } } } sample-04.jenkinsfile pipeline { agent { label 'ubuntu' } stages { stage ( 'pre-build' ) { .... } stage ( ‘build’ ) { .... } } } def myFunc() { …. } sample-05.jenkinsfile pipeline { agent { label 'ubuntu' } stages { stage ( 'pre-build' ) { .... } stage ( ‘build’ ) { .... } } } def myFunc() { …. } 重複部分を外部に定義 再利用性とメンテナンス性が向上
18 Shared Libraries
19 Shared Libraries : 概要 • 概要 ◦ Pipelineの外部に定義 ◦
ライブラリはSCM管理 ◦ ライブラリはPipeline毎にロードして利用 ▪ ロードは複数指定可能 • 特徴 ◦ ジョブ毎で異なるバージョンの利用が可能 ◦ メンテナンス性と再利用性の向上 ◦ クラスのstaticメソッドのapproveが不要 2
20 Shared Libraries : 特徴 - ジョブ毎で異なるバージョンの利用が可能 • ライブラリのロード時に以下の指定が可能
◦ タグ ◦ ブランチ ◦ コミットハッシュ 2 ライブラリのロード方法 // デフォルトバージョンの読み込み // "Global Pipeline Libraries 設定" の "Default version" @Library( 'ライブラリ名' ) _ // ブランチ,タグ,コミットハッシュを指定する場合 @Library( 'ライブラリ名@{branch | tag | commit hash}' ) _ // 複数ライブラリの読み込み @Library( ['ライブラリ名1', 'ライブラリ名2'] ) _ pipeline { agent { label 'ubuntu' } .... }
21 Shared Libraries : 特徴 - メンテナンス性と再利用性の向上 • 変更はライブラリ内に閉じる
• 他のJenkinsからも利用可能 ◦ ライブラリを管理しているリポジトリのアクセス権は必要 • Plugin利用をラップしたライブラリの作成 ◦ Pluginの更新による変更影響をライブラリ内に閉じれる場合あり 2
22 Shared Libraries : 特徴 - クラスのstaticメソッドのapproveが不要 • Pipelineではgroovyによるクラスのstaticメソッドが実行可能
◦ セキュリティ的に問題 ◦ 管理者が承認したクラスのstaticメソッドの場合実行可能 • Pipeline内のgroovyコードにてクラスのstaticメソッドを利用した場合 ◦ 利用メソッド全てにapproveが必要 ◦ 結構面倒な作業(管理者に承認してもらう必要があるため) 2
23 Shared Libraries : 特徴 - クラスのstaticメソッドのapproveが不要 • Pipelineではgroovyによるクラスのstaticメソッドが実行可能
◦ セキュリティ的に問題 ◦ 管理者が承認したクラスのstaticメソッドの場合実行可能 • Pipeline内のgroovyコードにてクラスのstaticメソッドを利用した場合 ◦ 利用メソッド全てにapproveが必要 ◦ 結構面倒な作業(管理者に承認してもらう必要があるため) • ライブラリであればapproveは不要 ◦ 承認の面倒な作業が発生しない 2
24 Shared Libraries : Jenkins Plugin と比較 3 Shared Libraries
Jenkins Plugin 他のcontrollerからの 利用 可能 Jenkins設定のみ 可能 Plugin のインストール 利用バージョン 複数 タグ/ブランチ/コミットハッシュ 1バージョン ※1 インストールされたバージョン メンテナンス ライブラリ管理者 / 作成者 Pluginメンテナー 変更影響 なし ※2 複数バージョン指定可能なため 全ジョブに影響 変更によりジョブの失敗の可能性あり ※1 Plugin の更新に controller のバージョン更新や依存 Plugin の更新が必要な場合あり ※2 Plugin を利用している場合は Plugin の更新に依存して変更影響が発生する場合あり
25 Shared Libraries : 作成と設定 • 作成方法と実際の設定に関しては公式サイトを参考 ◦ https://www.jenkins.io/doc/book/pipeline/shared-libraries/
• SWET Testing Blog に少し記載しているのでご参考に ◦ https://swet.dena.com/entry/2021/01/18/200000 4
26 3. 活用事例 社内で Shared Libraries をどのように活用しているか紹介
27 活用事例 • ジョブの成果物のGCS(Google Cloud Storage)保存 • エラーとなったstage名の検出 •
Slack通知時のアタッチメント作成 • Slack通知時のメンション先ユーザのID取得 1
28 活用事例:ジョブの成果物のGCS保存 • ジョブ実行時の成果物はJenkins controller自体に保存が可能 ◦ controllerの容量には制限 ▪ ディスクの拡張などのメンテが必要
◦ 成果物(アプリのバイナリなど)をJenkins外から取得する時に面倒 • ジョブの成果物をGCSへ保存 ◦ ストレージの拡張などメンテフリー ◦ オブジェクトのライフサイクル設定でデータ自動削除可能 ◦ パブリッククラウドのため他サービスへの取り回しが比較的楽 2
29 活用事例:ジョブの成果物のGCS保存 • GCSアップロードには Plugin が存在 ◦ Google Cloud
Storage Plugin: https://plugins.jenkins.io/google-storage-plugin/ ◦ アップロード時には以下のパス構成でGCSへ保存しておきたい ▪ backet_name/job_name/build_no/upload_files ◦ Plugin利用時は上記のアップロードファイル以前のパスの指定 ▪ 基本的にはどのプロジェクトでも同様の方針 2 Plugin を利用したGCSアップロード // backet_name/job_name/build_no のパス設定 UPLOAD_DIR = "gs://${params.bucket_name}/${env.JOB_NAME}/${env.BUILD_NUMBER}" googleStorageUpload( bucket: UPLOAD_DIR, credentialsId: params.credentialsId, pattern: uplodFiles ) • 上記改善のためPluginをラップしたライブラリを作成
活用事例:ジョブの成果物のGCS保存 2 • ライブラリ側で以下を付加して アップロード ◦ ジョブ名/ビルド番号 •
Pipeline側では以下を指定 ◦ バケット名 ◦ 認証情報ID ◦ アップロードファイル 30 ライブラリ側 (libUploadArtifactsToGCS) // バケット名にジョブ名/ビルド番号 を付与 def uploadDir = "gs://${params.bucket}/${env.JOB_NAME}/${env.BUILD_NUMBER}" // ファイルのGCSへアップロード googleStorageUpload( bucket: uploadDir, credentialsId: params.credentialsId, pattern: params.pattern ) Pipeline側(呼び出し側) steps { // バケット名、認証情報ID、アップロード対象を指定してライブラリ呼び出し libUploadArtifactsToGCS( bucket: 'jenkins-artifacts', credentialsId: 'google-service-account', pattern: 'upload-sample.ipa' ) }
31 活用事例:エラーとなったstageの検出 • ジョブ実行時にエラーとなったstage名を通知に利用したい ◦ エラーとなったstage名を取得は以下の方法知られている 3 エラーとなったstage名を通知などに利用する場合
pipeline { agent { label ‘ubuntu’ } stages { stage ( ‘pre-build’ ) { …. } post { // stage毎の post process にて失敗時タスクで環境変数に stage名を設定 failure { script { env.ERROR_STAGE_NAME = ‘pre-build’ } } } …. } post { failure { // env.ERROR_STAGE_NAME を利用して失敗 stage名を通知など実行 } } }
活用事例:エラーとなったstageの検出 3 • この方法は以下の問題あり ◦ コード量の増加 ◦ stageが新規追加される度 に追加が必要
32 エラーとなったstage名を通知などに利用する場合 pipeline { agent { label ‘ubuntu’ } stages { stage ( ‘pre-build’ ) { …. } post { // stage毎の post process にて失敗時タスクで環境変数にstage名を設定 failure { script { env.ERROR_STAGE_NAME = ‘pre-build’ } } } …. } post { failure { // env.ERROR_STAGE_NAME を利用して失敗stage名を通知など実行 } } } メンテナンス性低下の要因となる
活用事例:エラーとなったstageの検出 3 • ライブラリ側で以下の手順で失 敗したstage名を返却 ◦ 全てのstage情報取得 ◦ 先頭から順に調べて最初
に見つかった失敗状態の stage名を取得 • Pipeline 側は失敗したstage名が 欲しい時に呼び出すのみ 33 ライブラリ側 (libGetFailedStageName) // stage 情報の取得 ChunkVisitor visitor = new ChunkVisitor( workFlowRun ); ForkScanner.visitSimpleChunks( workFlowRun.getExecution().getCurrentHeads(), visitor, new StageChunkFinder() ); // 全ての stage のステータスを検索 for ( StageNodeExt stageExt : visitor.getStages() ) { if ( stageExt.getStatus() == StatusExt.FAILED ) { errorStageName = stageExt.getName(); break; } } return errorStageName Pipeline側 (呼び出し側) .... post { failure { sh "echo Error Stage: ${libGetFailedStageName()}" } }
34 活用事例:Slack通知時のアタッチメント作成 • Slack通知以下のような共通の処理が多く存在 ◦ 通知用のアタッチメント作成 4 アタッチメント作成 JSONObject
attachmentObj = new JSONObject(); attachmentObj.put( 'title', title.toString() ); attachmentObj.put( 'title_link', title_link.toString() ); attachmentObj.put( 'text', subject.toString() ); attachmentObj.put( 'color', colorCode ); if ( fieldsMessages.size() > 0 ) { JSONArray fileds = new JSONArray(); fieldsMessages.each { Map message -> JSONObject customField = new JSONObject(); customField.put( 'title', message.title.toString() ) customField.put( 'value', message.message.toString() ) customField.put( 'short', message.short ) fileds.add( customField ); } attachmentObj.put( 'fields', fileds ); } アタッチメント作成(続き) if ( messages.size() > 0 ) { messages.each { key, value -> // 既存の設定も上書きできるようにする attachmentObj.put( key, value ); } } JSONArray attachmentArray = new JSONArray(); attachmentArray.add( attachmentObj ); return attachmentArray.toString(); jsonオブジェクトを作成する必要ある
活用事例:Slack通知時のアタッチメント作成 4 • ライブラリ側でkey-valueの配列 で情報を受け取りjson文字列を 作成して返却 ◦ 受け取ったkey-value配列 からjsonオブジェクトを作
成 • Pipeline側ではkey-value配列を 渡す 35 ライブラリ側 (libCreateSlackAttachments) JSONObject attachmentObj = new JSONObject(); …. if ( fieldsMessages.size() > 0 ) { JSONArray fileds = new JSONArray(); fieldsMessages.each { Map message -> JSONObject customField = new JSONObject(); …. fileds.add( customField ); } attachmentObj.put( 'fields', fileds ); } JSONArray attachmentArray = new JSONArray(); attachmentArray.add( attachmentObj ); return attachmentArray.toString(); Pipeline側 (呼び出し側) script { def List fieldsMessages = [ [ "title":"Execute Node", "message":"test-node", "short":false ], [ "title":"Test Branch", "message":"origin/master", "short":true ] ] def messages = [ "text": "message" ] def attachments = libCreateSlackAttachments( currentBuild.currentResult, fieldsMessages, messages ) }
36 活用事例:Slack通知時のメンション先ユーザのID取得 • Slack通知時にジョブを実行した方へメンションをしたい ◦ ジョブ実行者のSlack IDを取得してメッセージにそのIDを設定 5
ジョブ実行ユーザのemailからslack id の取得 // Slack API: https://slack.com/api/users.list?token=xxx へのリクエスト // Response取得 Response response = client.newCall( request ).execute(); // json へ変換 Object json = new JsonSlurper().parseText( response.body().string() ) // User の mention 用 ID 文字列 String mentionIdsStr = ""; // email から User ID を検出 for ( user in json.members ) { for ( target in params.userEmails ) { if ( user.profile.email == target ) { mentionIdsStr += "<@" + user.id + "> " } } } return mentionIdsStr; これ
活用事例:Slack通知時のメンション先ユーザのID取得 5 • ライブラリ側でemailを受け取っ てslackのIDを通知形式で返却 ◦ Slack APIを活用
• Pipeline側はジョブ実行者の emailを渡すだけ 37 ライブラリ側 (libGetFailedStageName) // Slack API: https://slack.com/api/users.list?token=xxx へのリクエスト // Response取得 Response response = client.newCall( request ).execute(); // json へ変換 Object json = new JsonSlurper().parseText( response.body().string() ) // User の mention 用 ID 文字列 String mentionIdsStr = ""; // email から User ID を検出 for ( user in json.members ) { for ( target in params.userEmails ) { if ( user.profile.email == target ) { mentionIdsStr += "<@" + user.id + "> " } } } return mentionIdsStr; Pipeline側 (呼び出し側) step { def id = libGetFailedStageName( userEmails: ['
[email protected]
', '
[email protected]
'], slackAPIToken: 'token’ ) } 現在はSlack Notification Pluginでもemailから SlackのユーザIDの取得が可能になっている模 様
38 ライブラリ利用の現在 • 導入当初は1プロジェクトで利用 -> 現在は 複数プロジェクトが利用 ◦ Jenkins controller
はプロジェクト毎に構築 • 他のプロジェクトメンバーもライブラリを作成して共有 • 既存ライブラリの機能拡張 6
39 ライブラリ利用の現在:既存ライブラリの機能拡張 • GCSファイルのアップロード/ダウンロードに関して ◦ アップロード時に設定可能にした key/tagを利用してindexファイルも保存 ▪
indexファイル保存パス: bucket_name/index/key/tag • index ファイル内にはアップロードした成果物のダウンロードURLを記載 ◦ ダウンロードの際は key/tagを指定することで成果物のダウンロードが可能 ▪ 拡張前はジョブ名と、ビルド番号が必要であり目的のファイルの場所を探すのが面倒 6 GCSへのアップロード時 // key / tag を設定してアップロード libUploadArtifactsToGCS( bucket: BUCKET_NAME, credentialsId: GCS_CREDENTIAL_ID, pattern: build.ipa, key: "ios_app", tags: ["latest"] ) GCSからダウンロード時 // key / tag を指定して目的の成果物をダウンロード libDownloadArtifactsFromGCS( bucket: BUCKET_NAME, credentialsId: GCS_CREDENTIAL_ID, key: "ios_app", tag: "latest", dirPath: ARTIFACTS_DIR )
40 4. まとめ 本日の総括です
41 まとめ • Shared Libraries を利用することで以下の利点 ◦ ジョブのメンテナンス性向上 ◦
再利用性の向上 ◦ Jenkins Pluginとは異なり複数バージョン利用可能 ▪ 更新時の影響範囲が限定 • 他で作成されたライブラリを利用 ◦ アクセス権があれば他のJenkins controllerからも 容易に利用可能 ◦ より効率的にジョブの作成 • 多くのプロジェクトで利用しやすいよう ライブラリを改善 1
42 質疑応答 何かあれば
@ DeNA Co.,Ltd.