2022年のAnsibleとわたし

みなさんハッピークリスマス。Red Hatのさいとうです。

AnsibleユーザグループのAdvent Calender 2022最終日の記事として、2022年のAnsibleにどのような変化がありそうなのかといったあたりの個人的な予想を書き残しておこうと思います。

この記事は、AnsibleユーザコミュニティのAdvent Calendarですから、アップストリームの情報を元にして書いています。Red Hatのテクニカルサポートには問い合わせないでね!

2021年のAnsibleのふりかえりについては、コチラをどうぞ。

2022年にやってきそうな変化

現在のAnsible Core 2.xは、ある程度安定期に入っているため、機能面で劇的な変更が加えられることはしばらくないものと考えています。しかし、Ansible Coreが稼動するPlaybookの実行環境としては、2022年に大きな変化がやってきそうです。

現在、多くのAnsible Playbookの実行環境は、コントローラとなるノードのシステムワイドや、ユーザのホームディレクトリ、そしてPythonのvirtualenvを利用した仮想的な実行環境を利用して構築されています。

Ansibleのモジュール群は、Windows向けのモジュールを除いて、Pythonで書かれた小さなプログラムで構成されています。モジュールを書くうえで必要となる、ファイルのパーミッションチェックなどな基本的な機能は、Ansibleのコアにライブラリとしてバンドルされているため、特に意識することなくモジュールから利用できます。

しかし、例えばEC2インスタンスの作成といったオペレーションに利用するbotoなどのライブラリについては、利用者がモジュール毎に個別にコントロールノードの実行環境に準備する必要があります。Ansibleのコア機能に含まれない、モジュールが動作するためにのみ必要なライブラリ群のインストールやバージョンを意識して、実行環境を維持管理する必要がありました。この管理を常に意識していないと、あるコントロールノードの実行環境で動作したPlaybookが、別のコントロールノードではライブラリ不足やバージョンミスマッチで動作しない...といった問題が発生することになります。

この維持管理に関するコストは、Playbookによって自動化したいオペレーションが多様化すればするほど顕著に大きくなってきます。また、PlaybookをRole化して再利用が進むと、それらが想定外の環境で起動される可能性もでてきます。

このような、実行環境の差異を解決するために、これまでいくつかのアプローチが存在していました。

  1. 実行環境を構築するための手順書による手動構築する
  2. 1.の構築自体を自動化するためのブートストラップ的なPlaybookの作成と実行する
  3. 実行環境をPythonのvirtualenvで作成後にrpmなどでパッケージ化し、コントロールノードにインストールして利用する

水平展開しやすいのは、疑いなく3.ですが、パッケージの適用後にコントロールノードの管理者権限を持つ利用者によって改変されてしまう可能性は残ります。

そこで、3.のパッケージ化のアプローチをもう一歩進めてコンテナ化してしまえば良いのではないか...というアイデアが数年前から議論されていました。

以降では、2022年に向けて広く普及しそうな予感がしている、このコンテナベースのPlaybook実行環境についてご紹介します。

コンテナベースの実行環境

コンテナベースの実行環境は、その名の通り、Ansible CoreやCollections、それらが必要とするPythonモジュールなどのライブラリ群をコンテナとしてパッケージ化したものです。

コンテナ化された実行環境では、単純にpodmanやdockerでansible-playbookコマンドを実行するだけでなく、Playbookの実行ログを残したり、SSH接続に利用する鍵が配置されたントロールノードのディレクトリを透過マウントして利用できるようにするなど、これまでの実行環境では意識する必要のなかった点も考慮しなければなりません。

Ansibleプロジェクトでは、このようなコンテナ環境固有の設定を開発者や利用者がそれほど意識せずに、本来やりたいことに集中できるよう、コンテナベースの実行環境を「使う」、そして「作る」ためのツールを提供しています。

それぞれのツールの細い使い方は、来年のどこかでご紹介するとして、ここではソースコートリポジトリやドキュメンのリンク、簡単な動作サンプルをご紹介しようと思います。

使う

残念ながら、ansible-playbookコマンドには、コンテナベースの実行環境を利用してPlaybookを実行する機能はありません。

その役割の担うのがAnsible Navigatorです。Ansible Navigatorは、コンソールベースのPlaybookランチャーです。 バックエンドとしてAnsible Runnerを利用しており、従来のコントローラ上にインストールされたAnsible Coreや、コンテナベースの実行環境を利用してPlaybookを実行できます。

  • ディレクトリ構造
├── ansible-navigator.yml  ...(1)
├── inventory
│   └── hosts  ...(2)
├── logs
└── playbook
    └── test.yml  ...(3)
  • (1) 設定ファイル - ansible-navigator.yml 参考情報
---
ansible-navigator:
  execution-environment:
    container-engine: docker
    enabled: True
    image: quay.io/ansible/ansible-runner:stable-2.12-devel
    pull-policy: missing
  logging:
    level: debug
    append: True
    file: ./logs/ansible-navigator.log
  mode: stdout
  playbook-artifact:
    enable: True
    replay: ./logs/artifact/replay.json
    save-as: ./logs/artifact/replay.json
  • (2) インベントリファイル - inventory/hosts
[linux]
192.168.125.110
192.168.125.111
192.168.125.112

[linux:vars]
ansible_user=ansible
  • (3) Playbook - playbook/test.yml
---
- hosts: all
  gather_facts: false

  tasks:
    - ping:

それでは、テスト用のPlaybookを実行してみましょう。今回の実行例では、ansible-navigator runコマンドを実行すると、ansible-navigator.ymlファイルのenvironmentl.imageパラメータに指定したコンテナイメージをダウンロードし、そのコンテナ内でPlaybookを実行します。このようにして、Ansible Navigatorとコンテナベースの実行環境を利用すれば、開発環境、テスト環境、そして本番環境で完全に統一された実況環境を利用することができます。

Playbookの実行ログは、(1)のansible-navigator.logging.fileにしたがって、logs/ansible-navigator.logに記録されます。また、SSH接続に必要となるコントロールノード上の秘密鍵や、ssh-agentよってストアしている秘密鍵のパスフレーズも、ansible-navigatorによって透過的に参照する形でコンテナ実行環境が起動されます。

$ pip install --user ansible-navigator
$ eval `ssh-agent`
$ ssh-add
Enter passphrase for /home/hsaito/.ssh/id_rsa: ********
Identity added: /home/hsaito/.ssh/id_ecdsa (/home/hsaito/.ssh/id_ecdsa)
$ ansible-navigator run playbook/test.yml -i inventory/hosts
-----------------------------------------------------------------------------------
Execution environment image and pull policy overview
-----------------------------------------------------------------------------------
Execution environment image name:  quay.io/ansible/ansible-runner:stable-2.12-devel
Execution environment image tag:   stable-2.12-devel
Execution environment pull policy: missing
Execution environment pull needed: True
-----------------------------------------------------------------------------------
Updating the execution environment
-----------------------------------------------------------------------------------
stable-2.12-devel: Pulling from ansible/ansible-runner
a1d0c7532777: Pull complete
0051e33d76d8: Pull complete
3fb241a85b00: Pull complete
014e39b4ae38: Pull complete
442efd345444: Pull complete
79831b585400: Pull complete
27b3a0cd32c9: Pull complete
a0432b3d84b6: Pull complete
93e0336932fc: Pull complete
44e3598950f0: Pull complete
fc120b105d20: Pull complete
25df1b0a7e8d: Pull complete
b1cb03d0f630: Pull complete
324f5147ca8f: Pull complete
Digest: sha256:2c44521150e5f260a85ee99fee4f3a5e41216510c9f408d6e2a64df9eb9064ab
Status: Downloaded newer image for quay.io/ansible/ansible-runner:stable-2.12-devel
quay.io/ansible/ansible-runner:stable-2.12-devel

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

TASK [ping] ********************************************************************
ok: [192.168.125.110]
ok: [192.168.125.112]
ok: [192.168.125.111]

PLAY RECAP *********************************************************************
192.168.125.110            : ok=1    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0
192.168.125.111            : ok=1    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0
192.168.125.112            : ok=1    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

一方で、従来のコントローラに直接インストールされたPlaybook実行環境を利用し続けたい場合もあるでしょう。ansible-navigatorコマンドに--ee falseオプションを指定することで、コンテナベースの実行環境ではなく、従来のコントローラ上にインストールされたansible-playbookコマンドを利用することもできます。

$ ansible-navigator run --ee false playbook/test.yml -i inventory/hosts

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

TASK [ping] ********************************************************************
ok: [192.168.125.111]
ok: [192.168.125.112]
ok: [192.168.125.110]

PLAY RECAP *********************************************************************
192.168.125.110            : ok=1    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0
192.168.125.111            : ok=1    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0
192.168.125.112            : ok=1    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

このように、ansible-navigatorを利用すれば、Playbook実行時に、従来のコントロールノード上にインストールされた実行環境と、コンテナベースの実行環境を必要に応じて選択することができます。

作る

コンテナベースの実行環境で利用するコンテナイメージは、基本的にはQuay.ioから提供されるansible-runnnerのイメージを利用します。

これをカスタマイズして独自のCollectionsやPythonモジュールをインストールした状態で利用したいというユースケースも当然発生してくるでしょう。Ansible Builderを利用すれば、利用者がカスタマイズしたコンテナイメージを作成することができます。

公式ドキュメントと元にして、以下のようなティレクトリを構成してカスタムコンテナイメードを作成する例をご紹介します。

  • ディレクトリ構造
.
├── ansible.cfg  ...(1)
├── bindep.txt  ...(2)
├── custom_ee.yml  ...(3)
├── requirements.txt  ...(4)
└── requirements.yml  ...(5)
  • (1) Ansible Core設定ファイル - ansible.cfg
[defaults]
host_key_checking=false
  • (2) コンテナイメージ作成時にインストールするOSパッケージ群 - bindep.txt
krb5-devel [platform:rpm]
  • (3) Ansible Builderのコンテナビルド設定ファイル - custom_ee.yml
version: 1

build_arg_defaults:
  ANSIBLE_GALAXY_CLI_COLLECTION_OPTS: '-v'
  EE_BASE_IMAGE: 'quay.io/ansible/ansible-runner:stable-2.11-devel'

ansible_config: 'ansible.cfg'

dependencies:
  galaxy: requirements.yml
  python: requirements.txt
  system: bindep.txt

additional_build_steps:
  prepend: |
    RUN whoami
    RUN cat /etc/os-release
  append:
    - RUN echo This is a post-install command!
    - RUN ls -la /etc
  • (4) コンテナイメージ作成時にインストールするPythonモジュール群 - requirements.txt
awxkit
  • (5) コンテナイメージ作成時にインストールするCollections/Roles群 - requirements.yml 参考情報
collections:
  - ansible.posix
  - awx.awx
  - community.general

それでは、Ansible Builderを利用してカスタマイズされたコンテナ実行環境のイメージを作成してみます。以下の例では、-fオプションに(3)のビルド設定ファイル、-tオプションで、作成するコンテナイメージに付与するタグ名を指定してビルドしています。

$ pip install --user ansible-builder
$ ansible-builder build -f custom_ee.yml -t custom_ee:2.11
Running command:
  docker build -f context/Dockerfile -t custom_ee:2.11 context
Complete! The build context can be found at: /home/hsaito/work/testing/ansible-builder/custom_ee/context
$ docker images
REPOSITORY                        TAG                 IMAGE ID       CREATED              SIZE
custom_ee                         2.11                3c5ad277f944   19 seconds ago       780MB

作成したイメージは、Ansible Navigatorから利用できます。先程「使う」で利用したAnsible Navigatorのディレクトリで、実際にカスタムイメージを利用してPlaybookを実行してみましょう。(3)ではベースイメージ(build_arg_defaults.EE_BASE_IMAGE)として、Ansible Core 2.11を指定しています。

今回は、--eeiオプションで、カスタムイメージのタグを指定しています。また、Ansible Coreのバージョンが2.11であることを確認するために-vvオプションもあわせて指定しています。

$ ansible-navigator run --eei custom_ee:2.11 playbook/test.yml -i inventory/hosts -vv
ansible-playbook [core 2.11.7.post0]
  config file = None
  configured module search path = ['/home/runner/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules']
  ansible python module location = /usr/local/lib/python3.8/site-packages/ansible
  ansible collection location = /home/runner/.ansible/collections:/usr/share/ansible/collections
  executable location = /usr/local/bin/ansible-playbook
  python version = 3.8.8 (default, Aug 25 2021, 16:13:02) [GCC 8.5.0 20210514 (Red Hat 8.5.0-3)]
  jinja version = 2.10.3
  libyaml = True
No config file found; using defaults
Skipping callback 'awx_display', as we already have a stdout callback.
Skipping callback 'default', as we already have a stdout callback.
Skipping callback 'minimal', as we already have a stdout callback.
Skipping callback 'oneline', as we already have a stdout callback.

PLAYBOOK: test.yml *************************************************************
1 plays in /home/hsaito/work/testing/ansible-navigator/playbook/test.yml

PLAY [all] *********************************************************************
META: ran handlers

TASK [ping] ********************************************************************
task path: /home/hsaito/work/testing/ansible-navigator/playbook/test.yml:6
ok: [192.168.125.110] => {"ansible_facts": {"discovered_interpreter_python": "/usr/libexec/platform-python"}, "changed": false, "ping": "pong"}
ok: [192.168.125.112] => {"ansible_facts": {"discovered_interpreter_python": "/usr/libexec/platform-python"}, "changed": false, "ping": "pong"}
ok: [192.168.125.111] => {"ansible_facts": {"discovered_interpreter_python": "/usr/libexec/platform-python"}, "changed": false, "ping": "pong"}
META: ran handlers
META: ran handlers

PLAY RECAP *********************************************************************
192.168.125.110            : ok=1    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0
192.168.125.111            : ok=1    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0
192.168.125.112            : ok=1    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

まとめ

Ansible Navigatorは、Ansibleプロジェクトの中でも、2021年に立ち上げられた最も若いプロジェクトです。まだまだプロダクション環境での運用には耐えない部分もありますが、2022年も安定性の向上や機能拡張が進められていくことでしょう。

今回ご紹介したのはCLIでの利用例でしたが、リッチなテキストベースのユーザインターフェイスも提供しています。2022年は、Ansible Navigatorが提供するハイブリッドなPlaybook実行環境の利用が進むものと予想しています。この記事が、みなさんの2022年の活動のお役に立てば幸いです。

それではみなさん、2022年もHappy Automation! :)

* 各記事は著者の見解によるものでありその所属組織を代表する公式なものではありません。その内容については非公式見解を含みます。