Ansibleではじめる自動化　デプロイをKAIZENする

# はじめに
本記事は、Ansibleでデプロイの自動化を行う方法について記載しています。

Ansibleとは何か？という方は、以前書いた[Ansibleとは何か　構成管理ツールの目的〜Ansible導入まで最速で理解する](https://qiita.com/Brutus/items/1894629105d61f4854bc)を参照

働き方改革が叫ばれている今の世の中ですが、ITの世界でも既に改革は行われています。

この春より、AIスタートアップにJoinし、DeVOpsについて少しずつ取り組んでいます。SIのときに係わっていたレガシーシステムでは、以下の様な運用を多く見てきました。


【レガシーシステムの特徴】

- 運用で使用するツールは基本、3種の神器（TeraTerm、WinSCP、サクラエディタ）
- 保守作業時は、手順書を作成する（Excel等のチェックシート）
- 保守作業時に、負荷分散装置に接続しているWebサーバは1台ずつ手動で切り離して、手動でサービスの起動停止を行う

といっても、SIではAnsibleの様に便利な構成管理ツールを知っていても、使用することができないのには理由があったりします。

**Ansibleの様な構成管理ツールを使用することで、一部のオペレーションを自動化し、運用に係るエンジニアは幸せになれます。**


## Ansibleの必要性
極論、構成管理ツールがなくても運用を行うことはできます。
当然、構成管理ツールを導入しようとすると、学習コストはかかってきます。

**しかし、クラウドが浸透しDevOpsが注目され、インフラエンジニアは新しい技術を使用して、分散サービス及びマイクロサービスを構築・運用するスキルが求められています。**

まずは今までの経験や、働く場所の文化等あると思いますが、導入に対する障壁がないのであればAnsible等構成管理ツールの使用を検討しましょう。

以下の様な運用が行われている場合は、構成管理ツールを検討する必要性が十分にあると思います。

- 資材の転送を1台ずつ行う
- 構築及びテスト時に、何度もアプリケーションデプロイする
- 運用時に、同じコマンドを定期的に実行する（サーバにログインするときのsshコマンドの手打ちや、テキストに書いたコマンドの貼り付け等）

## Ansibleを使ったデプロイ
Ansibleを使ったデプロイの例を以下に記載します。

本記事の環境は、クラウドにおけるマイクロサービスとしてDockerコンテナを使用しています。イメージとして、A〜Cの３つの環境があり、図中の管理サーバがAnsibleでデプロイを行います。

当然、どのシステムも環境毎の差異はありますが、心配不要です。
本記事ではシンプルなデプロイ方法として、環境毎にPlaybookを分けて制御しています。

具体的には、デプロイ時に管理サーバで自作のツールを実行します。ツール内から「ansible-playbook」コマンドを実行し、 環境毎にデプロイを行ないます。なお、図のA環境では、保守時にSorry用コンテナへの切り替えもAnsibleで行います。

![Ansible.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/221759/397b5a63-d915-c290-3e1b-8947ec8b3364.png)

### Ansibleの設定
各設定ファイルの意味は割愛します。（※）hostsに記載しているIPアドレスは例
なお、本記事の環境はSSHの公開鍵認証を使用かつ、ポート番号もデフォルトから変更しています。

- hosts（インベントリファイル）

```text
[localhost]
127.0.0.1 ansible_connection=local

[webservers]
192.168.1.100
192.168.1.200
192.168.1.300

[dbservers]
10.25.1.56
10.25.1.57

[A_webservers]
192.168.1.100

[B_webservers]
192.168.1.200

[C_webservers]
192.168.1.300
```


- ansible.cfg　（※）変更部分のみ記載

```config
26c26
< remote_port    = ＜変更したポート番号＞
---
> #remote_port    = 22
107c107
< remote_user = ＜ユーザ名＞
---
> #remote_user = root
136c136
< private_key_file = /home/＜ユーザ名＞/.ssh/id_rsa 
---
> #private_key_file = /path/to/file
```

- playbook

```yaml
- hosts: A_webservers
  become: yes
  tasks:

  - name: move old file
    vars:
      now_date: "{{ lookup('pipe','date +%Y%m%d') }}"
    command: mv /＜デプロイ資材のパス＞ /＜デプロイ資材のパス＞_{{ now_date }}

  - name: program copy
    copy:
      src: /＜デプロイ資材のパス＞
      dest: /＜デプロイ資材のパス＞
      owner: root
      group: root
      mode: 0644

  - name: file decompression 
    unarchive:
      src: /＜デプロイ資材のパス＞
      dest: /＜デプロイ資材のパス＞
      remote_src: yes

  - name: docker compose start
    shell: |
      docker rm -f $(docker ps -a -q)
      docker rmi $(docker images -q)
      cd /＜デプロイ資材のパス（資材の展開先）＞
      /usr/local/bin/docker-compose up -d
    args:
      executable: /bin/bash

  - debug: msg='Deployment is complete. Please visit https://＜デプロイしたアプリケーションのURL＞'

```

## 実践
上記Ansibleの設定を使用した自作ツールのデプロイ例を以下に記載します。自作ツールはシェルで作成しています。

はじめに自作ツールを起動し、デプロイする環境を選択します。

```console
 *---------------------------------------------------------*
 * Deploy the application                                  *
 *---------------------------------------------------------*

 1 Development environment
 2 Staging environment
 3 Production environment
 4 Production environment maintenance


 ---<Choose your environment>------------------------------
```

3を選択しました。デプロイ前に確認のため、yかnを入力します。実行する場合はyを入力します。

```console
3
██████╗ ██████╗  ██████╗ ██████╗ ██╗   ██╗ ██████╗████████╗██╗ ██████╗ ███╗   ██╗
██╔══██╗██╔══██╗██╔═══██╗██╔══██╗██║   ██║██╔════╝╚══██╔══╝██║██╔═══██╗████╗  ██║
██████╔╝██████╔╝██║   ██║██║  ██║██║   ██║██║        ██║   ██║██║   ██║██╔██╗ ██║
██╔═══╝ ██╔══██╗██║   ██║██║  ██║██║   ██║██║        ██║   ██║██║   ██║██║╚██╗██║
██║     ██║  ██║╚██████╔╝██████╔╝╚██████╔╝╚██████╗   ██║   ██║╚██████╔╝██║ ╚████║
╚═╝     ╚═╝  ╚═╝ ╚═════╝ ╚═════╝  ╚═════╝  ╚═════╝   ╚═╝   ╚═╝ ╚═════╝ ╚═╝  ╚═══╝
Are you sure you want to proceed?  (y/n) :
```

デプロイを開始します。ssh接続が行われるため、パスワードを入力します。

```console

 *---------------------------------------------------------*
 * Deploy start                                            *
 *---------------------------------------------------------*

Agent pid 10180
Enter passphrase for ＜秘密鍵のパス＞: 
```

秘密鍵のパスワードを入力後、デプロイが行われます。
本記事の例では、以下のタスクを実行しています。

- TASK [move old file]
管理対象サーバ（デプロイ先）の古い資材を日付を付けて移動

- TASK [program copy]
管理サーバから管理対象サーバ（デプロイ先）に資材をコピー

- TASK [file decompression] 
管理対象サーバ（デプロイ先）の資材展開

- TASK [docker compose start] 
管理対象サーバ（デプロイ先）でコンテナの削除及びイメージを削除し、`docker compose`コマンドを実行

- TASK [debug] 
debugモジュールを使用して、デプロイしたアプリケーションのURLにアクセスする様メッセージを表示

```console
PLAY [A_webservers] **************************************************************************************************************************************************

TASK [Gathering Facts] *************************************************************************************************************************************************
ok: [192.168.1.100]

TASK [move old file] ***************************************************************************************************************************************************
changed: [192.168.1.100]

TASK [program copy] ****************************************************************************************************************************************************
ok: [192.168.1.100]

TASK [file decompression] **********************************************************************************************************************************************
changed: [192.168.1.100]

TASK [docker compose start] ********************************************************************************************************************************************
changed: [192.168.1.100]

TASK [debug] ***********************************************************************************************************************************************************
ok: [192.168.1.100] => {
    "msg": "Deployment is complete. Please visit https://＜デプロイしたアプリケーションのURL＞"
}

PLAY RECAP *************************************************************************************************************************************************************
192.168.1.100                 : ok=6    changed=3    unreachable=0    failed=0   


real	1m33.105s
user	0m3.384s
sys	0m0.869s

 *---------------------------------------------------------*
 * Deploy end succes!!                                     *
 *---------------------------------------------------------*
```

ツールの中でtimeコマンドを使用して、デプロイにかかる時間を出力しています。
デプロイにかかった時間は**約1分半**です。

**Dockerfileをチューニングして、ミラーリングサイトを日本に変更すれば、さらにデプロ時間の短縮ができます。**

## ナレッジ
学習したことをナレッジとして以下に記載します。

- anbileで使用するPythonのバージョン  
CentOSなどyumでインストールしたansibleが使用するPythonのバージョンは、2系になっています。3系でインストールしたい場合は、pipでインストールするとansibleが使用すすると、Pythonのバージョンを3系にできます。
- サーバで使用しているPythonのバージョン  
CentOSなどRHEL系を使用している場合、デフォルトのPythonは2系になっているため、/usr/bin/pythonのパスを変更する際は注意しましょう。/usr/bin/pythonのパスをPython3に変更すると、yumが使えなくなるなどの弊害が発生します。よって、anbileで使用するPythonのバージョンを３系で使用したい場合は、サーバ側のPythonのバージョンも考慮する必要があります。
- sshポート変更時    
sshのポートをデフォルトから変更した場合は、Ansibleはansible.cfgを見にいくため、ansible.cfgの「remote_port」を変更すれば大丈夫です。その他の設定は不要です。
- ssh公開鍵認証時のパスフレーズ   
ssh公開鍵認証時のパスフレーズは、`ssh-agent`コマンドで起動し、`ssh-add`コマンドで登録することで、なんどもパスフレーズを聞かれるのを省略できます。
- Ansibleのモジュール    
Ansilbeは様々な拡張モジュールがあります。Ansibleで実現しようとしていることが、拡張モジュールでないか確認しましょう。拡張モジュールで事足りるのであれば、わざわざコマンドをたくさん書いたりして頑張る必要はありません。

### 課題
Ansibleは万能薬ではありません。
実際に使ってみると、かゆいところに手が届かなかったりします。

本記事執筆にあたり、悩んだ点は以下になります。

playbookからdocker-composeコマンドを実行し、正常にコンテナを起動できなかった場合は、エラーを出力したいと思いました。理由として、docker-composeコマンドはコンテナが起動できなくても、戻り値0を返してしまうことです。そのため、playbook内で`docker container ps -a`コマンドを実行し、コンテナの状態が「Exited」の場合、戻り値はエラーを出す様に設定しても、playbook上では正常終了してしまい、コンテナが起動できなかった場合の確認が入れられませんでした。

あとで、ansibleのdocker-composのモジュールがあることに気づいたのですが、モジュールが期待通りの動作をしなかったため、ツール実行後に確認する様にしました。

# おわりに
システムは作ったら終わりではありません。
それは、オンプレでもクラウドでも同じです。

"KAIZEN”という言葉は、トヨタの生産方式を象徴する言葉として広く世界で知られています。運用は改善することで、デプロイが楽になったり、少しの演出で違った見え方ができます。

Ansibleはスモールスタートで始めることができるので、スタートアップをはじめ大きいプロジェクトでも効果を発揮するでしょう。

（※）本記事で紹介しているデプロイツールは、[Git](https://github.com/Brutus03/Ansible-deploy-tool)で公開しています。