初めてAnsible

# Ansibleはサーバーの構成管理をする

- 導入手順
  1. インストール
  2. Ansibleの**Hosts**ファイルに、対象サーバーの ホスト名 (またはIPアドレス) を書く
  3. 作る構成を **Playbook**(YAML形式) に書き実行



<br>

- 前提
  - **ssh接続**可能
  - **Python2**インストール済 (普通されてる)



<br>
![Screen Shot 2018-05-11 at 23.49.37.png](https://qiita-image-store.s3.amazonaws.com/0/35156/17389b97-67f3-dea0-01f8-abe3c719e418.png)

<br>

具体的には

- nginx,apache,mysqlの導入(yumモジュール)
- AWSの各サービスの構成管理(AWS用モジュール)
- ファイル配布、テキスト置換(fileモジュール)

<br>

<br>

## 構成を作成し保持する

- **Playbookの**実行結果は、
  - 失敗して「**<font color="OrangeRed">fatal</font>**」
  - 変更した「**<font color="DarkKhaki">changed</font>**」
  - そのままで「**<font color="MediumSeaGreen">ok</font>**」

<br>

- 最初は「**<font color="DarkKhaki">changed</font>**」
- その後は何回流しても「**<font color="MediumSeaGreen">ok</font>**」にする

![Screen Shot 2018-05-12 at 0.30.37.png](https://qiita-image-store.s3.amazonaws.com/0/35156/dedecdb2-edfa-ab63-60bf-e67aaf5cfe8f.png)

<br>

### 理想

![Screen Shot 2018-05-12 at 0.35.28.png](https://qiita-image-store.s3.amazonaws.com/0/35156/b778183f-28b3-5982-7cee-2450f8e5d2c0.png)

<br>
<br>

### Command(shell)モジュールは病

- 指定したコマンドを実行する子
- 「**<font color="DarkKhaki">changed</font>**」または「**<font color="OrangeRed">fatal</font>**」**のみ**返却する
- いつも「**<font color="MediumSeaGreen">ok</font>**」と返すようにするための回避策もある (それこそ無意味)

```yaml
- name : "ruby check"
  command: "ruby --version"
  failed_when:  False  # 失敗(fatal)しても「ok」返す
  changed_when: False  # 変更(changed)しても「ok」返す


```





<br>
<br>

# Ansibleフォルダ構成

- 私のテスト環境
  - 実用していないため、まだプロトタイプです
  - これから良くなっていく予定 (別記事にするかも)

![folfol.png](https://qiita-image-store.s3.amazonaws.com/0/35156/6072a2e2-4027-359c-e5e4-682029b372cb.png)



<br>

- 基本は公式にある[ベストプラクティス](http://docs.ansible.com/ansible/latest/user_guide/playbooks_best_practices.html)にする
- [Ansible オレオレベストプラクティス](https://qiita.com/tags/Ansible)取り入れた

<br>
<br>

## ssh設定ファイルの作り方

- 参考＝＝[ansible.cnfでssh_configを設定する](https://dev.classmethod.jp/server-side/ansible/enable_ssh_conf_using_via_ansible-cnf/)

**test_project01開発環境(development)の例**

- ansible.cfg 

```yaml
[ssh_connection]
ssh_args = -F "{{ project_name }}/ssh_config_{{ project_env }}"
```

- test_project01/hosts_development

```yaml
[web]
web-01

[all:vars]
project_name="test_project01"
project_env="development"
```

- test_project01/ssh_config_development 

```yaml
Host web-01
  User tetsuya
  HostName 127.0.0.1
  IdentityFile ~/.ssh/id_rsa
  StrictHostKeyChecking no
  UserKnownHostsFile /dev/null
```

- test_project01/site.yml (Playbook)

```yaml
- hosts: web
  become: yes
  user: tetsuya
  vars_files:
    # role > common-vars > host_vars > group_vars の順に優先
    - ../common-vars/common-vars.yml
  roles:
    - name: ../common-roles/common
    - name: test-role

```

- 実行

```bash
# ansible.cfgのあるフォルダで実行する(test_project01の1つ上)
ansible-playbook -i test_project01/hosts_development test_project01/site.
yml -v
```

<br>
<br>

## 設定ファイル

- ansible.cfg 
  - 自分で作る
  - Ansible-playbook実行時、下記の順に読む
      1. カレント
      2. 環境変数：ANSIBLE_CONFIG
      3. ホームディレクトリ
      4. /etc/ansible/ansible.cfg



<br>
<br>

## 変数

- 使うフォルダと命名規則を先に決めとく
- 優先順
  1. 各Role
  2. common-vars
  3. host_vars
  4. group_vars

- 同一ファイル内の重複はAnsibleが見つけて、Playbook実行時に警告出してくれる
  - 別ファイルの場合は、問答無用で上書きする

```bash
 [WARNING]: While constructing a mapping from /Users/tetsuya/Yama/ansible/common-vars/common-vars.yml, line 1, column
1, found a duplicate dict key (message). Using last defined value only.
```



<br>
<br>
<br>

###  

# チュートリアル

- [Ansibleをはじめる人に](https://qiita.com/t_nakayama0714/items/fe55ee56d6446f67113c)
  - 即刻やれる
- [Ansible Tutorial](http://yteraoka.github.io/ansible-tutorial/)
  - serverspecも





<br>

## 私も



## インストール

- Vagrantfile

```ruby
  Vagrant.configure(2) do |config|
    config.vm.define "controller" do |node|
          node.vm.box = "centos7_x64"
          node.vm.hostname = "controller"
          node.vm.network :private_network, ip: "192.168.101.100"
          node.vm.network :forwarded_port, id: "ssh", guest: 22, host: 2210
    end
    config.vm.define "target" do |node|
          node.vm.box = "centos7_x64"
          node.vm.hostname = "target"
          node.vm.network :private_network, ip: "192.168.101.200"
          node.vm.network :forwarded_port, id: "ssh", guest: 80, host: 8000
          node.vm.network :forwarded_port, id: "ssh", guest: 22, host: 2220
    end
  end
```

<br>



```sh
# 前提
vagrant up

vagrant status # running

ssh -p 2210 root@127.0.0.1 # passwordは "vagrant"  vagrant sshも可

Python --version # Python 2.7.5


# インストール
yum install ansible

ansible --version # ansible 2.4.2.0

    # sudo su -  # root化(vagrant ssh)

umask  # 0022

mkdir -p /work/ansible/test1 # Ansibleフォルダ(プロジェクトtest1用)

cd /work/ansible/test1

echo 192.168.101.100 >hosts # hosts(Inventoryファイル)作成

echo 192.168.101.200 >hosts


# ssh設定
ssh-keygen -t rsa # 秘密鍵作成

ssh-copy-id root@192.168.101.100 # 自分(controller)に秘密鍵送信

ssh-copy-id root@192.168.101.200 # targetに


# 疎通
ansible -i hosts 192.168.101.100 -m ping # 自分(controller)にAnsibleからping送信

ansible -i hosts 192.168.101.200 -m ping # targetに

ansible -i hosts 192.168.101.* -m ping   # 両方に
    # ↑秘密鍵にパスワード指定している場合、1台ずつ入力待ちになって止まる


ansible -i hosts 192.168.101.200 -m yum -s -a name=telnet # yumでtelnetを入れる
    # ----> SUCCESSとなり、"changed": trueになる
    #       インストールされた

ansible -i hosts 192.168.101.200 -m yum -s -a name=telnet # 再度
    # ----> SUCCESSとなり、"changed": falseになる
    #       既にインストール済みの場合は何もしない

```

<br>

<br>

### 初Playbook

- hosts

```yaml
  [test-servers]
  192.168.101.100
  192.168.101.200
```

<br>

- Playbook  : simple-playbook.yml

```yaml
  ---
  - hosts: test-servers
    become: yes
    tasks:
      - name: be sure httpd is installed
        yum: name=httpd state=installed

      - name: be sure httpd is running and enabled
        service: name=httpd state=started enabled=yes
```

  become? [Ansible1.9からはsudo/suの代わりにbecomeを使う](https://qiita.com/imoyoukan/items/12832aecd956d14b03f5)

<br>
<br>

- 実行

```sh
ansible-playbook -i hosts simple-playbook.yml --syntax-check # syntaxチェックのみ

ansible-playbook -i hosts simple-playbook.yml --list-tasks # taskリスト参照のみ

ansible-playbook -i hosts simple-playbook.yml --check # dry-run

ansible-playbook -i hosts simple-playbook.yml # 実行(changed)

ansible-playbook -i hosts simple-playbook.yml # 実行(okに)

service httpd status  # runnning
```

<br>

- ホスト情報取る

```bash
ansible -m setup -i hosts 192.168.101.100 # 膨大なJSON
```



<br>

- Playbook修正1  : simple-playbook.yml 追記 ( # ADD )

```yaml
  ---
  - hosts: test-servers
    become: yes
    tasks:
      - name: be sure httpd is installed
        yum: name=httpd state=installed

      - name: be sure httpd is running and enabled
        service: name=httpd state=started enabled=yes

      - name: gathering data task example  ## ADD
        command: echo {{ ansible_enp0s8.ipv4.address }} ## ADD ホスト情報取る
```

<br>

- 実行

```sh
ansible-playbook -i hosts simple-playbook.yml # IPv4を取得する (changed)
```

<br>

<br>

- Playbook修正2  : simple-playbook.yml 追記 ( # ADD2 )

```yaml
  ---
  - hosts: test-servers
    become: yes
    tasks:
      - name: be sure httpd is installed
        yum: name=httpd state=installed

      - name: be sure httpd is running and enabled
        service: name=httpd state=started enabled=yes

      - name: gathering data task example  ## ADD
        command: echo {{ ansible_enp0s8.ipv4.address }} ## ADD ホスト情報取る
        failed_when:  False # ADD2      fatal(失敗)の時もokを返す
        changed_when: False # ADD2    changed(変更)の時も
```

<br>

- 実行

```sh
ansible-playbook -i hosts simple-playbook.yml  # IPv4を取得する (ok)
```

<br>

<br>

## 名前解決

1. hosts に名前書く
2. ssh_config に名前解決の設定する
3. ansible.cfg  で ssh_config を読む



- hosts

```yams
  [test-servers]
  # 192.168.101.100  --> controller
  controller
  192.168.101.200
```



- ssh_config

```yams
   Host controller
    User root
    HostName 192.168.101.100
    IdentityFile ~/.ssh/id_rsa
    StrictHostKeyChecking no
    UserKnownHostsFile /dev/null
```



- ansible.cfg

```yaml
  [ssh_connection]
  ssh_args = -F ssh_config
```



<br>
<br>

**同じフォルダに置く**

```sh
/work/ansible
|--test1
   |--ansible.cfg
   |--simple-playbook.yml
   |--ssh_config
   |--hosts

```

- [tree コマンドが無い環境で tree コマンドを実現](https://qiita.com/yone098@github/items/bba8a42de6b06e40983b)  \\(^o^)/



<br>
<br>

## Ansible-Vaultでパスワード秘匿

作成

```bash
ansible-vault create vault_test.yml
# New Vault password:xxxxxx
# Confirm New Vault password:xxxxxx
```

- vault_test.yml

```yaml
---
some_key: value1
other_key: value2
```

<br>

編集

```bash
ansible-vault edit vault_test.yml # 編集
# Vault password:xxxxx 
```

- vault_test.yml

```yaml
---
some_key: value1
other_key: value2
one_key: value3 # 追加
```

<br>

暗号化の確認

```bash
vim vault_test.yml
```

- vault_test.yml

```yaml
$ANSIBLE_VAULT;1.1;AES256
32366165373238636134313832373834626661613532353132373337366134336130643338626339
3362656161626232626434316237646331633933383337350a613361363339343533623936343837
32376362366231626134393763346165316636343863336431333565313530393563356562336335
6164356561666636330a626436363635633736666465333161666332396565346536653639303631
30326461623137643334326161666535613139393638333239313663306637643438376431303965
31633131383665326438653531623630663532663933386164396536653939313838613763643436
383039626137633535363634366364323062
```

<br>

平文ファイル作成

```bash
vim vault_test_2.yml # 平文ファイル作成
```

- vault_test_2.yml

```yaml
---
new_key: new_value
```

平文ファイル暗号化

```bash
ansible-vault encrypt vault_test_2.yml
# New Vault password:xxxxxx
# Confirm New Vault password:xxxxxx
```

<br>

復号

```bash
ansible-vault decrypt vault_test_2.yml
# Vault password:xxxxxx
# Decryption successful
```

<br>

復号確認

```bash
vim vault_test_2.yml
```

- vault_test_2.yml

```
---
new_key: new_value

```

<br>

上で暗号化したファイルをgroup変数フォルダに入れ、
定義した環境変数を、Playbookを実行した時に参照します

    - あくまで検証ですので、パスワード等の扱いは気をつけてください
    - git管理の場合は.gitignoreに書きましょう

<br>

- 準備

```bash

ls -la group_vars/test-servers/
# total 8
# drwxr-xr-x 2 root root  50 May 13 08:03 .
# drwxr-xr-x 3 root root  25 May 13 08:03 ..
# -rw------- 1 root root 549 May 13 07:36 vault_test.yml
# -rw------- 1 root root  23 May 13 07:51 vault_test_2.yml

vim vault-playbook.yml

```

- vault-playbook.yml

```yaml
---
- hosts: test-servers
  become: yes
  tasks:
    - name: vault-test
      command: echo {{ one_key }}
```



<br>



- **使う**

```bash
# その1 失敗
ansible-playbook -i hosts vault-playbook.yml

# PLAY [test-servers] ***************************************************************************************************************************
# ERROR! Attempting to decrypt but no vault secrets found



# その2 成功(value3) --ask-vault-pass を付ける 
ansible-playbook -i hosts vault-playbook.yml --ask-vault-pass  # 成功
# Vault password:xxxxxx



# その3 成功(value3)  vaultのパスワードをbuzword.txtに書いておき、 --vault-password-file を付ける

ansible-playbook -i hosts vault-playbook.yml --vault-password-file buzword.txt




```





<br>

<br>

## sudoするときのパスワード秘匿

わかりづらくてすいません
ほぼ作業ログです

### 準備

対象サーバー

```bash
## sudo用ユーザー作成
useradd testansible # testansibleユーザー追加


grep testansible /etc/passwd # 確認
# testansible:x:1001:1001::/home/testansible:/bin/bash


passwd testansible # パスワード設定 パスワード:test


visudo # wheelグループのユーザーはパスワード付きでsudoできること確認
       # --> %wheel  ALL=(ALL)       ALL


usermod -G wheel testansible # wheelグループに所属させる


su - testansible # testansibleログイン


sudo echo test # sudoしてみる　パスワード聞かれる
# test


```

Ansibleサーバー

```bash
# ssh秘密鍵コピー
ssh-copy-id testansible@192.168.101.100


# 変数ファイル編集
ansible-vault edit group_vars/test-servers/vault_test.yml

```

- group_vars/test-servers/vault_test.yml

```yaml
---
some_key: value1
other_key: value2
one_key: value3
ansible_ssh_user: testansible  # sshユーザー名 (vaultで暗号化)
ansible_sudo_pass: test # sshユーザーのパスワード (vaultで暗号化)
```

- vault-playbook.yml

```yaml
---
- hosts: test-servers
  become: yes
  tasks:
    - name: vault-test
      command: echo {{ one_key }}
    - name: ssh_user_test
      command: whoami
```

- buzword.txt

```yaml
pass
```

<br>


### 実行1 

Ansibleサーバー

```bash
ansible-playbook -i hosts vault-playbook.yml --vault-password-file buzword.txt -vv # 実行

# one_key 取れてて,
# whoami は root になる

```

### 実行2 

- vault-playbook.yml

```yaml
---
- hosts: test-servers
  become: # yes    <--コメントアウトしてみる
  tasks:
    - name: vault-test
      command: echo {{ one_key }}
    - name: ssh_user_test
      command: whoami
```

```bash
ansible-playbook -i hosts vault-playbook.yml --vault-password-file buzword.txt -vv # 実行

# one_key 取れてて,
# whoami は testansible になる

```





<br>
<br>

## Role

- RoleがAnsible-GALAXYにある
- 検証中です

<br>
<br>

## Playbook各モジュール

- 検証中です
- 長くなったので別記事にします



<br>

<br>



# Serverspec

- Serverspec はテストツール
  - Ansibleと違ってchangeしない
  - テストだけする時使う

```bash
# インストール
ruby --version # ruby 2.0.0p598 (2014-11-13) [x86_64-linux]

gem list # serverspec なし

gem install serverspec

gem install rake

rake --version # rake, version 12.3.1

rspec --version # RSpec 3.7

gem list # serverspec 2.41.3


# 初期設定
serverspec-init # localhost / SSH

```

- spec/controller/httpd_spec.rb

```ruby
require 'spec_helper'

describe package('httpd') do
  it { should be_installed }
end

describe service('httpd') do
  it { should be_enabled   }
  it { should be_running   }
end

describe port(80) do
  it { should be_listening }
end

describe file('/etc/httpd/conf/httpd.conf') do
  it { should be_file }
  its(:content) { should match /ServerName www.example.com:80/ }
end
```

- 実行

```bash
rake # spec/ホスト名/\*_spec.rb を実行する
```



<br>
<br>



## ansible_spec (gem)

- Serverspecと統合する(どこかで記載予定)



<br>
<br>