インフラ開発部でテックリードをしております上畑です。
ラクスで利用しているAnsibleコードについて、Ansibleのバージョンアップを行った内容を記事にしました。 この記事が同じような境遇のどなたかの助力になれば幸いです。
- 1. 背景
- 2. Ansibleバージョンアップ
- 3. コード修正にはAnsible-Lintの自動修正(autofix)機能を使う
- 4. Ansible-Lintバージョンアップ
- 4-1. Ansible-Lintバージョン推移
- 4-2. Ansible-Lint各バージョンへの対応
- v4.7.0 to v5.4.0
- v5.4.0 to v6.14.0
- missing document start "---" (document-start)
- missing starting space in comment (comments)
- too few spaces before comment (yaml[comments])
- deprecated-module
- name[casing] ※autofix利用可能
- fqcn[action-core]※autofix利用可能
- fqcn[action]
- no-changed-when: Commands should not change things if nothing needs doing.
- yaml[truthy]: Truthy value should be one of
- v6.14.0 to v6.22.2
- risky-shell-pipe
- 5. まとめ
1. 背景
2019 - 2020年に私が作った共通Ansibleテンプレートはansible-2.9.x(旧型Ansible)のコード体系をベースとして構築しており、現在も各サービス環境の構築や設定変更等業務で利用しています。
また、CI/CD環境としてAnsibleの構文チェック(Lint)やAnsible実行環境をJenkinsと連携して整備しており、業務にがっつり組み込まれていることからAnsibleのバージョンアップに伴うサービス影響を鑑みて見送って(半ば放置)しておりました。
しかし、定期的なJenkins(Dockerコンテナ)のバージョンアップを進めていくにあたって、Jenkinsイメージ内のOS更新に伴うPythonサポートバージョン変更が上記環境の維持に影響が出たことが今回Ansibleバージョンアップを決心した背景となります。
2. Ansibleバージョンアップ
2-1. AnsibleとPythonの関係調査
Ansibleはご承知の通り2.9から2.10に伴いansibleとansible-core(or ansible-base)に分かれましたので現在(2024年11月18日)までの状況をまとめました。
下記の表にもある通り、Ansible実行環境及び実行先のPythonのサポートバージョンの範囲がある為、これに伴う影響を確認していきます。
Ansible Version | base/core Version | EOL | Ansible実行環境 | Ansible実行先 |
---|---|---|---|---|
ansible-2.9.x | - | EOL(2022/05/23) | 2.7, 3.5-3.8 | 2.6-2.7, 3.5-3.8 |
ansible-2.10.x | ansible-base 2.10.x | EOL(2022/05/23) | 2.7, 3.5-3.9 | 2.6-2.7, 3.5-3.9 |
ansible-3.x | ansible-base 2.10.x | EOL(2022/05/23) | 2.7, 3.5-3.9 | 2.6-2.7, 3.5-3.9 |
ansible-4.x | ansible-core 2.11.x | EOL(2022/11/07) | 2.7, 3.5-3.9 | 2.6-2.7, 3.5-3.9 |
ansible-5.x | ansible-core 2.12.x | EOL(2023/05/22) | 3.8-3.10 | 2.6-2.7, 3.5-3.10 |
ansible-6.x | ansible-core 2.13.x | EOL(2023/11/06) | 3.8-3.10 | 2.6-2.7, 3.5-3.10 |
ansible-7.x | ansible-core 2.14.x | EOL(2024/05/20) | 3.9-3.11 | 2.7, 3.5-3.11 |
ansible-8.x | ansible-core 2.15.x | EOL(2024/11/01) | 3.9-3.11 | 2.7, 3.5-3.11 |
ansible-9.x | ansible-core 2.16.x | 2025/05/01 | 3.10-3.12 | 2.7, 3.6-3.12 |
ansible-10.x | ansible-core 2.17.x | 2025/11/01 | 3.10-3.12 | 3.7-3.12 |
ansible-11.x | ansible-core 2.18.x | 2026/05/01 | 3.11-3.13 | 3.8-3.13 |
2-2. 各OSの標準Pythonバージョン一覧調査
いくつか抜粋しますが、各OS標準のpythonのバージョンを確認しました。
上記の表ではansible-9.xからansible-10.xへ移行する際に、Ansible実行先としてpython-2.xのサポートを終了しています。その為、RHEL/CentOSの7系への影響があります。
また、Python-3.6のサポートも終了している為、ここではAlmaLinux/RockyLinux/RHELの8系の影響にも考慮が必要となることが考えられます。
OS | OS Version | Python Version |
---|---|---|
RHEL/CentOS | 7 | 2.7 |
AlmaLinux/RockyLinux/RHEL | 8 | 3.6 |
AlmaLinux/RockyLinux/RHEL | 9 | 3.9 |
Ubuntu | 20.04 | 3.8 |
Ubuntu | 22.04 | 3.10 |
Ubuntu | 24.04 | 3.12 |
ラクスでも社内にあるいくつかの検証用の環境の一部がCentOS7の環境があり、現在リプレイス作業中でした。
その為、影響解決策として以下のいずれかの対応を検討しました。
並行で作業を行う為、まずはCentOS7環境のリプレイスが完了するまではansible-10.xへの変更は行わずに、ansible-9.12.0まで対応していくこととしました。
2-3. Porting Guideによる仕様変更の確認
Ansible公式サイトにはPorting Guide(移植ガイド)がありますので、利用しているAnsibleのモジュールにおいて仕様変更等がないか各バージョン毎に仕様変更への影響確認を行います。
その際に各モジュール単位で確認を行いますが、ラクスのAnsibleコードではAnsible標準の機能による実装が中心となっているため、community.general., ansible.builtin.などに限定することができ、比較的確認箇所が少なく済みました。
2-4. バージョンアップ戦略
一番留意が必要なのは、「サービスへ影響をしないこと」 が重要である為、ansibleのバージョンアップは段階的に実施していきます。
以下ansible アップデート順になります。
From Version | To Version | base/core Version | target Python Verison |
---|---|---|---|
2.9.x | 2.9.27(2.9最終バージョン) | --- | 2.6-2.7, 3.5-3.8 |
2.9.27 | 2.10.7 | ansible-base-2.10.17 | 2.6-2.7, 3.5-3.9 |
2.10.17 | 3.4 | ansible-base-2.10.17 | 2.6-2.7, 3.5-3.9 |
3.4 | 8.7.0 | ansible-core 2.15.13 | 2.7, 3.5-3.11 |
8.7.0 | 9.12.0 | ansible-core 2.16.13 | 2.7, 3.6-3.12 |
一旦ココまで | ---- | ---- | ---- |
9.12.0 | 10.6.0 | ansible-core 2.17.x | 3.7-3.12 |
2-5. Ansibleコード修正内容
以下、各Ansibleバージョン間において対応した内容を記載しておきます。
弊社環境では以下2種類の修正のみで、ansible-9.12.0までの修正において、実行時の動作は問題ありませんでした。
[修正対応内容]
ansible-2.9.27 to ansible-8.7.0
- 未定義の変数の使用について、厳格化されました。実際には[]内は文字列の予定でしたが、変数として評価されていた為対応しました。
The task includes an option with an undefined variable. --- - name: "{{ package_name }}" | default([httpd]) + name: "{{ package_name }}" | default(['httpd'])
ansible-8.7.0 to ansible-9.12.0
- Ansible 2.12(ansible 5.X)からDeprecatedとなっていたinclude:, import:の表記は[Ansible 9系から廃止]](https://docs.ansible.com/ansible/latest/porting_guides/porting_guide_9.html#id65)されました。
Removed include which has been deprecated in Ansible 2.12. Use include_tasks or import_tasks instead. --- - - include: setup.yml + - include_tasks: setup.yml
3. コード修正にはAnsible-Lintの自動修正(autofix)機能を使う
ansible-lintにはv6.15.0からautofix機能が実装されました。
この自動修正機能を利用することでAnsibleコードの修正の9割に対応することができましたので紹介します。
3-1. 実行方法
自動修正機能付きで実行するにはansible-lint実行時に--fixを付与するだけです。
渡したplaybookに記載されているroleに対して、引っかかったルールに対して修正が行われます。
※このオプションは、v6.20.0から追加されておりますので利用時はこれ以降のバージョンを使用してください。
ansible-lint [playbook].yml --fix
実際に修正が行われるとModified * files.と修正されたファイル数が表示されます。
diff機能はない為、git等で差分を確認しましょう。
# ansible-lint ansible-lint.yml --fix --- INFO Identified /etc/ansible as project root due .git directory. INFO Set ANSIBLE_LIBRARY=/etc/ansible/.cache/ansible-compat/0cb87f/modules:/usr/share/ansible/plugins/modules INFO Set ANSIBLE_ROLES_PATH=/etc/ansible/.cache/ansible-compat/0cb87f/roles:roles:/etc/ansible/roles INFO Executing syntax check on playbook ansible-lint.yml (0.77s) Modified 6 files. Passed: 0 failure(s), 0 warning(s) on 39 files. Last profile that met the validation criteria was 'production'.
オプションの使い方
ルール一覧
全てのルールに対して自動修正が行われるわけではなく、以下のルール一覧に記載されているものに対して修正が行われます。
ざっと紹介すると以下の修正が可能です。 * command-instead-of-shell ... shellをcommandに変換 * deprecated-local-action ... local_actionの代わりにdelegate_toを使う * fqcn ... モジュール名をfqcn形式に変換(ansible.builtin.など一部のみ) * jinja ... jinja表記のformat修正 * key-order ... blockにwhenをつける場合の記載修正 * name ... 先頭が小文字から始まっている場合、大文字に変換 * no-free-form ... one-linerの記載を複数行記載形式に修正 * no-jinja-when ... when文のjinja記載を修正 * no-log-password ... no-logの記載を修正 * partial-become ... becomeやbecome_userの記載を修正 * yaml ... yaml表記を修正
4. Ansible-Lintバージョンアップ
続いてAnsible-Lint環境についてもアップデートを検討しました。
4-1. Ansible-Lintバージョン推移
現行のAnsible-Lintはv4.3.7を利用しておりましたので、現時点での最新バージョンであるv24.10.0まで段階的にアップデートをおこない影響を確認しながら修正を実施しました。 以下バージョン推移
v4.3.7 > v5.4.0 > v6.14.0 > v6.22.2 > v24.10.0
4-2. Ansible-Lint各バージョンへの対応
ここからはAnsible-Lintのバージョンアップにおいて、各バージョン間における実際に修正が必要だった内容を記載しておきます。
v4.7.0 to v5.4.0
var_naming
- 変数名として使用できる文字の制限
- 影響が大きい為、一旦修正を行わず例外追加で対応(大文字を許可)
.ansible-lint --- var_naming_pattern: "^[A-Za-z_][A-Za-z0-9_]*$" # 大文字を許可
unnamed-task
- name定義のないタスクの禁止
- import_tasks: install.yml - import_tasks: setup.yml # 以下に修正 - name: Install import_tasks: install.yml - name: Setup import_tasks: setup.yml
v5.4.0 to v6.14.0
missing document start "---" (document-start)
- yamlファイルの先頭に---を付与
---
missing starting space in comment (comments)
- 先頭コメントの後にコメント文の前にスペースが必要
#-name # 以下に修正 # - name:
too few spaces before comment (yaml[comments])
- コメントの前のスペースは2つ以上。またはコメントの開始後のスペースがありません
command: test #noqa 503 command: test # noqa 503
deprecated-module
- include:, import:の禁止
- include: # 以下に修正 - name: ... include_tasks:
- import: # 以下に修正 - name: ... import_tasks:
name[casing] ※autofix利用可能
- nameの先頭文字は大文字であること
- name: test # 以下に修正 - name: Test
fqcn[action-core]※autofix利用可能
- module名をansible.builtin.など新しい表記に対応が必要
- name: Test command: echo 'test' # 以下に修正 - name: Test ansible.builtin.command: echo 'est'
fqcn[action]
- module名をansible.posix.やcommunity.general.など新しい表記に対応が必要
- name: Test sysctl: name: ... - name: Timezone timezone: name: ... # 以下に修正 - name: Test ansible.posix.sysctl: name: ... - name: Timezone community.general.timezone: name: ...
- ただし全ての修正が終わるまでは古いansible-lintでciを動かす為、一旦対象外にしておく
.ansible-lint --- skip_list: - fqcn[action]
no-changed-when: Commands should not change things if nothing needs doing.
- command module使用時にはchanged_whenの定義が必要
# コマンド実行結果がrc: 0の場合changedになる ... ansible.builtin.command: echo 'test' register: result changed_when: result.rc == 0 # コマンド実行結果に関わらずchangedにはしない ansible.builtin.command: echo 'test' register: result changed_when: false # コマンド実行結果に関わらずchangedにする ansible.builtin.command: echo 'test' register: result changed_when: true
yaml[truthy]: Truthy value should be one of
- yaml構文においてboolianの値はtrue or falseである必要がある
- name: Test ansible.builtin.command: echo 'test' register: result changed_when: no failed_when: True # 以下に修正 - name: Test ansible.builtin.command: echo 'test' register: result changed_when: false failed_when: true
また、上記対応においては修正量が多い為、role単位での修正を行う対応として、yaml-lintバージョンを1.26.3から1.35.1に更新しignore機能を利用して修正対象を絞り込んで順次対応を実施しています。
.yamllint --- rules: truthy: ignore: - "roles/roleA/*/*.yml" # ロール修正時に削除して対応 - "roles/roleA/*/*.yaml" # ロール修正時に削除して対応 - "roles/roleB/*/*.yml" # ロール修正時に削除して対応 - "roles/roleB//*/*.yaml" # ロール修正時に削除して対応
v6.14.0 to v6.22.2
var-naming[no-role-prefix]
- ロール内の変数名は role_name_プレフィックスとして使用する必要があります。プレフィックスの前では下線が使用できます。
- Ansibleドキュメントを確認しても、このルールが確認できませんでした。変更に伴う修正影響が大きい為、一旦修正対象外としました。(https://docs.ansible.com/ansible/latest/playbook_guide/playbooks_variables.html#playbooks-variables)
roles/hoge/vars/main.yml --- version: '0.1' # 以下に修正 hoge_version: '0.1'
- 今回はこのルールを全体的に対象外にする
.ansible-lint --- skip_list: - var-naming[no-role-prefix]
risky-shell-pipe
- shell内でpipeを使用する場合は、pipefailオプションを設定する必要がある
- name: Test Shell shell: echo 'test' | tail # 以下に修正 shell: set -o pipefail && echo 'test' | tail
5. まとめ
- Ansibleバージョンアップ時にはAnsibleのバージョンによってPythonのサポートバージョンが変わるので注意。Ansible実行環境、Ansible実行先の環境のPythonのバージョンを確認すること
- Ansibleコードの修正にはAnsible-Lintの自動修正機能が使える。ただしv6.20.0以上を使うこと
- Ansibleのバージョンアップは段階的に行う
- Ansible-Lintも段階的にバージョンアップを行い修正範囲を極小化して段階的に行う
実際には、これ以外に弊社にはAnsibleを本番環境に適用する前に実際に実行して、安全性を確認する環境が存在しますが詳細は別記事で紹介しようと思います。
以上長くなりましたが、Ansibleバージョンアップ作業のまとめになります。 ありがとうございました。