AnsibleのPlaybook CIをGitLabを使ってVMwareのVMインスタンスでやってみる

ここでは、AnsibleのPlaybook CIをするのにコンテナを使わずにVMwareのVMインスタンスで実行してみようと思います。

# 環境

|      項目      | バージョン |
|----------------|------------|
| Ansible        | 2.8.1      |
| GitLab         | 11.11.0-ce |
| VMware vCenter | 6.7.0      |
| VMware ESXi    | 6.7.0      |

# CIの流れ

* GitLabにローカルリポジトリをPush
* GitLab CIで起動したコンテナからvCenterに対してCI用のVMインスタンスを作成(クローン)するPlaybookを実行
* 動作テストをしたいPlaybookを実行
* CI用のVMインスタンスが起動したらSSHで接続してテストするPlaybookを実行
* Playbook実行終了後にCI用に作成したVMインスタンスを削除

ちなみに、ここではCI用のVMインスタンスはDHCPでIPを取得しています。

# 使用するPlaybook

## 構造

リポジトリの構造は以下のようになっています。

```
.
├── .gitlab-ci.yml
├── ci
│   ├── operation_ci_vm.yml
│   ├── playbook_ci.yml
│   └── vars
│       └── main.yml
└── main.yml
```

## ファイル説明

### operation_ci_vm.yml

CI用のVMインスタンスを作成したり削除するPlaybookです。

```yaml
---
- name: Operation of VM for CI
  hosts: localhost
  gather_facts: no
  vars_files:
    - vars/main.yml
  tasks:
    - name: Operation the virtual machine for CI.
      vmware_guest:
        hostname: "{{ vcenter }}"
        username: "{{ username }}"
        password: "{{ password }}"
        validate_certs: no
        datacenter: "{{ datacenter }}"
        name: "{{ vm_name }}"
        template: "{{ template }}"
        folder: "{{ datacenter }}/vm"
        state: "{{ item }}"
      loop: "{{ state }}"
```

### playbook_ci.yml

CI用 VMインスタンスの起動を待ち、起動後にVMware Tools経由でIPを取得し `add_host` でインベントリに追加するPlaybookです。
VMインスタンスが起動したらテストをしたいPlaybookを読み込んで実行します。

```yaml
---
- name: Add host for CI to inventory
  hosts: localhost
  gather_facts: no
  vars_files:
    - vars/main.yml
  tasks:
    - name: Wait for VMware tools.
      vmware_guest_tools_wait:
        hostname: "{{ vcenter }}"
        username: "{{ username }}"
        password: "{{ password }}"
        validate_certs: no
        name: "{{ vm_name }}"

    - name: Gather facts from vm.
      vmware_guest_facts:
        hostname: "{{ vcenter }}"
        username: "{{ username }}"
        password: "{{ password }}"
        validate_certs: no
        datacenter: "{{ datacenter }}"
        name: "{{ vm_name }}"
      register: gather_facts_from_vm_result
      retries: 60
      delay: 5
      until: gather_facts_from_vm_result.instance.ipv4 is not none

    - name: Add ci host.
      add_host:
        hostname: "{{ vm_name }}"
        ansible_host: "{{ gather_facts_from_vm_result.instance.ipv4 }}"
        ansible_user: root
        ansible_password: secret
        groups:
          - all

- name: Playbook test
  import_playbook: "{{ test_playbook_path }}"
```

### vars/main.yml

CI用のVMインスタンスを作成するための変数をまとめたファイルです。

```yaml
---
vcenter: 192.168.0.111
username: administrator@vsphere.local
password: secret
datacenter: DC
vm_name: CentOS7-CI
template: CentOS7_TMP
```

|    変数    |                           説明                           |
|------------|----------------------------------------------------------|
| vcenter    | vCenterのIPまたはホスト名を指定します                    |
| username   | vCenterへログインするユーザー名を指定します              |
| password   | vCenterへログインするパスワードを指定します              |
| datacenter | CI用のVMインスタンスを作成するデータセンターを指定します |
| vm_name    | 作成するVM名を指定します                                 |
| template   | クローン元のVMを指定します                               |

### main.yml

ここでは、テストでApacheをインストールして起動するPlaybookを作ってみました。
これがVMインスタンスで実行されるPlaybookです。

```yaml
---
- name: test playbook
  hosts: all
  gather_facts: no
  tasks:
    - name: install apache.
      yum:
        name: httpd
        state: present

    - name: start apache.
      systemd:
        name: httpd
        state: started
```

### gitlab-ci.yml

GitLab CIのファイルは以下のように作成しました。

```yaml
---
image: centos:7
stages:
  - test

variables:
  ANSIBLE_HOST_KEY_CHECKING: "False"

before_script:
  - yum -y install openssh-clients sshpass epel-release
  - yum -y install python2-pip
  - pip install ansible requests pyvmomi
  - "ansible-playbook ci/operation_ci_vm.yml -e \"{'state': ['poweredon']}\""

after_script:
  - "ansible-playbook ci/operation_ci_vm.yml -e \"{'state': ['poweredoff', 'absent']}\""

playbook_test:
  stage: test
  script:
    - "ansible-playbook ci/playbook_ci.yml -e \"{'test_playbook_path': '../main.yml'}\""
```

[GitLab CI/CD Pipeline Configuration Reference](https://docs.gitlab.com/ce/ci/yaml/)

# CI実行

CIを実行すると以下のようになります。

[![スクリーンショット 2019-06-26 22.44.48.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/180118/70612054-43aa-2cfb-293a-1ec73ea056db.png)](https://vimeo.com/344577633)

これで、VMインスタンスを使ったPlaybookのCIができました :)