Ansibleで多段階環境を管理する方法
序章
Ansibleは、さまざまな環境でインフラストラクチャとアプリケーションをセットアップおよび管理するために使用される強力な構成管理システムです。 Ansibleは、読みやすい構文、柔軟なワークフロー、および強力なツールを提供しますが、展開環境や機能によって異なる場合、多数のホストを管理するのは難しい場合があります。
このガイドでは、Ansibleを使用して多段階のデプロイメント環境で作業するためのいくつかの戦略について説明します。 通常、さまざまなステージの要件により、コンポーネントの数と構成が異なります。 たとえば、開発サーバーのメモリ要件は、ステージングおよび本番環境のメモリ要件とは異なる場合があり、これらの要件を表す変数の優先順位を明示的に制御することが重要です。 この記事では、これらの違いを抽象化できるいくつかの方法と、構成の再利用を促進するためにAnsibleが提供するいくつかの構成について説明します。
Ansibleで多段階環境を管理するための不完全な戦略
Ansible内の環境を管理する方法はいくつかありますが、Ansible自体は独創的なソリューションを提供していません。 むしろ、環境の管理に使用できる多くの構成を提供し、ユーザーが選択できるようにします。
このガイドで説明するアプローチは、Ansibleグループ変数および複数のインベントリに依存しています。 ただし、検討する価値のある他のいくつかの戦略があります。 以下では、これらのアイデアのいくつかと、複雑な環境で実装したときに問題が発生する理由について説明します。
Ansibleの推奨戦略を開始したい場合は、Ansibleグループと複数のインベントリの使用のセクションに進んでください。
グループ変数のみに依存する
一見すると、グループ変数はAnsibleが必要とする環境間のすべての分離を提供しているように見えるかもしれません。 特定のサーバーを開発環境に属するものとして指定し、他のサーバーをステージングおよび実稼働エリアに割り当てることができます。 Ansibleを使用すると、グループを簡単に作成して変数を割り当てることができます。
ただし、グループの交差は、このシステムに深刻な問題をもたらします。 グループは、複数のディメンションを分類するためによく使用されます。 例えば:
- デプロイメント環境(ローカル、開発、ステージ、製品など)
- ホスト機能(Webサーバー、データベースサーバーなど)
- データセンターリージョン(NYC、SFOなど)
このような場合、ホストは通常、カテゴリごとに1つのグループに属します。 たとえば、ホストは、NYC(データセンターリージョン)のステージ(展開環境)上のWebサーバー(機能)である場合があります。
同じ変数がホストの複数のグループによって設定されている場合、Ansibleには優先順位を明示的に指定する方法がありません。 デプロイメント環境に関連付けられた変数を他の値をオーバーライドすることをお勧めしますが、Ansibleはこれを定義する方法を提供していません。
代わりに、Ansibleは最後にロードされた値を使用します。 Ansibleはグループをアルファベット順に評価するため、辞書の順序で最後にあるグループ名に関連付けられた変数が優先されます。 これは予測可能な動作ですが、グループ名のアルファベット順を明示的に管理することは、管理の観点からは理想的とは言えません。
グループの子を使用して階層を確立する
Ansibleを使用すると、を使用してグループを他のグループに割り当てることができます。 [groupname:children]
インベントリの構文。 これにより、特定のグループに他のグループのメンバーに名前を付けることができます。 子グループには、親グループによって設定された変数をオーバーライドする機能があります。
通常、これは自然な分類に使用されます。 たとえば、次のようなグループを持つことができます environments
グループを含む dev
, stage
, prod
. これは、変数を設定できることを意味します environment
グループ化して、 dev
グループ。 同様に、という親グループを持つことができます functions
グループが含まれています web
, database
、 と loadbalancer
.
子グループは親のみをオーバーライドするため、この使用法ではグループの交差の問題は解決されません。 子グループは親内の変数をオーバーライドできますが、上記の組織は、次のようなグループカテゴリ間の関係を確立していません。 environments
と functions
. 2つのカテゴリ間の変数の優先順位はまだ定義されていません。
非自然なグループメンバーシップを設定することにより、このシステムを悪用することは可能です。 たとえば、次の優先順位を最高の優先順位から最低の優先順位に設定する場合:
- 開発環境
- 領域
- 働き
次のようなグループメンバーシップを割り当てることができます。
. . .
[function:children]
web
database
loadbalancer
region
[region:children]
nyc
sfo
environments
[environments:children]
dev
stage
prod
ここで階層を確立しました。これにより、地域変数が機能変数をオーバーライドできるようになります。 region
グループはの子です function
グループ。 同様に、 environments
グループは他のグループを上書きできます。 これは、同じ変数を別の値に設定した場合、 dev
, nyc
、 と web
グループ、これらのそれぞれに属するホストは、からの変数を使用します dev
.
これにより、望ましい結果が得られ、予測も可能です。 ただし、これは直感的ではなく、真の子と階層を確立するために必要な子の区別を混乱させます。 Ansibleは、その構成が明確で、新しいユーザーでも簡単に理解できるように設計されています。 このタイプの回避策は、その目標を妥協します。
明示的な読み込み順序を許可するAnsibleコンストラクトの使用
Ansibleには、明示的な可変負荷順序付けを可能にするいくつかの構造があります。 vars_files
と include_vars
. これらをAnsiblePlays 内で使用して、ファイル内で定義された順序で追加の変数を明示的にロードできます。 The vars_files
ディレクティブはプレイのコンテキスト内で有効ですが、 include_vars
モジュールはタスクで使用できます。
一般的な考え方は、基本的な識別変数のみを設定することです。 group_vars
次に、これらを活用して、必要な残りの変数を含む正しい変数ファイルをロードします。
たとえば、いくつかの group_vars
ファイルは次のようになります。
---
env: dev
---
env: stage
---
function: web
---
function: database
次に、各グループの重要な変数を定義する個別のvarsファイルを作成します。 これらは通常、別々に保管されます vars
明確にするためのディレクトリ。 ようではない group_vars
ファイル、処理するとき include_vars
、ファイルには .yml
ファイル拡張子。
設定する必要があるふりをしましょう server_memory_size
それぞれで異なる値に変数 vars
ファイル。 開発サーバーは、実稼働サーバーよりも小さい可能性があります。 さらに、Webサーバーとデータベースサーバーのメモリ要件が異なる場合があります。
---
server_memory_size: 512mb
---
server_memory_size: 4gb
---
server_memory_size: 1gb
---
server_memory_size: 2gb
次に、正しいものを明示的にロードするプレイブックを作成できます vars
からホストに割り当てられた値に基づくファイル group_vars
ファイル。 ロードされたファイルの順序によって優先順位が決まり、最後の値が優先されます。
と vars_files
、プレイ例は次のようになります。
---
- name: variable precedence test
hosts: all
vars_files:
- "vars/{{ env }}.yml"
- "vars/{{ function }}.yml"
tasks:
- debug: var=server_memory_size
官能基は最後にロードされるため、 server_memory_size
値はから取得されます var/web.yml
と var/database.yml
ファイル:
- ansible-playbook -i inventory example_play.yml
Output. . .
TASK [debug] *******************************************************************
ok: [host1] => {
"server_memory_size": "1gb" # value from vars/web.yml
}
ok: [host2] => {
"server_memory_size": "1gb" # value from vars/web.yml
}
ok: [host3] => {
"server_memory_size": "2gb" # value from vars/database.yml
}
ok: [host4] => {
"server_memory_size": "2gb" # value from vars/database.yml
}
. . .
ロードするファイルの順序を切り替えると、デプロイメント環境変数の優先度を高くすることができます。
---
- name: variable precedence test
hosts: all
vars_files:
- "vars/{{ function }}.yml"
- "vars/{{ env }}.yml"
tasks:
- debug: var=server_memory_size
プレイブックを再度実行すると、展開環境ファイルから適用されている値が表示されます。
- ansible-playbook -i inventory example_play.yml
Output. . .
TASK [debug] *******************************************************************
ok: [host1] => {
"server_memory_size": "512mb" # value from vars/dev.yml
}
ok: [host2] => {
"server_memory_size": "4gb" # value from vars/prod.yml
}
ok: [host3] => {
"server_memory_size": "512mb" # value from vars/dev.yml
}
ok: [host4] => {
"server_memory_size": "4gb" # value from vars/prod.yml
}
. . .
を使用した同等のプレイブック include_vars
タスクとして動作する、は次のようになります。
---
- name: variable precedence test
hosts: localhost
tasks:
- include_vars:
file: "{{ item }}"
with_items:
- "vars/{{ function }}.yml"
- "vars/{{ env }}.yml"
- debug: var=server_memory_size
これは、Ansibleが明示的な順序付けを可能にする1つの領域であり、非常に便利です。 ただし、前の例と同様に、いくつかの重大な欠点があります。
まず第一に、を使用して vars_files
と include_vars
グループに緊密に関連付けられている変数を別の場所に配置する必要があります。 The group_vars
locationは、にある実際の変数のスタブになります vars
ディレクトリ。 これもまた複雑さを増し、明快さを低下させます。 ユーザーは正しい変数ファイルをホストに一致させる必要があります。これは、Ansibleが使用するときに自動的に行うことです。 group_vars
.
さらに重要なことに、これらの手法に依存すると、これらの手法が必須になります。 すべてのプレイブックには、正しい変数ファイルを正しい順序で明示的にロードするセクションが必要です。 これがないと、関連する変数を使用できなくなります。 さらに、 ansible
アドホックタスクのコマンドは、変数に依存するものではほとんど完全に不可能です。
Ansibleの推奨戦略:グループと複数の在庫の使用
これまで、多段階環境を管理するためのいくつかの戦略を検討し、それらが完全なソリューションではない理由について説明してきました。 ただし、Ansibleプロジェクトは、環境全体でインフラストラクチャを抽象化するための最善の方法に関するいくつかの提案を提供します。
推奨されるアプローチは、各動作環境を完全に分離することにより、多段階環境で作業することです。 すべてのホストを単一のインベントリファイル内に維持する代わりに、個々の環境ごとにインベントリが維持されます。 別 group_vars
ディレクトリも維持されます。
基本的なディレクトリ構造は次のようになります。
.
├── ansible.cfg
├── environments/ # Parent directory for our environment-specific directories
│ │
│ ├── dev/ # Contains all files specific to the dev environment
│ │ ├── group_vars/ # dev specific group_vars files
│ │ │ ├── all
│ │ │ ├── db
│ │ │ └── web
│ │ └── hosts # Contains only the hosts in the dev environment
│ │
│ ├── prod/ # Contains all files specific to the prod environment
│ │ ├── group_vars/ # prod specific group_vars files
│ │ │ ├── all
│ │ │ ├── db
│ │ │ └── web
│ │ └── hosts # Contains only the hosts in the prod environment
│ │
│ └── stage/ # Contains all files specific to the stage environment
│ ├── group_vars/ # stage specific group_vars files
│ │ ├── all
│ │ ├── db
│ │ └── web
│ └── hosts # Contains only the hosts in the stage environment
│
├── playbook.yml
│
└── . . .
ご覧のとおり、各環境は個別で区分化されています。 環境ディレクトリには、インベントリファイル(任意の名前)が含まれています hosts
)と別の group_vars
ディレクトリ。
ディレクトリツリーには明らかな重複があります。 がある web
と db
個々の環境ごとのファイル。 この場合、複製が望ましいです。 変数の変更は、コードや構成の変更の場合と同じように、最初に1つの環境で変数を変更し、テスト後に次の環境に移動することで、環境全体に展開できます。 The group_vars
変数は、各環境の現在のデフォルトを追跡します。
1つの制限は、環境間で機能ごとにすべてのホストを選択できないことです。 幸い、これは上記の変数の複製の問題と同じカテゴリに分類されます。 タスクにすべてのWebサーバーを選択すると便利な場合もありますが、ほとんどの場合、変更を一度に1つずつ環境全体に展開する必要があります。 これにより、ミスが本番環境に影響を与えるのを防ぐことができます。
クロス環境変数の設定
推奨される設定では不可能なことの1つは、環境間での変数の共有です。 環境間変数共有を実装する方法はいくつかあります。 最も簡単な方法の1つは、ファイルの代わりにディレクトリを使用するAnsibleの機能を活用することです。 交換できます all
それぞれのファイル group_vars
ディレクトリと all
ディレクトリ。
ディレクトリ内で、すべての環境固有の変数をファイルに再度設定できます。 次に、環境間変数を含むファイルの場所へのシンボリックリンクを作成できます。 これらは両方とも、環境内のすべてのホストに適用されます。
階層内のどこかにクロス環境変数ファイルを作成することから始めます。 この例では、 environments
ディレクトリ。 そのファイルにすべての環境間変数を配置します。
- cd environments
- touch 000_cross_env_vars
次に、次のいずれかに移動します group_vars
ディレクトリの名前を変更します all
ファイルを作成し、 all
ディレクトリ。 名前を変更したファイルを新しいディレクトリに移動します。
- cd dev/group_vars
- mv all env_specific
- mkdir all
- mv env_specific all/
次に、環境間変数ファイルへのシンボリックリンクを作成できます。
- cd all/
- ln -s ../../../000_cross_env_vars .
環境ごとに上記の手順を完了すると、ディレクトリ構造は次のようになります。
.
├── ansible.cfg
├── environments/
│ │
│ ├── 000_cross_env_vars
│ │
│ ├── dev/
│ │ ├── group_vars/
│ │ │ ├── all/
│ │ │ ├── 000_cross_env_vars -> ../../../000_cross_env_vars
│ │ │ │ └── env_specific
│ │ │ ├── db
│ │ │ └── web
│ │ └── hosts
│ │
│ ├── prod/
│ │ ├── group_vars/
│ │ │ ├── all/
│ │ │ │ ├── 000_cross_env_vars -> ../../../000_cross_env_vars
│ │ │ │ └── env_specific
│ │ │ ├── db
│ │ │ └── web
│ │ └── hosts
│ │
│ └── stage/
│ ├── group_vars/
│ │ ├── all/
│ │ │ ├── 000_cross_env_vars -> ../../../000_cross_env_vars
│ │ │ └── env_specific
│ │ ├── db
│ │ └── web
│ └── hosts
│
├── playbook.yml
│
└── . . .
内に設定された変数 000_cross_env_vars
ファイルは、優先度の低い各環境で使用できます。
デフォルトの環境インベントリの設定
でデフォルトのインベントリファイルを設定することが可能です ansible.cfg
ファイル。 これはいくつかの理由で良い考えです。
まず、明示的なインベントリフラグを省略して ansible
と ansible-playbook
. したがって、入力する代わりに:
- ansible -i environments/dev -m ping
次のように入力すると、デフォルトのインベントリにアクセスできます。
- ansible -m ping
次に、デフォルトのインベントリを設定すると、不要な変更がステージング環境や本番環境に誤って影響を与えるのを防ぐのに役立ちます。 デフォルトで開発環境を使用することにより、最も重要度の低いインフラストラクチャが変更の影響を受けます。 新しい環境への変更を促進することは、明示的なアクションであり、 -i
国旗。
デフォルトの在庫を設定するには、 ansible.cfg
ファイル。 これは、プロジェクトのルートディレクトリまたはにある可能性があります /etc/ansible/ansible.cfg
構成によって異なります。
注:以下の例は、 ansible.cfg
プロジェクトディレクトリ内のファイル。 を使用している場合 /etc/ansibile/ansible.cfg
変更のファイルを作成するには、以下の編集パスを変更します。 使用する場合 /etc/ansible/ansible.cfg
、在庫が外部で維持されている場合 /etc/ansible
ディレクトリを設定するときは、相対パスではなく絶対パスを使用してください。 inventory
価値。
- nano ansible.cfg
上記のように、開発環境をデフォルトのインベントリとして設定することをお勧めします。 含まれているhostsファイルではなく、環境ディレクトリ全体を選択する方法に注目してください。
[defaults]
inventory = ./environments/dev
これで、デフォルトの在庫を使用せずに使用できるようになります。 -i
オプション。 デフォルト以外の在庫は、引き続き使用する必要があります -i
、偶発的な変更からそれらを保護するのに役立ちます。
結論
この記事では、Ansibleが複数の環境でホストを管理するために提供する柔軟性について説明しました。 これにより、ホストが複数のグループのメンバーである場合に、ユーザーは変数の優先順位を処理するためのさまざまな戦略を採用できますが、あいまいさや公式の方向性の欠如は難しい場合があります。 他のテクノロジーと同様に、組織に最適なものは、ユースケースと要件の複雑さによって異なります。 ニーズに合った戦略を見つける最良の方法は、実験することです。 以下のコメントでユースケースとアプローチを共有してください。