JenkinsとGitLabを連携する方法

JenkinsとGitLabのCI/CDのための連携設定を備忘録としてまとめました。

# 1. GitLabプラグインのインストール

Jenkinsに[Jenkins GitLab Plugin](https://github.com/jenkinsci/gitlab-plugin)をインストールします。
インストールは管理者権限のあるユーザでJenkinsにログインし、`Jenkinsの管理`→`プラグインの管理`→`利用可能`なタブを選択、GitLab Pluginにチェックをいれてインストールを実行します。

# 2. Jenkins側のGitLabの認証設定

JenkinsからGitLabのレポジトリやジョブの実行結果を連携するために、JenkinsにGitLabの認証情報を設定します。

### GitLabのAccess Tokenの取得

GitLabのAPIキーは、CI/CDの対象となるレポジトリのDeveloper権限以上をもつユーザのものが必要です。

APIキーはGitLabにログインし、右上の`Settings`→`Access Tokens`から発行ができます。

`Name(名前)`と`Expires at(有効期限)`と`Scopes（api、read_user）`を選択して`Create personal access token`を選択してAccess Tokenを発行します。
すると`Your New Personal Access Token`のところに英数字に文字列がでるので、コピーしておきます。このトークンは二度と表示されないため、保存に失敗した場合は再発行してください。

### グローバルドメインの設定

さきほど取得したAPIのAccess TokenをJenkinsの認証情報として保存します。

Jenkinsのメニューの`認証情報`→`System`→`グローバルドメイン`を選択、左にある`認証情報の追加`を選択し、以下の内容で追加します。

- 種類 : GitLab API token
- API token : さきほど発行したGitLabのAccess Token
- ID : 空欄(あとで自動発行される)
- 説明欄 : GitLab認証用のAPIトークンである旨の説明を記載

続けて、同じ要領でAccess Tokenを発行したユーザの認証情報も登録します。

- 種類 : ユーザ名とパスワード
- ユーザ名 : GitLabのユーザ名
- パスワード : GitLabのパスワード 
- ID : 空欄(あとで自動発行される)
- 説明欄 : GitLab認証用のユーザである説明を記載

### Jenkins GitLab Pluginの設定

次にGitlabのドメイン認証設定をします。

`Jenkinsの管理`→`システムの設定`を選択し、`GitLab`のところを設定します。設定値は以下の通りです。

- Enable autehntication for '/project' end-pointにチェック
- Gitlab connections
	- Connection name : Jenkins内部で識別するGitLabのコネクション名（例： GitLab）
	- GitLab host URL : GitLabのURL
	- Credentials : グローバルドメインで設定したGitLabのAccess Token

`高度な設定`ではAPIレベルの指定、SSL証明書のエラー無視の有無、コネクションタイムアウト秒数、リードタイムアウト秒数が設定できますが、ここではデフォルトのままにします。

すべて設定した後に`Test Connection`を押し、`Success`が出れば認証設定は完了なので、`保存`を押して設定を保存します。

# 3. Jenkinsのパイプラインジョブ作成

今回はbranch pushによるCI/CDを実現するために、`Multibranch Piline`でジョブを定義します。

左のメニューの`新規ジョブ作成`を選択し、`Enter an item name`のところにジョブ名を記載し、`Multibrancn Pipeline`を選択して`OK`を選択します。

ジョブの詳細設定は以下のように設定します。

- General
	- フォルダ名 : 前の画面で設定したジョブ名（URIに利用されます）
	- 表示名 : 表示名を設定
	- 説明 : ジョブの説明を記載
- Branch Sources
	- Gitを選択
	- プロジェクトレポジトリ : GitLabのgit cloneのアドレス（最後が.gitのやつ）を記載
	- 認証情報 : さきほど設定したGitLabのユーザ名・パスワードの認証情報を選択
	- Behaviours : Discovery branches(デフォルトのまま)
	- Property strategy : All branches get the same propeties(デフォルトのまま)
- Build Configuration
	- Mode : by Jenkinsfile
	- Script Path : gitレポジトリ内のJenkinsファイルのパス（ルートなら`Jenkinsfile`と記載）
- その他の設定※
	- Scan Multibranch Pipline Triggers
	- 不要アイテムの扱い
	- 健全性のメトリクス
	- Propetries
	- Pipeline Librares
	- Pipeline Model Definition

※その他の設定は今回はデフォルトのまま行います、必要に応じて設定してください。

設定が完了すると、対象のレポジトリのスキャンが始まり、Jenkinsfileの確認が実行されます。

定義したジョブをクリックして、`Scan Multibranch Pipeline Log`の最後が以下のように`Finished: Success`になればOKです。

```txt
Branch indexing
[Tue Mar 13 07:17:49 UTC 2018] Starting branch indexing...
 > git --version # timeout=10
using GIT_ASKPASS to set credentials xxxxxx
 > git ls-remote --symref https://xxxxxxxxxxx/yyy/zzz.git # timeout=10
 > git rev-parse --is-inside-work-tree # timeout=10
Setting origin to https://xxxxxxxxxxx/yyy/zzz.git
 > git config remote.origin.url https://xxxxxxxxxxx/yyy/zzz.git # timeout=10
Fetching & pruning origin...
Fetching upstream changes from origin
 > git --version # timeout=10
using GIT_ASKPASS to set credentials xxxxxx
 > git fetch --tags --progress origin +refs/heads/*:refs/remotes/origin/* --prune
Listing remote references...
 > git config --get remote.origin.url # timeout=10
using GIT_ASKPASS to set credentials xxxxxx
 > git ls-remote -h https://xxxxxxxxxxx/yyy/zzz.git # timeout=10
Checking branches...
  Checking branch master
      ‘Jenkinsfile’ found
    Met criteria
Changes detected: master (aaaaaaaaaaaaaaaaaaaaaaa → bbbbbbbbbbbbbbbbbbbb)
Scheduled build for branch: master
Processed 1 branches
[Tue Mar 13 07:17:50 UTC 2018] Finished branch indexing. Indexing took 0.96 sec
Finished: SUCCESS
```

# 4. GitLabのWebhook設定

次にGitLabのレポジトリへのPushやMerge RequestのイベントトリガーでJenkinsが実行されるようにWebhookの設定を行います。

GitLabにJenkinsに設定したユーザでログインし、対象のレポジトリにアクセスしてメニューから`Settings`→`Integrations`を選択します。

以下のパラメータを入力して`Add webhook`をクリックして設定します。

- URL : `https://[JenkinsのユーザID]:[JenkinsユーザのAPI Token]@[JenkinsのホストURI]/project/[Jenkinsのジョブ名]`
	- `JenkinsのユーザID`、`JenkinsユーザのAPI Token`は、Jenkinsにログインして右上のユーザ名をクリックし、`設定`→`APIトークン`→`APIトークンの表示`で確認できます。
- Secret Token : 空欄
- Triggers
	- Push events, Merge Request events, Job events, Pipeline eventsにチェックを入れます。必要に応じてチェックを追加してください
- SSL verification
	- チェックします（必要に応じてチェックを外してください）

設定後に`Test`をクリックして`Hook executed successfully: HTTP 200`が返ってこれば成功です。エラーになった場合は認証情報や接続情報を見直してみてください。

# 5. Jenkinsfileの設定と確認

Jenkinsのジョブの定義はJenkinsfileで定義します。
対象のレポジトリのJenkinsfileに以下を記載して、レポジトリへPushしてみましょう。

```Groovy
pipeline {
    agent any

    post {
        success {
            updateGitlabCommitStatus name: 'build', state: 'success'
            updateGitlabCommitStatus name: 'test', state: 'success'
            updateGitlabCommitStatus name: 'deploy', state: 'success'
        }
        failure {
            updateGitlabCommitStatus name: 'build', state: 'failed'
            updateGitlabCommitStatus name: 'test', state: 'failed'
            updateGitlabCommitStatus name: 'deploy', state: 'failed'
        }
    }

    options {
        gitLabConnection('GitLab')
        gitlabBuilds(builds: ['build', 'test', 'deploy'])
    }

    triggers {
        gitlab(
            triggerOnPush: true,
            triggerOnMergeRequest: true,
            branchFilterType: 'All',
            addNoteOnMergeRequest: true,
            addCiMessage: true
        )
    }

    stages {
        stage('build'){
            steps {
                echo "BUILD"
            }
        }
        
        stage('test'){
            steps {
                echo "TEST"
            }
        }

        stage('deploy'){
            steps {
                echo "DEPLOY"
            }
        }
    }
}
```

Push完了後にJenkinsのジョブが自動で実行され、実行結果がGitLabに連携されれば設定完了です。

# 6. Jenkinsのジョブに成功したMerge Requestだけマージできるようにする

Gitlabの対象レポジトリの`Settings`の`Merge request settings`の`Expand`を押し、`Only allow merge requests to be merged if the pipeline succeeds`にチェックを入れます。

# その他

ローカルネットワークで疎通する場合はGitLabの`Admin Settings`→`Outbound Request`→`Allow requests to the local network`にチェックを入れる必要があるケースがあります。

# 参考情報

- https://github.com/jenkinsci/gitlab-plugin
- https://jenkins.io/doc/pipeline/steps/gitlab-plugin/
- https://jenkins.io/doc/book/pipeline/syntax/

Mattermostも連携する手順は[JenkinsとGitLabとMattermostを連携する方法](https://qiita.com/takamii228/items/a0f4b2ef8107d6d3cd34)をご覧ください。