Gitlab + Jenkins + hugo(in Docker)で静的サイトをpush時に自動Deploy

# 概要
`hugo` で作っている静的サイトを、 `Gitlab` に `push` したらあとは自動的にデプロイできないかな、と思ったのがことの始まり。方法はいくらでもあるんでしょうけど、 **Jenkinsを触ってみたかった** ってだけでとりあえず `Jenkins` でやってみることにしました。 `Gitlab` の実際の本番環境とか触りたくなかったので以下の構成で自分のMacbook Proで検証。(Docker in Dockerはやりたくなかったので、VirtualBoxにUbuntu入れてその中にJenkins入れてます）

![hugodeploy.png](https://qiita-image-store.s3.amazonaws.com/0/38528/5efb821f-173d-8b9f-2a75-37916fefc0b0.png)

**「こうした方がいいのでは？」という意見など大歓迎です！**

# 前提知識
この記事ではDocker, Virtualbox, Gitlabをそれとなく使ったことある人、かつ `hugo` のコードベースが既にある人を前提に書いています。なのでこれらが揃ってない人はよくわからない内容になっている可能性が高いです（ごめんなさい）。

# Gitlabの準備
Webhookを試せるようにテスト用のGitlabを準備します。お手軽なDockerのイメージが [sameersbn/docker-gitlab](https://github.com/sameersbn/docker-gitlab) にあるのでこちらを使わせてもらいます。

```bash
docker-compose up
```

叩いたら本当にすぐにGitlabが使えます。とりあえずここに自分の `hugo` の `git` リポジトリを上げておきましょう。また、後ほど `jenkins` さんと連携したいので、 `jenkins` ユーザもGitlabに追加します。
Gitlabの `Admin Area > Users > New User` に行って `jenkins` ユーザ追加しましょう。

![image](https://qiita-image-store.s3.amazonaws.com/0/38528/56547004-cc4b-3429-1922-6012b3cef0ec.png)

External Userでいいはずなので、チェックを忘れずに。
![image](https://qiita-image-store.s3.amazonaws.com/0/38528/c4c31fe5-f5fe-cff2-2c90-80fdd8a11e8b.png)


作ったあとは `Edit` ページからパスワードを設定します。適当に「jenkinsjenkins」とでもしておきましょう。

ユーザが追加できたら、対象となる `hugo` プロジェクトのメンバーにReporterとして追加しておきます。
![image](https://qiita-image-store.s3.amazonaws.com/0/38528/69566d8e-aed7-5941-42d9-e6fc2a8bde17.png)

これでGitlab側の準備はいったん完了。

# Jenkinsの準備
## Jenkins初期設定
VirtualBoxを[ダウンロード](https://www.virtualbox.org/wiki/Downloads)して、Ubuntu(とりあえず16.04.1)も[ダウンロード](https://www.ubuntu.com/download/desktop)してVirtualBoxの中にインストールします。

インストールが完了したら基本的に[こちら](http://tecadmin.net/install-jenkins-in-ubuntu/)のサイトに記載されている手順でJenkinsをインストールします。

```bash
# LTSバージョンのPPA追加
wget -q -O - http://pkg.jenkins-ci.org/debian-stable/jenkins-ci.org.key | sudo apt-key add -
sudo sh -c 'echo deb http://pkg.jenkins-ci.org/debian-stable binary/ > /etc/apt/sources.list.d/jenkins.list'

# Jenkinsのインストール
sudo apt-get update
sudo apt-get install jenkins
```

インストールが完了しますと `http://<VMのIP>:8080/` にアクセスすると、 **Administrator Password** を入力してくださいっていうような画面が出て来るはずです。

```bash
sudo cat /var/lib/jenkins/secrets/initialAdminPassword
```

これで最初のパスワードが手に入るので入力すると先の画面に進むことができます。
次の画面では **Select plugins to install** の方を選択して、この時点でGitlabのプラグインをインストールしちゃいましょう。
![image](https://qiita-image-store.s3.amazonaws.com/0/38528/150d7cea-a548-fb7f-542b-94368f9a91c6.png)

次にAdmin Userを作る画面にいくので適当に `admin` というような名前のユーザでも作っておきます。これで初回のセットアップ完了です。

## Docker Pluginのインストール
さっそく先程作った `admin` ユーザでログインして、今度は **Docker Plugin** をインストールしましょう。

`Jenkinsの管理 > プラグインの管理` の `利用可能` タブをクリックして、検索ボックスで **Docker** と入力します。 `Docker Plugin` というのが見つかるはずなのでインストールしましょう。
![image](https://qiita-image-store.s3.amazonaws.com/0/38528/26578b92-94c4-9fbe-5cfe-c25a24ad14e7.png)

Jenkinsも再起動しておいて、これでいったん準備完了です。

# Dockerの準備
## dockerのインストール
JenkinsのSlaveとしてDockerを使うので、UbuntuにDockerをインストールします。[こちら](https://www.digitalocean.com/community/tutorials/how-to-install-and-use-docker-on-ubuntu-16-04)を参考にインストールしました。

```bash
#　とりあえずパッケージデータベースをアップデート
sudo apt-get update

# GPG keyの登録
sudo apt-key adv --keyserver hkp://p80.pool.sks-keyservers.net:80 --recv-keys 58118E89F3A912897C070ADBF76221572C52609D

# リポジトリ追加
sudo apt-add-repository 'deb https://apt.dockerproject.org/repo ubuntu-xenial main'

# パッケージデータベース再びアップデート
sudo apt-get update

# dockerインストール
sudo apt-get install -y docker-engine

# docker起動してるか確認
sudo systemctl status docker

# jenkinsユーザでdockerが使えるようにdockerグループに追加
sudo usermod -aG docker jenkins
```

これでdockerのインストール完了です。一応 `jenkins` ユーザで使えるかテストしておきましょう。

```bash
# rootユーザになって
sudo -i

# jenkinsユーザになって
su jenkins

# hello-worldコンテナ実行してみる
docker run hello-world
```

↑これが正常に実行できたらdockerの準備OKです。一応ここで　**OSの再起動** しておきます。（たぶんOSの再起動じゃなくてJenkinsの再起動だけで大丈夫ですが、念のため）

## hugoのビルド用Dockerイメージ準備
JenkinsのSlaveとして使うDockerイメージの準備をします。 `hugo` が叩けたら良いんですけど、とりあえずは[publysher/docker-hugo](https://github.com/publysher/docker-hugo)がお手頃に見つかったので、これをベースにDockerイメージを作っていきます。 `ssh` できるようにしておきたいのと、 `jdk` が必要なのでこのイメージにインストールしておきます。

```bash
# publysher/docker-hugoからdockerコンテナ作ってbash起動
docker run -it publysher/docker-hugo

# ↓ここからdockerコンテナの中
# パッケージデータベースの更新
apt-get update

# sshサーバインストール
apt-get install openssh-server
mkdir /var/run/sshd

# jdkインストール（とりあえずの7）
apt-get install openjdk-7-jdk

# ssh用のjenkinsユーザ追加（このときのパスワード覚えておくこと）
adduser jenkins

# ssh起動しとく
/usr/sbin/sshd

# コンテナから抜ける
exit
# ↑dockerコンテナの中ここまで

# 今作ったコンテナを確認
docker ps -a
# ↓こんなのが出てくるはずなのでCONTAINER IDを取得
# CONTAINER ID        IMAGE               COMMAND
# 223f94679c0f        publysher/hugo      "/bin/bash"

# コンテナをjenkins-hugoイメージとして登録（このイメージ名覚えておく）
docker commit 223f94679c0f jenkins-hugo

# イメージの確認
docker images
# ↓こういうのがあるはず
# REPOSITORY          TAG                 IMAGE ID
# jenkins-hugo        latest              cfbeadf0f958
```

以上でコンテナの準備完了です！

# JenkinsにDocker設定＆ジョブ追加
## Dockerの設定
Jenkinsで「Jenkinsの管理 > システムの設定」にて、一番下に「クラウド」という項目があるので、そこで **Docker** を選択します。
![image](https://qiita-image-store.s3.amazonaws.com/0/38528/a6c63368-b412-52e5-9da4-9407f286ecf2.png)

項目は以下のようにしときます。ローカルのDocker使うので **Docker URL** は `unix:///var/run/docker.sock` にします。ここまでうまく設定できていたら **Test Connection** も正常にパスするはずです。
![image](https://qiita-image-store.s3.amazonaws.com/0/38528/f114f378-b915-a9db-41bd-9e9806ad3813.png)

下の方の項目にAdd Docker Templateというのがあるので追加します。
![image](https://qiita-image-store.s3.amazonaws.com/0/38528/df943c9e-7b75-07e2-95f2-a9210d1f3c55.png)


**Docker Image** には先程作ったイメージ名（ `jenkins-hugo` )を。 **Labels** はあとで使うのでわかりやすい名前にします。 **用途** には「このマシーンを特定ジョブ専用にする」を指定して、明示的に指定されたときだけ使われるようにします。 **Launch method** は 「Docker SSH computer launcher」として認証情報には先程のSSH用のユーザ情報を入力します。
![image](https://qiita-image-store.s3.amazonaws.com/0/38528/c5626e2f-557b-64b5-c108-a467981b88da.png)

## ジョブの設定
Jenkinsに新規ジョブを追加します。「フリースタイル」で `hugo-deploy` とでも名前をつけて作りましょう。

「実行するノードを制限」の項目で先程のDockerでの設定で指定したラベルを入力します。
![image](https://qiita-image-store.s3.amazonaws.com/0/38528/d5899543-3bb1-5342-43c2-19bc2b1dc80d.png)

「ソースコード管理」ではpull元となるGitlabのURLを入力し、 `external` で登録したGitlabのユーザの認証情報も追加します。
<img width="937" alt="hugo-deploy_Config__Jenkins_.png" src="https://qiita-image-store.s3.amazonaws.com/0/38528/21c04e19-5f89-6e60-bdf5-2db058fdc523.png">

「ビルド・トリガ」の項目で以下の部分に注目。Gitlab連携のURLをコピーしておきます。
<img width="938" alt="hugo-deploy_Config__Jenkins_.png" src="https://qiita-image-store.s3.amazonaws.com/0/38528/611cffa1-faf3-d857-e079-fb937416a707.png">

「ビルド」ではとりあえず `hugo` でビルドして、生成された `public` をデプロイ先にコピーします。（検証用なので、以下は単純に `scp` だけしてます。実際はここで `aws` の `s3` に `sync` とかすることになります。）
![image](https://qiita-image-store.s3.amazonaws.com/0/38528/17f95b17-95c9-2782-f3c1-722c22ab152d.png)

ジョブの設定はこれで完了！

# 実行！
それでは、あとはGitlabにwebhookを追加して、`push` 時にJenkinsのジョブが発火するようにします。
<img width="917" alt="Webhooks_·_Settings_·_fukuyama___SSL_·_GitLab.png" src="https://qiita-image-store.s3.amazonaws.com/0/38528/7d3a51be-d9c2-3b2d-9e58-242f0de21457.png">

今までの設定が正常にできていれば、これでJenkinsジョブが発火して、Jenkinsのコンソールログには以下のような内容が出力されるはずです。

```
Started by user admin
Building remotely on docker-ee2d2b9f2a26 (hugo-docker-slave) in workspace /home/jenkins/workspace/hugo-deploy
Cloning the remote Git repository
Cloning repository http://192.168.56.1:10080/hoge/hoge.git
 > git init /home/jenkins/workspace/hugo-deploy # timeout=10
Fetching upstream changes from http://192.168.56.1:10080/hoge/hoge.git
 > git --version # timeout=10
using GIT_ASKPASS to set credentials 
 > git fetch --tags --progress http://192.168.56.1:10080/hoge/hoge.git +refs/heads/*:refs/remotes/origin/*
 > git config remote.origin.url http://192.168.56.1:10080/hoge/hoge.git # timeout=10
 > git config --add remote.origin.fetch +refs/heads/*:refs/remotes/origin/* # timeout=10
 > git config remote.origin.url http://192.168.56.1:10080/hoge/hoge.git # timeout=10
Fetching upstream changes from http://192.168.56.1:10080/hoge/hoge.git
using GIT_ASKPASS to set credentials 
 > git fetch --tags --progress http://192.168.56.1:10080/hoge/hoge.git +refs/heads/*:refs/remotes/origin/*
 > git rev-parse refs/remotes/origin/master^{commit} # timeout=10
 > git rev-parse refs/remotes/origin/origin/master^{commit} # timeout=10
Checking out Revision 56d16c24249d9fa87de990f03e006b1b7412706e (refs/remotes/origin/master)
 > git config core.sparsecheckout # timeout=10
 > git checkout -f 56d16c24249d9fa87de990f03e006b1b7412706e
 > git rev-list 56d16c24249d9fa87de990f03e006b1b7412706e # timeout=10
[hugo-deploy] $ /bin/sh -xe /tmp/hudson4974744254848556844.sh
+ hugo
Started building sites ...
Built site for language en:
0 draft content
0 future content
0 expired content
78 regular pages created
18 other pages created
0 non-page files copied
24 paginator pages created
1 tags created
9 categories created
total in 226 ms
+ scp -r public ubuntu@172.17.0.1:/home/ubuntu/.
Finished: SUCCESS
```

実際のデプロイ方法は変わってきますが、これをベースに本当のデプロイフローも組んでいけるかな、っていうのがわかりました！楽しいですね！