【Rundeck】RundeckからAnsibleを実行すると思ったより捗りそうだった話

# はじめに
なにかにささやかれてしまった結果抗えなかった。

# Ansible
### nginxのAnsible
先日チューニングしていたnginxの[Ansible](https://github.com/vildi-5567/Ansible/tree/main/nginx)を作った。

記事にしてなかったが現在すごく雑にawscliでインスタンスを立てるJobをランチャーとして使っている。
もう少しリッチにしたいのだが方向性が決まっていない為、ホスト管理の方法が絶賛迷走中。
よって巷ではあまりみない[IPアドレス],というホスト指定で実行するPlaybookとなった。

<details><summary>インスタンス作成</summary><div>
- defaultTab: nodes
  description: EC2のインスタンスを作成します。
  executionEnabled: true
  id: 5ff10465-99ec-4e76-9458-72925c447eef
  loglevel: INFO
  name: インスタンス作成
  nodeFilterEditable: false
  nodefilters:
    dispatch:
      excludePrecedence: true
      keepgoing: false
      rankOrder: ascending
      successOnEmptyNodeFilter: false
      threadcount: '1'
    filter: 'name: Rundeck'
  nodesSelectedByDefault: true
  options:
  - description: サーバ名を入力してください。
    name: name
    required: true
  - description: AMIイメージのIDを入力してください。(デフォルト：CentOS8)
    name: AMIID
    required: true
    value: ami-00f65b9dfc6773444
  - description: 台数を指定してください。(デフォルト1台)
    label: 台数
    name: count
    required: true
    value: '1'
  - description: インスタンスタイプを指定してください。(デフォルト:t3.micro)
    label: インスタンスタイプ
    name: instancetype
    required: true
    value: t3.micro
  - description: 私用するキーペア名を指定してください。(デフォルト:aws-1)
    name: keyname
    required: true
    value: aws-1
  - description: セキュリティグループを指定してください。(デフォルト:sg-03179fefab86413aa)
    name: securitygroup
    required: true
    value: sg-03179fefab86413aa
  - description: サブネットIDを指定してください。(デフォルト:subnet-095c2be997f1ffc36)
    name: subnetid
    required: true
    value: subnet-095c2be997f1ffc36
  plugins:
    ExecutionLifecycle: null
  scheduleEnabled: true
  sequence:
    commands:
    - exec: 'aws ec2 run-instances --image-id ${option.AMIID}  --count ${option.count}
        --instance-type ${option.instancetype} --key-name ${option.keyname} --security-group-ids
        ${option.securitygroup} --subnet-id ${option.subnetid} --tag-specifications
        ''ResourceType=instance,Tags=[{Key=Name,Value=${option.name}}]'''
    keepgoing: false
    strategy: node-first
  uuid: 5ff10465-99ec-4e76-9458-72925c447eef
</div></details>



実行するともちろん通る

```ruby:ansible-nginx
$ ansible-playbook -i 192.168.0.98, -u centos site.yml
[DEPRECATION WARNING]: Ansible will require Python 3.8 or newer on the controller starting with Ansible 2.12. Current version: 3.6.8
(default, Apr 16 2020, 01:36:27) [GCC 8.3.1 20191121 (Red Hat 8.3.1-5)]. This feature will be removed from ansible-core in version 2.12.
Deprecation warnings can be disabled by setting deprecation_warnings=False in ansible.cfg.

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

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

TASK [nginx : modify ulimit open files] ******************************************************************************************************
changed: [192.168.0.98]

TASK [nginx : modify sysctl net.ipv4.ip_local_port_range] ************************************************************************************
ok: [192.168.0.98]

TASK [nginx : modify sysctl fs.file-max] *****************************************************************************************************
ok: [192.168.0.98]

TASK [nginx : install nginx repository for centos6] ******************************************************************************************
skipping: [192.168.0.98]

TASK [nginx : install nginx repository for centos7] ******************************************************************************************
skipping: [192.168.0.98]

TASK [nginx : install nginx packages] ********************************************************************************************************
ok: [192.168.0.98]

TASK [nginx : copy nginx.conf] ***************************************************************************************************************
changed: [192.168.0.98]

TASK [nginx : copy server.crt] ***************************************************************************************************************
changed: [192.168.0.98]

TASK [nginx : copy server.key] ***************************************************************************************************************
changed: [192.168.0.98]

TASK [nginx : enable and start nginx related service] ****************************************************************************************
changed: [192.168.0.98]

PLAY RECAP ***********************************************************************************************************************************
192.168.0.98               : ok=9    changed=5    unreachable=0    failed=0    skipped=2    rescued=0    ignored=0
```

# RundeckからAnsibleを実行する
### Rundeck with Ansible
で、これをRundeckから実行してみようという話。
予めRundeckのサーバに`git clone`している想定。
ワークフローステップのほうの`Ansible playbook`を選択して以下のようにする。

- ansibleやplaybookのパスに関してはそれぞれ適正なものを記載する。
- コマンドラインオプションは全部`Extra Ansible arguments`に入れる。
- sshのユーザがデフォルトだと`rundeck`なので使ってるユーザが違う場合は注意。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1092362/553c378d-6524-a74c-e01a-9eaae6ee3ccb.png)

で、実行してみると普通にansibleが通る。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1092362/7b1f1e2c-efc4-9c4a-4a62-05cd8a75325a.png)

ワークフローステップの場合は本当にRundeck上でAnsible-playbookを実行するだけ。
ホストも指定したinbentoryファイルしか見ないのでRundeck的にはノード設定も不要。
(ただダミーとしてノードの指定は必要)
あとほかのansibleステップでも言えるがJob側でbecomeを設定できるのでplayboookに記載しなくてもいいのはメリット。
平時は普通にやってるとはいえsudo考えながらplaybook書くのってなんだかんだしんどいので。
この場合、正直RundeckはUIしか提供してないまである感じ。わかりやすいかも。

### 一旦完成
テストとしてはここまででよかったがせっかくAnsibleを流すなら`git pull`もセットでやってほしいのでこうなった。
`ansible-playbook`の実行前に`local script`でgit pullしているだけ。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1092362/c368aaa5-bca9-f5ed-0cd3-df5665529a39.png)

<details><summary>ansible-playbook(ワークフローステップ)</summary><div>
- defaultTab: nodes
  description: ansible-playbookをワークフローステップで実行するサンプルジョブ。
  executionEnabled: true
  id: f977bc3a-df86-4edc-9061-ec3893b04942
  loglevel: INFO
  name: ansible-playboook(ワークフローステップ)
  nodeFilterEditable: false
  nodefilters:
    dispatch:
      excludePrecedence: true
      keepgoing: false
      rankOrder: ascending
      successOnEmptyNodeFilter: false
      threadcount: '1'
    filter: 'name: Rundeck'
  nodesSelectedByDefault: true
  plugins:
    ExecutionLifecycle: null
  scheduleEnabled: true
  sequence:
    commands:
    - configuration:
        script: cd Ansible/;git pull
      description: ソースを最新の状態に更新します。
      nodeStep: false
      type: nixy-local-workflow-step
    - configuration:
        ansible-base-dir-path: ./Ansible/nginx
        ansible-become: 'false'
        ansible-disable-limit: 'false'
        ansible-extra-param: -i hosts --diff --limit production
        ansible-playbook: site.yml
        ansible-ssh-auth-type: privateKey
        ansible-ssh-passphrase-option: option.password
        ansible-ssh-use-agent: 'false'
        ansible-ssh-user: centos
      description: ngnxをインストールします。
      nodeStep: false
      type: com.batix.rundeck.plugins.AnsiblePlaybookWorkflowStep
    keepgoing: false
    strategy: node-first
  uuid: f977bc3a-df86-4edc-9061-ec3893b04942
</div></details>

本当はディレクトリ見て無ければ`git clone`するスクリプト書くつもりだったがやめた。
よくよく考えるとJobが出来ている時点でcloneされているはずなので多分仕組みとしては外だしされるはずと考えたため。
多分フランクに考えて以下のようなJobが任意に実行できればよいのではないかと思う。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1092362/8d71e006-db3d-eb46-a251-27878d46fd99.png)
※ちなみにこのJobはcloneしても動かないので注意。(ユーザ名入れてください)

# 番外編
### ノードフローステップ

実は昔から私がRundeckに抱えている疑念というか疑問がある。
以下のような対象が広範囲でかつノードを選んで実行しないとJobがあるとする。(実際はもっとノード数が多いイメージ)
これを実運用で回していると押し間違えなどが発生するであろうことは想像に難くない。
そういったオペミスをどうやって防げばいいのか疑問だった。
まぁノード対象絞れっていう話なのだが実環境って「そうはならんやろ」が割と起きるので。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1092362/6ce0f9b0-b5cd-8bcc-cc20-5e6287c0a3f3.png)

そこで登場するのがNode Stepのほうの`Ansible Playbook Workflow Node Step`。

なのだが、その前にインベントリファイルの内容を共有しておきたい。
`production`というグループに`nginx-test`というサーバが一台だけ登録されている。
(IP書きたくないけどLaunch時に毎回なにかしらDNS書くのは因果が逆な気がしている)

```ruby:Ansible/nginx/hosts
$ cat Ansible/nginx/hosts
[production]
nginx-test ansible_ssh_host=192.168.0.98
[all:vars]
env=production
```

そして`Ansible Playbook Workflow Node Step`のJobがこれ。
細部に違いはあれど基本的にワークフローステップの時と設定は同じ。
重要なのは`--limit production`でグループを絞っていること。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1092362/eab0917e-bf46-d72e-2a06-cf47551a5c8e.png)

で、実行してみるとこうなる。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1092362/f0f85e11-49d9-9d34-c7b6-d6c8e51bdd5e.png)
これはどういうことかというと`nginx-test`というホストに対してノード数の数だけ`ansible-playbook`を実行している。
本来はノードを指定して対象にだけ実行するのだがグループを絞ったことで各ノード毎に`nginx-test`だけを対象にansibleを実行する状態になってしまっている。
なのでこの状態だとどうあがいてもansible-playbookの適用先が間違えられなくなっている。これは面白い。
大変頭が悪くて私自身大好きな挙動をしているのだが先ほどのオペミスの話と照らし合わせて考えるとそう笑ってだけもいられない。
オペミス撲滅やセルフサービスの観点から考えると「間違えられない環境」というのは一つのキーワードになると思うので。

というわけでまとめると

### 絶対にオペミスを許さないという強い意志を感じた

# あとがき
真面目に書くと「Jenkinsでいいじゃん」という呪いに押しつぶされそうだったので少しネタ寄りにしてしまった。
とはいえAnsible with Rundeck普通に使える印象。しばらくはこの形で運用してもいいかも。
なにもラクにならないかとおもっていたがラクになる部分はちゃんとあるしRundeckに乗せるメリットはあった。
(Activityとか実行結果の確認をRundeckの画面一つで完結できるので)
なによりRundeck本来のStepとAnsibleは普通に共存できるのでそこが一番のメリットなのではないかと感じた。
冒頭にも出したがこういった話だと「～～～でいいじゃん問題」が付きまとう。
Rundeckであれば一つの画面で例えばインフラはscript step、開発はplaybookみたいな住み分けができる。他とケンカしない。
あと基礎的なところだが「ansibleって実際のところみんな打ってるコマンド違うよね問題」ってあると思っている。
そういった問題に対してこういったUIで実行コマンドを指定して強制的に標準化できるというのは大きなメリットを感じた。
これでやっと目的のことが進められそうなのでまたしばらく更新がなくなる予定。(とか書くとまた更新するのだろうが)
時間ができたらほかのところもさらに深堀りしていきたい。