Jenkinsのgit連携には、いくつかのシナリオがあります。
素朴な使い方は、ジョブで使うリポジトリをgit cloneするパターンで、これは gitステップで実装できます。
一方、git pushについてはPipelineステップやプラグインは存在せず、自ら実装する必要があります。
結論的に要点のコードを提示すると、以下のような実装になります。
sshagent(credentials: ['some-credential-id']) {
sh('GIT_SSH_COMMAND="ssh -oStrictHostKeyChecking=no" git push origin master')
}
sh()
ステップでJenkins実行環境内のgitコマンドを実行する- SSH鍵は
SSH Agent Pluginから供給する
- クレデンシャルIDは、Jenkinsの「認証情報」に登録した鍵IDを指定
GIT_SSH_COMMAND
環境変数でsshの挙動を制御- 対話的に公開鍵を承認できないため、この例では
-oStrictHostKeyChecking=no
オプションで接続先ホスト認証をスキップ。man in middle攻撃への耐性は下がる - SSH接続ユーザーが決まっている環境では、
ssh -l
オプションを追加することでユーザー指定も可能
- 対話的に公開鍵を承認できないため、この例では
要するにJenkinsの実行環境にgitをインストールすればフル機能を使えるという素朴なアプローチです。最大の課題となる秘密鍵はsshagent()
ステップでセットアップします。Jenkinsの「認証情報」に登録した秘密鍵はID文字列の指定のみで参照できるため、セキュアな方式と言えます。
ホスト認証については、known_hostsを適切にセットアップした方がセキュアです。ツールのサポートはなく、ビルド実行ユーザーの~/.ssh/known_hosts
を参照する挙動になります。マルチノード構成の場合、実行ホストのスレーブノードに設定が必要です。
一般的な環境ではjenkinsユーザーで動作することが多いと思いますが、kubernetes pluginを用いてコンテナ内でビルドするケースでは特に指定しなければrootで動作します。known_hostsは以下のようなコマンドで生成できます。
$ ssh-keyscan some-host >> known_hosts
注意事項
git pushの前提として、以下のような準備が必要です。
- JenkinsにSSH Agent Pluginをインストール
- gitリポジトリにアクセス可能な秘密鍵をJenkinsの認証情報に登録しておく
- ジョブの実行環境にgitをインストール
- Kubernetes Plugin環境ではコンテナイメージにgitをインストールしておく
- 上の例ではホスト確認をスキップしているが
known_hosts
を登録してホスト確認した方がベター
- git pushの前段階で、
git config
を用いて user.email と user.name を設定しておく
また、ジョブの内容にもよりますが、checkout scm
などでcloneしたリポジトリの場合、“detached head"になっていることがあります。push時に"src refspec master does not match any"といったエラーに遭遇する場合には、git checkoutなどでHEADを適切にセットアップしておく必要があるでしょう。
エラー時のプリントデバッグコマンドとして、以下のようなものが使えます。
- git branch
- detached headの確認
- git remote -v
- リモートリポジトリ設定の確認
- ssh-add -l
- ssh-agentが供給する鍵の確認
まとめ
この方式は、Jenkinsとgitとsshの3つのレイヤを適切にセットアップする必要があり、手軽な方法ではありません。
ただ、gitの高度な機能を利用したい場合、git
コマンドを直接使う方が見通しが良いケースがあります。
また、以下の点で明確なメリットもあります。
- Pipelineに記述することでコード化でき、プラグイン依存を低減できる
- Jenkins標準のクレデンシャル管理を活用して、秘密鍵をシンプルに供給できる
- Kubernetes Pluginのコンテナ上でも実装を変えずに動作する
gitとsshのスキルは相当求められますが、目的に対して必要な柔軟性を得られます。
Chuma Takahiro