Azureに素早くGitLabを構築する（ついでに独自ドメインでHTTPS）

# 経緯
GitHubは外部へ公開してしまうので、社員しか見れない環境はないかと調べていると、
GitLabが要件にあっていましたので、Azure上に構築することにしました。
ドメインはやはり自社のものが良いのと、
セキュリティの観点からHTTPS化もやってしまおうと、
欲張り構成に挑戦しました。
（まずは個人アカウントで練習）

# AzureにGitLabを構築

仮想サーバを構築します。
幸いGitLab導入済みのVMイメージがあります。

## VMの作成
<img width="1084" alt="create_gitlab_01.png" src="https://qiita-image-store.s3.amazonaws.com/0/145504/00f4e56c-93be-f1e5-fe16-bda5c4c0f54c.png">
新規から検索欄に「gitlab」と入力するといくつか候補が表示されます。
その中の「GitLab Community Edition」を選択します。

<img width="855" alt="create_gitlab_02.png" src="https://qiita-image-store.s3.amazonaws.com/0/145504/5badba7a-307f-d346-c2b2-82511e0e9af1.png">
お好きなように設定してください。

<img width="1126" alt="create_gitlab_03.png" src="https://qiita-image-store.s3.amazonaws.com/0/145504/55d0e7ea-6f47-5a82-2c5e-85c2f54c6288.png">
VMの性能をお好きなものから選びます。
ただし、とにかく安いものを選んではいけません。
メモリが「0.75GB」だとGitLabの一部サービスが起動できませんでした。
使っていくうちに動かなくなった等にならないように余裕を持って
少なくともメモリは「2GB」以上のものを選びましょう。
(推奨はvCPU「2」以上、メモリ「4GB」以上です)

<img width="855" alt="create_gitlab_04.png" src="https://qiita-image-store.s3.amazonaws.com/0/145504/46f4f278-7f8c-076d-0f5c-ed799fb9d8f3.png">
新規作成時の名称とかも自動的につけてくれるみたいです。（newがついている項目）
ですので特に設定の変更は必要ありません。
好みでAvailability setを設定しても良いです。
（可用性が99.9%から99.95%になるそうです）

<img width="1127" alt="create_gitlab_05.png" src="https://qiita-image-store.s3.amazonaws.com/0/145504/f5c4f77a-2780-adbd-38cc-0795c98eeae4.png">
検証が成功しましたら、購入で完了です。

## NWの確認と設定
<img width="1139" alt="create_gitlab_06.png" src="https://qiita-image-store.s3.amazonaws.com/0/145504/abe9d240-28a0-b40d-99ea-883ed95e3823.png">
ダッシュボードから作成したVMを選択します。
「Overview」から「Public IP address」を選択します。

<img width="797" alt="create_gitlab_07.png" src="https://qiita-image-store.s3.amazonaws.com/0/145504/410bcb0d-3103-0bc3-25d1-b6f5f3f25d7c.png">
DNS名ラベルを入力して保存します。

<img width="1439" alt="create_gitlab_08.png" src="https://qiita-image-store.s3.amazonaws.com/0/145504/217d1620-aba6-1135-0b44-41e4e32a7f52.png">
前の画面に戻って、「Networking」から受信ポートの規則に「SSH」「HTTP」「HTTPS」が設定されていることを確認します。
ない場合は「受信ポートの規則を追加する」から該当ポートを開いてください。

## 接続確認
<img width="936" alt="create_gitlab_09.png" src="https://qiita-image-store.s3.amazonaws.com/0/145504/acaa6596-0a89-edb6-c2d7-eb0d1921ea6c.png">
最後にブラウザからURLにIPアドレスまたはDNS名（「〜.japaneast.cloudapp.azure.com」など）を入力します。
初回アクセス時はrootユーザのパスワードの登録画面が表示されます。
次回以降は上記のログイン画面が表示されます。

## 更新
VMイメージの内容が古いことは往々にしてあります。
パッケージの更新をします。

※2017/9/11時点ではGitLabの最新バージョンは9系ですが、
VMの初期状態では8系でしたので、更新すると見た目が結構変わります。

```
$ sudo apt-get update
$ sudo apt-get upgrade
```
余談ですが、更新前ですとVMのvCPUが１つ、メモリ2GBでも割ときびきび動作しましたが、
更新後は実用に耐えないほど重くなります。
（VMのサイズ変更でvCPUを２つ、メモリ4GBに変更したら従前程度になりました）

なるべく軽いまま使用したい場合は、upgradeをしないのも手ですが、
OpenSSLは最新にしないと後ほど問題がおきますので、
個別に更新してください。
`$ sudo apt-get install openssl`

以上でAzure上にGitLabの構築が完了しました。

# セキュリティの向上
**2017/9/16追記**
最低限のセキュリティ設定を行います。

## SSHポート番号変更
SSHのデフォルトポート「22」を別の番号に変更します。

VMの設定画面の「Networking」が「受信ポートの規則を追加する」ボタンで許可するポートを追加します。
<img width="434" alt="sec_01.png" src="https://qiita-image-store.s3.amazonaws.com/0/145504/38a89a9b-7a88-91d2-a43f-eec46e4076ae.png">
例の場合はポート「10119」を使用するように設定しました。

使っていないポートであれば好きな数値を設定できます。
念のため以下のサイトで空いているところを探しておくのが無難でしょう。
[TCPやUDPにおけるポート番号の一覧](https://ja.wikipedia.org/wiki/TCP%E3%82%84UDP%E3%81%AB%E3%81%8A%E3%81%91%E3%82%8B%E3%83%9D%E3%83%BC%E3%83%88%E7%95%AA%E5%8F%B7%E3%81%AE%E4%B8%80%E8%A6%A7)

<img width="1214" alt="sec_02.png" src="https://qiita-image-store.s3.amazonaws.com/0/145504/d0592b75-ff61-d032-6f82-0efc985e1e4f.png">
指定したポートが許可されたらOKです。

SSHでVMにログインします。（この時はまだデフォルトの「22」）
設定ファイルを開きます。
`sudo vi /etc/ssh/sshd_config`

以下の箇所を修正します。

```
# Port 22
Port 10119
```

変更を保存したらSSHを再起動します。
`sudo /etc/init.d/ssh restart`

念のためまだログアウトせず、別セッションでSSHログインを試してみます。
ポートを指定する場合は以下の通りです。
`ssh -p 10119 ryo_4947123@gitlab.example.work`

<img width="1190" alt="sec_03.png" src="https://qiita-image-store.s3.amazonaws.com/0/145504/7d3e8cb4-e97c-798a-544a-bae403fd64ac.png">
最後にポート「22」の許可設定を削除して完了です。

# 起動/停止のスケジュール
**2017/9/18追記**
VM使用料の節約のため、使用しない時間帯は停止します。
起動と停止の自動化を行います。

## Automationの登録
起動と停止を行うスクリプト（PowerShell）を毎日指定した時間に実行してくれるAutomationを作成します。
幸いスクリプトは自前で用意しなくてもできるようになっています。（2017/9/18時点ではプレビュー）

<img width="812" alt="schedule_01.png" src="https://qiita-image-store.s3.amazonaws.com/0/145504/e286a42a-db7f-410d-439d-edccbf87f7c8.png">
新規から検索欄に「start stop」と入力すると「Start/Stop VMs during off-hours[Preview]」が出てきますので選択します。

<img width="943" alt="schedule_02.png" src="https://qiita-image-store.s3.amazonaws.com/0/145504/7de59471-eb29-d027-3b9f-bcbffe53e783.png">
初めて作成する場合は、OMSワークスペースを新規作成します。
（後述しますが、価格レベルは「Free」を選ばない方が良さそうです）

<img width="943" alt="schedule_03.png" src="https://qiita-image-store.s3.amazonaws.com/0/145504/481d3d86-8de6-58a3-c608-287189a89953.png">
続いて、Automationアカウントを作成します。

<img width="627" alt="schedule_04.png" src="https://qiita-image-store.s3.amazonaws.com/0/145504/75016246-2daf-9cf7-d9b2-4ee67861b382.png">
最後にパラメータを設定します。

ターゲットリソースグループ名に対象のVMが属するリソースグループの名称を入れます。
（*のままだと全てのVMが対象になります）

時間はこの段階では適当な値にしておきます。
（後ほど修正します）

<img width="314" alt="schedule_05.png" src="https://qiita-image-store.s3.amazonaws.com/0/145504/5099f24e-d850-8833-b3a4-df178877750c.png">
いざ作成！
・・・と思いきや、謎のエラーが発生して作成できないことがあります。
説明がいまいちわかりづらいのですが、
要するに価格レベルが「Free」の制限を超えているので他の有料プランにしてねということです。

推測ですが、FreeのAutomation実行時間の上限が500分/月なのですが、
パラメータの開始〜終了時間を参照して上限を超過していると判断しているのではと思います。
作成当時はその考えには至らなかったので以下の対処を行いました。

<img width="580" alt="schedule_06.png" src="https://qiita-image-store.s3.amazonaws.com/0/145504/8fce9d94-924a-1515-8974-866838363919.png">
作成したOMSワークスペースの価格レベルを「Free」から「ノードごと(OMS)」に変更してから、
もう一度作成を行い、作成が完了したら「Free」に戻します。

## スケジュールの設定
起動時刻と停止時刻を設定します。

<img width="1027" alt="schedule_07.png" src="https://qiita-image-store.s3.amazonaws.com/0/145504/f9b4e5e1-af13-3e79-3f92-92960d4da3c3.png">
作成したAutomationアカウントを開いて、「スケジュール」を選択します。
すると、起動と停止それぞれの実行時刻が登録されたリストが表示されます。

<img width="312" alt="schedule_08.png" src="https://qiita-image-store.s3.amazonaws.com/0/145504/31b457cb-5c3f-5861-34a7-113ba8d5b573.png">
まずは、起動時刻の設定を行います。
開始欄に次に起動する日時を入力します。（例の場合は午前9時ちょうどに起動する）
新規作成時は時間がUTCでの入力でしたが、ここでは日本時間で入力できるようになります。
毎日実行するので、繰り返しは「定期的」に設定し、間隔は「1日」とします。

<img width="309" alt="schedule_09.png" src="https://qiita-image-store.s3.amazonaws.com/0/145504/bdd64c32-a308-5c56-d285-aefe75b5b5c8.png">
停止時刻も同様に設定します。
（例の場合は午前1時ちょうどに起動する）

これでスケジュール完了です。

# バックアップ
**2017/9/18追記**
VMの自動バックアップを設定します。

## Recovery Servicesの作成
Azure上でバックアップとリカバリを一元管理するためのRecovery Servicesコンテナを作成します。

<img width="576" alt="Recovery_01.png" src="https://qiita-image-store.s3.amazonaws.com/0/145504/edb0d23a-3d5e-e3f0-bdcc-6c47de04955e.png">
VMの設定画面の「Backup」からRecovery Servicesコンテナの作成が行えます。

<img width="505" alt="Recovery_02.png" src="https://qiita-image-store.s3.amazonaws.com/0/145504/fc52df3d-387b-8cdc-4c3e-7fed8999ee32.png">
バックアップ実行時間と間隔、保存数を指定できます。
例の場合は、午前2時に実行で、60日間保存。

<img width="850" alt="Recovery_03.png" src="https://qiita-image-store.s3.amazonaws.com/0/145504/28f0e519-e4fa-c4c6-db36-322c6fd0de70.png">
前回のバックアップの状態が「警告」となっています。
これは、スケジュールされたバックアップが１回も実行されていないためです。
バックアップ時刻までそのままでも問題ありませんし、
今すぐバックアップで初回だけ手動実行でも良いです。

これでバックアップ設定完了です。
ちなみにRecovery Servicesコンテナはデフォルトでgeo冗長となっています。
geo冗長は遠隔地にもバックアップをレプリケーションしてくれるというもので、
例えば自然災害などに強くなります。
その代わりGBあたりの単価がほぼ倍になるのでお高いです・・・

# 独自ドメインの設定

任意のドメイン名でアクセスできるように設定します。
例として[お名前.com](https://www.onamae.com)での設定方法を記述しますが、
DNSの設定はどのサービスでも同じです。

## DNSの設定
<img width="657" alt="dns_01.png" src="https://qiita-image-store.s3.amazonaws.com/0/145504/ecb18d7f-3d46-c4a7-cf4c-076455658ffb.png">
「ドメイン設定」タブからDNS関連機能の設定を選択します。

<img width="660" alt="dns_02.png" src="https://qiita-image-store.s3.amazonaws.com/0/145504/364622ca-ea62-91d0-ddad-0566c4b57178.png">
DNSレコード設定を利用するの「設定する」を選択します。

<img width="661" alt="dns_03.png" src="https://qiita-image-store.s3.amazonaws.com/0/145504/797e86f4-4ef5-579e-017c-1f1acfb75de8.png">

ホスト名はお好きな名前を設定してください。
TYPEに「CNAME」を指定します。
VALUEにVMに設定したDNS名（「〜.japaneast.cloudapp.azure.com」など）を指定して追加します。

以上で設定完了です。
数分〜数十分ほどでホスト名に指定したアドレスをブラウザのURLに入力することで、
GitLabにアクセスできるようになります。

# HTTPS化

## 登録

まずはVMのディストリビューションを確認します。

```
$ uname -a
Linux Gitlab 3.19.0-58-generic #64~14.04.1-Ubuntu SMP Fri Mar 18 19:05:43 UTC 2016 x86_64 x86_64 x86_64 GNU/Linux
```

[https://certbot.eff.org](https://certbot.eff.org)にアクセスします。
<img width="866" alt="https_02.png" src="https://qiita-image-store.s3.amazonaws.com/0/145504/419ec9a8-df8c-b279-c0f8-bcba018c3bef.png">

Softwareに「None of the above」を、SystemにVMのディストリビューション（例の場合「Ubuntu 14.04」）を指定します。
GitLabを実行しているサーバはNginxなので、Softwareに指定すれば設定まで自動化してくれると思いましたが、
駄目でした。
どうもGitLab内蔵のNginxではなく、別のNginxの設定を行なってしまうようです。
そもそもGitLab内蔵のNginxの設定ファイルがどこにあるかわかりませんでした。
（わからなくても/etc/gitlab/gitlab.rbに設定を書けば自動的に構築する仕組みのため問題なし）

あとは説明通りコマンドを実行していきます。
今回実行したコマンド

```
$ sudo apt-get install software-properties-common
$ sudo add-apt-repository ppa:certbot/certbot
$ sudo apt-get update
$ sudo apt-get install certbot
$ sudo certbot certonly --standalone -d mygitlab.example.com
```
「mygithub.example.com」の部分にHTTPS化したいURLを指定します。
(以降は上記URLを読み替えてください)

`Enter email address (used for urgent renewal and security notices) (Enter 'c' to
cancel):`
途中でメールアドレスの登録が必要となりますので入力します。

```
Congratulations! Your certificate and chain have been saved at:
   /etc/letsencrypt/live/mygitlab.example.com/fullchain.pem
   Your key file has been saved at:
   /etc/letsencrypt/live/mygitlab.example.com/privkey.pem
   Your cert will expire on 2017-12-09. To obtain a new or tweaked
   version of this certificate in the future, simply run certbot again
   with the "certonly" option. To non-interactively renew *all* of
   your certificates, run "certbot renew"
```
上記メッセージが表示されれば無事登録が完了しました。
このメッセージ中の
`/etc/letsencrypt/live/mygitlab.example.com/fullchain.pem`と
`/etc/letsencrypt/live/mygitlab.example.com/privkey.pem`
が重要なパスです。

証明書は90日ごとに更新が必要となります。
以下のコマンドで更新ができるかのテストができます。
`$ sudo certbot renew --dry-run`

問題なければcrontabに登録しておきます。


## GitLabに設定

設定ファイルを開きます。
`$ sudo vi /etc/gitlab/gitlab.rb`

以下の通り設定します。
（HTTPSに関係ありませんがついでにタイムゾーンも設定しています）

```
external_url 'https://mygitlab.example.com'
・・・
gitlab_rails['time_zone'] = 'Asia/Tokyo'
・・・
nginx['ssl_certificate'] = "/etc/letsencrypt/live/mygitlab.example.com/fullchain.pem"
nginx['ssl_certificate_key'] = "/etc/letsencrypt/live/mygitlab.example.com/privkey.pem"
```
設定を反映します。
`$ sudo gitlab-ctl reconfigure`

最後にブラウザから「[https://mygitlab.example.com](https://mygitlab.example.com)」でアクセスして、
問題ないことを確認できましたら完了です。

## 安全性確認

以下のサイトにアクセスして、接続の安全性を確認します。
[https://www.ssllabs.com/ssltest/](https://www.ssllabs.com/ssltest/)

<img width="995" alt="https_03.png" src="https://qiita-image-store.s3.amazonaws.com/0/145504/727b0780-deaf-d146-bc09-fa62ad46ea3a.png">

これで完了です！！

# コスト
**2017/9/18追記**
ざっくり月額使用料を計算してみました。(小数点以下切り捨て)
独自ドメイン使用料は別です。
※単価は2017/9/18時点です。為替等でよく変動します。

| 項目 | プラン | 単価 | 月額 |
|:--|:--|--:|--:|
| VM使用料(全稼働時)       | Standard_A2_v2 | ¥11.53/時 |  ¥7,209 |
| VM使用料(停止分)         | Standard_A2_v2 | ¥11.53/時 | ¥-2,403 |
| ディスク使用料            | 管理対象S6(64GB) | ¥306.82/月 |   ¥306 |
| IPアドレス使用料          | 動的IP          | ¥0.41/時  |    ¥202 |
| Automation使用料        | Free          　|        ¥0 |      ¥0 |
| Recovery Services使用料 | 50~500GB以下   | ¥1,020/月 |  ¥1,020 |
| バックアップディスク使用料    | geo冗長(256GBを想定)　|   ¥4.9/GB |  ¥1,254 |
| 合計 |  |  | ¥7,588 |

- 上記のほかネットワーク使用量、ディスクIOによって課金があります。  
不特定多数に公開するのでなければ、微々たる額ですので省略しました。
- ディスクを管理対象で作成したので非管理対象（Strage Acount使用）にすればディスク単価は半額くらいになります。  
- バックアップを自前（スクリプト）で行えばそれなりにコスト削減できそうです。  
Recovery Servicesを使用すると障害復帰が早い事と、VMを丸ごと復元できる利点があります。

ディスク容量が少なすぎるように見えますが、増量は文字通り一瞬でできるので、
困ってからでも間に合います（汗）


# 終わりに

GitLabそのものの設定はほとんど行なっていないので、
これから調べつつやっていこうと思います。

セキュリティ的にはまだ完璧とは言えませんが、
通信経路上は安全になったのではないでしょうか。
※特定ユーザが使用することを想定しているので、サーバ偽装はあまり意識していません。
（自己署名で良いくらいでしたが実験も兼ねて）

お試しになる場合は全て自己責任でお願いします。