こんにちはこんにちは。
サイバーエージェント24卒の近藤です。普段はプライベートクラウドのIaaS周りの開発・運用をしています。
Ansible Advent Calendar 2024 14日目の記事ということで、私が自宅クラウドのOpenStackを構築するのに使っているAnsibleを題材にして、Ansibleの基本的な使い方について紹介したいと思います。
業務で使っているものとは何の関係もないので、これをこのまま本番環境で使える、みたいなものではないのす。ご注意ください。
目次
- Ansibleのディレクトリ構成
- Inventoryファイルの解説
-
各コンポーネントの構築手順
- データベースノード
- コントローラノード
- コンピュートノード
- まとめ
- 参考資料
1. Ansibleのディレクトリ構成
以下が本記事で使用するAnsibleのディレクトリ構成です。
全てのソースコードを見たい方はこちらからどうぞ。
諸事情によりprivate repoにしました。
なおOpenStackにはちゃんと公式のAnsible Playbookもありますが、今回は自分で作ってみたかったため作りました。
.
├── compute.yml
├── controller.yml
├── database.yml
├── inventory.yml
├── requirements.txt
├── roles
│ ├── common
│ │ └── tasks
│ │ └── main.yml
│ ├── compute
│ │ ├── files
│ │ │ └── chrony.conf
│ │ ├── handlers
│ │ │ └── main.yml
│ │ ├── tasks
│ │ │ ├── main.yml
│ │ │ ├── neutron.yml
│ │ │ ├── nova.yml
│ │ │ └── ntp.yml
│ │ └── templates
│ │ ├── neutron.conf.j2
│ │ ├── nova-compute.conf.j2
│ │ ├── nova.conf.j2
│ │ └── openvswitch_agent.ini.j2
│ ├── controller
│ │ ├── files
│ │ │ ├── apache2.conf
│ │ │ ├── apache2_openstack_dashboard.conf
│ │ │ ├── dhcp_agent.ini
│ │ │ ├── horizon_local_settings.py
│ │ │ └── ml2_conf.ini
│ │ ├── handlers
│ │ │ └── main.yml
│ │ ├── tasks
│ │ │ ├── cinder.yml
│ │ │ ├── etcd.yml
│ │ │ ├── glance.yml
│ │ │ ├── horizon.yml
│ │ │ ├── keystone.yml
│ │ │ ├── main.yml
│ │ │ ├── memcached.yml
│ │ │ ├── neutron.yml
│ │ │ ├── nova.yml
│ │ │ ├── ntp.yml
│ │ │ ├── placement.yml
│ │ │ └── rabbitmq.yml
│ │ └── templates
│ │ ├── chrony.conf.j2
│ │ ├── cinder.conf.j2
│ │ ├── etcd.j2
│ │ ├── glance-api.conf.j2
│ │ ├── keystone.conf.j2
│ │ ├── memcached.conf.j2
│ │ ├── metadata_agent.ini.j2
│ │ ├── neutron.conf.j2
│ │ ├── nova.conf.j2
│ │ ├── openvswitch_agent.ini.j2
│ │ └── placement.conf.j2
│ ├── database
│ │ ├── handlers
│ │ │ └── main.yml
│ │ ├── tasks
│ │ │ ├── create_user.yml
│ │ │ ├── main.yml
│ │ │ └── secure_installation.yml
│ │ └── templates
│ │ └── 99-openstack.cnf.j2
│ └── openstack
│ └── tasks
│ └── main.yml
└── vars
├── credentials.yml
└── vars.yml
エントリポイントとなるplaybook
- database.yml: データベースノードの構築
- controller.yml: コントローラノードの構築
- compute.yml: コンピュートノードの構築
インベントリファイル
- inventory.yml: 対象ノードのIPアドレスやパラメータを定義
各コンポーネントのplaybook
- roles/common: 全ノード共通設定のplaybook
- roles/openstack: OpenStackノード共通設定のplaybook
- roles/database: データベースノードのplaybook
- roles/controller: コントローラノードのplaybook
- roles/compute: コンピュートノードのplaybook
変数ファイル
- vars/vars.yml: 変数ファイル
- vars/credentials.yml: センシティブな変数ファイル
2. インベントリファイルの解説
Ansibleでは、インベントリファイルに構築対象ノードのIPアドレスやパラメータを定義します。
今回用いたinventory.ymlファイルの中身は以下の様になっています。
all:
children:
databases:
controllers:
computes:
vars:
ansible_user: admin
openstack:
children:
controllers:
computes:
databases:
hosts:
master01:
ansible_host: 192.168.1.101
controllers:
hosts:
master01:
ansible_host: 192.168.1.101
provider_interface: eth0
computes:
hosts:
worker01:
ansible_host: 192.168.1.102
provider_interface: enx68e1dcc5f7fa
worker02:
ansible_host: 192.168.1.103
provider_interface: enp5s0f0
- all
- 全てのノードを含むグループ
- vars.ansible_user
- Ansibleでssh接続するユーザー名を一括で設定
- openstack
- OpenStack関連のノードを含むグループ
- databases
- データベースノードを含むグループ
- 今回はcontrollerと同居する構成
- controllers
- OpenStackの主要コンポーネントを動作させるコントローラノードを含むグループ
- master01の単一コントローラ構成
-
provider_interface
変数を定義してPlaybook内で使用
- computes
- VMを起動するコンピュートノードを含むグループ
- worker01, worker02の2台のハイパーバイザを使用
-
provider_interface
変数を定義してPlaybook内で使用
3. 各コンポーネントの構築手順
3.1 データベースノード
データベースノードを構築するPlaybookのエントリポイントのdatebase.ymlは以下の様になっています。
- hosts: databases
become: yes
roles:
- database
vars_files:
- ./vars/vars.yml
- ./vars/credentials.yml
ここで database
roleを指定することで、roles/database/tasks/main.yml
が実行されます。
roles/database/tasks/main.yml
では、以下のようなタスクを実行します。
---
- name: install_database
ansible.builtin.apt:
name: mariadb-server
- name: start_database
ansible.builtin.service:
name: mariadb
state: started
enabled: true
- name: install_python_mysql_package
ansible.builtin.apt:
name: python3-pymysql
- name: put_config
ansible.builtin.template:
src: ./99-openstack.cnf.j2
dest: /etc/mysql/mariadb.conf.d/99-openstack.cnf
owner: root
group: root
mode: '644'
notify: restart_database
- name: secure_installation
ansible.builtin.include_tasks:
file: secure_installation.yml
- name: create_viewer_user
community.mysql.mysql_user:
login_user: root
login_unix_socket: /run/mysqld/mysqld.sock
name: viewer
host: "{{ item }}"
password: "{{ database_viewer_pass }}"
priv: '*.*:SELECT'
loop:
- localhost
- '%'
run_once: true
- name: create_openstack_dbs
community.mysql.mysql_db:
name: "{{ item }}"
login_unix_socket: /run/mysqld/mysqld.sock
loop:
- keystone
- glance
- placement
- nova_api
- nova
- nova_cell0
- neutron
- cinder
run_once: true
- name: create_openstack_db_users
ansible.builtin.include_tasks:
file: create_user.yml
with_items:
- { user: 'keystone', dbs: ['keystone'], pass: "{{ database_keystone_pass }}" }
- { user: 'glance', dbs: ['glance'], pass: "{{ database_glance_pass }}" }
- { user: 'placement', dbs: ['placement'], pass: "{{ database_placement_pass }}" }
- { user: 'nova', dbs: ['nova_api', 'nova', 'nova_cell0'], pass: "{{ database_nova_pass }}" }
- { user: 'neutron', dbs: ['neutron'], pass: "{{ database_neutron_pass }}" }
- { user: 'cinder', dbs: ['cinder'], pass: "{{ database_cinder_pass }}" }
loop_control:
loop_var: outer_item
run_once: true
1つずつ説明していきましょう。
以下は ansible.builtin.apt
モジュールを使用して、mariadb-serverのaptパッケージをインストールしています。
sudo apt intsall mariadb-server
みたいなもんですね。
以降、同じ様なパッケージのインストールについては説明を省略します。
- name: install_database
ansible.builtin.apt:
name: mariadb-server
以下は ansible.builtint.service
モジュールを使用して、systemdのmariadbi.serviceを起動&登録しています。
sudo systemctl enabled --now mariadb
に相当します。
こちらも同じ様なタスクが今後も出てくるため、以降は説明を省略します。
- name: start_database
ansible.builtin.service:
name: mariadb
state: started
enabled: true
以下は ansible.builtin.template
モジュールを使用して、mariadbの設定ファイルを投入しています。
- name: put_config
ansible.builtin.template:
src: ./99-openstack.cnf.j2
dest: /etc/mysql/mariadb.conf.d/99-openstack.cnf
owner: root
group: root
mode: '644'
notify: restart_database
テンプレートの 99-openstack.cnf.j2
は roles/database/templates/99-openstack.cnf.j2
に格納されています。
{{ ansible_host }}
の様に {{ }}
で囲まれた変数は、 vars/vars.yml
に定義された変数を参照し、templateモジュールによって埋め込むことができます。
[mysqld]
bind-address = {{ ansible_host }}
default-storage-engine = innodb
innodb_file_per_table = on
max_connections = 4096
collation-server = utf8_general_ci
character-set-server = utf8
また、上記タスクでは notify: restart_database
という記述により、もしこのタスクが実行されたならば全タスクの完了後に restart_database
というハンドラを呼び出します。
ハンドラの記述は roles/database/handlers/main.yml
にあります。
---
- name: restart_database
ansible.builtin.service:
name: mariadb
state: restarted
上記の仕組みにより、設定ファイルが変更された時のみその設定を反映するためにmariadbを再起動するというフローを実現することができます。
続いて以下は ansible.builtin.include_tasks
モジュールを使用して、別ファイルのタスクをインクルードし、mariadbのsecure_installation相当の処理を実行しています。
- name: secure_installation
ansible.builtin.include_tasks:
file: secure_installation.yml
インクルードされるタスクファイルは roles/database/tasks/secure_installation.yml
に格納されています。
secure_installation タスクでは、community.mysql
モジュールを使用して、rootユーザーのパスワード設定や不要なユーザーの削除、不要なデータベースの削除を行います。
database_root_pass
は vars/credentials.yml
に定義されたセンシティブな変数です。以降も同じ様な変数が度々登場します(パスワードとか)。
---
- name: set_root_pass
community.mysql.mysql_user:
login_user: root
login_unix_socket: /run/mysqld/mysqld.sock
name: root
host_all: true
password: "{{ database_root_pass }}"
- name: disable_remote_root_login
community.mysql.mysql_user:
login_user: root
login_unix_socket: /run/mysqld/mysqld.sock
name: root
host: "{{ ansible_fqdn | lower }}"
state: absent
- name: remove_anonymous_users
community.mysql.mysql_user:
login_user: root
login_unix_socket: /run/mysqld/mysqld.sock
name: ''
host_all: true
state: absent
- name: remove_test_database
mysql_db:
login_user: root
login_unix_socket: /run/mysqld/mysqld.sock
db: test
state: absent
以下は community.mysql.mysql_user
モジュールを使用して、運用時に使うread onlyのviewerユーザーを作成し、SELECT権限を付与しています。
ここでは loop
ディレクティブを使用して、localhostと全てのホスト(%
(に対して同じ設定を適用しています。
この様にすることで同じ様なタスクを重複した記述なく実行することができます。
- name: create_viewer_user
community.mysql.mysql_user:
login_user: root
login_unix_socket: /run/mysqld/mysqld.sock
name: viewer
host: "{{ item }}"
password: "{{ database_viewer_pass }}"
priv: '*.*:SELECT'
loop:
- localhost
- '%'
run_once: true
以下は community.mysql.mysql_db
モジュールを使用して、OpenStackの各コンポーネント用のデータベースを作成しています。
- name: create_openstack_dbs
community.mysql.mysql_db:
name: "{{ item }}"
login_unix_socket: /run/mysqld/mysqld.sock
loop:
- keystone
- glance
- placement
- nova_api
- nova
- nova_cell0
- neutron
- cinder
run_once: true
最後に以下は、viewerユーザと同じように、OpenStackの各コンポーネント用のユーザを作成しています。
- name: create_openstack_db_users
ansible.builtin.include_tasks:
file: create_user.yml
with_items:
- { user: 'keystone', dbs: ['keystone'], pass: "{{ database_keystone_pass }}" }
- { user: 'glance', dbs: ['glance'], pass: "{{ database_glance_pass }}" }
- { user: 'placement', dbs: ['placement'], pass: "{{ database_placement_pass }}" }
- { user: 'nova', dbs: ['nova_api', 'nova', 'nova_cell0'], pass: "{{ database_nova_pass }}" }
- { user: 'neutron', dbs: ['neutron'], pass: "{{ database_neutron_pass }}" }
- { user: 'cinder', dbs: ['cinder'], pass: "{{ database_cinder_pass }}" }
loop_control:
loop_var: outer_item
run_once: true
ここでインクルードしている create_user.yml
は以下の様になっています。
---
- name: create_user
community.mysql.mysql_user:
login_user: root
login_unix_socket: /run/mysqld/mysqld.sock
name: "{{ outer_item['user'] }}"
host: "{{ item }}"
password: "{{ outer_item['pass'] }}"
priv: "{{ outer_item['dbs'] | map('regex_replace', '(.+)', '\\1.*:ALL') | join ('/') }}"
loop:
- localhost
- "%"
タスクをインクルードするときに loop_control.loop_var: outer_item
とすることで、with_items
で渡した変数をインクルードされるタスク内で outer_item
として参照することができます。
3.2 コントローラノード
OpenStackのコントローラノードを構築するPlaybookのエントリポイントのcontroller.ymlは以下の様になっています。
コントローラノードには、common, openstack, controllerの3つのroleを指定し、全ノード共通の設定、OpenStack用の設定、そしてOpenStackのコントローラノード構築の設定を行います。
- hosts: controllers
become: yes
roles:
- common
- openstack
- controller
vars_files:
- ./vars/vars.yml
- ./vars/credentials.yml
environment:
OS_PROJECT_DOMAIN_NAME: Default
OS_USER_DOMAIN_NAME: Default
OS_PROJECT_NAME: admin
OS_USERNAME: admin
OS_PASSWORD: "{{ openstack_admin_pass }}"
OS_AUTH_URL: http://controller:5000/v3
OS_IDENTITY_API_VERSION: 3
OS_IMAGE_API_VERSION: 2
OpenStack用の設定をするタスク roles/openstack/tasks/main.yml
は以下の様になっています。
---
- name: install_ubuntu_cloud_keyring
ansible.builtin.apt:
name: ubuntu-cloud-keyring
- name: add_cloud_archive_repo
ansible.builtin.apt_repository:
repo: deb http://ubuntu-cloud.archive.canonical.com/ubuntu {{ ansible_distribution_release }}-updates/dalmatian main
- name: install_packages
ansible.builtin.apt:
name: "{{ item }}"
loop:
- software-properties-common
- cpu-checker
- bridge-utils
- vlan
- libvirt-clients
- zip
- python3-openstackclient
- name: load_kernel_modules
community.general.modprobe:
name: "{{ item.name }}"
params: "{{ item.params | default('') }}"
persistent: 'present'
loop:
- { 'name': 'bridge' }
- { 'name': 'br_netfilter' }
- { 'name': '8021q' }
- { 'name': 'vhost_net' }
- name: disable_iptables_for_bridge
ansible.posix.sysctl:
name: "{{ item }}"
value: '0'
loop:
- net.bridge.bridge-nf-call-arptables
- net.bridge.bridge-nf-call-ip6tables
- net.bridge.bridge-nf-call-iptables
以下は ansible.builtin.apt
, ansible.builtin.apt_repository
モジュールを使用して、ubuntu-cloud-keyringパッケージをインストールし、OpenStackのリポジトリを追加しています。
OpenStack公式のInstallation GuideにはUbuntu Nobleでのリポジトリの追加方法が書いていなかったため、Server Worldの記事 を参考にさせていただきました。ありがとうございます。
- name: install_ubuntu_cloud_keyring
ansible.builtin.apt:
name: ubuntu-cloud-keyring
- name: add_cloud_archive_repo
ansible.builtin.apt_repository:
repo: deb http://ubuntu-cloud.archive.canonical.com/ubuntu {{ ansible_distribution_release }}-updates/dalmatian main
以下は community.general.modprobe
モジュールを使用して、OpenStackを動かすのに必要なカーネルモジュールをロードしています。
- name: load_kernel_modules
community.general.modprobe:
name: "{{ item.name }}"
params: "{{ item.params | default('') }}"
persistent: 'present'
loop:
- { 'name': 'bridge' }
- { 'name': 'br_netfilter' }
- { 'name': '8021q' }
- { 'name': 'vhost_net' }
以下は ansible.posix.sysctl
モジュールを使用して、Installation Guideに書いてある通りにiptables周りの設定を無効化しています。
- name: disable_iptables_for_bridge
ansible.posix.sysctl:
name: "{{ item }}"
value: '0'
loop:
- net.bridge.bridge-nf-call-arptables
- net.bridge.bridge-nf-call-ip6tables
- net.bridge.bridge-nf-call-iptables
以下は roles/controller/tasks/main.yml
に記述された、コントローラノード構築用のタスクの一覧です。
---
- name: setup_ntp
ansible.builtin.include_tasks:
file: ntp.yml
- name: setup_rabbitmq
ansible.builtin.include_tasks:
file: rabbitmq.yml
- name: setup_memcached
ansible.builtin.include_tasks:
file: memcached.yml
- name: setup_etcd
ansible.builtin.include_tasks:
file: etcd.yml
- name: setup_keystone
ansible.builtin.include_tasks:
file: keystone.yml
- name: setup_glance
ansible.builtin.include_tasks:
file: glance.yml
- name: setup_placement
ansible.builtin.include_tasks:
file: placement.yml
- name: setup_nova
ansible.builtin.include_tasks:
file: nova.yml
- name: setup_neutron
ansible.builtin.include_tasks:
file: neutron.yml
- name: setup_horizon
ansible.builtin.include_tasks:
file: horizon.yml
ntp
setup_ntpタスクの内容は以下の様になっており、chronyのインストールと設定ファイルの配置を行なっています。
---
- name: install_chrony
ansible.builtin.apt:
name: chrony
- name: start_chrony
ansible.builtin.service:
name: chrony
state: started
enabled: true
- name: put_chrony_config
ansible.builtin.template:
src: ./chrony.conf.j2
dest: /etc/chrony/chrony.conf
owner: root
group: root
mode: '644'
notify: restart_chrony
rabbitmq
setup_rabbitmqタスクの内容は以下の様になっており、rabbitmq-serverのインストールと設定を行なっています。
ここでは community.rabbitmq.rabbitmq_user
モジュールを使用して、OpenStack用のユーザを作成しています。
この様に既存のモジュールを使用して楽に設定をすることができるのがAnsibleの強みです。
---
- name: install_rabbitmq
ansible.builtin.apt:
name: rabbitmq-server
- name: start_rabbitmq
ansible.builtin.service:
name: rabbitmq-server
state: started
enabled: true
- name: create_openstack_user
community.rabbitmq.rabbitmq_user:
user: openstack
password: "{{ rabbitmq_pass }}"
configure_priv: .*
read_priv: .*
write_priv: .*
run_once: true
memcached
setup_memcachedタスクの内容は以下の様になっており、memcachedのインストールと設定を行なっています。
なんか同じ様なのばっかですね、、、
---
- name: install_memcached
ansible.builtin.apt:
name: memcached
- name: install_python_memcached_package
ansible.builtin.apt:
name: python3-memcache
- name: start_memcached
ansible.builtin.service:
name: memcached
state: started
enabled: true
- name: put_memcached_config
ansible.builtin.template:
src: ./memcached.conf.j2
dest: /etc/memcached.conf
owner: root
group: root
mode: '644'
notify: restart_memcached
etcd
setup_etcdタスクの内容は以下の様になっており、etcdのインストールと設定を行なっています。
---
- name: install_etcd
ansible.builtin.apt:
name: etcd-server
- name: start_etcd
ansible.builtin.service:
name: etcd
state: started
enabled: true
- name: put_etcd_config
ansible.builtin.template:
src: ./etcd.j2
dest: /etc/default/etcd
owner: root
group: root
mode: '644'
notify: restart_etcd
Keystone
さてここからはOpenStackコンポーネントの設定を行っていきます。
setup_keystoneタスクの内容は以下の様になっており、Keystoneのインストールと設定を行なっています。
---
- name: install_keystone
ansible.builtin.apt:
name: keystone
- name: put_keystone_config
ansible.builtin.template:
src: ./keystone.conf.j2
dest: /etc/keystone/keystone.conf
owner: root
group: root
mode: '644'
- name: check_db_sync
ansible.builtin.command:
cmd: keystone-manage db_sync --check
register: check_db_sync
failed_when: check_db_sync.rc == 1
changed_when: check_db_sync.rc != 0
run_once: true
- name: run_db_sync
ansible.builtin.command:
cmd: su -s /bin/sh -c "keystone-manage db_sync" keystone
when: check_db_sync.changed
run_once: true
- name: run_fernet_setup
ansible.builtin.command:
cmd: keystone-manage fernet_setup --keystone-user keystone --keystone-group keystone
when: check_db_sync.changed
run_once: true
- name: run_credential_setup
ansible.builtin.command:
cmd: keystone-manage credential_setup --keystone-user keystone --keystone-group keystone
when: check_db_sync.changed
run_once: true
- name: run_bootstrap
ansible.builtin.command:
cmd: >
keystone-manage bootstrap --bootstrap-password "{{ openstack_admin_pass }}"
--bootstrap-admin-url http://controller:5000/v3/
--bootstrap-internal-url http://controller:5000/v3/
--bootstrap-public-url http://controller:5000/v3/
--bootstrap-region-id RegionOne
changed_when: false
run_once: true
- name: put_apache2_config
ansible.builtin.copy:
src: ./apache2.conf
dest: /etc/apache2/apache2.conf
owner: root
group: root
mode: '644'
notify: restart_apache2
以下は ansible.builtin.command
モジュールを使用して、Keystoneのデータベースの構築を行います。
shellでコマンドを実行する様なイメージです。
register
によって、このタスクの結果を後から参照することができます。
また、failed_when
、changed_when
によってこのタスクが失敗した、実行されたとみなされる条件を定義しています。
ansible.builtin.command
モジュールはデフォルトではコマンドのステータスコードが0かどうかしか確認しないため、実際に実行するコマンドによってカスタマイズすることが必要です。
また、run_once
を定義することによって、もしコントローラノードが複数あった際にもこのタスクは一回しか実行されません。
- name: check_db_sync
ansible.builtin.command:
cmd: keystone-manage db_sync --check
register: check_db_sync
failed_when: check_db_sync.rc == 1
changed_when: check_db_sync.rc != 0
run_once: true
続く以下のタスクでは、先ほどのタスクの結果を参照し、先ほどのタスクが実行されていた場合のみ実行する様に制御しています。
これは when
ディレクティブで check_db_sync.changed
を参照することで実現しています。
- name: run_fernet_setup
ansible.builtin.command:
cmd: keystone-manage fernet_setup --keystone-user keystone --keystone-group keystone
when: check_db_sync.changed
run_once: true
- name: run_credential_setup
ansible.builtin.command:
cmd: keystone-manage credential_setup --keystone-user keystone --keystone-group keystone
when: check_db_sync.changed
run_once: true
Glance
以下は OpenStackのVMディスクイメージ管理コンポーネントのGlanceを構築します。
---
- name: create_glacne_user
openstack.cloud.identity_user:
name: glance
password: "{{ openstack_glance_pass }}"
domain: default
- name: add_admin_role_to_glance
openstack.cloud.role_assignment:
user: glance
role: admin
project: service
- name: add_glance_service
openstack.cloud.catalog_service:
name: glance
type: image
description: OpenStack Image
- name: create_endpoints
openstack.cloud.endpoint:
service: glance
endpoint_interface: "{{ item }}"
url: http://controller:9292
region: RegionOne
loop:
- public
- internal
- admin
register: endpoints
- name: install_glance
ansible.builtin.apt:
name: glance
- name: put_glance_config
ansible.builtin.template:
src: ./glance-api.conf.j2
dest: /etc/glance/glance-api.conf
owner: root
group: root
mode: '644'
vars:
glance_public_endpoint: "{{ endpoints['results'][0]['endpoint']['id'] }}"
notify: restart_glance_api
- name: add_reader_role_to_glance
openstack.cloud.role_assignment:
user: glance
domain: Default
system: all
role: reader
- name: run_db_sync
ansible.builtin.command:
cmd: su -s /bin/sh -c "glance-manage db_sync" glance
changed_when: false
run_once: true
ここでは openstack.cloud
モジュールを使用し、OpenStackのサービスユーザ作成や権限の設定とその他諸々をします。
ここでもエコシステムの恩恵に預かり楽をすることができます。素晴らしいですね。
- name: create_glacne_user
openstack.cloud.identity_user:
name: glance
password: "{{ openstack_glance_pass }}"
domain: default
- name: add_admin_role_to_glance
openstack.cloud.role_assignment:
user: glance
role: admin
project: service
- name: add_glance_service
openstack.cloud.catalog_service:
name: glance
type: image
description: OpenStack Image
- name: create_endpoints
openstack.cloud.endpoint:
service: glance
endpoint_interface: "{{ item }}"
url: http://controller:9292
region: RegionOne
loop:
- public
- internal
- admin
register: endpoints
Placement
以下は OpenStackのリソース管理コンポーネントのPlacementを構築します。
Glanceとほとんど同じ様なタスクで特に説明することもないので詳細は割愛します。
---
- name: create_placement_user
openstack.cloud.identity_user:
name: placement
password: "{{ openstack_placement_pass }}"
domain: default
- name: add_admin_role_to_placement
openstack.cloud.role_assignment:
user: placement
role: admin
project: service
- name: add_placement_service
openstack.cloud.catalog_service:
name: placement
type: placement
description: Placement API
- name: create_endpoints
openstack.cloud.endpoint:
service: placement
endpoint_interface: "{{ item }}"
url: http://controller:8778
region: RegionOne
loop:
- public
- internal
- admin
- name: install_placement
ansible.builtin.apt:
name: placement-api
- name: put_placement_config
ansible.builtin.template:
src: ./placement.conf.j2
dest: /etc/placement/placement.conf
owner: root
group: root
mode: '644'
notify: restart_apache2
- name: run_db_sync
ansible.builtin.command:
cmd: su -s /bin/sh -c "placement-manage db sync" placement
changed_when: false
run_once: true
Nova
以下は OpenStackでの仮想マシン管理コンポーネントのNovaを構築します。
---
- name: create_nova_user
openstack.cloud.identity_user:
name: nova
password: "{{ openstack_nova_pass }}"
domain: default
- name: add_admin_role_to_nova
openstack.cloud.role_assignment:
user: nova
role: admin
project: service
- name: add_nova_service
openstack.cloud.catalog_service:
name: nova
type: compute
description: OpenStack Compute
- name: create_endpoints
openstack.cloud.endpoint:
service: nova
endpoint_interface: "{{ item }}"
url: http://controller:8774/v2.1
region: RegionOne
loop:
- public
- internal
- admin
- name: install_nova_packages
ansible.builtin.apt:
name: "{{ item }}"
loop:
- nova-api
- nova-conductor
- nova-novncproxy
- nova-scheduler
- name: put_nova_config
ansible.builtin.template:
src: ./nova.conf.j2
dest: /etc/nova/nova.conf
owner: root
group: root
mode: '644'
notify: restart_nova
- name: run_api_db_sync
ansible.builtin.command:
cmd: su -s /bin/sh -c "nova-manage api_db sync" nova
changed_when: false
run_once: true
- name: list_nova_cells
ansible.builtin.command:
cmd: su -s /bin/sh -c "nova-manage cell_v2 list_cells" nova
changed_when: false
register: cell_list
- name: setl_cell_facts
set_fact:
cell0_record: '{{ cell_list.stdout_lines | select("regex", "[0-]{36}") }}'
cell1_record: '{{ cell_list.stdout_lines | select("regex", " cell1 ") }}'
- name: run_map_cell0
ansible.builtin.command:
cmd: su -s /bin/sh -c "nova-manage cell_v2 map_cell0" nova
when: not cell0_record
- name: run_create_cell1
ansible.builtin.command:
cmd: su -s /bin/sh -c "nova-manage cell_v2 create_cell --name=cell1 --verbose" nova
when: not cell1_record
- name: run_db_sync
ansible.builtin.command:
cmd: su -s /bin/sh -c "nova-manage db sync" nova
changed_when: false
特筆すべきことでいうとこちらのset_factを利用したタスク実行の制御ですかね。
list_nova_cells
タスクの出力に対して正規表現で一致したものがあれば、すでに作成したいリソースが作成されていると判断して後続のタスクをスキップする様にしています。
ここら辺の処理は悔しいですが本家のopenstack-ansibleをめっちゃ参考にしました。
- name: list_nova_cells
ansible.builtin.command:
cmd: su -s /bin/sh -c "nova-manage cell_v2 list_cells" nova
changed_when: false
register: cell_list
- name: setl_cell_facts
set_fact:
cell0_record: '{{ cell_list.stdout_lines | select("regex", "[0-]{36}") }}'
cell1_record: '{{ cell_list.stdout_lines | select("regex", " cell1 ") }}'
- name: run_map_cell0
ansible.builtin.command:
cmd: su -s /bin/sh -c "nova-manage cell_v2 map_cell0" nova
when: not cell0_record
- name: run_create_cell1
ansible.builtin.command:
cmd: su -s /bin/sh -c "nova-manage cell_v2 create_cell --name=cell1 --verbose" nova
when: not cell1_record
Neutron
以下は OpenStackのネットワーク管理コンポーネントのNeutronを構築します。
---
- name: create_neutron_user
openstack.cloud.identity_user:
name: neutron
password: "{{ openstack_neutron_pass }}"
domain: default
- name: add_admin_role_to_neutron
openstack.cloud.role_assignment:
user: neutron
role: admin
project: service
- name: add_neutron_service
openstack.cloud.catalog_service:
name: neutron
type: network
description: OpenStack Networking
- name: create_endpoints
openstack.cloud.endpoint:
service: neutron
endpoint_interface: "{{ item }}"
url: http://controller:9696
region: RegionOne
loop:
- public
- internal
- admin
- name: install_neutron_packages
ansible.builtin.apt:
name: "{{ item }}"
loop:
- neutron-server
- neutron-plugin-ml2
- neutron-openvswitch-agent
- neutron-dhcp-agent
- neutron-metadata-agent
- name: create_br_provider
openvswitch.openvswitch.openvswitch_bridge:
bridge: br-provider
fail_mode: secure
- name: create_br_provider_port
openvswitch.openvswitch.openvswitch_port:
bridge: br-provider
port: "{{ provider_interface }}"
- name: put_neutron_config_templates
ansible.builtin.template:
src: "{{ item.src }}"
dest: "{{ item.dest }}"
owner: root
group: root
mode: '644'
notify: restart_neutron
loop:
- { src: './neutron.conf.j2', dest: '/etc/neutron/neutron.conf' }
- { src: './openvswitch_agent.ini.j2', dest: '/etc/neutron/plugins/ml2/openvswitch_agent.ini' }
- { src: './metadata_agent.ini.j2', dest: '/etc/neutron/metadata_agent.ini' }
- name: put_neutron_config_files
ansible.builtin.copy:
src: "{{ item.src }}"
dest: "{{ item.dest }}"
owner: root
group: root
mode: '644'
notify: restart_neutron
loop:
- { src: './ml2_conf.ini', dest: '/etc/neutron/plugins/ml2/ml2_conf.ini' }
- { src: './dhcp_agent.ini', dest: '/etc/neutron/dhcp_agent.ini' }
- name: populate_neutron_db
ansible.builtin.command:
cmd: >
su -s /bin/sh -c "neutron-db-manage \
--config-file /etc/neutron/neutron.conf \
--config-file /etc/neutron/plugins/ml2/ml2_conf.ini \
upgrade head" neutron
changed_when: false
run_once: true
Neutronの設定で特筆する所は、openvswitch.openvswitch
モジュールを使ってノードのovsの設定をいじっている所です。
以下は openvswitch.openvswitch.openvswitch_bridge
モジュールを使用して、br-providerという外部ネットワーク用のインターフェースにつながるbridgeを作成しています。
- name: create_br_provider
openvswitch.openvswitch.openvswitch_bridge:
bridge: br-provider
fail_mode: secure
以下は openvswitch.openvswitch.openvswitch_port
モジュールを使用して、br-providerに外部ネットワーク用のインターフェースを接続しています。
ここで接続するインターフェースはノードごとに異なるので、インベントリファイルで指定したインターフェース名を使用して指定します。
ノードのネットワーク設定でMacアドレス指定でインターフェース名を書き換えて、全ノードでインターフェース名を揃えるのでもいいかもしれないですね。
- name: create_br_provider_port
openvswitch.openvswitch.openvswitch_port:
bridge: br-provider
port: "{{ provider_interface }}"
Horizon
以下は OpenStackのダッシュボードコンポーネントのHorizonを構築します。
こちらは特に目新しいものはなく、パッケージをインストールして設定ファイルを置き、サービスを再起動する、といった感じです。
---
- name: install_horizon
ansible.builtin.apt:
name: openstack-dashboard
- name: put_horizon_config
ansible.builtin.copy:
src: ./horizon_local_settings.py
dest: /etc/openstack-dashboard/local_settings.py
owner: root
group: root
mode: '644'
notify: reload_apache2
- name: put_apache2_config
ansible.builtin.copy:
src: ./apache2_openstack_dashboard.conf
dest: /etc/apache2/conf-available/openstack-dashboard.conf
owner: root
group: root
mode: '644'
notify: reload_apache2
3.3 コンピュートノード
OpenStackのコンピュートノードを構築するPlaybookのエントリポイントのcompute.ymlは以下の様になっています。
コンピュートノードには、common, openstack, computeの3つのroleを指定し、全ノード共通の設定、OpenStack用の設定、そしてOpenStackのコンピュートノード構築の設定を行います。
- hosts: computes
become: yes
roles:
- common
- openstack
- compute
vars_files:
- ./vars/vars.yml
- ./vars/credentials.yml
environment:
OS_PROJECT_DOMAIN_NAME: Default
OS_USER_DOMAIN_NAME: Default
OS_PROJECT_NAME: admin
OS_USERNAME: admin
OS_PASSWORD: "{{ openstack_admin_pass }}"
OS_AUTH_URL: http://controller:5000/v3
OS_IDENTITY_API_VERSION: 3
OS_IMAGE_API_VERSION:
以下は roles/compute/tasks/main.yml
に記述されたタスクの一覧です。
ntpについてはコントローラノードと大差ないため、ここでは説明を省略します。
---
- name: setup_ntp
ansible.builtin.include_tasks:
file: ntp.yml
- name: setup_nova
ansible.builtin.include_tasks:
file: nova.yml
- name: setup_neutron
ansible.builtin.include_tasks:
file: neutron.yml
Nova
以下は コンピュートノード上で動作し実際に仮想マシンの作成等を行うnova-computeを構築します。
特筆すべきところとして、ここでも既存の community.libvirt
モジュールを使用して、libvirtの設定を行っています。
libvirtはインストールするとデフォルトで default
という名前のネットワークを作成しますが、OpenStackではこのネットワークを使わないため、変な競合が起こらないようにこのネットワークを削除しています。
---
- name: install_packages
ansible.builtin.apt:
name: "{{ item }}"
loop:
- nova-compute
- seabios
- name: disable_libvirt_default_network
community.libvirt.virt_net:
name: default
state: absent
autostart: false
- name: put_nova_config
ansible.builtin.template:
src: "{{ item.src }}"
dest: "{{ item.dest }}"
owner: root
group: root
mode: '644'
notify: restart_nova
loop:
- { src: './nova.conf.j2', dest: '/etc/nova/nova.conf' }
- { src: './nova-compute.conf.j2', dest: '/etc/nova/nova-compute.conf' }
Neutron
以下は コンピュートノード上で動作し、実際にovsをいじって仮想マシンのネットワーク設定を行うneutron-openvswitch-agentを構築します。
コンピュートノードでもコントローラノードと同じように、openvswitch.openvswitch
モジュールを使用してovsのbridgeの作成と、bridgeへのインターフェースの接続を行なっています。
---
- name: install_neutron_ovs_agent
ansible.builtin.apt:
name: neutron-openvswitch-agent
- name: create_br_provider
openvswitch.openvswitch.openvswitch_bridge:
bridge: br-provider
fail_mode: secure
- name: create_br_provider_port
openvswitch.openvswitch.openvswitch_port:
bridge: br-provider
port: "{{ provider_interface }}"
- name: put_neutron_config_templates
ansible.builtin.template:
src: "{{ item.src }}"
dest: "{{ item.dest }}"
owner: root
group: root
mode: '644'
notify: restart_neutron
loop:
- { src: './neutron.conf.j2', dest: '/etc/neutron/neutron.conf' }
- { src: './openvswitch_agent.ini.j2', dest: '/etc/neutron/plugins/ml2/openvswitch_agent.ini' }
4. まとめ
この記事では、Ansibleを使用してOpenStack環境を構築する方法を解説しました。
OpenStackはコンポーネントや必要な設定が多く、毎回手動で構築するのはかなり大変です。
Ansibleの様なツールを利用することで繰り返し行う作業を自動化し、効率的にOpenStack環境を構築することができます。
最後まで読んだいただき、ありがとうございました。
5. 参考資料
- [1] 公式のopenstack-ansible
- [2] OpenStack Installation Guide
- [3] Ubuntu NobleでのOpenStack Dalmatianのインストール
-
[4] https://github.com/TOMOFUMI-KONDO/openstack-ansible- 諸事情によりprivate repoにしました。
- 諸事情によりprivate repoにしました。