[Ansible]Ansible Builder v3.1で追加された依存関係の除外オプション

Ansible Builderは、Ansibleの実行環境(EE)コンテナを作成するためのツールです。
EEで利用する`Ansibleコレクション`、`Pythonパッケージ`、`Linuxパッケージ`を明示的に指定してあげることで、Builderが依存関係を解決してコンテナ化してくれます。

先日、Ansible Builder v3.1がリリースされて依存関係の解決のためのオプションが追加されたためその機能について動作を検証しました。

# ansible-builderの依存関係解決

PythonパッケージとLinuxパッケージの依存関係は、`pip`、`dnf`コマンドをそのまま動かしています。

Ansibleコレクションの依存関係は、`ansible-galaxy`コマンドだと依存する`Ansibleコレクション`のみを解決してくれます。
一方、Ansible Builderではさらに`Pythonパッケージ`、`Linuxパッケージ`の依存関係を解決してくれます。
これは、ありがたい反面Builder利用者側で依存関係を制御することができないという問題点がありました。

例えば、複数のAnsibleコレクションが指定した依存関係でバージョン衝突が起こり得ます。

これを解決するためAnsible Builder v3.1では、[Ansibleコレクションの依存関係を無視できるオプション](https://ansible.readthedocs.io/projects/builder/en/latest/definition/#dependencies)ができました。

# 追加されたオプション(exclude)について

`execution-environment.yml`で以下のように記載することでAnsibleコレクションの依存関係解決を無視することができます。

```yaml
dependencies:
  exclude:
    python:
      - <無視したいPythonパッケージ>
    system:
      - <無視したいLinuxパッケージ>
    all_from_collections:
      - <Python、Linuxの依存関係を無視したいAnsibleコレクション>
```

正規表現が使えるためazure関連のものすべてを無視したい場合は、`azure-.*`で指定できます。

また、Pythonパッケージ以外にもLinuxパッケージも指定することができたり、Ansbleコレクション単位で無視をすることもできます。

Pythonパッケージ、Linuxパッケージを指定する際の注意点としては、無視できるのはAnsibleコレクションで直接指定される依存関係のみで、間接的な依存関係は無視されません。



# 検証したこと

## 概要

### やりたいこと

以下をインストールしたEEを作成する。

- Ansibleコレクション
    - azure.azcollectionの最新版(2.4.0)
- Pythonパッケージ
    - ansible-lintの最新版(24.6.1)

### 問題点

`azure.azcollection`はPythonパッケージの`azure-cli-core==2.34.0`に依存しており、さらに[`packaging>=20.9,<22.0`](https://github.com/Azure/azure-cli/blob/azure-cli-2.34.0/src/azure-cli-core/setup.py#L57
)に間接依存しています。
※`azure-cli-core==2.61.0`は`packaging`の依存関係自体ないのでそちらはインストールできます。

一方、`ansible-lint`は`black>=24.3.0`経由で[`packaging>=22.0`](https://github.com/psf/black/blob/24.3.0/pyproject.toml#L68)に間接依存しています。

この`packaging>=20.9,<22.0`と`packaging>=22.0`がコンフリクトを起こしてしまうため、ビルド中に以下エラーが出て失敗してしまいます。

```
ERROR: Cannot install -r /tmp/src/requirements.txt (line 5), -r /tmp/src/requirements.txt (line 52), ansible-lint and packaging because these package versions have conflicting dependencies.

The conflict is caused by:
    The user requested packaging
    azure-cli-core 2.34.0 depends on packaging<22.0 and >=20.9
    ansible-lint 24.6.1 depends on packaging>=21.3
    ansible-compat 24.5.1a0 depends on packaging
    ansible-core 2.13.0 depends on packaging
    black 24.4.2 depends on packaging>=22.0
```


## 定義ファイル

EEを作成する3ファイルは以下の通り。

### execution-environment.yml

コンテナのベースイメージはデフォルトでPython3.9が入っているが、ansible-lintの最新版をインストールできないためPython3.11に置き換えている。

```yaml:execution-environment.yml
---
version: 3

images:
  base_image:
    name: quay.io/centos/centos:stream9-minimal

options:
  package_manager_path: /usr/bin/microdnf
dependencies:
  python_interpreter:
    package_system: python3.11
    python_path: /usr/bin/python3.11
  ansible_core:
    package_pip: ansible-core==2.17.1
  ansible_runner:
    package_pip: ansible-runner==2.4.0
  python: requirements.txt
  galaxy: requirements.yml
additional_build_steps:
  append_base:
    - RUN alternatives --install /usr/bin/python3 python3 /usr/bin/python3.11 0
```

### requirements.yml

```yaml
---
collections:
  - name: azure.azcollection
    version: 2.4.0
```

### requirements.txt

```yaml
ansible-lint==24.6.1
```

## 解決方法

`execution-environment.yml`で`azure-cli-core`を無視する対象に指定します。

```yaml:execution-environment.yml
dependencies:
  exclude:
    python:
      - azure-cli-core
```

また、このままだと`azure-cli-core`自体がインストールされないので、`requirements.txt`で`azure-cli-core`を指定する必要があります。

```:requirements.txt
azure-cli-core==2.61.0
```

ここでインストールされた依存関係がAnsibleコレクションで利用できるかは利用者側で別途確認が必要です。

## 結果

Pythonパッケージで`azure-cli-core`がインストールされ、バージョンも`2.61.0`になっていることが確認できます。
Azure Ansibleコレクションの動作は調べ切れていないですが、調査した限りはある程度の後方互換性があるようなので問題ないかと思います。

```bash
bash-5.1$ pip3 list | grep azure-cli-core
azure-cli-core                       2.61.0
```

# 参考リンク

https://ansible.readthedocs.io/projects/builder/en/latest/definition/#dependencies

https://github.com/ansible/ansible-builder/pull/664