Ansibleコントロールノード を Dockerコンテナ でビルドし、リモートサーバに公開鍵認証でSSH接続してインストール済みのパッケージの一覧を取得するまで の続きです。
手動でサーバに接続して yum update
するのは面倒なので Ansible の力を借りようと思った次第です。
試験環境については上述記事を参照。
設定
ディレクトリ階層
PROJECT_ROOT/
├ workspace/ // データ永続化領域
│ ├ entrypoint.sh // Dockerコンテナ起動時に実行するシェルスクリプト
│ └ ansible/ // Ansible 用ディレクトリ
│ ├ targets/ // リモートホストの情報を収めるディレクトリ
│ │ └ hosts // リモートサーバの一覧 (今回は1つのみ)
│ │
│ ├ tasks/ // Ansible のタスクを収めるディレクトリ
│ │ ├ get_packages.yml // リモートサーバのパッケージとバージョンの一覧を取得
│ │ ├ output_packages.yml // get_packages.yml で取得したパッケージの一覧を package_list.j2 を使って出力
│ │ └ yum_update.yml // yum update を実行
│ │
│ ├ templates/ // 出力用テンプレートを収めるディレクトリ
│ │ └ package_list.j2 // パッケージとバージョンの一覧のリストのテンプレート
│ │
│ └ main.yml // Ansible の playbook
│
├ docker-compose.yml // Docker Compose 設定ファイル
└ Dockerfile // Dockerfile
前回の記事の内容をベースに修正。 Ansible のタスクが多くなったのでタスクごとにファイルを分割したこと、それに併せて Ansible 関係のファイルを整理するためにディレクトリを切りました。
前回同様一揃いを Github に置きました。
Dockerfile, docker-compose.yml, entrypoint.sh
これらは前回のままです。
Ansible
今回の主眼はココ。
全体を通してやっている内容は以下の通りとなります。
- 自PC内の Dockerコンテナ から Ansible 実行
XXX.XXX.XXX.XXX
にSSH接続XXX.XXX.XXX.XXX
に現時点でインストールされているパッケージ一覧を取得、 データ永続化領域 にファイルとして書き出しXXX.XXX.XXX.XXX
でyum update
を実行- 3.と同様
XXX.XXX.XXX.XXX
にインストールされているパッケージ一覧の取得・ファイル書き出し (yum update
でアップデートが実行されたのでパッケージの内容やバージョンが3.とは差分が生じるはず)
main.yml
- name: Get packages from hosts and do yum update
become: yes
become_user: ADMIN_USER
become_method: su
hosts:
- update_servers
tasks:
- name: Get packages from hosts before update
include_tasks: ./tasks/get_packages.yml
- name: Output packages from hosts before update
include_tasks: ./tasks/output_packages.yml
vars:
flag: before
- name: Do yum update
include_tasks: ./tasks/yum_update.yml
- name: Get packages from hosts after update
include_tasks: ./tasks/get_packages.yml
- name: Output packages from hosts after update
include_tasks: ./tasks/output_packages.yml
vars:
flag: after
- タスクを各ファイルに分割
vars
:flag
で./tasks/output_packages.yml
で出力されるファイル名を変更していますyum update
前はXXX.XXX.XXX.XXX_packages_before
,yum update
後はXXX.XXX.XXX.XXX_packages_after
となります
get_packages.yml
- name: Get packages
package_facts:
manager: auto
become: true
極めてシンプル。ちなみに分割したタスクの yml ファイルの中で tasks:
は使えなさそう(確かに分割しているのにさらに読み込めたら依存関係の解決が面倒なことになりそう)ので前回はパッケージ一覧取得→ファイルに書き出しが1つの yml ファイルに記述されていましたが今回は分割しました。
output_packages.yml
- name: Output packages
template:
src: ../templates/package_list.j2
dest: "/workspace/{{ inventory_hostname }}_packages_{{ flag }}"
mode: '0644'
delegate_to: localhost
上述の yml で取得したパッケージの一覧を ../templates/package_list.j2
のテンプレートファイルを使ってファイルに書き出し。
{{ flag }}
は main.yml
で既述した変数が渡ってきて、ファイル名が変更されるというわけですね。
yum_update.yml
- name: Yum update at hosts
yum:
name: '*'
state: latest
async: 1000
poll: 1
register: yum_sleeper
- name: Yum check on fire and forget task
async_status:
jid: "{{ yum_sleeper.ansible_job_id }}"
register: job_result
until: job_result.finished
retries: 30
delay: 10
本題の yum update
を実行する部分。
ちなみに Ansible のSSH接続はデフォルトだと5分で切断されてしまうようで、アップデート対象のパッケージが大量にあって yum update
の実行に時間がかかると、途中で切断されてしまうので注意。
今回それに気付くまでに何回か失敗していましたが、パッケージチェック中の切断などタイミング的に良かったのか、幸運なことに特に支障は起きませんでした。
不幸にも切断されてしまうと不整合パッケージのチェックが終わらずどうにもならない、なんていうケースも見受けられたので注意。
そのため、自動切断を回避するために async
, poll
指定、 async_status
モジュールの使用など細工を色々と加えています。
hosts
[update_servers]
XXX.XXX.XXX.XXX
ここは前回と変わらずグループとIPアドレスの指定を記述。
package_list.j2
# {{ inventory_hostname }}
{% if ansible_facts.os_family == 'RedHat' %}
{% for package_name in ansible_facts.packages.keys()|sort %}
{% for package in ansible_facts.packages[package_name] %}
{{ package['name'] }}-{{package['version']}}-{{package['release']}}.{{package['arch']}}
{% endfor %}
{% endfor %}
{% elif ansible_facts.os_family == 'Debian' %}
{% for package_name in ansible_facts.packages.keys()|sort %}
{% for package in ansible_facts.packages[package_name] %}
{{ [package['name'], package['version']] | join('_') }}
{% endfor %}
{% endfor %}
{% endif %}
こちらも前回と変わらず。
動作確認
# ansible-playbook -i /workspace/ansible/targets/hosts /workspace/ansible/main.yml -u SSH_REMOTEUSER --private-key="/root/.ssh/PRIVATE_KEY" -K
BECOME password:
PLAY [Get packages from hosts and do yum update] *******************************************************************
TASK [Gathering Facts] *********************************************************************************************
ok: [XXX.XXX.XXX.XXX]
TASK [Get packages from hosts before update] ***********************************************************************
included: /workspace/ansible/tasks/get_packages.yml for XXX.XXX.XXX.XXX
TASK [Get packages] ************************************************************************************************
ok: [XXX.XXX.XXX.XXX]
TASK [Output packages from hosts before update] ********************************************************************
included: /workspace/ansible/tasks/output_packages.yml for XXX.XXX.XXX.XXX
TASK [Output packages] *********************************************************************************************
changed: [XXX.XXX.XXX.XXX]
TASK [Do yum update] ***********************************************************************************************
included: /workspace/ansible/tasks/yum_update.yml for XXX.XXX.XXX.XXX
TASK [Yum update at hosts] *****************************************************************************************
changed: [XXX.XXX.XXX.XXX]
TASK [Yum check on fire and forget task] ***************************************************************************
changed: [XXX.XXX.XXX.XXX]
TASK [Get packages from hosts after update] ************************************************************************
included: /workspace/ansible/tasks/get_packages.yml for XXX.XXX.XXX.XXX
TASK [Get packages] ************************************************************************************************
ok: [XXX.XXX.XXX.XXX]
TASK [Output packages from hosts after update] *********************************************************************
included: /workspace/ansible/tasks/output_packages.yml for XXX.XXX.XXX.XXX
TASK [Output packages] *********************************************************************************************
changed: [XXX.XXX.XXX.XXX]
PLAY RECAP *********************************************************************************************************
XXX.XXX.XXX.XXX : ok=12 changed=4 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
#
OK、上手く行きました。
失敗時: UNREACHABLE! => {“changed”: false, “msg”: “Failed to connect to the host via ssh: Shared connection to XXX.XXX.XXX.XXX closed.”, “unreachable”: true}
- name: Yum update at hosts
yum:
name: '*'
state: latest
上述の通り、 yum update
で時間がかかった場合、 yum_update.yml
がシンプルな内容だと途中でSSH接続が切れてしまいます。
# ansible-playbook -i /workspace/ansible/targets/hosts /workspace/ansible/main.yml -u SSH_REMOTEUSER --private-key="/root/.ssh/PRIVATE_KEY" -K
BECOME password:
PLAY [Get packages from hosts and do yum update] *******************************************************************
TASK [Gathering Facts] *********************************************************************************************
ok: [XXX.XXX.XXX.XXX]
TASK [Get packages from hosts before update] ***********************************************************************
included: /workspace/ansible/tasks/get_packages.yml for XXX.XXX.XXX.XXX
TASK [Get packages] ************************************************************************************************
ok: [XXX.XXX.XXX.XXX]
TASK [Output packages from hosts before update] ********************************************************************
included: /workspace/ansible/tasks/output_packages.yml for XXX.XXX.XXX.XXX
TASK [Output packages] *********************************************************************************************
ok: [XXX.XXX.XXX.XXX]
TASK [Do yum update] ***********************************************************************************************
included: /workspace/ansible/tasks/yum_update.yml for XXX.XXX.XXX.XXX
TASK [Yum update at hosts] *****************************************************************************************
fatal: [XXX.XXX.XXX.XXX]: UNREACHABLE! => {"changed": false, "msg": "Failed to connect to the host via ssh: Shared connection to XXX.XXX.XXX.XXX closed.", "unreachable": true}
PLAY RECAP *********************************************************************************************************
XXX.XXX.XXX.XXX : ok=6 changed=0 unreachable=1 failed=0 skipped=0 rescued=0 ignored=0
fatal: [XXX.XXX.XXX.XXX]: UNREACHABLE! => {“changed”: false, “msg”: “Failed to connect to the host via ssh: Shared connection to XXX.XXX.XXX.XXX closed.”, “unreachable”: true}
結果、上のようなエラーで失敗してしまいます。
対処については上述の通り、 yum_update.yml
に細工を施します。
結果
XXX.XXX.XXX.XXX_packages_before
# XXX.XXX.XXX.XXX
acl-2.2.51-15.el7.x86_64
acl-2.2.51-14.el7.x86_64
aic94xx-firmware-30-6.el7.noarch
alsa-firmware-1.0.28-2.el7.noarch
alsa-lib-1.1.6-2.el7.x86_64
alsa-tools-firmware-1.1.0-1.el7.x86_64
apr-1.4.8-3.el7_4.1.x86_64
apr-1.4.8-5.el7.x86_64
## 略
vsftpd-3.0.2-25.el7.x86_64
webmin-1.900-1.noarch
which-2.20-7.el7.x86_64
wpa_supplicant-2.6-12.el7.x86_64
xfsprogs-4.5.0-18.el7.x86_64
xmlsec1-1.2.20-7.el7_4.x86_64
xmlsec1-openssl-1.2.20-7.el7_4.x86_64
xz-5.2.2-1.el7.x86_64
xz-devel-5.2.2-1.el7.x86_64
xz-libs-5.2.2-1.el7.x86_64
yum-3.4.3-167.el7.centos.noarch
yum-3.4.3-161.el7.centos.noarch
yum-metadata-parser-1.1.4-10.el7.x86_64
yum-plugin-fastestmirror-1.1.31-50.el7.noarch
yum-plugin-fastestmirror-1.1.31-54.el7_8.noarch
yum-utils-1.1.31-54.el7_8.noarch
zlib-1.2.7-18.el7.x86_64
zlib-devel-1.2.7-18.el7.x86_64
XXX.XXX.XXX.XXX_packages_after
# XXX.XXX.XXX.XXX
acl-2.2.51-15.el7.x86_64
acl-2.2.51-14.el7.x86_64
aic94xx-firmware-30-6.el7.noarch
alsa-firmware-1.0.28-2.el7.noarch
alsa-lib-1.1.8-1.el7.x86_64
alsa-tools-firmware-1.1.0-1.el7.x86_64
apr-1.4.8-3.el7_4.1.x86_64
apr-1.4.8-5.el7.x86_64
## 略
vsftpd-3.0.2-27.el7.x86_64
webmin-1.900-1.noarch
which-2.20-7.el7.x86_64
wpa_supplicant-2.6-12.el7.x86_64
xfsprogs-4.5.0-20.el7.x86_64
xmlsec1-1.2.20-7.el7_4.x86_64
xmlsec1-openssl-1.2.20-7.el7_4.x86_64
xz-5.2.2-1.el7.x86_64
xz-devel-5.2.2-1.el7.x86_64
xz-libs-5.2.2-1.el7.x86_64
yum-3.4.3-167.el7.centos.noarch
yum-3.4.3-161.el7.centos.noarch
yum-metadata-parser-1.1.4-10.el7.x86_64
yum-plugin-fastestmirror-1.1.31-50.el7.noarch
yum-plugin-fastestmirror-1.1.31-54.el7_8.noarch
yum-utils-1.1.31-54.el7_8.noarch
zlib-1.2.7-18.el7.x86_64
zlib-devel-1.2.7-18.el7.x86_64
かなり省略していますが、それでも alsa-lib
, vsftpd
, xfsprogs
がアップデートされたことが確認できます。
参考
yum update
タスクの分割
- Ansibleタスクの再利用性を高めるためのタスクの粒度について – Qiita
- include_tasks と import_tasks
- 【Ansible】メンテナンスしやすいPlaybookの書き方 | 電算星組
- はじめてのAnsible #2 Playbook分割編
- Ansibleまとめ – Qiita
(最終的に未使用) ansible.cfg のパラメータ
- ansible.cfgの項目をリスト化してみた – Qiita
- [Ansible] “[WARNING]: Ignoring timeout(10) for ios_facts” の正体とタイムアウトの設定方法 – てくなべ (tekunabe)
yum update 中のタイムアウトを防ぐ
- 【小ネタ】Ansibleでyum updateするときはBackgroundオプションをつけると良いという話 | Developers.IO :方法についてはここをきっかけに
- 非同期アクションおよびポーリング — Ansible Documentation
- Asynchronous actions and polling — Ansible Documentation :大体ここの yml を採用
- Ansibleのplaybookで使用できるアトリビュートの一覧 – Qiita
(今回は reboot までしていないので未使用) Ansible で reboot
将来的には Raspberry Pi を自動で焼いていきたいですね。