楽するためにAnsibleで一括実行しよう

## はじめに
私: 4つのVMで同じコマンドを打つのがめんどいんだけど一括でできる？
ChatGPT: はい、できます。複数のVMに同じコマンドを一括で実行するには、Ansibleなどのツールを使うと便利です。

以下はChatGPTの出力と自分が躓いたところをまとめた備忘録＆初心者輪講教材です。

初心者ゆえお手柔らかにお願いいたします。

## 環境
Rocky Linux release 8.9 (Green Obsidian)内にインストールしたRocky Linux release 9.4 (Blue Onyx)のLinuxVMで実験を行っています。

## 手順
1. **Ansibleのインストール**:
   ```bash
   sudo dnf install ansible -y
   ```

   not foundの場合、epel-releaseを有効にしてください。
   ```bash
   sudo dnf install epel-release
   ```


2. **インベントリファイルの作成**:
   Ansibleが管理するVMのリストを定義する。
    `/etc/ansible/hosts`に以下の内容を追加する。
    ansible_userはそれぞれ適切なものに変更すること。`ssh ここの部分@172.16.1.1`
   ```
   [myvms]
    vm1 ansible_host=172.16.1.1 ansible_user=admin
    vm2 ansible_host=172.16.1.2 ansible_user=admin
    vm3 ansible_host=172.16.1.3 ansible_user=admin
    vm4 ansible_host=172.16.1.4 ansible_user=admin
   ```

3. **Playbookの作成**:
   実行したいコマンドを定義したYAMLファイルを作成する。例えば、`myplaybook.yml`というファイルを作成し、以下の内容を記載する。
   YAML（YAML Ain't Markup Language）（.yml or .yaml）：異なるソフトウェア間のデータ交換で使うファイル。要するにプログラムが読み取りやすい言語。
 
   ```yaml
   - hosts: myvms
     tasks:
       - name: say ho
         command: echo "ho"
   ```
     YAMLの定義にYAMLが出てきてるから変な感じ。

4. **Playbookの実行**:
   Ansible Playbookを実行して、コマンドをすべてのVMに適用する。
   ```bash
   ansible-playbook myplaybook.yml
   ```
    標準出力を見たいならこう。
   ```bash
   ansible-playbook myplaybook.yml　-v
   ```
    こうなれば成功。
   ```
    PLAY [myvms] ************************************************************************************************************************************************
    
    TASK [Gathering Facts] **************************************************************************************************************************************
    ok: [vm2]
    ok: [vm1]
    ok: [vm3]
    ok: [vm4]
    
    TASK [say ho] ***********************************************************************************************************************************************
    changed: [vm2] => {"changed": true, "cmd": ["echo", "ho"], "delta": "0:00:00.002864", "end": "2024-05-19 01:19:05.400496", "msg": "", "rc": 0, "start": "2024-05-19 01:19:05.397632", "stderr": "", "stderr_lines": [], "stdout": "ho", "stdout_lines": ["ho"]}
    changed: [vm1] => {"changed": true, "cmd": ["echo", "ho"], "delta": "0:00:00.003441", "end": "2024-05-19 01:19:05.398650", "msg": "", "rc": 0, "start": "2024-05-19 01:19:05.395209", "stderr": "", "stderr_lines": [], "stdout": "ho", "stdout_lines": ["ho"]}
    changed: [vm4] => {"changed": true, "cmd": ["echo", "ho"], "delta": "0:00:00.002860", "end": "2024-05-19 01:19:05.401005", "msg": "", "rc": 0, "start": "2024-05-19 01:19:05.398145", "stderr": "", "stderr_lines": [], "stdout": "ho", "stdout_lines": ["ho"]}
    changed: [vm3] => {"changed": true, "cmd": ["echo", "ho"], "delta": "0:00:00.002873", "end": "2024-05-19 01:19:05.406218", "msg": "", "rc": 0, "start": "2024-05-19 01:19:05.403345", "stderr": "", "stderr_lines": [], "stdout": "ho", "stdout_lines": ["ho"]}
    
    PLAY RECAP **************************************************************************************************************************************************
    vm1                        : ok=2    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0
    vm2                        : ok=2    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0
    vm3                        : ok=2    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0
    vm4                        : ok=2    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0
   ```

   ansibleを使いこなせば、VMにssh接続して実行、別のVMに接続して実行、、、なんてしなくてよくなりますね！
## 発展系（やりたかったこと）
ymlを極めればOpenMPIをインストールしてパスを通してファイルを配って、、全部できるはずです。(以下は	ChatGPT4oが生成、責任はおいかねます。)


```bash
- name: Install OpenMPI and run MPI program
  hosts: myvms
  become: yes
  tasks:
    - name: Install development tools
      yum:
        name: "@Development Tools"
        state: present

    - name: Install EPEL repository
      yum:
        name: epel-release
        state: present

    - name: Install OpenMPI
      yum:
        name:
          - openmpi
          - openmpi-devel
        state: present

    - name: Ensure /usr/lib64/openmpi/bin is in PATH
      lineinfile:
        path: /etc/profile.d/openmpi.sh
        line: 'export PATH=$PATH:/usr/lib64/openmpi/bin'
        create: yes

    - name: Source /etc/profile.d/openmpi.sh
      shell: source /etc/profile.d/openmpi.sh
      args:
        executable: /bin/bash

    - name: Create directory for MPI program
      file:
        path: /home/{{ ansible_user }}/mpi_program
        state: directory
        mode: '0755'
        owner: "{{ ansible_user }}"
        group: "{{ ansible_user }}"

    - name: Copy MPI program to nodes
      copy:
        src: mpi_program.c
        dest: /home/{{ ansible_user }}/mpi_program/mpi_program.c
        owner: "{{ ansible_user }}"
        group: "{{ ansible_user }}"
        mode: '0644'

    - name: Create MPI hostfile
      copy:
        content: |
          vm1 slots=1
          vm2 slots=1
          vm3 slots=1
          vm4 slots=1
        dest: /home/{{ ansible_user }}/mpi_program/hostfile
        owner: "{{ ansible_user }}"
        group: "{{ ansible_user }}"
        mode: '0644'

    - name: Compile MPI program
      shell: mpicc -o /home/{{ ansible_user }}/mpi_program/mpi_program /home/{{ ansible_user }}/mpi_program/mpi_program.c
      args:
        chdir: /home/{{ ansible_user }}/mpi_program
      environment:
        PATH: "{{ ansible_env.PATH }}:/usr/lib64/openmpi/bin"
```
    

## 引っ掛かりポイント
### ansible-playbookの結果、unreachable=1になる
各環境に公開鍵認証でssh接続できるのが前提となります。
鍵生成→鍵を渡す→各VMのsshd.confingを変更してパスワード認証をnoにする
この辺りの手順はやってください。

何故かうまくいかない、そんなときは鍵を作り直したらうまくいったりします。他のホストとの公開鍵認証がない今回は許されます。