Ansible Playbook検証環境構築 (MAC + KitchenCI + Docker)

#目的
[Ansible Playbook検証環境構築 (2019版)](https://qiita.com/drafts/b3a19d41cc640e6146d6/edit)では、ローカルに色々導入したので、ローカルにあまり多くを導入しない様に内容を更新した。
ansible controllerもdockerコンテナとし、検証環境もdockerとしてKitchenCIを回す

[Windows10環境に関してはこちら](https://qiita.com/hiroyuki_onodera/items/7416a3a1330f5f5af0ae)

#環境

MAC

- macOS 10.14.6


#ローカルに以下を導入

MAC:

- docker desktop (2.1.0.3)
- Chef Workstation (0.3.2)
https://downloads.chef.io/chef-workstation/


#環境変数設定

MAC:

```
$ echo 'eval "$(chef shell-init bash)"' >> ~/.bash_profile
$ . ~/.bash_profile
```


#ローカルに導入するgem

- kitchen-ansible (0.50.0)
- kitchen-docker (2.9.0)

```
$ gem install kitchen-ansible
$ gem install kitchen-docker
```


#環境構築

ansible controllerもkitchenCIで導入する
(なお、DockerFileでも可能と思える)


```
$ mkdir ansible_controller
$ cd ansible_controller
$ vi kitchen.yml
...
$ vi site.yml
...
```


```yaml:kitchen.yml
---
driver:
  name: docker
  run_options: -v /var/run/docker.sock:/var/run/docker.sock -v /usr/local/bin/docker:/bin/docker

provisioner:
  name: ansible_playbook
  chef_bootstrap_url: false
  hosts: ansible-controller
  playbook: site.yml

platforms:
- name: centos-7

suites:
- name: ansible-controller
```
- /var/run/docker.sockを共有することで、dockerコンテナからdockerの操作を可能とする。
    - この場合、コンテナで制御を奪われるとベースOSも制御を奪われるので要注意
- kitchen-ansible は対象にansibleを導入し、ローカルモードで実行する。
    - この導入されたansibleをそのまま利用する。
- \-v を追加し、ローカルのansible repoをansible controllerコンテナと共有させることも可能

- centos-7を対象としている。ubuntu-16.04 とした場合、幾つか修正が必要となる可能性がある。


```yaml:site.yml
---
- hosts: all
  gather_facts: false
  tasks:

  - name: install the chef-workstation rpm from a remote repo
    yum:
      name: https://packages.chef.io/files/stable/chef-workstation/0.11.21/el/7/chef-workstation-0.11.21-1.el7.x86_64.rpm

  - name: add 'eval "$(chef shell-init bash)"' to ~/.bash_profile
    lineinfile:
      dest: ~kitchen/.bash_profile
      line: eval "$(chef shell-init bash)"
    become: true
    become_user: kitchen

  - name: gem install
    shell: |
      set -e
      eval "$(chef shell-init bash)"
      gem install kitchen-ansiblepush
      gem install kitchen-docker
    become: true
    become_user: kitchen

```


#ansible controllerのdockerコンテナ起動、作成
```
$ kitchen test -d never
-----> Starting Kitchen (v1.25.0)
-----> Cleaning up any prior instances of <ansible-controller-centos-7>

...

       PLAY [all] *********************************************************************
       
       TASK [install the chef-workstation rpm from a remote repo] *********************
       ok: [localhost]
       
       TASK [add 'eval "$(chef shell-init bash)"' to ~/.bash_profile] *****************
       changed: [localhost]
       
       TASK [gem install] *************************************************************
       changed: [localhost]
       
       PLAY RECAP *********************************************************************
       localhost                  : ok=3    changed=2    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
       
       Downloading files from <ansible-controller-centos-7>
       Finished converging <ansible-controller-centos-7> (5m22.82s).
-----> Setting up <ansible-controller-centos-7>...
       Finished setting up <ansible-controller-centos-7> (0m0.00s).
-----> Verifying <ansible-controller-centos-7>...
       Preparing files for transfer
       Transferring files to <ansible-controller-centos-7>
       Finished verifying <ansible-controller-centos-7> (0m0.00s).
       Finished testing <ansible-controller-centos-7> (5m28.24s).
-----> Kitchen is finished. (5m29.68s)
```

これでansible controllerコンテナが起動する。
削除は、kitchen destroyで可能。
kitchenコマンドからdocker stopやstartなど細かい操作は出来ないので、必要があればdockerコマンドを使用。

#ansible controllerにログインして利用

```
$ kitchen login
Last login: Wed Oct 23 07:44:58 2019 from 172.17.0.1

[kitchen@7b012ce1d2a9 ~]$ id
uid=1000(kitchen) gid=1000(kitchen) groups=1000(kitchen)

[kitchen@7b012ce1d2a9 ~]$ pwd
/home/kitchen

[kitchen@7b012ce1d2a9 ~]$ ansible --version
ansible 2.8.5
  config file = /etc/ansible/ansible.cfg
  configured module search path = [u'/home/kitchen/.ansible/plugins/modules', u'/usr/share/ansible/plugins/modules']
  ansible python module location = /usr/lib/python2.7/site-packages/ansible
  executable location = /usr/bin/ansible
  python version = 2.7.5 (default, Oct 30 2018, 23:45:53) [GCC 4.8.5 20150623 (Red Hat 4.8.5-36)]

[kitchen@7b012ce1d2a9 ~]$ kitchen --version
Test Kitchen version 2.3.3

[kitchen@7b012ce1d2a9 ~]$ gem list | grep kitchen
kitchen-ansiblepush (0.10.1)
kitchen-azurerm (0.14.9)
kitchen-digitalocean (0.10.4)
kitchen-docker (2.9.0)
kitchen-dokken (2.7.0)
kitchen-ec2 (3.2.0)
kitchen-google (2.0.1)
kitchen-hyperv (0.5.3)
kitchen-inspec (1.2.0)
kitchen-vagrant (1.6.0)
kitchen-vcenter (2.5.2)
test-kitchen (2.3.3)

[kitchen@7b012ce1d2a9 ~]$ mkdir roles                

[kitchen@7b012ce1d2a9 ~]$ cd roles/

[kitchen@7b012ce1d2a9 roles]$ ansible-galaxy init role01 
- role01 was created successfully

[kitchen@7b012ce1d2a9 roles]$ cd role01/

[kitchen@7b012ce1d2a9 role01]$ vi kitchen.yml
...

[kitchen@7b012ce1d2a9 role01]$ vi site.yml
...

[kitchen@7b012ce1d2a9 role01]$ vi tasks/main.yml
...

# 以下はInSpecの設定
[kitchen@7b012ce1d2a9 role01]$ mkdir -p test/integration/default

[kitchen@7b012ce1d2a9 role01]$ vi test/integration/default/default_test.rb
...


```

#KitchenCI設定
```yaml:kitchen.yml
---
driver:
  name: docker
  use_sudo: true
  use_internal_docker_network: true

provisioner:
  name: ansible_push
  chef_bootstrap_url: nil

platforms:
- name: centos-7

suites:
- name: ansiblepush
  provisioner:
    playbook: ./site.yml

verifier:
  name: inspec
  inspec_tests:
  - test/integration/default
```
kitchen-dockerとkitchen-ansiblepushを使用。
kitchen-ansiblepushは、ターゲットにansibleを導入せずにcontrollerのansibleを使用する。

##プレイブック (site.yml)
```yaml:site.yml

---
- hosts: all
  #gather_facts: false
  become: true
  tasks:
    - name: include_role 
      include_role:
        name: "../{{ lookup('env', 'PWD') | basename }}"
```

ここではテスト実行時のカレントディレクトリーをロール名としてincludeしている。


##ロールのtasks (tasks/main.yml)
```yaml:tasks/main.yml 
---
- debug:
    msg: hello world!
```

##InSpecテスト
```ruby:test/integration/default/default_test.rb
# # encoding: utf-8

# This is an example test, replace it with your own test.
describe port(80) do
  it { should_not be_listening }
end
```


#テスト実施 (kitchen test -d never)
```
[kitchen@7b012ce1d2a9 role01]$ kitchen test -d never 
-----> Starting Kitchen (v2.3.3)
-----> Cleaning up any prior instances of <ansiblepush-centos-7>
-----> Destroying <ansiblepush-centos-7>...
       Finished destroying <ansiblepush-centos-7> (0m0.00s).
-----> Testing <ansiblepush-centos-7>
-----> Creating <ansiblepush-centos-7>...
...

PLAY [all] *********************************************************************************************************************

TASK [Gathering Facts] *********************************************************************************************************
ok: [centos-7]

TASK [include_role] ************************************************************************************************************

TASK [../role01 : debug] *******************************************************************************************************
ok: [centos-7] => {
    "msg": "hello world!"
}

PLAY RECAP *********************************************************************************************************************
centos-7                   : ok=2    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   

       *************** AnsiblePush end run *******************
       Downloading files from <ansiblepush-centos-7>
       Finished converging <ansiblepush-centos-7> (0m6.98s).
-----> Setting up <ansiblepush-centos-7>...
       Finished setting up <ansiblepush-centos-7> (0m0.00s).
-----> Verifying <ansiblepush-centos-7>...
       Loaded tests from {:path=>".home.kitchen.roles.role01.test.integration.default"} 

Profile: tests from {:path=>"/home/kitchen/roles/role01/test/integration/default"} (tests from {:path=>".home.kitchen.roles.role01.test.integration.default"})
Version: (not specified)
Target:  ssh://kitchen@172.17.0.3:22

  Port 80
     ✔  should not be listening

Test Summary: 1 successful, 0 failures, 0 skipped
       Finished verifying <ansiblepush-centos-7> (0m1.13s).
       Finished testing <ansiblepush-centos-7> (0m9.58s).
-----> Kitchen is finished. (0m13.83s)
```
ターゲットとなる別のdockerコンテナを立ち上げ、playbook適用、およびInSpecテスト実施



#kitchen list, login, destroy
```
[kitchen@7b012ce1d2a9 role01]$ kitchen list 
Instance              Driver  Provisioner  Verifier  Transport  Last Action  Last Error
ansiblepush-centos-7  Docker  AnsiblePush  Inspec    Ssh        Verified     <None>

[kitchen@7b012ce1d2a9 role01]$ kitchen login
Last login: Wed Oct 23 08:23:19 2019 from 172.17.0.2
[kitchen@b72f869eae28 ~]$ id
uid=1000(kitchen) gid=1000(kitchen) groups=1000(kitchen)
[kitchen@b72f869eae28 ~]$ ls
[kitchen@b72f869eae28 ~]$ logout
Connection to 172.17.0.3 closed.

[kitchen@7b012ce1d2a9 role01]$ kitchen destroy
-----> Starting Kitchen (v2.3.3)
-----> Destroying <ansiblepush-centos-7>...
       PID                 USER                TIME                COMMAND
       72332               root                0:00                /usr/sbin/sshd -D -o UseDNS=no -o UsePAM=no -o PasswordAuthentication=yes -o UsePrivilegeSeparation=no -o PidFile=/tmp/sshd.pid
       b72f869eae282ebcdff9c1a20a03b85e94bd1aa709e8e750202f5265ef7c81d4
       b72f869eae282ebcdff9c1a20a03b85e94bd1aa709e8e750202f5265ef7c81d4
       Finished destroying <ansiblepush-centos-7> (0m0.84s).
-----> Kitchen is finished. (0m5.17s)

[kitchen@7b012ce1d2a9 role01]$ kitchen list
Instance              Driver  Provisioner  Verifier  Transport  Last Action    Last Error
ansiblepush-centos-7  Docker  AnsiblePush  Inspec    Ssh        <Not Created>  <None>

```