MicroAd Developers Blog

マイクロアドのエンジニアブログです。インフラ、開発、分析について発信していきます。

Toxを活用してAnsibleのアップグレードとUbuntu対応を進めている話 〜Ansible v2.9脱出作戦〜

はじめに

インフラエンジニアの長田です。これまでマイクロアドのインフラ環境ではCentOS7を使っていましたが、現在はUbuntu20.04への乗り換えを順次進めています。
それに伴い、CentOS用に作ってきたAnsibleロールのUbuntu対応やGitHubリポジトリの構成見直し、新しいバージョンのAnsibleへの追随など様々なリファクタリングを進めています。
また、複数のansible-core、Moleculeバージョンで同時にテストするために、Pythonのテスト用仮想環境を管理するtoxというツールを活用しています。

Ubuntuへの対応

これまでマイクロアドのインフラ環境ではCentOS7を使っていましたが、現在はUbuntuへの乗り換えを順次進めています。 それにあたり、これまでCentOS用に作り込んでいたAnsibleロールをUbuntuでも動作するように作り替える必要があり、以下のような修正をしています。

  • vars ディレクトリ配下に、OS毎に異なるファイルパスなどを定義する変数ファイルを作成する
  • tasks ディレクトリ配下に、OS別のタスクファイルを作成する
  • tasks/main.yml に、上記のファイルをincludeするタスクを記述する

以下は、PostgreSQLをインストールするロールからOS毎に異なる内容の抜粋です。OSのディストリビューション名を取得する変数 ansible_distribution によって、includeする変数ファイルとタスクファイルを分岐させています。

  • defaults/main.yml (OS共通のデフォルト変数)
---
postgresql_version: 14
  • vars/CentOS.yml
---
postgresql_datadir: "/var/lib/pgsql/data"
  • vars/Ubuntu.yml
---
postgresql_datadir: "/var/lib/postgresql/{{ postgresql_version }}/main"
  • tasks/package-CentOS.yml
---
- name: PostgreSQLをインストール
  ansible.builtin.package:
    name:
      - "postgresql{{ postgresql_version }}"
      - "postgresql{{ postgresql_version }}-devel"
      - "postgresql{{ postgresql_version }}-server"
      - "postgresql{{ postgresql_version }}-libs"
      - "postgresql{{ postgresql_version }}-contrib"
  • tasks/package-Ubuntu.yml
---
- name: PostgreSQLをインストール
  ansible.builtin.apt:
    name:
      - "postgresql-{{ postgresql_version }}"
      - "postgresql-client-{{ postgresql_version }}"
      - "postgresql-client-common"
      - "postgresql-common"
    state: present
    update_cache: true
  • tasks/main.yml
---
- name: OS毎の変数を取得
  ansible.builtin.include_vars: "{{ ansible_distribution }}.yml"

- name: OS毎のインストールタスクを実行
  ansible.builtin.include_tasks: "package-{{ ansible_distribution }}.yml"

ロールのリポジトリ分離

これまで、マイクロアドのインフラチームで管理しているAnsibleのリソースはgroup_varsやロール、プレイブックを含め、全て単一のリポジトリで管理していました。
しかし、CIによるテストの動作制御や、後述する複数バージョンのansible-core、Moleculeでのテストが行いずらいといった問題が生じてきました。そこで、ロールについては1ロール1リポジトリの形式に分離することとしました。
これにより、ロール毎に異なるバージョンでのCI実行が容易になり、移植性が向上しました。

  • 既存のリソース構成(抜粋)
.
├── group_vars
│   └── some_host
├── roles
│   └── some_role
└── playbook.yml
  • リポジトリ分離後のリソース構成
# ansibleリポジトリ
.
├── group_vars
│   └── some_host
├── roles
│   └── requirements.yml
└── playbook.yml
  • 分離したロールのリポジトリ(抜粋)
.
├── README.md
├── defaults
│   └── main.yml
├── meta
│   └── main.yml
├── molecule
├── tasks
│   ├── main.yml
│   ├── package-CentOS.yml
│   └── package-Ubuntu.yml
├── tox.ini
└── vars
    ├── CentOS.yml
    └── Ubuntu.yml

roles/requirements.ymlには、リポジトリ分離したロールをインストールするための情報を記載しています。ロール名の先頭には ma_ansible というnamespaceを付与し、次に説明する meta/main.yml の記述と一致させてロールをインストールできるようにします。

---
roles:
  - name: "ma_ansible.some_role"
    src: "git+<ロールリポジトリのURL>"

また、リポジトリ分離したロール側には meta/main.yml を作成し、元のリポジトリからCollectionとしてインストールできるようにしています。この中の namespace に、上述した ma_ansible を指定します。

---
galaxy_info:
  role_name: "some_role"
  namespace: ma_ansible
  company: MicroAd, Inc.
  author: "Yasuhiro Nagata"
  description: "〇〇〇をインストールするロール"
  license: "MicroAd, Inc."
  platforms:
    - name: EL
      versions:
        - '7'
    - name: Ubuntu
      versions:
        - focal
  min_ansible_version: 2.9.27

ansible-coreおよびMoleculeのアップグレード、複数バージョンでの同時テスト

現在、マイクロアドでは主にansible-core 2.9を使っていますが、すでにEOLを迎えているため、アップグレードを進めています。
理想的には最新バージョンを使用したいですが、Python3.9以上のバージョンが必要です。テスト環境で複数バージョンのPythonを使用する方法が定まっていないため、ひとまず現環境で使用しているPython3.8で動作するansible-core 2.12へアップグレードしています。

マイクロアドでは全てのAnsibleロールにMoleculeでのテストを実装しており、こちらについても新しいバージョンへの追従を進めています。 Moleculeの最新バージョンは直近2つのメジャーバージョンしかサポートしないため、一旦はansible-core 2.12に合わせたもので動作する内容に作り替えています。 この際、上述したtoxを使って molecule test を実行しています。toxの仮想環境設定は以下のようなiniファイルで行っています。

  • tox.ini
[tox]
envlist = py38-ansible{209,212}
skipsdist = true
[testenv]
parallel_show_output = true
deps =
    #ansible-core 2.9
    ansible209: ansible==2.9.27
    ansible209: rich<11.0.0
    ansible209: ansible-lint==4.3.7
    ansible209: jmespath==0.9.5
    ansible209: molecule==3.2.4
    # ansible-core 2.12
    ansible212: ansible==5.10
    ansible212: ansible-lint==6.12.2
    ansible212: jmespath
    ansible212: molecule==3.6
    -r {toxinidir}/requirements_tox.txt
setenv =
    PATH = {toxworkdir}/bin{:}{env:PATH}
    ANSIBLE_FORCE_COLOR = True
    ROLE_CURDIR={env:ROLE_CURDIR}
    TEST_ENVNAME={envname}
    MOLECULE_EPHEMERAL_DIRECTORY={toxworkdir}/tmp/{envname}
    PY_COLORS={env:color}
commands =
    molecule test

CIでのテストは、Makefileのタスクを呼び出してtoxを実行しています。また、ローカルでテストする場合、テストが失敗した場合にMolecule実行環境のコンテナ内がどうなっているかを確認したいケースがあるため、venvで仮想環境を構築する方法も併用しています。Makefileのタスクでvenv環境の構築と、 molecule test --destroy=never 相当のコマンドを実行できるようにしています。

  • Makefile
# CIで実行するタスク
.PHONY: test
test:
    @tox --parallel --quiet --parallel-live true auto

# ローカル実行用venv環境の構築
.PHONY: venv-init
venv-init:
ifeq ($(shell uname),Linux)
# Ubuntu
ifeq ($(shell source /etc/os-release && echo "$$ID"),ubuntu)
    @python3 -m venv .venv && \
    source .venv/bin/activate && \
    .venv/bin/pip install --upgrade pip && \
    .venv/bin/pip install -r requirements_venv.txt ;
endif
# macOSの場合
else ifeq ($(shell uname),Darwin)
    @python3 -m venv .venv && \
    source .venv/bin/activate && \
    .venv/bin/pip install --upgrade pip && \
    .venv/bin/pip install -r requirements_venv.txt ;
endif

# テスト実行用コマンド(moleculeコンテナを削除しない)
.PHONY: test-destroy-never
test-destroy-never:
    @TEST_ENVNAME=py38-ansible209 molecule test --destroy=never

おわりに

今後、Ubuntu22.04への対応や更に先のansible-coreのバージョンへのアップグレードも進めたいと考えています。
インフラのコードも放置すれば技術的負債となりかねないため、これからも改善を進めていきます。