Stackdriver+Gitlab-CI+Ansibleで自動復旧の仕組みを構築する

# はじめに

GCE上のプロセスをStackdriverで監視していて、プロセスが落ちたらSlackにアラートを飛ばす・・・・

**ちゃうねん！アラートが飛ばすことが目的じゃなくて、サービスをいち早く復旧させるのが目的やねん！**

どうせAlert飛んだあとにやることは、`systemctl status XXXXX`でステータス確認して、`sudo systemctl start XXXXX`をするだけじゃん。

ということで、Stackdriver+Gitlab-CI+Ansibleを連携させて、アラートを飛ばすだけじゃなく、サービスを復旧させる仕組みを構築してみようと思う。

チームのメンバーがSlack botでもいい感じに自動復旧の仕組みを作ってる記事があるので、`Slack botでやりたいんだよ！俺は！`っていう人は↓を参考にすると幸せになれる。
**Stackdriverとslackbotでサービス自動復旧させる**
https://qiita.com/andromeda/items/fcb2ea02e9bb32e329e4

## 全体構成

![autohealing (2).png](https://qiita-image-store.s3.amazonaws.com/0/33101/b007186e-d743-1534-39b0-c5ebff63f330.png)




### 補足
後述もしているが、proxy経由でStackdriverのwebhookをしている理由は、SourceIPが固定化出来ないのでGitLabのFirewallルールにSourceIPを追加出来ないため。
一定のセキュリティを担保するためにBasic認証付きにしている。

## 前提
* gitlab自体はすでにインストール(稼働)済みとする
* GCPプロジェクトが利用可能な状態である

## Gitlab-runner+Ansibleサーバを構築

適当にGCEインスタンスを作成する。
今回はCentOS7のイメージを使用。

### Ansibleのインストール

適当にインストール

```shell
sudo yum install ansible
```

#### ansibleの設定ファイル

すごく単純でこんな構成

```shell
$ tree
.
├── inventories
│   └── hosts
├── roles
│   └── nginx
│       └── tasks
│           └── main.yml
└── site_test.yml

```

```shell:hosts
[nginx]
XXX.XXX.XXX.XXX
```

```yaml:main.yml
- name: start nginx
  systemd:
    name: nginx
    state: started
```

```yaml:site_test.yml
- name: start nginx
  hosts: nginx
  become: yes
  roles: 
    - nginx
```

#### .gilab-ci.ymlの設定
ansibleというユーザーを作って、ansibleユーザーで実行する。
また、ansibleユーザーの公開鍵は、監視対象となるNginxサーバがあるGCPプロジェクトに登録しておく。

```yaml:.gitlab-ci.yml
stages:
  - start-service

start-service:
  stage: start-service
  tags:
    - autohealing
  script:
    - sudo ansible-playbook -i ./ansible/inventories/hosts -u ansible --private-key=/home/ansible/.ssh/id_rsa ./ansible/site_test.yml

```

### GitLab-Runnerのインストール

[公式ドキュメント](https://docs.gitlab.com/runner/install/linux-repository.html)を参考にインストール

```shell
$ sudo curl -L https://packages.gitlab.com/install/repositories/runner/gitlab-runner/script.rpm.sh | sudo bash

$ sudo yum install gitlab-runner

# 起動確認
$ systemctl status gitlab-runner
● gitlab-runner.service - GitLab Runner
   Loaded: loaded (/etc/systemd/system/gitlab-runner.service; enabled; vendor preset: disabled)
   Active: active (running) since Sat 2018-10-20 01:04:37 JST; 11h ago
 Main PID: 25635 (gitlab-runner)
   CGroup: /system.slice/gitlab-runner.service
           └─25635 /usr/lib/gitlab-runner/gitlab-runner run --working-directory /home/gitlab-runner --config /etc/gitlab-runner/config.toml --service gitla...

```

### gitlab-runnerにsudo権限を与える

```shell
$ sudo visudo
# 以下を末尾に追加
gitlab-runner ALL=(ALL) NOPASSWD: ALL
```

### GitLab-Runnerを登録する

[公式ドキュメント](https://docs.gitlab.com/runner/register/)通り対話形式で以下のようにRegisterする

```shell
$ sudo gitlab-runner register
Running in system-mode.                            
                                                   
Please enter the gitlab-ci coordinator URL (e.g. https://gitlab.com/):
https://example.gitlab.com/
Please enter the gitlab-ci token for this runner:
XXXXXXXXXXXXXXX
Please enter the gitlab-ci description for this runner:
[ansible-server]　: autohealing
Please enter the gitlab-ci tags for this runner (comma separated):
autohealing
Registering runner... succeeded                     runner=yJC3cma3
Please enter the executor: docker+machine, docker-ssh+machine, kubernetes, docker, virtualbox, shell, ssh, docker-ssh, parallels:
shell
Runner registered successfully. Feel free to start it, but if it's running already the config should be automatically reloaded! 
```

こんな感じでrunnerが登録される
![CI : CD Settings · CI : CD · blcloud-infra : blcloud-autohealing · GitLab 2018-10-20 14-13-28.png](https://qiita-image-store.s3.amazonaws.com/0/33101/aa2c9f83-45d5-d37c-027f-93bfdd83ceb8.png)

#### .netrcを作成する
git pullとかするときにアカウント情報聞かれてめんどいので、 .netrcを作っておく

```shell
$ su - gitlab-runner
$ vi .netrc
machine gitlab.com
login ci-user(適当)
password ci-password(適当)
```

#### Pipeline triggerを設定

GitLabにてtriggerを設定して、webhookで使用するtokenを取得する。

![スクリーンショット 2018-10-20 22.28.13.png](https://qiita-image-store.s3.amazonaws.com/0/33101/225f60db-960d-949c-3be3-6af5dc245b98.png)


## gitlab-proxyサーバの作成
Stackdriver AlertのWebhookはGIPが一定ではない(Googleサポートにも問合せたけど、左記の回答)。
GitlabにIPでFireWallがあった場合は、Webhookが通知できない。
なので、Nginxでproxyとなるサーバを用意して、GIPを固定化する。
そして、NginxにBasic認証を用いることで、一定のセキュリティを担保するようにする。

IPを固定できるようにしてーという[issues](https://issuetracker.google.com/issues/110917343)が上がっているので、ここをウォッチしていくと、このgitlab-proxyが不要になったら分かるようになる。
是非、スターつけてください！

### nginxのインストール

```shell
$ sudo yum install -y nginx
```

### basic認証を設定する

```shell
$ sudo yum install -y httpd-tools
$ htpasswd -c /etc/nginx/.htpasswd なんか適当にID
New password: なんか適当にPW
Re-type new password: なんか適当にPW

$ vi /etc/nginx/nginx.conf

       auth_basic "Restricted";
       auth_basic_user_file /etc/nginx/.htpasswd;

        location / {
            proxy_pass https://gitlabのアドレス/;
        }

```

## 監視対象のサーバ作成

今回、監視される側となるサーバを作成する。
このNginxがダウンしたら、stackdriverが検知して、gitlabに通知後にgitlab-runnerを発火する。

### Nginxのインストール
適当にGCEにNginxをインストールしておく

```shell
$ sudo install -y nginx
$ systemctl status nginx
● nginx.service - The nginx HTTP and reverse proxy server
   Loaded: loaded (/usr/lib/systemd/system/nginx.service; disabled; vendor preset: disabled)
   Active: active (running) since Sat 2018-10-20 04:29:30 UTC; 42min ago
  Process: 1726 ExecStart=/usr/sbin/nginx (code=exited, status=0/SUCCESS)
  Process: 1723 ExecStartPre=/usr/sbin/nginx -t (code=exited, status=0/SUCCESS)
  Process: 1722 ExecStartPre=/usr/bin/rm -f /run/nginx.pid (code=exited, status=0/SUCCESS)
 Main PID: 1728 (nginx)
   CGroup: /system.slice/nginx.service
           ├─1728 nginx: master process /usr/sbin/nginx
           └─1729 nginx: worker process
```

### StackdriverAgentのインストール
プロセスのメトリクスを取得するには[StackdriverMonitoringAgentのインストール](https://cloud.google.com/monitoring/agent/install-agent)がいる。

```shell
$ curl -sSO https://dl.google.com/cloudagents/install-monitoring-agent.sh
$ sudo bash install-monitoring-agent.sh

# 起動確認
$ systemctl status stackdriver-agent
● stackdriver-agent.service - LSB: start and stop Stackdriver Agent
   Loaded: loaded (/etc/rc.d/init.d/stackdriver-agent; bad; vendor preset: disabled)
   Active: active (running) since Sat 2018-10-20 11:27:42 UTC; 37s ago
     Docs: man:systemd-sysv-generator(8)
  Process: 9464 ExecStart=/etc/rc.d/init.d/stackdriver-agent start (code=exited, status=0/SUCCESS)
 Main PID: 9495 (stackdriver-col)
   CGroup: /system.slice/stackdriver-agent.service
           └─9495 /opt/stackdriver/collectd/sbin/stackdriver-collectd -C /etc/stackdriver/collectd.conf -P /var/run/stackdriver-agent.pid
```

## Stackdriverのアラート設定
### webhookの設定

![スクリーンショット 2018-10-25 9.46.41.png](https://qiita-image-store.s3.amazonaws.com/0/33101/6a652250-62c4-76d2-a872-002c2744ff3a.png)

### alertの設定
![スクリーンショット 2018-10-25 9.43.51.png](https://qiita-image-store.s3.amazonaws.com/0/33101/33bff4e7-0ee3-a5fc-98ca-aecd0f7cacfa.png)

### notificationの設定
![スクリーンショット 2018-10-25 9.53.01.png](https://qiita-image-store.s3.amazonaws.com/0/33101/336c44a7-bae5-3b39-6826-65e09f1f92ad.png)

## いざ実践

Nginxを落とす

```shell
$ sudo systemctl stop nginx
$ systemctl status nginx
● nginx.service - The nginx HTTP and reverse proxy server
   Loaded: loaded (/usr/lib/systemd/system/nginx.service; disabled; vendor preset: disabled)
   Active: inactive (dead)

Oct 25 05:05:39 web-test systemd[1]: Started The nginx HTTP and reverse proxy server.
Oct 25 05:36:07 web-test systemd[1]: Stopping The nginx HTTP and reverse proxy server...
Oct 25 05:36:07 web-test systemd[1]: Stopped The nginx HTTP and reverse proxy server.
Oct 25 05:44:40 web-test systemd[1]: Starting The nginx HTTP and reverse proxy server...
Oct 25 05:44:40 web-test nginx[13630]: nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
Oct 25 05:44:40 web-test nginx[13630]: nginx: configuration file /etc/nginx/nginx.conf test is successful
Oct 25 05:44:40 web-test systemd[1]: Failed to read PID from file /run/nginx.pid: Invalid argument
Oct 25 05:44:40 web-test systemd[1]: Started The nginx HTTP and reverse proxy server.
Oct 26 08:33:01 web-test systemd[1]: Stopping The nginx HTTP and reverse proxy server...
Oct 26 08:33:01 web-test systemd[1]: Stopped The nginx HTTP and reverse proxy server.
```

Stackdriverで障害を検知！
![スクリーンショット 2018-10-26 17.41.43.png](https://qiita-image-store.s3.amazonaws.com/0/33101/ce38cd28-4f38-f474-b478-87eaa454584e.png)


すると・・・パイプラインが動き出す

<img width="988" alt="Pipelines · blcloud-infra : blcloud-autohealing · GitLab 2018-10-25 13-24-57.png" src="https://qiita-image-store.s3.amazonaws.com/0/33101/5628a8b2-6819-ea43-6717-4f8c2061c834.png">


```
Running with gitlab-runner 11.3.1 (0aa5179e)
  on autohealing 2cd3b42d
Using Shell executor...
Running on ansible-server...
Fetching changes...
HEAD is now at 324102c 改装を変更
Checking out 324102c4 as master...
Skipping Git submodules setup
$ sudo ansible-playbook -i ./ansible/inventories/hosts -u ansible --private-key=/home/ansible/.ssh/id_rsa ./ansible/site_test.yml

PLAY [start nginx] *************************************************************

TASK [Gathering Facts] *********************************************************
ok: [XXX.XXX.XXX.XXX]

TASK [nginx : start nginx] *****************************************************
changed: [XXX.XXX.XXX.XXX]

PLAY RECAP *********************************************************************
XXX.XXX.XXX.XXX             : ok=2    changed=1    unreachable=0    failed=0   

Job succeeded
```

Nginxのステータスを見てみると・・・復活している！

```
$ systemctl status nginx
● nginx.service - The nginx HTTP and reverse proxy server
   Loaded: loaded (/usr/lib/systemd/system/nginx.service; disabled; vendor preset: disabled)
   Active: active (running) since Fri 2018-10-26 08:41:40 UTC; 1min 16s ago
  Process: 15845 ExecStart=/usr/sbin/nginx (code=exited, status=0/SUCCESS)
  Process: 15842 ExecStartPre=/usr/sbin/nginx -t (code=exited, status=0/SUCCESS)
  Process: 15841 ExecStartPre=/usr/bin/rm -f /run/nginx.pid (code=exited, status=0/SUCCESS)
 Main PID: 15847 (nginx)
   CGroup: /system.slice/nginx.service
           ├─15847 nginx: master process /usr/sbin/nginx
           └─15848 nginx: worker process

Oct 26 08:41:39 web-test systemd[1]: Starting The nginx HTTP and reverse proxy server...
Oct 26 08:41:40 web-test nginx[15842]: nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
Oct 26 08:41:40 web-test nginx[15842]: nginx: configuration file /etc/nginx/nginx.conf test is successful
Oct 26 08:41:40 web-test systemd[1]: Failed to read PID from file /run/nginx.pid: Invalid argument
Oct 26 08:41:40 web-test systemd[1]: Started The nginx HTTP and reverse proxy server.
```

![スクリーンショット 2018-10-26 18.08.07.png](https://qiita-image-store.s3.amazonaws.com/0/33101/e92ab98b-b739-a01c-89e6-00366ae32ef3.png)


## 今後やりたいこと
gitlabの通知をする際に、variablesを付加してansibleで使用するplaybookを動的に変更出来るようにしておきたい。