Установка OpenStack | Evgenii Baburin
Главная страница Установка OpenStack
Публикация
Отменить

Установка OpenStack

OpenStack - свободная и открытая платформа для облачных вычислений. Облачные вычисления - модель предоставления широкодоступного, удобного доступа по сети к общему пулу настраиваемых вычислительных ресурсов по требованию. Эти ресурсы оперативно выделяются и освобождаются при минимальных усилиях, затрачиваемых заказчиком на организацию управления и на взаимодействие с поставщиком услуг. История релизов OpenStack размещена на странице: releases.openstack.org.

Общие сведения

Установка будет проводиться на CentOS Stream 9, устанавливаемая версия OpenStack - Yoga. Можно использовать и более свежий образ, однако в этом случае могут возникнуть ошибки из-за проблем с зависимостями и различиями в конфигурациях. Для примера достаточно использовать именно эту версию. Во многом статья основана на книге Андрея Маркелова (markelov.blogspot.com), но содержит множество поправок, касающихся более новых версий CentOS и OpenStack.

Установка всех сервисов будет производиться в Libvirt на одном физическом компьютере с ОС Fedora 42. Для корректной работы сети необходимо внести изменения в файл /etc/libvirt/network.conf:

1
firewall_backend = "iptables"

После сохранения перезагружаем демон libvirtd:

1
$ sudo systemctl restart libvirtd

Для управления используется проект OpenStackClient - единый клиент для доступа к OpenStack API. В целом, делает всё то же самое, что и утилиты каждого отдельного сервиса (nova, cinder и другие). Команда openstack help -h выводит подсказку по командам (help - в интерактивном режиме).

Инструкция по установке клиента OpenStack CLI: docs.openstack.org/newton/user-guide/common/cli-install-openstack-command-line-clients.html.

Автоматическая установка

PackStack

Общие сведения

Packstack - это утилита, которая использует модули Puppet для автоматического развёртывания различных компонентов OpenStack (дистрибутив RDO). Утилита предназначена в первую очередь для дистрибутивов RHEL и производных от него (AlmaLinux, CentOS, RockyLinux и другие). Для установки использует специальный файл ответов, в котором содержится множество настроек устанавливаемого образа. При перезапуске команды packstack обновит параметры в соответствии с этим файлом.

Подробная инструкция на странице rdoproject.org/deploy/packstack/.

Подготовка к установке

Перед установкой PackStack сервер необходимо подготовить. Для начала обновляем пакеты и добавляем репозиторий CRB:

1
2
$ sudo yum update -y
$ sudo dnf config-manager --enable crb

Отключаем SELinux и брандмауэр:

1
2
$ sudo setenforce 0
$ sudo systemctl stop firewalld.service; sudo systemctl disable firewalld.service 

Проверяем доступные версии OpenStack:

1
$ sudo dnf search centos-release-openstack

Для примера PackStack устанавливаем OpenStack Yoga. Добавляем его репозиторий и устанавливаем PackStacl:

1
2
$ sudo yum -y install centos-release-openstack-yoga.noarch
$ sudo dnf install -y openstack-packstack

Установка PackStack

PackStack предлагает два метода установки OpenStack: “всё в одном” с использованием стандартных параметров и установку с помощью заранее подготовленного файла ответов.

Для первого метода достаточно выполнить команду:

1
$ packstack --allinone

Установка вторым методом производится из под пользователя root, поэтому при установке на несколько серверов необходимо временно предоставить подключение к пользователю root по ключу без пароля.

Для начала необходимо сгенерировать файл ответов, который представляет собой специальный конфигурационный документ. В нем можно указать конкретные значения для различных параметров настройки OpenStack, что позволяет более точно настроить установку в соответствии с требованиями. Генерируется файл ответов командой:

1
$ packstack --gen-answer-file ~/packstack.txt

В самом файле packstack.txt необходимо установить минимальные параметры:

1
2
3
4
5
6
CONFIG_NEUTRON_ML2_MECHANISM_DRIVERS=openvswitch
CONFIG_NEUTRON_L2_AGENT=openvswitch

CONFIG_DEFAULT_PASSWORD=openstack
CONFIG_KEYSTONE_ADMIN_PW=openstack
CONFIG_KEYSTONE_DEMO_PW=openstack

После изменения можно запустить установку:

1
$ sudo packstack --answer-file ~/packstack.txt

После установки в домашнем каталоге создастся файл keystonerc_admin с административными доступами к OpenStack, с которым можно дальше настраивать окружение.

DevStack

Общие сведения

Этот способ предполагает установку из исходных кодов и подходит, теоретически, для любого дистрибутива.

Установка происходит следующим образом (согласно документации docs.openstack.org/devstack/latest). Создаём сервисного пользователя

1
$ sudo useradd -s /bin/bash -d /opt/stack -m stack

Добавляем созданного пользователя в sudo:

1
$ echo "stack ALL=(ALL) NOPASSWD: ALL" | sudo tee /etc/sudoers.d/stack

Устанавливаем права на каталог /opt/stack:

1
$ sudo chmod +x /opt/stack

Авторизовываемся под созданным пользователем:

1
$ sudo -u stack -i

Загружаем DevStack с Github:

1
$ git clone https://opendev.org/openstack/devstack; cd devstack

После загрузки нужно создать файл local.conf с минимальным содержимым:

1
2
3
4
5
[[local|localrc]]
ADMIN_PASSWORD=openstack
DATABASE_PASSWORD=openstack
RABBIT_PASSWORD=openstack
SERVICE_PASSWORD=openstack

Если на устройстве несколько IP, то нужно указать тот, который будет использоваться сервисами. IP обязательно должен быть доступен в выводе ip a:

1
HOST_IP=192.168.122.90

На CentOS Stream 9 установлен Python 3.9, и более свежей версии в репозиториях нет. Для установки DevStack требуется Python 3.10, поэтому в нашем случае его необходимо установить вручную (на более свежих дистрибутивах, например на Ubuntu 24.04, такой проблемы нет):

1
2
3
4
5
6
7
8
9
$ sudo dnf groupinstall 'development tools'
$ sudo dnf install wget openssl-devel bzip2-devel libffi-devel
$ sudo curl -O https://www.python.org/ftp/python/3.10.18/Python-3.10.18.tgz
$ cd Python-3.10.18/ 
$ sudo ./configure --enable-optimizations 
$ sudo make altinstall

$ python3 -V
Python 3.10.18

Запускаем установку:

1
$ ./stack.sh

В некоторых случаях от ошибок при установке поможет избавиться запуск команды установки в следующем виде:

1
$ FORCE=yes ./stack.sh

Для удаления нужно запустить скрипты:

1
$ ./unstack.sh; ./clean.sh

Ручная установка каждого компонента

Общая информация

Installation Guide для версии Yoga расположен по ссылке: docs.openstack.org/yoga/install/.

Сначала на нашем физическом устройстве создаём в Libvirt 2 новые сети:

  • private с сетью 192.168.100.0/24 - для всех виртуальных машин OpenStack (сервисная сеть);
  • public с сетью 10.100.1.0/24 - для гостевых виртуальных машин (клиентская сеть): в ней будет 1 порт для машины network и тестовая машина для проверки сети.

Всего будут создано 8 виртуальных машин (одна из них тестовая и нужна будет только для проверки “внешней” сети в самом конце):

#Виртуальная машинаАдресvCPU, RAM
1controller192.168.100.1283, 3072
2swift-proxy192.168.100.2321, 1024
3swift-storage-1192.168.100.2081, 1024
4swift-storage-2192.168.100.2091, 1024
5compute-1192.168.100.1974, 3072
6compute-2192.168.100.2134, 3072
7network192.168.100.1341, 1024
8test10.100.1.1841, 1024

На всех созданных виртуальных машинах (кроме test) необходимо выполнить общие настройки:

  1. обновляем пакеты:
    1
    
    $ sudo yum -y update
    
  2. устанавливаем hostname (где ROLE - роль сервера: controller, swift-proxy и так далее):
    1
    
    $ sudo hostnamectl set-hostname ROLE
    
  3. отключаем SELinux в файле /etc/sysconfig/selinux: SELINUX=disabled

  4. перечисляем рабочие ноды в файле /etc/hosts. Мои IP-адреса вам нужно заменить на свои:
    1
    2
    3
    4
    5
    6
    7
    8
    
    # OpenStack Nodes
    192.168.100.128    controller
    192.168.100.232    swift-proxy
    192.168.100.208    swift-storage-1
    192.168.100.209    swift-storage-2
    192.168.100.197    compute-1
    192.168.100.213    compute-2
    192.168.100.134    network
    
  5. отключаем Firewall:
    1
    
    $ sudo systemctl stop firewalld.service; sudo systemctl disable firewalld.service 
    
  6. включаем репозиторий CRB - в нём, в репозитории extras-common, предоставлены необходимые библиотеки:
    1
    
    $ sudo dnf config-manager --enable crb
    
  7. находим и добавляем репозиторий с необходимой версией OpenStack:
    1
    2
    
    $ yum search openstack
    $ sudo yum -y install centos-release-openstack-yoga.noarch
    

После подготовки серверов их нужно перезагрузить и можно приступать к установке сервисов.

RabbitMQ

RabbitMQ - брокер сообщений протокола AMQP. В нашем случае брокер будет работать на сервере controller. Устанавливается следующим образом:

1
2
3
4
$ yum search rabbitmq # поиск актуальной версии в репозиториях
$ sudo yum install -y centos-release-rabbitmq-38 # устанавливаем репозиторий
$ sudo yum install -y rabbitmq-server # устанавливаем RabbitMQ Server
$ sudo systemctl start rabbitmq-server; sudo systemctl enable rabbitmq-server # запускаем сервер

Для корректного взаимодействия с RabbitMQ Server необходимо создать пользователя (пользователь openstack с паролем openstack) и предоставить ему необходимые права:

1
2
$ sudo rabbitmqctl add_user openstack openstack
$ sudo rabbitmqctl set_permissions openstack ".*" ".*" ".*"

MariaDB

Практически все сервисы OpenStack используют базу данных. Чаще всего это - MariaDB или MySQL. Устанавливаем базу данных на controller:

1
$ sudo yum -y install mariadb-server python3-PyMySQL

Создаём конфигурационный файл /etc/my.cnf.d/openstack.cnf и заполняем его. В опции bind-address указываем адрес контроллера:

1
2
3
4
5
6
7
[mysqld]
bind-address = 192.168.100.128
default-storage-engine = innodb
innodb_file_per_table = on
max_connections = 4096
collation-server = utf8_general_ci
character-set-server = utf8

Включаем и запускаем базу данных:

1
$ sudo systemctl enable mariadb; sudo systemctl start mariadb

Запускаем скрипт mysql_secure_installation, который в том числе задаёт пароль администратора базы данных (для простоты укажем пароль openstack):

1
$ sudo mysql_secure_installation

Проверяем работу:

1
2
$ sudo mysqladmin -uroot -popenstack status
Uptime: 22  Threads: 1  Questions: 14  Slow queries: 0  Opens: 20  Open tables: 13  Queries per second avg: 0.636

Keystone

Общие сведения

Сервис идентификации Keystone представляет собой централизованный каталог пользователей и сервисов, к которым они имеют доступ. Keystone выступает в роли единой системы аутентификации и авторизации облачной операционной системы. Основной конфигурационный файл - /etc/keystone/keystone.conf. Устанавливается на сервер controller.

Установка и настройка

Устанавливаем необходимые пакеты на контроллере:

1
$ sudo yum -y install openstack-keystone python-openstackclient httpd mod_wsgi

Создаём базу данных keystone и предоставляем привилегии:

1
$ sudo mysql -u root -popenstack
1
2
3
4
CREATE DATABASE keystone;

GRANT ALL PRIVILEGES ON keystone.* TO 'keystone'@'localhost' IDENTIFIED BY 'openstack';
GRANT ALL PRIVILEGES ON keystone.* TO 'keystone'@'%' IDENTIFIED BY 'openstack';

Редактируем конфигурационный файл /etc/keystone/keystone.conf:

1
2
3
4
5
[database]
connection = mysql+pymysql://keystone:openstack@controller/keystone

[token]
provider = fernet

Инициализируем базу данных и репозиторий ключей Fernet:

1
2
3
4
$ sudo su -s /bin/sh -c "keystone-manage db_sync" keystone

$ sudo keystone-manage fernet_setup --keystone-user keystone --keystone-group keystone
$ sudo keystone-manage credential_setup --keystone-user keystone --keystone-group keystone

Keystone работает в Apache, поэтому сервер необходимо настроить. В файле /etc/httpd/conf/httpd.conf задаём имя веб-сервера:

1
ServerName controller

Создаём ссылку на стандартную конфигурацию Apache для Keystone:

1
$ sudo ln -s /usr/share/keystone/wsgi-keystone.conf /etc/httpd/conf.d

Активируем и запускаем сервер (здесь можно встретить первую ошибку, если забыть его перезагрузить после настройки :):

1
$ sudo systemctl enable httpd; sudo systemctl start httpd

Для инициализации Keystone можно пойти двумя путями: использовать рекомендованную разработчиками команду keystone-manage bootstrap, которая выполнит всю инициализацию за нас, или пойти длинным путём и выполнить всё вручную. Однако второй способ считается устаревшим из-за использования ADM_TOKEN, поэтому он не рассматривается.

Инициализируем Keystone выполнением команды:

1
$ sudo keystone-manage bootstrap --bootstrap-password openstack --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

Выполнение следующей команды создаёт проект admin, домен Default, роль и пользователя admin с паролем, заданным в параметре --bootstrap-password, сервис identity и точки входа для него. Роль admin является глобальной. Если она присваивается пользователю в одном проекте, то она же присваивается ему во всём облаке.

Теперь можно создать скрипт для пользователя admin (~/keystone_admin):

1
2
3
4
5
6
7
8
9
10
11
export OS_AUTH_TYPE=password
export OS_USERNAME=admin
export OS_PASSWORD=openstack
export OS_PROJECT_NAME=admin
export OS_USER_DOMAIN_NAME=Default
export OS_PROJECT_DOMAIN_NAME=Default
export OS_AUTH_URL=http://controller:5000/v3
export OS_IDENTITY_API_VERSION=3
export OS_IMAGE_API_VERSION=2

export PS1='[\u@\h \W(OS Admin)]\$ '

Создаём специальный проект для остальных сервисов OpenStack (так как каждый сервис требует пользователя и роль администратора в специальном сервисном контейнере):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
$ source keystone_admin

$ openstack project create --domain default --description "Service Project" service
+-------------+----------------------------------+
| Field       | Value                            |
+-------------+----------------------------------+
| description | Service Project                  |
| domain_id   | default                          |
| enabled     | True                             |
| id          | 679197412d5e4542bf43b4f0c42fd3ea |
| is_domain   | False                            |
| name        | service                          |
| options     | {}                               |
| parent_id   | default                          |
| tags        | []                               |
+-------------+----------------------------------+

Теперь создаём непривилегированного пользователя:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
$ source keystone_admin

$ openstack project create --domain default --description "Demo Tenant" demo
+-------------+----------------------------------+
| Field       | Value                            |
+-------------+----------------------------------+
| description | Demo Tenant                      |
| domain_id   | default                          |
| enabled     | True                             |
| id          | 000aca557baf409db7b14b884c639d13 |
| is_domain   | False                            |
| name        | demo                             |
| options     | {}                               |
| parent_id   | default                          |
| tags        | []                               |
+-------------+----------------------------------+

$ openstack user create --domain default --project demo --email user@controller --password openstack demo
+---------------------+----------------------------------+
| Field               | Value                            |
+---------------------+----------------------------------+
| default_project_id  | 000aca557baf409db7b14b884c639d13 |
| domain_id           | default                          |
| email               | user@controller                  |
| enabled             | True                             |
| id                  | c1e0d27f36f746b79aa38c92d58ad600 |
| name                | demo                             |
| options             | {}                               |
| password_expires_at | None                             |
+---------------------+----------------------------------+

$ openstack role create user
+-------------+----------------------------------+
| Field       | Value                            |
+-------------+----------------------------------+
| description | None                             |
| domain_id   | None                             |
| id          | 25a85168ffa7421cb3cc2b1602dbfb25 |
| name        | user                             |
| options     | {}                               |
+-------------+----------------------------------+

$ openstack role add --project demo --user demo user

Создаём скрипт для пользователя demo (~/keystone_demo):

1
2
3
4
5
6
7
8
9
10
11
export OS_AUTH_TYPE=password
export OS_USERNAME=demo
export OS_PASSWORD=openstack
export OS_PROJECT_NAME=demo
export OS_USER_DOMAIN_NAME=Default
export OS_PROJECT_DOMAIN_NAME=Default
export OS_AUTH_URL=http://controller:5000/v3
export OS_IDENTITY_API_VERSION=3
export OS_IMAGE_API_VERSION=2

export PS1='[\u@\h \W(OS Demo)]\$ '

Проверяем его работу:

1
2
3
4
5
6
7
8
9
10
11
$ source keystone_demo 

$ openstack token issue
+------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Field      | Value                                                                                                                                                                                   |
+------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| expires    | 2025-07-30T11:23:39+0000                                                                                                                                                                |
| id         | gAAAAABoifKrPsoetARifP16RecV9SywMKqj4wNYUSBSUu-D3CQI4AhKfapgbPLlyihR_1eaFXsbLlNd4wBtBLli_ecswzu8GCACqDH1sBUV7deBXS6CHSe1QONahh6mDPxX906XAbsbP_D3yuZAY4n0z2KS644kb52_H-SlitV5RATOqS_efiM |
| project_id | 000aca557baf409db7b14b884c639d13                                                                                                                                                        |
| user_id    | c1e0d27f36f746b79aa38c92d58ad600                                                                                                                                                        |
+------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+

Glance

Общие сведения

Glance - каталог образов виртуальных машин, является реализацией проекта “образы виртуальных машин как сервис”. Он отвечает за ведение каталога, регистрацию и доставку образов ВМ. По сути, они выполняют роль шаблонов и, как правило, требуют дополнительной настройки после запуска ВМ. При этом сам Glance не реализует фактическое хранение образов, а через один из адаптеров использует в качестве бэкэнда ту или иную систему хранения - это может быть локальное хранилище, Ceph, S3, GlusterFS, NFS или OpenStack Swift. Glance одновременно поддерживает несколько хранилищ: то, где создаётся образ, зависит от приоритета и свободного места на диске. Приоритет можно задать в файле /etc/glance/glance-api.conf:

1
2
3
[glance_store]
filesystem_store_datadirs = /var/lib/glance/images/diskA/:20
filesystem_store_datadirs = /var/lib/glance/images/diskB/:20

Метаданные образов (размер, формат, имя и так далее) - хранятся в базе данных.

Glance поддерживает целый ряд форматов образов виртуальных машин - vhd, vmdk, vdi, iso, qcow2, ami и так далее. Также в качестве образа может выступать ядро и initrd-файл, которые при запуске ВМ необходимо связывать вместе.

Для своей работы Glance требует работающий сервис Keystone и базу данных для хранения метаданных об образах.

Установка и настройка

Создаём пользователя glance, присваиваем ему роль admin и создаём сам сервис glance (с точками входа):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
$ source keystone_admin

$ openstack user create --domain default --password openstack glance
+---------------------+----------------------------------+
| Field               | Value                            |
+---------------------+----------------------------------+
| domain_id           | default                          |
| enabled             | True                             |
| id                  | 29eafde4bd6b4526acc709a27912674e |
| name                | glance                           |
| options             | {}                               |
| password_expires_at | None                             |
+---------------------+----------------------------------+

$ openstack role add --project service --user glance admin

$ openstack service create --name glance --description "OpenStack Image service" image
+-------------+----------------------------------+
| Field       | Value                            |
+-------------+----------------------------------+
| description | OpenStack Image service          |
| enabled     | True                             |
| id          | 6cd363b1a2db42a292ca7fad02cff847 |
| name        | glance                           |
| type        | image                            |
+-------------+----------------------------------+

$ openstack endpoint create --region RegionOne image public http://controller:9292
+--------------+----------------------------------+
| Field        | Value                            |
+--------------+----------------------------------+
| enabled      | True                             |
| id           | df7b113a548a4ecfb7af44c82edd16a2 |
| interface    | public                           |
| region       | RegionOne                        |
| region_id    | RegionOne                        |
| service_id   | 6cd363b1a2db42a292ca7fad02cff847 |
| service_name | glance                           |
| service_type | image                            |
| url          | http://controller:9292           |
+--------------+----------------------------------+

$ openstack endpoint create --region RegionOne image internal http://controller:9292
+--------------+----------------------------------+
| Field        | Value                            |
+--------------+----------------------------------+
| enabled      | True                             |
| id           | e1a4abc95ab24cd68e6f079013f30445 |
| interface    | internal                         |
| region       | RegionOne                        |
| region_id    | RegionOne                        |
| service_id   | 6cd363b1a2db42a292ca7fad02cff847 |
| service_name | glance                           |
| service_type | image                            |
| url          | http://controller:9292           |
+--------------+----------------------------------+

$ openstack endpoint create --region RegionOne image admin http://controller:9292
+--------------+----------------------------------+
| Field        | Value                            |
+--------------+----------------------------------+
| enabled      | True                             |
| id           | d59868ce72f14eca950c80ca60f903f6 |
| interface    | admin                            |
| region       | RegionOne                        |
| region_id    | RegionOne                        |
| service_id   | 6cd363b1a2db42a292ca7fad02cff847 |
| service_name | glance                           |
| service_type | image                            |
| url          | http://controller:9292           |
+--------------+----------------------------------+

Устанавливаем необходимые пакеты на управляющем узле:

1
$ sudo yum -y install openstack-glance

Создаём базу данных:

1
$ sudo mysql -u root -popenstack
1
2
3
4
CREATE DATABASE glance;

GRANT ALL PRIVILEGES ON glance.* TO 'glance'@'localhost' IDENTIFIED BY 'glance';
GRANT ALL PRIVILEGES ON glance.* TO 'glance'@'%' IDENTIFIED BY 'glance';

Указываем параметры подключения в конфигурационных файле Glance /etc/glance/glance-api.conf:

1
2
[database]
connection = mysql+pymysql://glance:glance@controller/glance

Завершаем настройку базы данных инициализацией:

1
$ sudo su -s /bin/sh -c "glance-manage db_sync" glance

Далее нужно указать проект, предназначенный для сервисов (созданный ранее), имя пользователя и пароль для glance-api в Keystone и сведения о RabbitMQ в файле /etc/glance/glance-api.conf:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
[DEFAULT]
rabbit_password = openstack
rabbit_userid = openstack
rabbit_host = controller

[keystone_authtoken]
auth_uri = http://controller:5000
auth_url = http://controller:5000
auth_type = password
project_domain_name = default
user_domain_name = default
project_name = service
username = glance
password = openstack

[glance_store]
default_store = file
filesystem_store_datadir = /var/lib/glance/images/

[paste_deploy]
flavor = keystone

Запускаем сервис:

1
$ sudo systemctl start openstack-glance-api; sudo systemctl enable openstack-glance-api

Загрузка образов

В качестве проверки скачаем образ Cirros из Github и загрузим его в Glance:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
$ wget https://github.com/cirros-dev/cirros/releases/download/0.6.3/cirros-0.6.3-x86_64-disk.img

$ source keystone_admin

$ openstack image create "Cirros" --file cirros-0.6.3-x86_64-disk.img --disk-format qcow2 --container-format bare --public # альтернативная команда - glance image-create --name "Cirros" --file cirros-0.6.3-x86_64-disk.img --disk-format qcow2 --container-format bare --visibility public
+------------------+--------------------------------------------------------------------------------------------------------------------------------------------+
| Field            | Value                                                                                                                                      |
+------------------+--------------------------------------------------------------------------------------------------------------------------------------------+
| container_format | bare                                                                                                                                       |
| created_at       | 2025-07-30T10:30:27Z                                                                                                                       |
| disk_format      | qcow2                                                                                                                                      |
| file             | /v2/images/20120ae4-d320-421e-b8c9-1b95549a3995/file                                                                                       |
| id               | 20120ae4-d320-421e-b8c9-1b95549a3995                                                                                                       |
| min_disk         | 0                                                                                                                                          |
| min_ram          | 0                                                                                                                                          |
| name             | Cirros                                                                                                                                     |
| owner            | 7120a6037766473c8cf4db4e68e5258f                                                                                                           |
| properties       | os_hidden='False', owner_specified.openstack.md5='', owner_specified.openstack.object='images/Cirros', owner_specified.openstack.sha256='' |
| protected        | False                                                                                                                                      |
| schema           | /v2/schemas/image                                                                                                                          |
| status           | queued                                                                                                                                     |
| tags             |                                                                                                                                            |
| updated_at       | 2025-07-30T10:30:27Z                                                                                                                       |
| visibility       | public                                                                                                                                     |
+------------------+--------------------------------------------------------------------------------------------------------------------------------------------+

Проверяем наличие образа в каталоге Glance:

1
2
$ sudo ls -l /var/lib/glance/images
-rw-r----- 1 glance glance 21692416 июл 30 13:30 20120ae4-d320-421e-b8c9-1b95549a3995

C помощью утилиты openstack можно загружать образы из Glance (в том числе из коммерческих облаков):

1
$ openstack image save Cirros > Cirros.img

Cinder

Общие сведения

В состав базовых проектов OpenStack входят два принципиально разных сервисов хранения информации - Swift и Cinder. Swift представляет из себя объектное хранилище (подобное Amazon S3). Cinder же похож на Amazon EBS.

Когда сервис Nova получает образ виртуальной машины из Glance, образ копируется на локальный диск вычислительного узла, где работает Nova, и из образа запускается виртуальная машина. Между перезагрузками виртуальной машины изменения, произведённые на файловой системе, сохраняются в локальной копии образа, которая по умолчанию хранится в /var/lib/nova/instances. Поэтому необходимо хранилище постоянной информации, где данные сохранялись бы между перезагрузками или в случае сбоя узла с запущенными машинами. Такое хранилище предоставляет Cinder - “блочное хранилище данных как сервис”.

Помимо функционирования в качестве постоянного дополнительного хранилища для виртуальных машин без сохранения состояния, Cinder также может использоваться в качестве устройств начальной загрузки. Кроме того, можно создавать снимки томов, доступные в режиме “только для чтения”. В дальнейшем их можно использовать для создания новых томов, доступных на запись.

Сервис состоит из четырёх служб:

  • openstack-cinder-api - точка входа для запросов в сервис по протоколу HTTP. Приняв запрос, сервис проверяет полномочия на выполнение запроса и переправляет запрос брокеру сообщений для доставки другим службам;
  • openstack-cinder-scheduler - сервис-планировщик принимает запросы от брокера сообщений и определяет, какой узел с сервисом openstack-cinder-volume должен обработать запрос;
  • openstack-cinder-volume - сервис отвечает за взаимодействие с бэкэндом - блочным устройством. Получает запросы от планировщика и транслирует непосредственно в хранилище. Cinder позволяет одновременно использовать несколько бэкэндов, при этом для каждого из них запускается свой openstack-cinder-volume. При помощи фильтров CapacityFilter и CapacityWeigher можно управлять тем, какой бэкэнд выберет планировщик;
  • openstack-cinder-backup - сервис отвечает за создание резервных копий томов в объектное хранилище.

Установка и настройка

Обычно внедряют много узлов с сервисом openstack-cinder-volume, которые непосредственно отвечают за доступ к данным, и несколько управляющих, обеспечивающих за доступ к API и планировщику.

Для установки Cinder на платформе виртуализации желательно использовать отдельный диск или отдельный раздел. Создадим такой диск в libvirt и подключим к серверу; на нём создаём LVM-группу:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
$ sudo lsblk # обнаруживаем диск (vdb)
NAME        MAJ:MIN RM  SIZE RO TYPE MOUNTPOINTS
sr0          11:0    1 1024M  0 rom  
vda         252:0    0   20G  0 disk 
├─vda1      252:1    0    1G  0 part /boot
└─vda2      252:2    0   19G  0 part 
  ├─cs-root 253:0    0   17G  0 lvm  /
  └─cs-swap 253:1    0    2G  0 lvm  [SWAP]
vdb         252:16   0   30G  0 disk 

$ sudo fdisk /dev/vdb # входим в программу создания раздела
$ sudo mkfs.ext4 /dev/vdb1 # создаём раздел

$ sudo vgcreate cinder-volumes /dev/vdb1 # создаём группу томов
  Wiping ext4 signature on /dev/vdb1.
  Physical volume "/dev/vdb1" successfully created.
  Creating devices file /etc/lvm/devices/system.devices
  Volume group "cinder-volumes" successfully created 

Устанавливаем пакеты Cinder на контроллере:

1
$ sudo yum -y install openstack-cinder

Далее нужно внести изменения в файл конфигурации /etc/cinder/cinder.conf:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
[DEFAULT]
transport_url = rabbit://openstack:openstack@controller
auth_strategy = keystone
enabled_backends = lvm
glance_api_servers = http://controller:9292
my_ip = 192.168.100.128

[database]
connection = mysql+pymysql://cinder:cinder@controller/cinder

[keystone_authtoken]
project_name = service
user_domain_name = default
project_domain_name = default
auth_type = password
username = cinder
password = openstack
auth_uri = http://controller:5000
auth_url = http://controller:5000

[lvm]
volume_group = cinder-volumes
volume_driver = cinder.volume.drivers.lvm.LVMVolumeDriver
iscsi_protocol = iscsi
iscsi_helper = lioadm

[oslo_concurrency]
lock_path = /var/lib/cinder/tmp

Далее создаём базу данных для Cinder:

1
$ sudo mysql -u root -popenstack
1
2
3
4
CREATE DATABASE cinder;

GRANT ALL PRIVILEGES ON cinder.* TO 'cinder'@'localhost' IDENTIFIED BY 'cinder';
GRANT ALL PRIVILEGES ON cinder.* TO 'cinder'@'%' IDENTIFIED BY 'cinder';

Инициализируем базу данных:

1
$ sudo su -s /bin/sh -c "cinder-manage --config-file /etc/cinder/cinder.conf db sync" cinder

Заводим пользователя в Keystone и добавляем роль администратора в проекте service:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
$ source keystone_admin

$ openstack user create --domain default --password openstack cinder
+---------------------+----------------------------------+
| Field               | Value                            |
+---------------------+----------------------------------+
| domain_id           | default                          |
| enabled             | True                             |
| id                  | cf85528ca4a04cabb1309b0d40442560 |
| name                | cinder                           |
| options             | {}                               |
| password_expires_at | None                             |
+---------------------+----------------------------------+

$ openstack role add --project service --user cinder admin

$ openstack service create --name cinderv3 --description "OpenStack Block Storage" volumev3
+-------------+----------------------------------+
| Field       | Value                            |
+-------------+----------------------------------+
| description | OpenStack Block Storage          |
| enabled     | True                             |
| id          | 777bf6ceb2d94c108c740d22403c1cc2 |
| name        | cinderv3                         |
| type        | volumev3                         |
+-------------+----------------------------------+

$ openstack endpoint create --region RegionOne volumev3 public http://controller:8776/v3/%\(project_id\)s
+--------------+------------------------------------------+
| Field        | Value                                    |
+--------------+------------------------------------------+
| enabled      | True                                     |
| id           | cc6fb124b1e249de8f2799e94ab9ca36         |
| interface    | public                                   |
| region       | RegionOne                                |
| region_id    | RegionOne                                |
| service_id   | 777bf6ceb2d94c108c740d22403c1cc2         |
| service_name | cinderv3                                 |
| service_type | volumev3                                 |
| url          | http://controller:8776/v3/%(project_id)s |
+--------------+------------------------------------------+

$ openstack endpoint create --region RegionOne volumev3 internal http://controller:8776/v3/%\(project_id\)s
+--------------+------------------------------------------+
| Field        | Value                                    |
+--------------+------------------------------------------+
| enabled      | True                                     |
| id           | 8c7fc2014d2b41e49f92e2a7637e6e3b         |
| interface    | internal                                 |
| region       | RegionOne                                |
| region_id    | RegionOne                                |
| service_id   | 777bf6ceb2d94c108c740d22403c1cc2         |
| service_name | cinderv3                                 |
| service_type | volumev3                                 |
| url          | http://controller:8776/v3/%(project_id)s |
+--------------+------------------------------------------+

$ openstack endpoint create --region RegionOne volumev3 admin http://controller:8776/v3/%\(project_id\)s
+--------------+------------------------------------------+
| Field        | Value                                    |
+--------------+------------------------------------------+
| enabled      | True                                     |
| id           | 9bd5bee065824ab088a1cb409da4e182         |
| interface    | admin                                    |
| region       | RegionOne                                |
| region_id    | RegionOne                                |
| service_id   | 777bf6ceb2d94c108c740d22403c1cc2         |
| service_name | cinderv3                                 |
| service_type | volumev3                                 |
| url          | http://controller:8776/v3/%(project_id)s |
+--------------+------------------------------------------+

Активируем и запускаем сервис iSCSI:

1
% sudo systemctl enable target.service; sudo systemctl start target.service

В конце активируем и запускаем Cinder:

1
2
$ sudo systemctl enable openstack-cinder-api openstack-cinder-scheduler openstack-cinder-volume openstack-cinder-backup
$ sudo systemctl start openstack-cinder-api openstack-cinder-scheduler openstack-cinder-volume openstack-cinder-backup

Для проверки работы сервисов можно воспользоваться openstack volume service list:

1
2
3
4
5
6
7
8
9
10
$ source keystone_admin

$ openstack volume service list
+------------------+----------------+------+---------+-------+----------------------------+
| Binary           | Host           | Zone | Status  | State | Updated At                 |
+------------------+----------------+------+---------+-------+----------------------------+
| cinder-backup    | controller     | nova | enabled | up    | 2025-07-30T10:38:45.000000 |
| cinder-scheduler | controller     | nova | enabled | up    | 2025-07-30T10:38:40.000000 |
| cinder-volume    | controller@lvm | nova | enabled | up    | 2025-07-30T10:38:40.000000 |
+------------------+----------------+------+---------+-------+----------------------------+

Создание и удаление томов Cinder

Для проверки создадим том размером 1 Гб:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
$ source keystone_demo

$ openstack volume create --size 1 testvol1 # альтернативная команда: cinder create --display-name testvol1 1
+---------------------+--------------------------------------+
| Field               | Value                                |
+---------------------+--------------------------------------+
| attachments         | []                                   |
| availability_zone   | nova                                 |
| bootable            | false                                |
| consistencygroup_id | None                                 |
| created_at          | 2025-07-30T10:39:00.938369           |
| description         | None                                 |
| encrypted           | False                                |
| id                  | 840fb860-d352-47c1-86c2-69ba3317f88a |
| multiattach         | False                                |
| name                | testvol1                             |
| properties          |                                      |
| replication_status  | None                                 |
| size                | 1                                    |
| snapshot_id         | None                                 |
| source_volid        | None                                 |
| status              | creating                             |
| type                | __DEFAULT__                          |
| updated_at          | None                                 |
| user_id             | c1e0d27f36f746b79aa38c92d58ad600     |
+---------------------+--------------------------------------+

Проверяем создание:

1
2
3
4
5
6
$ cinder list
+--------------------------------------+-----------+----------+------+----------------+-------------+----------+-------------+
| ID                                   | Status    | Name     | Size | Consumes Quota | Volume Type | Bootable | Attached to |
+--------------------------------------+-----------+----------+------+----------------+-------------+----------+-------------+
| 840fb860-d352-47c1-86c2-69ba3317f88a | available | testvol1 | 1    | True           | __DEFAULT__ | false    |             |
+--------------------------------------+-----------+----------+------+----------------+-------------+----------+-------------+

Можем убедиться, что том создан в группе cinder-volumes:

1
2
3
4
5
6
7
8
9
10
$ sudo vgs
  VG             #PV #LV #SN Attr   VSize   VFree  
  cinder-volumes   1   2   0 wz--n- <20,00g 980,00m
  cs               1   2   0 wz--n- <19,00g      0 
$ sudo lvs
  LV                                          VG             Attr       LSize   Pool                Origin Data%  Meta%  Move Log Cpy%Sync Convert
  cinder-volumes-pool                         cinder-volumes twi-aotz--  19,00g                            0,00   10,57                           
  volume-840fb860-d352-47c1-86c2-69ba3317f88a cinder-volumes Vwi-a-tz--   1,00g cinder-volumes-pool        0,00                                   
  root                                        cs             -wi-ao---- <17,00g                                                                   
  swap                                        cs             -wi-ao----   2,00g

Зоны доступности в Cinder

Зоны доступности Cinder настраиваются в /etc/cinder/cinder.conf на всех узлах, где запускается cinder-volume. Для создания новой зоны доступности необходимо изменить параметр storage_availability_zone в блоке [DEFAULT] с указанием зоны доступности текущей ноды, после чего перезапустить сервис openstack-cinder-volume (зона обновится через 1-2 минуты):

1
2
3
[DEFAULT]
# ...
storage_availability_zone = MyStorageAvailabilityZone

Перезапускаем сервис:

1
$ sudo systemctl restart openstack-cinder-volume

Проверяем:

1
2
3
4
5
6
7
8
9
10
$ source keystone_admin

$ openstack volume service list
+------------------+----------------+---------------------------+---------+-------+----------------------------+
| Binary           | Host           | Zone                      | Status  | State | Updated At                 |
+------------------+----------------+---------------------------+---------+-------+----------------------------+
| cinder-backup    | controller     | nova                      | enabled | up    | 2025-07-30T10:40:45.000000 |
| cinder-scheduler | controller     | nova                      | enabled | up    | 2025-07-30T10:40:50.000000 |
| cinder-volume    | controller@lvm | MyStorageAvailabilityZone | enabled | up    | 2025-07-30T10:40:44.000000 |
+------------------+----------------+---------------------------+---------+-------+----------------------------+

Для установки зоны доступности Cinder по умолчанию нужно внести в /etc/cinder/cinder.conf в [DEFAULT] значение с зоной доступности по умолчанию в storage_availability_zone, но только на той ноде, где запущен cinder-api.

Swift

Общие сведения

Объектное хранилище Swift - один из двух самых первых сервисов OpenStack. Swift - это программно определяемое хранилище (sofware-defined storage, SDS), работающее с объектами. Объектное хранилище предоставляет доступ не к файлам и блочным устройствам, а к объектам в едином пространстве имён. У него есть свой API, и обычно доступ осуществляется по HTTP. Такое хранилище абстрагирует объекты от их физического расположения и позволяет осуществлять масштабирование без привязки к физической инфраструктуре хранилища.

Логическая структура Swift состоит из трёх уровней:

  • учетная запись (account) - соответствует понятию “проект” в OpenStack. Важно не путать учетную запись Swift с пользователем - учетная запись сама может включать в себя множество пользователей;
  • контейнер (container) - принадлежит учетной записи. Можно представить как директорию или бакет;
  • объект (object) - единица хранения в Swift. С объектом могут быть связаны метаданные.

Физическая структура не пересекается с логической и состоит из следующих элементов:

  • регион - соответствует одной площадке или ЦОД. Каждый регион имеет свою точку входа API;
  • зона - набор серверов в регионе, характеризующийся общим компонентом доступности, например набор стоек, завязанных на одну линию питания;
  • серверы - отдельные серверы, хранящие данные;
  • диски - диски серверов хранения.

Рекомендуемая файловая система - XFS. Также рекомендуется большой размер inode для целей хранения метаданных.

Сервисы Swift могут работать на всех узлах, или под отдельные сервисы могут выделяться отдельные узлы. Зачастую openstack-swift-proxy выносится на отдельные узлы, а три остальных работают на всех узлах кластера:

  • openstack-swift-proxy - отвечает за коммуникацию Swift с клиентами по протоколу HTTP и за распределение запросов на чтение и запись между узлами;
  • openstack-swift-account - отвечает за поддержку баз данных SQLite, содержащих информацию о контейнерах, доступных конкретной учетной записи. Для каждой учетной записи создаётся своя база данных; базы реплицируются внутри кластера;
  • openstack-swift-container - отвечает за поддержку баз данных, содержащих информацию об объектах, имеющихся в каждом контейнере. Для каждого контейнера создаётся своя база SQLite; базы реплицируются внутри кластера;
  • openstack-swift-object - отвечает за хранение, доставку и удаление объектов, сгруппированных в логические группы, называемые разделами на дисках узла. Тут разделы - не разделы диска, а директория на файловой системе, поддерживающей расширенные атрибуты файлов (например XFS или ext4). Объекты хранятся в поддиректориях директории-раздела. Для идентификации объекта используется MD5-хэш пути к объекту. Благодаря этому сервису Swift может хранить несколько версий одного объекта.

Кроме перечисленных выше существует ещё ряд периодически запускающихся процессов, в том числе:

  • репликатор - процесс, отвечающий за целостность данных. Для сравнения репликатор использует хэш-функцию, а для копирования файлов - rsyncd;
  • аудитор - данный процесс периодически рассчитывает MD5-суммы файлов и сравнивает их с хранящимися в метаданных. Если обнаруживается расхождение, то файл помещается в специальную директорию на карантин, а при следующей репликации создаётся новая целостная копия файла;
  • процесс удаления учётных записей - удаляет учетную запись и связанные с ней контейнеры и объекты;
  • процессы обновления контейнеров и объектов;
  • процесс, отвечающий за автоматическое удаление объектов по прошествии определённого времени. Это позволяет задавать жизненный цикл объектам.

Для установки Swift на нашем стенде понадобится 3 дополнительных сервера с 1 Гб оперативной памяти на каждом - 1 для Swift Proxy (своего рода контроллер) и 2 сервера под хранение.

Настройка контроллера

Для начала создаём пользователя для Swift, добавляет его с ролью admin в проект service, создаём сервис и точки входа (с адресом сервера swift-proxy):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
$ source keystone_admin

$ openstack user create --domain default --password openstack swift
+---------------------+----------------------------------+
| Field               | Value                            |
+---------------------+----------------------------------+
| domain_id           | default                          |
| enabled             | True                             |
| id                  | 62012a75efc045c9b579eb0d448945b4 |
| name                | swift                            |
| options             | {}                               |
| password_expires_at | None                             |
+---------------------+----------------------------------+

$ openstack role add --project service --user swift admin

$ openstack service create --name swift --description "OpenStack Object Storage" object-store
+-------------+----------------------------------+
| Field       | Value                            |
+-------------+----------------------------------+
| description | OpenStack Object Storage         |
| enabled     | True                             |
| id          | 44cb7365fb20407ea5f32db830bbc678 |
| name        | swift                            |
| type        | object-store                     |
+-------------+----------------------------------+

$ openstack endpoint create --region RegionOne object-store public http://swift-proxy:8080/v1/AUTH_%\(project_id\)s
+--------------+------------------------------------------------+
| Field        | Value                                          |
+--------------+------------------------------------------------+
| enabled      | True                                           |
| id           | 4013a862ae9a46469b101822f070fc32               |
| interface    | public                                         |
| region       | RegionOne                                      |
| region_id    | RegionOne                                      |
| service_id   | 44cb7365fb20407ea5f32db830bbc678               |
| service_name | swift                                          |
| service_type | object-store                                   |
| url          | http://swift-proxy:8080/v1/AUTH_%(project_id)s |
+--------------+------------------------------------------------+

$ openstack endpoint create --region RegionOne object-store internal http://swift-proxy:8080/v1/AUTH_%\(project_id\)s
+--------------+------------------------------------------------+
| Field        | Value                                          |
+--------------+------------------------------------------------+
| enabled      | True                                           |
| id           | 6411753202b9401c9c56678bc1695e73               |
| interface    | internal                                       |
| region       | RegionOne                                      |
| region_id    | RegionOne                                      |
| service_id   | 44cb7365fb20407ea5f32db830bbc678               |
| service_name | swift                                          |
| service_type | object-store                                   |
| url          | http://swift-proxy:8080/v1/AUTH_%(project_id)s |
+--------------+------------------------------------------------+

$ openstack endpoint create --region RegionOne object-store admin http://swift-proxy:8080/v1/AUTH_%\(project_id\)s
+--------------+------------------------------------------------+
| Field        | Value                                          |
+--------------+------------------------------------------------+
| enabled      | True                                           |
| id           | 6a1585877e8c42149c0d5723861f298d               |
| interface    | admin                                          |
| region       | RegionOne                                      |
| region_id    | RegionOne                                      |
| service_id   | 44cb7365fb20407ea5f32db830bbc678               |
| service_name | swift                                          |
| service_type | object-store                                   |
| url          | http://swift-proxy:8080/v1/AUTH_%(project_id)s |
+--------------+------------------------------------------------+

Настройка swift-proxy

Устанавливаем необходимые пакеты:

1
$ sudo yum -y install openstack-swift-proxy python-swiftclient python-keystoneclient python-keystonemiddleware memcached

Редактируем конфигурацию /etc/swift/proxy-server.conf:

1
2
3
4
5
6
7
8
9
10
11
12
13
[filter:authtoken]
paste.filter_factory = keystonemiddleware.auth_token:filter_factory
auth_uri = http://controller:5000
auth_url = http://controller:5000
auth_type = password
project_domain_id = default
user_domain_id = default
project_name = service
username = swift
password = openstack
delay_auth_decision = true
operator_toles = admin,user
use = egg:swift#keystoneauth

Настройка узлов хранения swift-storage

Устанавливаем необходимые пакеты на каждом сервере swift-storage-*:

1
$ sudo yum -y install openstack-swift-account openstack-swift-container openstack-swift-object rsync rsync-daemon

Каждой ВМ нужно добавить по два локальных диска и создать на них по разделу с XFS по общей инструкции:

1
2
3
4
5
6
7
8
9
$ sudo lsblk # проверяем устройства
NAME    MAJ:MIN RM  SIZE RO TYPE MOUNTPOINTS
vda     253:0    0   10G  0 disk 
├─vda1  253:1    0    9G  0 part /
├─vda14 253:14   0    4M  0 part 
├─vda15 253:15   0  106M  0 part /boot/efi
└─vda16 259:0    0  913M  0 part /boot
vdb     253:16   0    2G  0 disk 
vdc     253:32   0    2G  0 disk 

Создаём таблицы:

1
2
$ sudo fdisk /dev/vdb
$ sudo fdisk /dev/vdc

Создаём разделы:

1
2
$ sudo mkfs.xfs /dev/vdb1
$ sudo mkfs.xfs /dev/vdc1

Добавляем данные о дисках в /etc/fstab и монтируем их в /srv/node/:

1
2
3
4
5
6
7
8
9
$ sudo mkdir -p /srv/node/vd{b,c}1

$ echo "/dev/vdb1 /srv/node/vdb1 xfs noatime,nodiratime,logbufs=8 0 2" >> /etc/fstab
$ echo "/dev/vdc1 /srv/node/vdc1 xfs noatime,nodiratime,logbufs=8 0 2" >> /etc/fstab

$ sudo systemctl daemon-reload

$ sudo mount -t xfs /dev/vdb1 /srv/node/vdb1
$ sudo mount -t xfs /dev/vdc1 /srv/node/vdc1

Назначаем корректные права:

1
2
$ sudo chown -R swift:swift /srv/node/
$ sudo chmod -R 755 /srv/node

Настраиваем демон rsyncd на swift-storage-* в файле /etc/rsyncd.conf (важно не забыть указать точный адрес в параметре address):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
uid = swift
gid = swift
log file = /var/log/rsyncd.log
pid file = /var/run/rsyncd.pid
address = IP_АДРЕС_КОНКРЕТНОЙ_НОДЫ

[account]
max connections = 25
path = /srv/node/
read only = false
lock file = /var/lock/account.lock

[container]
max connections = 25
path = /srv/node/
read only = false
lock file = /var/lock/container.lock

[object]
max connections = 25
path = /srv/node/
read only = false
lock file = /var/lock/object.lock

Активируем и запускаем сервис:

1
$ sudo systemctl enable rsyncd; sudo systemctl start rsyncd

Проверяем работу демона rsync:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
$ sudo rsync 192.168.100.208::
account        	
container      	
object         	

$ sudo rsync 192.168.100.208::object
drwxr-xr-x             30 2025/07/29 16:38:37 .
drwxr-xr-x              6 2025/07/29 16:38:09 vdb1
drwxr-xr-x              6 2025/07/29 16:38:14 vdc1

$ sudo rsync 192.168.100.208::account
drwxr-xr-x             30 2025/07/29 16:38:37 .
drwxr-xr-x              6 2025/07/29 16:38:09 vdb1
drwxr-xr-x              6 2025/07/29 16:38:14 vdc1

$ sudo rsync 192.168.100.208::container
drwxr-xr-x             30 2025/07/29 16:38:37 .
drwxr-xr-x              6 2025/07/29 16:38:09 vdb1
drwxr-xr-x              6 2025/07/29 16:38:14 vdc1

Теперь на каждом из двух узлов нужно создать по три конфигурационных файла оставшихся сервисов. В них также обязательно в параметре bind_ip нужно указать адрес текущего узла. Для начала файл /etc/swift/account-server.conf:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
[DEFAULT]
bind_ip = IP_АДРЕС_КОНКРЕТНОЙ_НОДЫ
bind_port = 6002
workers = 2
user = swift
swift_dir = /etc/swift
devices = /srv/node

[pipeline:main]
pipeline = healthcheck recon account-server

[app:account-server]
use = egg:swift#account

[filter:recon]
use = egg:swift#recon
recon_cache_path = /var/cache/swift

[filter:healthcheck]
use = egg:swift#healthcheck

[account-replicator]
[account-auditor]
[account-reaper]

Файл /etc/swift/object-server.conf:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
[DEFAULT]
bind_ip = IP_АДРЕС_КОНКРЕТНОЙ_НОДЫ
bind_port = 6000
workers = 3
user = swift
swift_dir = /etc/swift
devices = /srv/node

[pipeline:main]
pipeline = healthcheck recon object-server

[filter:recon]
use =egg:swift#recon
recon_cache_path = /var/cache/swift

[app:object-server]
use = egg:swift#object

[filter:healthcheck]
use = egg:swift#healthcheck

[object-replicator]
[object-updater]
[object-auditor]

Файл /etc/swift/container-server.conf:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
[DEFAULT]
bind_ip = IP_АДРЕС_КОНКРЕТНОЙ_НОДЫ
bind_port = 6001
workers = 2
user = swift
swift_dir = /etc/swift
devices = /srv/node

[pipeline:main]
pipeline = healthcheck recon container-server

[filter:recon]
use = egg:swift#recon
recon_cache_path = /var/cache/swift

[app:container-server]
use = egg:swift#container

[filter:healthcheck]
use = egg:swift#healthcheck

[container-replicator]
[container-updater]
[container-auditor]
[container-sync]

Создание сервисных колец

Следующий шаг - создание сервисных колец (Ring Files) Swift. Эти файлы сопоставляют имена объектов их физическому местоположению. Создаётся по одному файлу для каждого объекта, контейнера и учетной записи. Каждый диск делится на разделы, каждый из которых представляет собой директорию. Для того, чтобы определить, в каком разделе должен располагаться файл объекта, вычисляется хэш-функция по алгоритму MD5, и далее часть этого хэша используется как идентификатор раздела.

При создании файла кольца один из требуемых параметров - число битов, используемых для определения раздела. Для определения числа битов проще всего прикинуть максимальное число дисков в кластере. Например, при $100$ разделах на диске и $5000$ дисках общее число разделов будет $5000 * 100 = 500000$. Для такого числа разделов надо определить ближайшую степень числа два, большую, чем $500000$ - это будет $17$ ($2^{17}=524288$). Второй параметр - число реплик файла (рекомендуется минимум $3$), и, наконец, минимальное число часов, по прошествии которых раздел можно перемещать.

Выполняем действия на сервере swift-proxy. Для избежания возможных ошибок сначала нужно закомменитровать строку swift_hash_path_suffix в файле /etc/swift/swift.conf, после чего выполнить:

1
2
$ sudo cd /etc/swift
$ sudo swift-ring-builder account.builder create 10 3 1

Теперь добавляем каждый из двух дисков на узлах swift-storage-1 и swift-storage-2, указывая их IP-адреса и порты сервисов (те же, что и ранее в соответствующих конфигурациях) выполнив swift-ring-builder add четыре раза (также на swift-proxy):

1
2
3
4
5
6
7
8
$ sudo swift-ring-builder account.builder add --region 1 --zone 1 --ip 192.168.100.208 --port 6002 --device vdb1 --weight 100
Device d0r1z1-192.168.100.208:6002R192.168.100.208:6002/vdb1_"" with 100.0 weight got id 0
$ sudo swift-ring-builder account.builder add --region 1 --zone 1 --ip 192.168.100.208 --port 6002 --device vdc1 --weight 100
Device d1r1z1-192.168.100.208:6002R192.168.100.208:6002/vdc1_"" with 100.0 weight got id 1
$ sudo swift-ring-builder account.builder add --region 1 --zone 2 --ip 192.168.100.209 --port 6002 --device vdb1 --weight 100
Device d2r1z2-192.168.100.209:6002R192.168.100.209:6002/vdb1_"" with 100.0 weight got id 2
$ sudo swift-ring-builder account.builder add --region 1 --zone 2 --ip 192.168.100.209 --port 6002 --device vdc1 --weight 100
Device d3r1z2-192.168.100.209:6002R192.168.100.209:6002/vdc1_"" with 100.0 weight got id 3

Проверяем содержимое кольца:

1
2
3
4
5
6
7
8
9
10
11
12
$ sudo swift-ring-builder account.builder

account.builder, build version 4, id fdbad5f79a9940bb94f8c639e0200a8f
1024 partitions, 3.000000 replicas, 1 regions, 2 zones, 4 devices, 100.00 balance, 0.00 dispersion
The minimum number of hours before a partition can be reassigned is 1 (0:00:00 remaining)
The overload factor is 0.00% (0.000000)
Ring file account.ring.gz not found, probably it hasn't been written yet
Devices:   id region zone      ip address:port  replication ip:port  name weight partitions balance flags meta
            0      1    1 192.168.100.208:6002 192.168.100.208:6002  vdb1 100.00          0 -100.00       
            1      1    1 192.168.100.208:6002 192.168.100.208:6002  vdc1 100.00          0 -100.00       
            2      1    2 192.168.100.209:6002 192.168.100.209:6002  vdb1 100.00          0 -100.00       
            3      1    2 192.168.100.209:6002 192.168.100.209:6002  vdc1 100.00          0 -100.00

Распределяем разделы по устройствам в кольце:

1
2
$ sudo swift-ring-builder account.builder rebalance
Reassigned 3072 (300.00%) partitions. Balance is now 0.00.  Dispersion is now 0.00

Затем подобные же команды нужно повторить для колец container и object, после чего сгенерированные файлы колец нужно скопировать на сервера swift-storage-1 и swift-storage-2:

1
2
3
4
5
6
7
8
9
10
11
12
13
$ sudo swift-ring-builder container.builder create 10 3 1
$ sudo swift-ring-builder container.builder add --region 1 --zone 1 --ip 192.168.100.208 --port 6001 --device vdb1 --weight 100
$ sudo swift-ring-builder container.builder add --region 1 --zone 1 --ip 192.168.100.208 --port 6001 --device vdc1 --weight 100
$ sudo swift-ring-builder container.builder add --region 1 --zone 2 --ip 192.168.100.209 --port 6001 --device vdb1 --weight 100
$ sudo swift-ring-builder container.builder add --region 1 --zone 2 --ip 192.168.100.209 --port 6001 --device vdc1 --weight 100
$ sudo swift-ring-builder container.builder rebalance

$ sudo swift-ring-builder object.builder create 10 3 1
$ sudo swift-ring-builder object.builder add --region 1 --zone 1 --ip 192.168.100.208 --port 6000 --device vdb1 --weight 100
$ sudo swift-ring-builder object.builder add --region 1 --zone 1 --ip 192.168.100.208 --port 6000 --device vdc1 --weight 100
$ sudo swift-ring-builder object.builder add --region 1 --zone 2 --ip 192.168.100.209 --port 6000 --device vdb1 --weight 100
$ sudo swift-ring-builder object.builder add --region 1 --zone 2 --ip 192.168.100.209 --port 6000 --device vdc1 --weight 100
$ sudo swift-ring-builder object.builder rebalance

Копируем всё на ВМ в /etc/swift:

1
2
$ sudo scp *.ring.gz root@swift-storage-1:/etc/swift
$ sudo scp *.ring.gz root@swift-storage-2:/etc/swift

Завершение настройки

В завершение настройки в файл /etc/swift/swift.conf на каждом сервере необходимо добавить два случайных параметра, которые будут играть роль соли файла /etc/shadow и будут добавляться к имени объекта для предотвращения DoS-атаки. Если злоумышленник будет знать значение этих параметров, то он сможет узнать реальное расположение объектов в разделах Swift. Для этого сначала сгенерируем значения параметров:

1
2
3
4
5
$ openssl rand -hex 10
0d2da2446d11dc339c7f

$ openssl rand -hex 10
062b5923a768c6480d9c

Внесём параметры на каждом сервере swift-* в файл /etc/swift/swift.conf:

1
2
3
[swift-hash]
swift_hash_path_suffix = 04d12e291ef1fe72b1be
swift_hash_path_prefix = 7eb34bc31831089ea33b

Меняем владельца сервисного каталога:

1
$ sudo chown -R swift:swift /etc/swift

Активируем и запускаем сервисы на swift-proxy:

1
$ sudo systemctl enable openstack-swift-proxy memcached; sudo systemctl start openstack-swift-proxy memcached

Теперь тоже самое на каждом swift-storage:

1
2
3
$ sudo systemctl enable openstack-swift-account openstack-swift-account-auditor openstack-swift-account-reaper openstack-swift-account-replicator openstack-swift-container openstack-swift-container-auditor openstack-swift-container-replicator openstack-swift-container-updater openstack-swift-object openstack-swift-object-auditor openstack-swift-object-replicator openstack-swift-object-updater

$ sudo systemctl start openstack-swift-account openstack-swift-account-auditor openstack-swift-account-reaper openstack-swift-account-replicator openstack-swift-container openstack-swift-container-auditor openstack-swift-container-replicator openstack-swift-container-updater openstack-swift-object openstack-swift-object-auditor openstack-swift-object-replicator openstack-swift-object-updater

Проверка работы сервиса

1
2
3
4
5
6
7
8
9
10
11
12
13
$ source keystone_demo

$ swift stat
               Account: AUTH_27d44a393b3e4a14a87f60c590eb4c90
            Containers: 0
               Objects: 0
                 Bytes: 0
          Content-Type: text/plain; charset=utf-8
           X-Timestamp: 1753798406.80641
       X-Put-Timestamp: 1753798406.80641
                  Vary: Accept
            X-Trans-Id: txa3bbc9f9bae64e508809a-006888d706
X-Openstack-Request-Id: txa3bbc9f9bae64e508809a-006888d706

Загрузим файл /etc/hosts в контейнер test-cont1, проверим его наличие в нём и загрузим обратно:

1
2
3
4
5
6
7
8
9
10
11
$ swift upload test-cont1 /etc/hosts
etc/hosts
    
$ swift list
test-cont1
    
$ swift list test-cont1
etc/hosts
    
$ swift download test-cont1
etc/hosts [auth 0.237s, headers 0.265s, total 0.265s, 0.014 MB/s]

Загруженные объекты хранятся в файлах *.data на swift-storage, найти их можно командой:

1
$ find /srv/node/ -type f -name *.data

Последнее что нужно сделать - указать корректную точку входа для сервиса Swift в настройках Cinder на контроллере (в файле /etc/cinder/cinder.conf):

1
2
[DEFAULT]
backup_swift_url = http://swift-proxy:8080/v1/AUTH

Перезапускаем сервис:

1
$ sudo systemctl restart openstack-cinder-backup

Настройка Swift в качестве хранилища для Glance

Для начала создадим резервную копию файла конфигурации:

1
$ sudo cp /etc/glance/glance-api.conf /etc/glance/glance-api.conf.backup

Вносим изменения в раздел [glance_store] файла /etc/glance/glance-api.conf:

1
2
3
4
5
6
[glance_store]
default_store = swift
stores = swift
default_swift_reference = ref1
swift_store_config_file = /etc/glance/glance-swift.conf
swift_store_create_container_on_put = true

Для хранения настроек бэкэнда будет использоваться файл /etc/glance/glance-swift.conf:

1
2
3
4
5
6
7
[ref1]
auth_address = http://controller:5000/v3
user_domain_id = default
project_domain_id = default
auth_version = 3
user = service:swift
key = openstack

Чтобы Glance мог создавать контейнеры, ему необходимо добавить роль ResellerAdmin в сервисном проекте:

1
2
3
4
5
6
7
8
9
10
11
12
$ openstack role create ResellerAdmin
+-------------+----------------------------------+
| Field       | Value                            |
+-------------+----------------------------------+
| description | None                             |
| domain_id   | None                             |
| id          | 4b76a45e82494240a44bb889ae05e2b9 |
| name        | ResellerAdmin                    |
| options     | {}                               |
+-------------+----------------------------------+

$ openstack role add --project service --user glance ResellerAdmin

Перезагружаем сервис Glance

1
$ sudo systemctl restart openstack-glance-api

После настройки можно проверить работу. Для этого создадим новый образ Cirros (если до этого был загруженный локально образ, то его лучше удалить, так как при сохранённых настройках Swift он станет недоступен):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
$ openstack image create "Cirros" --file cirros-0.6.3-x86_64-disk.img --disk-format qcow2 --container-format bare --public
+------------------+--------------------------------------------------------------------------------------------------------------------------------------------+
| Field            | Value                                                                                                                                      |
+------------------+--------------------------------------------------------------------------------------------------------------------------------------------+
| container_format | bare                                                                                                                                       |
| created_at       | 2025-07-29T14:16:40Z                                                                                                                       |
| disk_format      | qcow2                                                                                                                                      |
| file             | /v2/images/42c38761-0c5e-4d8c-a25d-cdaa2b732158/file                                                                                       |
| id               | 42c38761-0c5e-4d8c-a25d-cdaa2b732158                                                                                                       |
| min_disk         | 0                                                                                                                                          |
| min_ram          | 0                                                                                                                                          |
| name             | Cirros                                                                                                                                     |
| owner            | 405ec2afc2c44f24bfa112645d1dc085                                                                                                           |
| properties       | os_hidden='False', owner_specified.openstack.md5='', owner_specified.openstack.object='images/Cirros', owner_specified.openstack.sha256='' |
| protected        | False                                                                                                                                      |
| schema           | /v2/schemas/image                                                                                                                          |
| status           | queued                                                                                                                                     |
| tags             |                                                                                                                                            |
| updated_at       | 2025-07-29T14:16:40Z                                                                                                                       |
| visibility       | public                                                                                                                                     |
+------------------+--------------------------------------------------------------------------------------------------------------------------------------------+

Для восстановления работы без сервиса Swift достаточно удалить созданный образ, восстановить файл /etc/glance/glance-api из резервной копии и перезагрузить сервис openstack-glance-api.

Nova

Общие сведения

Nova - главный компонент OpenStack. Он отвечает за управление запущенными экземплярами виртуальных машин. Помимо управления ВМ, часть сервисов Nova может обеспечивать управление сетью, но, сейчас эта задача делегирована сервиса Neutron.

Главные сервисы Nova:

  • openstack-nova-api - отвечает за обработку пользовательских вызовов API;
  • openstack-nova-scheduler - сервис-планировщик. Получает запросы из очереди на запуск ВМ и выбирает узел для их запуска. Выбор осуществляется согласно весам после применения фильтров. Вес рассчитывается каждый раз при запуске или миграции ВМ;
  • openstack-nova-conductor - выступает в качестве посредника между базой данных и nova-compute, позволяя осуществлять горизонтальное масштабирование. Этот сервис нельзя развёртывать на тех же узлах, что и nova-compute. Появился в версии Grizzly;
  • openstack-nova-novncproxy - выступает в роли VNC-прокси и позволяет подключаться к консоли виртуальных машин при помощи браузера;
  • openstack-nova-placement-api - отвечает за отслеживание списка ресурсов и их использование. Появился в версии Newton;
  • openstack-nova-compute - демон, управляющий виртуальными машинами через API гипервизора. Как правило, запускается на узлах, где расположен сам гипервизор.

Сервисам Nova требуется брокер сообщений и база данных. Сервисы openstack-nova-api, openstack-nova-scheduler, openstack-nova-conductor и openstack-nova-novncproxy будут расположены вместе с Cinder и Keystone, а openstack-nova-compute - на новом сервере с ролью compute.

OpenStack Nova позволяет подтверждать виртуальным машинам больше физической памяти и вычислительных ресурсов, чем имеется в наличии. По умолчанию планировщик ассоциирует с одним физическим или Hyper-Threading-ядром 16 виртуальных процессоров (vCPU). Конкретной значение устанавливается в файле /etc/nova/nova.conf параметром cpu_allocation_ratio = 16.0.

Таким образом один восьмиядерный процессор с технологией Hyper-Threading даёт $8 * 2 * 16 = 256$ vCPU. Если запускаются требовательные к процессору приложения, то коэффициент снижается (вплоть до 1). Если нагрузка не высокая - то устанавливается значение $16$. Если сложно рассчитать, то лучше использовать значение от $2$ до $5$.

Объём памяти, выделяемой виртуальным машинам по умолчанию, в полтора раза больше, чем имеющейся физической. За это отвечает параметр ram_allocation_ratio = 1.5 в /etc/nova/nova.conf. Рекомендуется указывать значение $0.9$ и задать резервирование оперативной памяти при помощи параметра reserved_host_memory_mb. Обычно в расчётах можно руководствоваться закладыванием на накладные расходы порядка 100 Мб на одну виртуальную машину.

После изменения этих параметров необходимо перезапускать openstack-nova-scheduler.

Настройка контроллера

Устанавливаем необходимые пакеты на контроллере:

1
$ sudo yum install -y openstack-nova-api openstack-nova-conductor openstack-nova-novncproxy openstack-nova-scheduler openstack-placement-api

Создаём базу данных для сервисов Nova и Placement:

1
$ sudo mysql -u root -popenstack
1
2
3
4
5
6
7
8
9
10
11
12
13
CREATE DATABASE nova_api;
CREATE DATABASE nova;
CREATE DATABASE nova_cell0;
CREATE DATABASE placement;

GRANT ALL PRIVILEGES ON nova_api.* TO 'nova'@'localhost' IDENTIFIED BY 'nova';
GRANT ALL PRIVILEGES ON nova_api.* TO 'nova'@'%' IDENTIFIED BY 'nova';
GRANT ALL PRIVILEGES ON nova.* TO 'nova'@'localhost' IDENTIFIED BY 'nova';
GRANT ALL PRIVILEGES ON nova.* TO 'nova'@'%' IDENTIFIED BY 'nova';
GRANT ALL PRIVILEGES ON nova_cell0.* TO 'nova'@'localhost' IDENTIFIED BY 'nova';
GRANT ALL PRIVILEGES ON nova_cell0.* TO 'nova'@'%' IDENTIFIED BY 'nova';
GRANT ALL PRIVILEGES ON placement.* TO 'placement'@'localhost' IDENTIFIED BY 'placement';
GRANT ALL PRIVILEGES ON placement.* TO 'placement'@'%' IDENTIFIED BY 'placement';

Создаём пользователя, роль, сервис и точки входа для сервиса nova:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
$ source keystone_admin

$ openstack user create --domain default --password openstack nova
+---------------------+----------------------------------+
| Field               | Value                            |
+---------------------+----------------------------------+
| domain_id           | default                          |
| enabled             | True                             |
| id                  | 4593ce3cfff04497b3c31b4eac0cd1f6 |
| name                | nova                             |
| options             | {}                               |
| password_expires_at | None                             |
+---------------------+----------------------------------+

$ openstack role add --project service --user nova admin

$ openstack service create --name nova --description "OpenStack Compute Service" compute
+-------------+----------------------------------+
| Field       | Value                            |
+-------------+----------------------------------+
| description | OpenStack Compute Service        |
| enabled     | True                             |
| id          | 5ba848acacdd4365acd0f891620fea1b |
| name        | nova                             |
| type        | compute                          |
+-------------+----------------------------------+

$ openstack endpoint create --region RegionOne compute public http://controller:8774/v2.1
+--------------+----------------------------------+
| Field        | Value                            |
+--------------+----------------------------------+
| enabled      | True                             |
| id           | 804da33633a549d1ba180496bc86cfc7 |
| interface    | public                           |
| region       | RegionOne                        |
| region_id    | RegionOne                        |
| service_id   | 5ba848acacdd4365acd0f891620fea1b |
| service_name | nova                             |
| service_type | compute                          |
| url          | http://controller:8774/v2.1      |
+--------------+----------------------------------+

$ openstack endpoint create --region RegionOne compute internal http://controller:8774/v2.1
+--------------+----------------------------------+
| Field        | Value                            |
+--------------+----------------------------------+
| enabled      | True                             |
| id           | d21e84429f0a44ca9b45b027219242d9 |
| interface    | internal                         |
| region       | RegionOne                        |
| region_id    | RegionOne                        |
| service_id   | 5ba848acacdd4365acd0f891620fea1b |
| service_name | nova                             |
| service_type | compute                          |
| url          | http://controller:8774/v2.1      |
+--------------+----------------------------------+

$ openstack endpoint create --region RegionOne compute admin http://controller:8774/v2.1
+--------------+----------------------------------+
| Field        | Value                            |
+--------------+----------------------------------+
| enabled      | True                             |
| id           | bec4f39b251c42879eb4b2088994ae7e |
| interface    | admin                            |
| region       | RegionOne                        |
| region_id    | RegionOne                        |
| service_id   | 5ba848acacdd4365acd0f891620fea1b |
| service_name | nova                             |
| service_type | compute                          |
| url          | http://controller:8774/v2.1      |
+--------------+----------------------------------+

Повторяем то же самое для сервиса placement:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
$ openstack user create --domain default --password openstack placement
+---------------------+----------------------------------+
| Field               | Value                            |
+---------------------+----------------------------------+
| domain_id           | default                          |
| enabled             | True                             |
| id                  | b149ac740fe5468c86df0f66af6ef742 |
| name                | placement                        |
| options             | {}                               |
| password_expires_at | None                             |
+---------------------+----------------------------------+

$ openstack role add --project service --user placement admin

$ openstack service create --name placement --description "OpenStack Placement API" placement
+-------------+----------------------------------+
| Field       | Value                            |
+-------------+----------------------------------+
| description | OpenStack Placement API          |
| enabled     | True                             |
| id          | 08f7d73484e34f169a9c2bc4144c0b08 |
| name        | placement                        |
| type        | placement                        |
+-------------+----------------------------------+

$ openstack endpoint create --region RegionOne placement public http://controller:8778
+--------------+----------------------------------+
| Field        | Value                            |
+--------------+----------------------------------+
| enabled      | True                             |
| id           | a1c51294328c4d309d002d95e281b2ed |
| interface    | public                           |
| region       | RegionOne                        |
| region_id    | RegionOne                        |
| service_id   | 08f7d73484e34f169a9c2bc4144c0b08 |
| service_name | placement                        |
| service_type | placement                        |
| url          | http://controller:8778           |
+--------------+----------------------------------+

$ openstack endpoint create --region RegionOne placement internal http://controller:8778
+--------------+----------------------------------+
| Field        | Value                            |
+--------------+----------------------------------+
| enabled      | True                             |
| id           | f209b7a67a8b4763bea986d7526774e9 |
| interface    | internal                         |
| region       | RegionOne                        |
| region_id    | RegionOne                        |
| service_id   | 08f7d73484e34f169a9c2bc4144c0b08 |
| service_name | placement                        |
| service_type | placement                        |
| url          | http://controller:8778           |
+--------------+----------------------------------+

$ openstack endpoint create --region RegionOne placement admin http://controller:8778
+--------------+----------------------------------+
| Field        | Value                            |
+--------------+----------------------------------+
| enabled      | True                             |
| id           | 5a36a3663d554b1e8a02a672175eda78 |
| interface    | admin                            |
| region       | RegionOne                        |
| region_id    | RegionOne                        |
| service_id   | 08f7d73484e34f169a9c2bc4144c0b08 |
| service_name | placement                        |
| service_type | placement                        |
| url          | http://controller:8778           |
+--------------+----------------------------------+

Общие параметры для контроллера и вычислительных узлов

Добавляем записи в конфигурационный файл /etc/nova/nova.conf (эти же настройки потом нужно будет перенести на вычислительные узлы compute-*):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
[DEFAULT]
transport_url = rabbit://openstack:openstack@controller
enabled_apis = osapi_compute,metadata
use_neutron = true
firewall_driver = nova.virt.firewall.NoopFirewallDriver

[api]
auth_strategy = keystone

[keystone_authtoken]
project_name = service
user_domain_name = Default
project_domain_name = Default
auth_type = password
username = nova
password = openstack
www_authenticate_uri = http://controller:5000/v3
auth_uri = http://controller:5000
auth_url = http://controller:5000

[glance]
api_servers = http://controller:9292

[cinder]
os_region_name = RegionOne

[oslo_concurrency]
lock_path = /var/lib/nova/tmp

[placement]
os_region_name = RegionOne
project_name = service
user_domain_name = Default
project_domain_name = Default
auth_type = password
username = placement
password = openstack
auth_url = http://controller:5000/v3

[service_user]
send_service_user_token = true
auth_url = http://controller:5000/v3
auth_strategy = keystone
auth_type = password
project_domain_name = Default
project_name = service
user_domain_name = Default
username = nova
password = openstack

Специфичные настройки для контроллера

Добавляем в файл /etc/nova/nova.conf настройки, специфичные для сервера-контроллера:

1
2
3
4
5
6
7
8
9
10
11
12
13
[DEFAULT]
my_ip = 192.168.100.128

[database]
connection = mysql+pymysql://nova:nova@controller/nova

[api_database]
connection = mysql+pymysql://nova:nova@controller/nova_api

[vnc]
server_listen = 192.168.100.128
server_proxyclient_address = 192.168.100.128
enabled = true

В файл /etc/placement/placement.conf добавляем:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
[placement_database]
connection = mysql+pymysql://placement:placement@controller/placement

[api]
auth_strategy = keystone

[keystone_authtoken]
auth_url = http://controller:5000/v3
auth_type = password
project_domain_name = Default
user_domain_name = Default
project_name = service
username = placement
password = openstack

Инициализируем базы данных:

1
2
$ sudo su -s /bin/sh -c "nova-manage api_db sync" nova
$ sudo su -s /bin/sh -c "placement-manage db sync" placement

Регистрируем базу данных cell0 и создаём ячейку cell1:

1
2
$ sudo su -s /bin/sh -c "nova-manage cell_v2 map_cell0" nova
$ sudo su -s /bin/sh -c "nova-manage cell_v2 create_cell --name=cell1 --verbose" nova

Проверяем:

1
2
3
4
5
6
7
$ sudo su -s /bin/sh -c "nova-manage cell_v2 list_cells" nova
+-------+--------------------------------------+------------------------------------+-------------------------------------------------+----------+
|  Name |                 UUID                 |           Transport URL            |               Database Connection               | Disabled |
+-------+--------------------------------------+------------------------------------+-------------------------------------------------+----------+
| cell0 | 00000000-0000-0000-0000-000000000000 |               none:/               | mysql+pymysql://nova:****@controller/nova_cell0 |  False   |
| cell1 | 48931a40-08c3-4371-a97c-d0c742358152 | rabbit://openstack:****@controller |    mysql+pymysql://nova:****@controller/nova    |  False   |
+-------+--------------------------------------+------------------------------------+-------------------------------------------------+----------+

Заполняем базу данных:

1
$ sudo su -s /bin/sh -c "nova-manage db sync" nova

В файл /etc/httpd/conf.d/00-placement-api.conf нужно добавить блок с разрешениями в <VirtualHost *:8778>:

1
2
3
4
5
<Directory /usr/bin>
 Require all granted
 AllowOverride None
 Options +ExecCGI
</Directory>

Проверяем корректность синтаксиса:

1
$ apachectl configtest

Перезапускаем Apache (в первую очередь); активируем и запускаем сервисы Nova на контроллере:

1
2
3
$ sudo systemctl restart httpd
$ sudo systemctl enable openstack-nova-api openstack-nova-scheduler openstack-nova-conductor openstack-nova-novncproxy
$ sudo systemctl start openstack-nova-api openstack-nova-scheduler openstack-nova-conductor openstack-nova-novncproxy

Настройка вычислительных узлов

Устанавливаем необходимые пакеты на нодах compute:

1
$ sudo yum -y install openstack-nova-compute sysfsutils libvirt

Далее нужно указать общие с контроллером параметры Nova в файле /etc/nova/nova.conf:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
[DEFAULT]
transport_url = rabbit://openstack:openstack@controller
enabled_apis = osapi_compute,metadata
use_neutron = true
firewall_driver = nova.virt.firewall.NoopFirewallDriver

[api]
auth_strategy = keystone

[keystone_authtoken]
project_name = service
user_domain_name = Default
project_domain_name = Default
auth_type = password
username = nova
password = openstack
www_authenticate_uri = http://controller:5000/v3
auth_uri = http://controller:5000
auth_url = http://controller:5000

[glance]
api_servers = http://controller:9292

[cinder]
os_region_name = RegionOne

[oslo_concurrency]
lock_path = /var/lib/nova/tmp

[placement]
os_region_name = RegionOne
project_name = service
user_domain_name = Default
project_domain_name = Default
auth_type = password
username = placement
password = openstack
auth_url = http://controller:5000/v3

[service_user]
send_service_user_token = true
auth_url = http://controller:5000/v3
auth_strategy = keystone
auth_type = password
project_domain_name = Default
project_name = service
user_domain_name = Default
username = nova
password = openstack

Далее важно определиться, поддерживает ли каждый узел аппаратную виртуализацию:

1
$ sudo grep -E 'svm|vpx' /proc/cpuinfo

Если какой-то вывод присутствует, то никаких действий не требуется. Однако же если вывод пуст, то нужно указать виртуализацию QEMU в файле /etc/nova/nova.conf в [libvirt].

1
2
[libvirt]
virt_type = qemu

Указываем оставшиеся параметры в /etc/nova/nova.conf (не забывая заменить IP адрес конкретного вычислительного узла в server_proxyclient_address):

1
2
3
4
5
6
7
8
9
10
11
12
[DEFAULT]
my_ip = {IP_адрес_вычислительного_узла}
instances_path = /var/lib/nova/instances
# следующую строку нужно разкомментировать
compute_driver=libvirt.LibvirtDriver

[vnc]
enabled = true
server_listen = 0.0.0.0
# здесь указываем адрес контроллера
novncproxy_base_url = http://192.168.100.128:6080/vnc_auto.html
server_proxyclient_address = {IP_адрес_вычислительного_узла}

Активируем и запускаем сервисы:

1
2
$ sudo systemctl enable libvirtd openstack-nova-compute
$ sudo systemctl start libvirtd openstack-nova-compute

Теперь можно проверить работу сервисов:

1
2
3
4
5
6
7
8
9
10
11
$ source keystone_admin

$ nova service-list # или openstack compute service list
+--------------------------------------+----------------+------------+----------+---------+-------+----------------------------+-----------------+-------------+
| Id                                   | Binary         | Host       | Zone     | Status  | State | Updated_at                 | Disabled Reason | Forced down |
+--------------------------------------+----------------+------------+----------+---------+-------+----------------------------+-----------------+-------------+
| 26463490-59bc-4851-9d8e-ffc69a05282e | nova-scheduler | controller | internal | enabled | up    | 2025-07-30T11:14:21.000000 | -               | False       |
| eae12d31-d116-45b0-845d-656266dd6aa2 | nova-conductor | controller | internal | enabled | up    | 2025-07-30T11:14:21.000000 | -               | False       |
| fd14c728-22fd-487c-9eb0-d973b356e0b5 | nova-compute   | compute-1  | nova     | enabled | up    | 2025-07-30T11:14:20.000000 | -               | False       |
| 0dfa773b-a35d-4bfa-bb69-ba1fb935d91a | nova-compute   | compute-2  | nova     | enabled | up    | 2025-07-30T11:14:20.000000 | -               | False       |
+--------------------------------------+----------------+------------+----------+---------+-------+----------------------------+-----------------+-------------+

Теперь регистрирует гипервизоры:

1
$ sudo su -s /bin/sh -c "nova-manage cell_v2 discover_hosts --verbose" nova

Для проверки регистрации гипервизоров в Placement необходимо установить дополнительный пакет и выполнить команду:

1
2
3
4
5
6
7
8
9
$ sudo yum -y install python3-osc-placement

$ openstack resource provider list
+--------------------------------------+-----------+------------+--------------------------------------+----------------------+
| uuid                                 | name      | generation | root_provider_uuid                   | parent_provider_uuid |
+--------------------------------------+-----------+------------+--------------------------------------+----------------------+
| 8703c883-8363-4f00-82ee-f527f582f984 | compute-1 |          2 | 8703c883-8363-4f00-82ee-f527f582f984 | None                 |
| 02d2ea3c-26df-479a-877b-b185be68a4b7 | compute-2 |          2 | 02d2ea3c-26df-479a-877b-b185be68a4b7 | None                 |
+--------------------------------------+-----------+------------+--------------------------------------+----------------------+

Проверяем работу Placement API:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
$ sudo su -s /bin/sh -c "nova-status upgrade check" nova
+-------------------------------------------+
| Upgrade Check Results                     |
+-------------------------------------------+
| Check: Cells v2                           |
| Result: Success                           |
| Details: None                             |
+-------------------------------------------+
| Check: Placement API                      |
| Result: Success                           |
| Details: None                             |
+-------------------------------------------+
| Check: Cinder API                         |
| Result: Success                           |
| Details: None                             |
+-------------------------------------------+
| Check: Policy Scope-based Defaults        |
| Result: Success                           |
| Details: None                             |
+-------------------------------------------+
| Check: Policy File JSON to YAML Migration |
| Result: Success                           |
| Details: None                             |
+-------------------------------------------+
| Check: Older than N-1 computes            |
| Result: Success                           |
| Details: None                             |
+-------------------------------------------+
| Check: hw_machine_type unset              |
| Result: Success                           |
| Details: None                             |
+-------------------------------------------+
| Check: Service User Token Configuration   |
| Result: Success                           |
| Details: None                             |
+-------------------------------------------+

Командой hypervisor-show можно получить подробную информацию по конкретному гипервизору:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
$ nova --os-compute-api-version 2 hypervisor-show compute-1
+---------------------------+------------------------------------------+
| Property                  | Value                                    |
+---------------------------+------------------------------------------+
| cpu_info_arch             | x86_64                                   |
| cpu_info_features         | ["sbdr-ssdp-no", "tsc_adjust", "fbsdp-   |
|                           | no", "fsrs", "tsc", "x2apic", "vme",     |
|                           | "cx16", "sse2", "de", "umip", "sse",     |
|                           | "clwb", "mca", "vmx", "xsave", "arat",   |
|                           | "sep", "flush-l1d", "pse36", "gds-no",   |
|                           | "vpclmulqdq", "lm", "pni", "apic",       |
|                           | "sse4.1", "vaes", "spec-ctrl", "rfds-    |
|                           | clear", "bmi1", "3dnowprefetch", "amd-   |
|                           | ssbd", "waitpkg", "fxsr", "rdrand",      |
|                           | "f16c", "mce", "lahf_lm", "avx2", "pse", |
|                           | "cx8", "pat", "pschange-mc-no",          |
|                           | "syscall", "skip-l1dfl-vmentry", "avx",  |
|                           | "smap", "aes", "pae", "mmx",             |
|                           | "serialize", "sha-ni", "bmi2",           |
|                           | "xgetbv1", "ibrs-all", "clflushopt",     |
|                           | "stibp", "adx", "erms", "fsrm", "arch-   |
|                           | capabilities", "fma", "movbe", "ibpb",   |
|                           | "tsc-deadline", "xsavec", "pclmuldq",    |
|                           | "gfni", "ssse3", "amd-stibp",            |
|                           | "xsaveopt", "psdp-no", "mtrr", "cmov",   |
|                           | "mds-no", "rdpid", "md-clear", "pcid",   |
|                           | "invpcid", "popcnt", "hypervisor", "avx- |
|                           | vnni", "movdir64b", "nx", "fpu",         |
|                           | "rdseed", "ibrs", "movdiri", "fsgsbase", |
|                           | "clflush", "pge", "abm", "sse4.2",       |
|                           | "xsaves", "ss", "msr", "ssbd", "rdctl-   |
|                           | no", "pku", "rdtscp", "pdpe1gb", "smep"] |
| cpu_info_model            | Skylake-Client-v3                        |
| cpu_info_topology_cells   | 1                                        |
| cpu_info_topology_cores   | 1                                        |
| cpu_info_topology_sockets | 2                                        |
| cpu_info_topology_threads | 1                                        |
| cpu_info_vendor           | Intel                                    |
| current_workload          | 0                                        |
| disk_available_least      | 13                                       |
| free_disk_gb              | 16                                       |
| free_ram_mb               | 1195                                     |
| host_ip                   | 192.168.100.197                          |
| hypervisor_hostname       | compute-1                                |
| hypervisor_type           | QEMU                                     |
| hypervisor_version        | 9001000                                  |
| id                        | 1                                        |
| local_gb                  | 16                                       |
| local_gb_used             | 0                                        |
| memory_mb                 | 1707                                     |
| memory_mb_used            | 512                                      |
| running_vms               | 0                                        |
| service_disabled_reason   | None                                     |
| service_host              | compute-1                                |
| service_id                | 9                                        |
| state                     | up                                       |
| status                    | enabled                                  |
| vcpus                     | 2                                        |
| vcpus_used                | 0                                        |
+---------------------------+------------------------------------------+

$ nova --os-compute-api-version 2 hypervisor-show compute-2
+---------------------------+------------------------------------------+
| Property                  | Value                                    |
+---------------------------+------------------------------------------+
| cpu_info_arch             | x86_64                                   |
| cpu_info_features         | ["adx", "gds-no", "smap", "cx16",        |
|                           | "pcid", "fsrm", "fsrs", "rdseed", "pni", |
|                           | "avx-vnni", "sbdr-ssdp-no", "lahf_lm",   |
|                           | "mds-no", "pat", "sse2", "lm", "mtrr",   |
|                           | "apic", "pschange-mc-no", "syscall",     |
|                           | "mce", "pku", "fxsr", "movbe", "xsavec", |
|                           | "movdiri", "psdp-no", "3dnowprefetch",   |
|                           | "gfni", "mca", "fbsdp-no", "flush-l1d",  |
|                           | "arat", "vme", "amd-ssbd", "avx", "fma", |
|                           | "amd-stibp", "popcnt", "invpcid",        |
|                           | "sse4.2", "erms", "clflush", "xsaveopt", |
|                           | "x2apic", "pae", "sep", "spec-ctrl",     |
|                           | "pclmuldq", "xsaves", "vaes",            |
|                           | "movdir64b", "cx8", "rfds-clear",        |
|                           | "cmov", "vmx", "rdtscp", "ssbd", "sse",  |
|                           | "tsc", "smep", "skip-l1dfl-vmentry",     |
|                           | "ss", "clflushopt", "hypervisor", "de",  |
|                           | "avx2", "rdpid", "stibp", "fsgsbase",    |
|                           | "fpu", "mmx", "tsc-deadline", "aes",     |
|                           | "sse4.1", "clwb", "bmi1", "xsave",       |
|                           | "ssse3", "abm", "vpclmulqdq", "rdctl-    |
|                           | no", "sha-ni", "pse36", "serialize",     |
|                           | "xgetbv1", "pse", "umip", "f16c", "arch- |
|                           | capabilities", "bmi2", "ibpb", "nx",     |
|                           | "msr", "pdpe1gb", "waitpkg", "ibrs-all", |
|                           | "ibrs", "pge", "md-clear", "rdrand",     |
|                           | "tsc_adjust"]                            |
| cpu_info_model            | Skylake-Client-v3                        |
| cpu_info_topology_cells   | 1                                        |
| cpu_info_topology_cores   | 1                                        |
| cpu_info_topology_sockets | 2                                        |
| cpu_info_topology_threads | 1                                        |
| cpu_info_vendor           | Intel                                    |
| current_workload          | 0                                        |
| disk_available_least      | 13                                       |
| free_disk_gb              | 16                                       |
| free_ram_mb               | 1195                                     |
| host_ip                   | 192.168.100.213                          |
| hypervisor_hostname       | compute-2                                |
| hypervisor_type           | QEMU                                     |
| hypervisor_version        | 9001000                                  |
| id                        | 2                                        |
| local_gb                  | 16                                       |
| local_gb_used             | 0                                        |
| memory_mb                 | 1707                                     |
| memory_mb_used            | 512                                      |
| running_vms               | 0                                        |
| service_disabled_reason   | None                                     |
| service_host              | compute-2                                |
| service_id                | 10                                       |
| state                     | up                                       |
| status                    | enabled                                  |
| vcpus                     | 2                                        |
| vcpus_used                | 0                                        |
+---------------------------+------------------------------------------+

Зоны доступности и агрегирование вычислительных узлов в Nova

Агрегатор узлов - логическое объединение узлов, но с привязкой дополнительных метаданных. Агрегаторы позволяют группировать узлы по различным специфичным признакам. Один узел может входить в несколько агрегаторов.

Создаём агрегатор, добавляем в него гипервизор и метаданные, которые в дальнейшем будут использоваться для выбора узла:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
$ source keystone_admin

$ nova aggregate-create MyAggregate
+----+-------------+-------------------+-------+----------+--------------------------------------+
| Id | Name        | Availability Zone | Hosts | Metadata | UUID                                 |
+----+-------------+-------------------+-------+----------+--------------------------------------+
| 1  | MyAggregate | -                 |       |          | cffb7d5c-a838-443e-8397-3037aa6a50c8 |
+----+-------------+-------------------+-------+----------+--------------------------------------+

$ nova aggregate-add-host MyAggregate compute-1
Host compute-1 has been successfully added for aggregate 1 
+----+-------------+-------------------+-------------+----------+--------------------------------------+
| Id | Name        | Availability Zone | Hosts       | Metadata | UUID                                 |
+----+-------------+-------------------+-------------+----------+--------------------------------------+
| 1  | MyAggregate | -                 | 'compute-1' |          | cffb7d5c-a838-443e-8397-3037aa6a50c8 |
+----+-------------+-------------------+-------------+----------+--------------------------------------+

$ nova aggregate-set-metadata MyAggregate mynewmetadata=true
Metadata has been successfully updated for aggregate 1.
+----+-------------+-------------------+-------------+----------------------+--------------------------------------+
| Id | Name        | Availability Zone | Hosts       | Metadata             | UUID                                 |
+----+-------------+-------------------+-------------+----------------------+--------------------------------------+
| 1  | MyAggregate | -                 | 'compute-1' | 'mynewmetadata=true' | cffb7d5c-a838-443e-8397-3037aa6a50c8 |
+----+-------------+-------------------+-------------+----------------------+--------------------------------------+

Теперь с этим агрегатом можно создать флейвор и добавить к нему необходимые метаданные:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
$ nova flavor-create --is-public true m2.mynewmdvm auto 300 1 1
+--------------------------------------+--------------+------------+------+-----------+------+-------+-------------+-----------+-------------+
| ID                                   | Name         | Memory_MiB | Disk | Ephemeral | Swap | VCPUs | RXTX_Factor | Is_Public | Description |
+--------------------------------------+--------------+------------+------+-----------+------+-------+-------------+-----------+-------------+
| 69b1e5c2-ff17-4e94-acf0-7dc12239b20d | m2.mynewmdvm | 300        | 1    | 0         | 0    | 1     | 1.0         | True      | -           |
+--------------------------------------+--------------+------------+------+-----------+------+-------+-------------+-----------+-------------+

$ nova flavor-key m2.mynewmdvm set mynewmetadata=true

$ nova flavor-show m2.mynewmdvm
+----------------------------+--------------------------------------+
| Property                   | Value                                |
+----------------------------+--------------------------------------+
| OS-FLV-DISABLED:disabled   | False                                |
| OS-FLV-EXT-DATA:ephemeral  | 0                                    |
| description                | -                                    |
| disk                       | 1                                    |
| extra_specs                | {"mynewmetadata": "true"}            |
| id                         | 69b1e5c2-ff17-4e94-acf0-7dc12239b20d |
| name                       | m2.mynewmdvm                         |
| os-flavor-access:is_public | True                                 |
| ram                        | 300                                  |
| rxtx_factor                | 1.0                                  |
| swap                       | 0                                    |
| vcpus                      | 1                                    |
+----------------------------+--------------------------------------+

Теперь виртуальная машина, созданная с флейвором m2.mynewmdvm, будет размещена только на вычислительном узле compute-1.

Все зоны доступности в Nova - это подмножества агрегаторов. Они позволяют группировать узлы OpenStack в логические группы с общим элементов доступности. Например, это могут быть две независимые площадки с раздельным питанием и доступом в интернет, или просто две соседние стойки. По умолчанию все вычислительные узлы создаются в зоне доступности Nova.

Создание зоны доступности:

1
2
3
4
5
6
7
8
$ source keystone_admin 

$ nova aggregate-create MyAggregateZ MyZone
+----+--------------+-------------------+-------+----------------------------+--------------------------------------+
| Id | Name         | Availability Zone | Hosts | Metadata                   | UUID                                 |
+----+--------------+-------------------+-------+----------------------------+--------------------------------------+
| 2  | MyAggregateZ | MyZone            |       | 'availability_zone=MyZone' | 49750781-9a93-4b22-9125-833bb10584cc |
+----+--------------+-------------------+-------+----------------------------+--------------------------------------+

Добавляем второй доступный хост в зону доступности:

1
2
3
4
5
6
7
$ nova aggregate-add-host MyAggregateZ compute-2
Host compute-2 has been successfully added for aggregate 2 
+----+--------------+-------------------+-------------+----------------------------+--------------------------------------+
| Id | Name         | Availability Zone | Hosts       | Metadata                   | UUID                                 |
+----+--------------+-------------------+-------------+----------------------------+--------------------------------------+
| 2  | MyAggregateZ | MyZone            | 'compute-2' | 'availability_zone=MyZone' | 49750781-9a93-4b22-9125-833bb10584cc |
+----+--------------+-------------------+-------------+----------------------------+--------------------------------------+

Проверяем:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
$ nova availability-zone-list
+---------------------+----------------------------------------+
| Name                | Status                                 |
+---------------------+----------------------------------------+
| MyZone              | available                              |
| |- compute-2        |                                        |
| | |- nova-compute   | enabled :-) 2025-07-30T11:17:20.000000 |
| internal            | available                              |
| |- controller       |                                        |
| | |- nova-scheduler | enabled :-) 2025-07-30T11:17:21.000000 |
| | |- nova-conductor | enabled :-) 2025-07-30T11:17:21.000000 |
| nova                | available                              |
| |- compute-1        |                                        |
| | |- nova-compute   | enabled :-) 2025-07-30T11:17:20.000000 |
+---------------------+----------------------------------------+

Зона доступности по умолчанию устанавливается параметром default_availability_zone в /etc/nova/nova.conf на управляющих узлах.

Для удаления агрегатора нужно сначала удалить гипервизоры из него, затем и сами агрегаторы:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
$ source keystone_admin

$ nova aggregate-remove-host MyAggregate compute-1
Host compute-1 has been successfully removed from aggregate 1 
+----+-------------+-------------------+-------+----------------------+--------------------------------------+
| Id | Name        | Availability Zone | Hosts | Metadata             | UUID                                 |
+----+-------------+-------------------+-------+----------------------+--------------------------------------+
| 1  | MyAggregate | -                 |       | 'mynewmetadata=true' | cffb7d5c-a838-443e-8397-3037aa6a50c8 |
+----+-------------+-------------------+-------+----------------------+--------------------------------------+

$ nova aggregate-remove-host MyAggregateZ compute-2
Host compute-2 has been successfully removed from aggregate 2 
+----+--------------+-------------------+-------+----------------------------+--------------------------------------+
| Id | Name         | Availability Zone | Hosts | Metadata                   | UUID                                 |
+----+--------------+-------------------+-------+----------------------------+--------------------------------------+
| 2  | MyAggregateZ | MyZone            |       | 'availability_zone=MyZone' | 49750781-9a93-4b22-9125-833bb10584cc |
+----+--------------+-------------------+-------+----------------------------+--------------------------------------+

$ nova aggregate-delete MyAggregate
Aggregate 1 has been successfully deleted.

$ nova aggregate-delete MyAggregateZ
Aggregate 2 has been successfully deleted.

Neutron

Общие сведения

Neutron - сетевой сервис облачной операционной системы, использующий множество технологий, включая стандартные технологии коммутации (NetFlow, RSPAN, SPAN, LACP, 802.1q, GRE, VXLAN), балансировку нагрузки, брандмауэр, VPN и другое. Часть функционала реализуется через подключаемые модули сторонних производителей, а часть зависит от компонентов GNU/Linux (например, OpenVSwitch).

Основные абстракции, которыми оперирует Neutron:

  • сеть - содержит в себе подсети. Различают внутренние (виртуальные) сети, которых может быть много, и как минимум одну внешнюю сеть. Доступ к ВМ внутри внутренней сети могут получить только машины из этой же сети или узлы, связанные через виртуальные маршрутизаторы. Внешняя сеть представляет собой отображение части реально существующей физической сети и необходима для обеспечения сетевой связанности ВМ внутри облака, использующих внутренние сети, и “внешнего мира”;
  • подсеть - ассоциированные с сетью подсеть; именно через неё задаётся диапазон IP-адресов;
  • маршрутизатор - служит для маршрутизации между сетями. Может иметь шлюз и множество интерфейсов, соединяющих подсети;
  • группа безопасности - набор правил брандмауэра, применяющихся к виртуальным машинам в этой группе;
  • плавающий IP-адрес - IP-адрес внешний сети, назначаемый экземпляру виртуальной машины. Может быть выделен только из существующей внешней сети;
  • порт - подключение к сети. Включает в себя MAC и IP.

Один узел может обслуживать несколько проектов с отдельными сетями, адресные пространства которых могут совпадать. Пересечение сетевых пространств реализуется при помощи пространств имён (namespaces). Сетевые пространства имён позволяют на одной машине иметь несколько ARP и таблиц маршрутизации, сетевых устройств и так далее.

Основные сервисы компонента Neutron:

  • сервис узла контроллера:
    • neutron-server - центральный управляющий компонент. Не занимается непосредственно маршрутизацией пакетов. Взаимодействует через брокер сообщений;
  • сервисы сетевого узла:
    • neutron-openvswitch-agent - взаимодействует с neutron-server через брокер сообщений и отдаёт команды OVS для построения таблицы потоков. При этом используются локальные команды OVS и протокол OpenFlow не используется;
    • neutron-l3-agent - обеспечивает маршрутизацию и NAT;
    • openvswitch - программный коммутатор, используемый для построения сетей. Не является проектом OpenStack;
    • neutron-dhcp-agent - сервис отвечает за запуск и управление процессами dnsmasq (легковесный dhcp-сервер и сервис кеширования DNS). Также он отвечает за запуск прокси-процессов сервера предоставления метаданных. По умолчанию каждая сеть, создаваемая агентом, получает собственное пространство имён qdhcp-UUID_сети;
    • neutron-metadata-agent - позволяет ВМ запрашивать данные о себе (имя узла, ssh-ключ и так далее). Экземпляры ВМ получают эту информацию во время загрузки скриптом, подобным cloud-init, обращаясь на адрес http://169.254.169.254. Агент проксирует соответствующие запросы к nova-api при помощи пространства имён или DHCP;
    • neutron-ovs-cleanup - отвечает во время старта за удаление из базы данных OVS неиспользуемых мостов старых виртуальных машин;
  • сервисы вычислительных узлов:
    • openvswitch;
    • neutron-openvswitch-agent.

Во время создания экземпляра ВМ сервис Nova отправляет запрос на сервис neutron-server, отвечающий за API. Тот, в свою очередь, отправляет запросу агенту DHCP на создание IP-адреса. Он обращается к dnsmasq, отвечающему за подсеть, в которой создаётся виртуальная машина. dnsmasq возвращает первый свободный IP-адрес из диапазона подсети, после чего агент DHCP отправляет этот адрес сервису neutron-server.

После того как за ВМ закрепится IP-адрес, сервис Neutron отправляет запрос на Open vSwitch для создания конфигурации, включающей IP-адрес в существующую сеть. Требуемые параметры конфигурации возвращаются обратно на сервис Neutron при помощи шины сообщений, а далее Neutron отправляет их сервису Nova.

Общие настройки для управляющего, сетевого и вычислительных узлов

Следующие конфигурационные файлы необходимо иметь на управляющем, сетевом и вычислительных узлах (controller, network и compute-*1*).

Файл /etc/neutron/neutron.conf:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
[DEFAULT]
transport_url = rabbit://openstack:openstack@controller
auth_strategy = keystone
core_plugin = ml2 
service_plugins = router
allow_overlapping_ips = true

[keystone_authtoken]
project_name = service
user_domain_name = Default
project_domain_name = Default
auth_type = password
username = neutron
password = openstack
auth_uri = http://controller:5000/v3
auth_url = http://controller:5000/v3

[oslo_concurrency]
lock_path = /var/lib/neutron/tmp

Файл /etc/neutron/plugins/ml2/ml2_conf.ini:

1
2
3
4
5
6
7
8
9
10
11
[ml2]
type_drivers = flat,gre,vlan,vxlan
tenant_network_types = gre
mechanism_drivers = openvswitch

[ml2_type_gre]
tunnel_id_ranges = 1:1000

[securitygroup]
enable_security_group = true
enable_ipset = true

Настройка узла управления

Устанавливаем необходимые пакеты на контроллере:

1
$ sudo yum -y install openstack-neutron openstack-neutron-ml2

Создаём экземпляр базы данных:

1
$ sudo mysql -u root -popenstack
1
2
3
4
CREATE DATABASE neutron;

GRANT ALL PRIVILEGES ON neutron.* TO 'neutron'@'localhost' IDENTIFIED BY 'neutron';
GRANT ALL PRIVILEGES ON neutron.* TO 'neutron'@'%' IDENTIFIED BY 'neutron';

Создаём пользователя, сервис и точки входа:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
$ source keystone_admin

$ openstack user create --domain default --password openstack neutron
+---------------------+----------------------------------+
| Field               | Value                            |
+---------------------+----------------------------------+
| domain_id           | default                          |
| enabled             | True                             |
| id                  | 1829837309244512923553fc121b95da |
| name                | neutron                          |
| options             | {}                               |
| password_expires_at | None                             |
+---------------------+----------------------------------+

$ openstack role add --project service --user neutron admin

$ openstack service create --name neutron --description "OpenStack Networking" network
+-------------+----------------------------------+
| Field       | Value                            |
+-------------+----------------------------------+
| description | OpenStack Networking             |
| enabled     | True                             |
| id          | 15c7855d72de4d5c9b242d2fce462695 |
| name        | neutron                          |
| type        | network                          |
+-------------+----------------------------------+

$ openstack endpoint create --region RegionOne network public http://controller:9696
+--------------+----------------------------------+
| Field        | Value                            |
+--------------+----------------------------------+
| enabled      | True                             |
| id           | 2fca2af79d50428bac3ef48d1fb4a6ca |
| interface    | public                           |
| region       | RegionOne                        |
| region_id    | RegionOne                        |
| service_id   | 15c7855d72de4d5c9b242d2fce462695 |
| service_name | neutron                          |
| service_type | network                          |
| url          | http://controller:9696           |
+--------------+----------------------------------+

$ openstack endpoint create --region RegionOne network internal http://controller:9696
+--------------+----------------------------------+
| Field        | Value                            |
+--------------+----------------------------------+
| enabled      | True                             |
| id           | 85fbfa21a7c04683b676c7141eca10f4 |
| interface    | internal                         |
| region       | RegionOne                        |
| region_id    | RegionOne                        |
| service_id   | 15c7855d72de4d5c9b242d2fce462695 |
| service_name | neutron                          |
| service_type | network                          |
| url          | http://controller:9696           |
+--------------+----------------------------------+

$ openstack endpoint create --region RegionOne network admin http://controller:9696
+--------------+----------------------------------+
| Field        | Value                            |
+--------------+----------------------------------+
| enabled      | True                             |
| id           | 9e0ff015e3d64c58a4cd8bcbbd742aa2 |
| interface    | admin                            |
| region       | RegionOne                        |
| region_id    | RegionOne                        |
| service_id   | 15c7855d72de4d5c9b242d2fce462695 |
| service_name | neutron                          |
| service_type | network                          |
| url          | http://controller:9696           |
+--------------+----------------------------------+

Далее устанавливаем общие с другими (network, compute-*) узлами настройки из предыдущего раздела. Файл /etc/neutron/neutron.conf:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
[DEFAULT]
transport_url = rabbit://openstack:openstack@controller
auth_strategy = keystone
core_plugin = ml2 
service_plugins = router
allow_overlapping_ips = true

[keystone_authtoken]
project_name = service
user_domain_name = Default
project_domain_name = Default
auth_type = password
username = neutron
password = openstack
auth_uri = http://controller:5000/v3
auth_url = http://controller:5000/v3

[oslo_concurrency]
lock_path = /var/lib/neutron/tmp

Файл /etc/neutron/plugins/ml2/ml2_conf.ini:

1
2
3
4
5
6
7
8
9
10
11
[ml2]
type_drivers = flat,gre,vlan,vxlan
tenant_network_types = gre
mechanism_drivers = openvswitch

[ml2_type_gre]
tunnel_id_ranges = 1:1000

[securitygroup]
enable_security_group = true
enable_ipset = true

Добавляем специфичные настройки контроллера.

Файл /etc/neutron/neutron.conf:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
[DEFAULT]
notify_nova_on_port_status_changes = true
notify_nova_on_port_data_changes = true

[database]
connection = mysql+pymysql://neutron:neutron@controller/neutron

[nova]
auth_url = http://controller:5000
auth_type = password
project_domain_name = default
user_domain_name = default
region_name = RegionOne
project_name = service
username = nova
password = openstack

Файл /etc/nova/nova.conf:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
[DEFAULT]
network_api_class = nova.network.neutronv2.api.API
security_group_api = neutron
linuxnet_interface_driver = nova.network.linux_net.LinuxOVSInterfaceDriver
firewall_driver = nova.virt.firewall.NoopFirewallDriver

[neutron]
url = http://controller:9696
auth_url = http://controller:5000/v3
auth_type = password
project_domain_name = Default
user_domain_name = Default
region_name = RegionOne
project_name = service
username = neutron
password = openstack
service_metadata_proxy = true
metadata_proxy_shared_secret = openstack

После сохранения заполняем базу данных:

1
$ sudo 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

Поскольку Neutron ожидает, что настройки основного подключаемого модуля задаются в файлах директории /etc/neutron/, нужно создать символическую ссылку на конфигурационный файл подключаемого модуля ML2:

1
$ sudo ln -s /etc/neutron/plugins/ml2/ml2_conf.ini /etc/neutron/plugin.ini

Перезапускаем и активируем сервисы:

1
2
$ sudo systemctl restart openstack-nova-api openstack-nova-scheduler openstack-nova-conductor
$ sudo systemctl enable neutron-server; sudo systemctl start neutron-server

Проверяем, что все расширения Neutron загружены и сервис работает:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
$ neutron ext-list
neutron CLI is deprecated and will be removed in the Z cycle. Use openstack CLI instead.
+---------------------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------+
| alias                                 | name                                                                                                                                                           |
+---------------------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------+
| address-group                         | Address group                                                                                                                                                  |
| address-scope                         | Address scope                                                                                                                                                  |
| router-admin-state-down-before-update | Enforce Router's Admin State Down Before Update Extension                                                                                                      |
| agent                                 | agent                                                                                                                                                          |
| agent-resources-synced                | Agent's Resource View Synced to Placement                                                                                                                      |
| allowed-address-pairs                 | Allowed Address Pairs                                                                                                                                          |
| auto-allocated-topology               | Auto Allocated Topology Services                                                                                                                               |
| availability_zone                     | Availability Zone                                                                                                                                              |
| availability_zone_filter              | Availability Zone Filter Extension                                                                                                                             |
| default-subnetpools                   | Default Subnetpools                                                                                                                                            |
| dhcp_agent_scheduler                  | DHCP Agent Scheduler                                                                                                                                           |
| dvr                                   | Distributed Virtual Router                                                                                                                                     |
| empty-string-filtering                | Empty String Filtering Extension                                                                                                                               |
| external-net                          | Neutron external network                                                                                                                                       |
| extra_dhcp_opt                        | Neutron Extra DHCP options                                                                                                                                     |
| extraroute                            | Neutron Extra Route                                                                                                                                            |
| extraroute-atomic                     | Atomically add/remove extra routes                                                                                                                             |
| filter-validation                     | Filter parameters validation                                                                                                                                   |
| fip-port-details                      | Floating IP Port Details Extension                                                                                                                             |
| flavors                               | Neutron Service Flavors                                                                                                                                        |
| floatingip-pools                      | Floating IP Pools Extension                                                                                                                                    |
| ip-substring-filtering                | IP address substring filtering                                                                                                                                 |
| router                                | Neutron L3 Router                                                                                                                                              |
| ext-gw-mode                           | Neutron L3 Configurable external gateway mode                                                                                                                  |
| l3-ha                                 | HA Router extension                                                                                                                                            |
| l3-flavors                            | Router Flavor Extension                                                                                                                                        |
| l3-port-ip-change-not-allowed         | Prevent L3 router ports IP address change extension                                                                                                            |
| l3_agent_scheduler                    | L3 Agent Scheduler                                                                                                                                             |
| multi-provider                        | Multi Provider Network                                                                                                                                         |
| net-mtu                               | Network MTU                                                                                                                                                    |
| net-mtu-writable                      | Network MTU (writable)                                                                                                                                         |
| network_availability_zone             | Network Availability Zone                                                                                                                                      |
| network-ip-availability               | Network IP Availability                                                                                                                                        |
| pagination                            | Pagination support                                                                                                                                             |
| port-device-profile                   | Port device profile                                                                                                                                            |
| port-mac-address-regenerate           | Neutron Port MAC address regenerate                                                                                                                            |
| port-numa-affinity-policy             | Port NUMA affinity policy                                                                                                                                      |
| binding                               | Port Binding                                                                                                                                                   |
| binding-extended                      | Port Bindings Extended                                                                                                                                         |
| project-id                            | project_id field enabled                                                                                                                                       |
| provider                              | Provider Network                                                                                                                                               |
| quota-check-limit                     | Quota engine limit check                                                                                                                                       |
| quotas                                | Quota management support                                                                                                                                       |
| quota_details                         | Quota details management support                                                                                                                               |
| rbac-policies                         | RBAC Policies                                                                                                                                                  |
| rbac-address-group                    | Add address_group type to RBAC                                                                                                                                 |
| rbac-address-scope                    | Add address_scope type to RBAC                                                                                                                                 |
| rbac-security-groups                  | Add security_group type to network RBAC                                                                                                                        |
| rbac-subnetpool                       | Add subnetpool type to RBAC                                                                                                                                    |
| revision-if-match                     | If-Match constraints based on revision_number                                                                                                                  |
| standard-attr-revisions               | Resource revision numbers                                                                                                                                      |
| router_availability_zone              | Router Availability Zone                                                                                                                                       |
| security-groups-normalized-cidr       | Normalized CIDR field for security group rules                                                                                                                 |
| port-security-groups-filtering        | Port filtering on security groups                                                                                                                              |
| security-groups-remote-address-group  | Remote address group id field for security group rules                                                                                                         |
| security-groups-shared-filtering      | Security group filtering on the shared field                                                                                                                   |
| security-group                        | security-group                                                                                                                                                 |
| service-type                          | Neutron Service Type Management                                                                                                                                |
| sorting                               | Sorting support                                                                                                                                                |
| standard-attr-description             | standard-attr-description                                                                                                                                      |
| stateful-security-group               | Stateful security group                                                                                                                                        |
| subnet_onboard                        | Subnet Onboard                                                                                                                                                 |
| subnet-service-types                  | Subnet service types                                                                                                                                           |
| subnet_allocation                     | Subnet Allocation                                                                                                                                              |
| subnetpool-prefix-ops                 | Subnet Pool Prefix Operations                                                                                                                                  |
| standard-attr-tag                     | Tag support for resources with standard attribute: port, subnet, subnetpool, network, security_group, router, floatingip, policy, trunk, network_segment_range |
| standard-attr-timestamp               | Resource timestamps                                                                                                                                            |
+---------------------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------+

Настройка вычислительных узлов

Устанавливаем пакеты:

1
$ sudo yum -y install openstack-neutron openstack-neutron-ml2 openstack-neutron-openvswitch

Добавляем общие для управляющего, сетевого и вычислительных узлов настройки. Файл /etc/neutron/neutron.conf:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
[DEFAULT]
transport_url = rabbit://openstack:openstack@controller
auth_strategy = keystone
core_plugin = ml2 
service_plugins = router
allow_overlapping_ips = true

[keystone_authtoken]
project_name = service
user_domain_name = Default
project_domain_name = Default
auth_type = password
username = neutron
password = openstack
auth_uri = http://controller:5000/v3
auth_url = http://controller:5000/v3

[oslo_concurrency]
lock_path = /var/lib/neutron/tmp

Файл /etc/neutron/plugins/ml2/ml2_conf.ini:

1
2
3
4
5
6
7
8
9
10
11
[ml2]
type_drivers = flat,gre,vlan,vxlan
tenant_network_types = gre
mechanism_drivers = openvswitch

[ml2_type_gre]
tunnel_id_ranges = 1:1000

[securitygroup]
enable_security_group = true
enable_ipset = true

Вносим изменения в параметры ядра (файл /etc/sysctl.conf) при помощи sysctl:

1
2
3
4
5
net.ipv4.ip_forward = 1
net.ipv4.conf.all.rp_filter = 0
net.ipv4.conf.default.rp_filter = 0

$ sudo sysctl -p

Вносим изменения в конфигурационные файл /etc/neutron/plugins/ml2/openvswitch_agent.ini (не забывая подставить IP адрес текущего узла):

1
2
3
4
5
6
7
8
[ovs]
local_ip = {IP_адрес_вычислительного_узла}

[agent]
tunnel_types = gre

[securitygroup]
firewall_driver = neutron.agent.linux.iptables_firewall.OVSHybridIptablesFirewallDriver

Активируем и запускаем сервис Open vSwitch:

1
$ sudo systemctl enable openvswitch; sudo systemctl start openvswitch

Вносим изменения в /etc/nova/nova.conf:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
[DEFAULT]
network_api_class = nova.network.neutronv2.api.API
security_group_api = neutron
linuxnet_interface_driver = nova.network.linux_net.LinuxOVSInterfaceDriver
firewall_driver = nova.virt.firewall.NoopFirewallDriver

[neutron]
url = http://controller:9696
auth_url = http://controller:5000/v3
auth_type = password
project_domain_name = Default
user_domain_name = Default
region_name = RegionOne
project_name = service
username = neutron
password = openstack

Создаём символическую ссылку на конфигурационный модуль ML2:

1
$ sudo ln -s /etc/neutron/plugins/ml2/ml2_conf.ini /etc/neutron/plugin.ini

Перезапускаем Nova и включаем агента Open vSwitch:

1
2
$ sudo systemctl restart openstack-nova-compute
$ sudo systemctl enable neutron-openvswitch-agent ; sudo systemctl start neutron-openvswitch-agent

Настройка сетевого узла Neutron

Устанавливаем пакеты на сетевой ноде:

1
$ sudo yum -y install openstack-neutron openstack-neutron-ml2 openstack-neutron-openvswitch openvswitch

Вносим изменения в параметры ядра (файл /etc/sysctl.conf) при помощи sysctl - включаем маршрутизацию пакетов и выключаем их фильтрацию по исходящему адресу (которая по умолчанию предотвращает DDoS-атаки):

1
2
3
4
5
net.ipv4.ip_forward = 1
net.ipv4.conf.all.rp_filter = 0
net.ipv4.conf.default.rp_filter = 0

$ sudo sysctl -p

Далее устанавливаем общие с управляющим и вычислительными узлами настройки. Файл /etc/neutron/neutron.conf:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
[DEFAULT]
transport_url = rabbit://openstack:openstack@controller
auth_strategy = keystone
core_plugin = ml2 
service_plugins = router
allow_overlapping_ips = true

[keystone_authtoken]
project_name = service
user_domain_name = Default
project_domain_name = Default
auth_type = password
username = neutron
password = openstack
auth_uri = http://controller:5000/v3
auth_url = http://controller:5000/v3

[oslo_concurrency]
lock_path = /var/lib/neutron/tmp

Файл /etc/neutron/plugins/ml2/ml2_conf.ini:

1
2
3
4
5
6
7
8
9
10
11
[ml2]
type_drivers = flat,gre,vlan,vxlan
tenant_network_types = gre
mechanism_drivers = openvswitch

[ml2_type_gre]
tunnel_id_ranges = 1:1000

[securitygroup]
enable_security_group = true
enable_ipset = true

Далее вносим специфичные настройки.

Файл /etc/neutron/neutron.conf:

1
2
[database]
connection = mysql+pymysql://neutron:neutron@controller/neutron

Файл /etc/neutron/plugins/ml2/ml2_conf.ini:

1
2
[ml2_type_flat]
flat_networks = external

Файл /etc/neutron/plugins/ml2/openvswitch_agent.ini:

1
2
3
4
5
6
7
[ovs]
local_ip = 192.168.100.134
bridge_mappings = external:br-ex
enable_tunneling = true

[agent]
tunnel_types = gre

Файл /etc/neutron/l3_agent.ini:

1
2
3
4
5
[DEFAULT]
interface_driver = neutron.agent.linux.interface.OVSInterfaceDriver
use_namespaces = true
external_network_bridge = br-ex
router_delete_namespaces = true

Файл /etc/neutron/dhcp_agent.ini:

1
2
3
4
5
[DEFAULT]
interface_driver = neutron.agent.linux.interface.OVSInterfaceDriver
dhcp_driver = neutron.agent.linux.dhcp.Dnsmasq
use_namespaces = true
dhcp_delete_namespaces = true

Файл /etc/neutron/metadata_agent.ini:

1
2
3
4
[DEFAULT]
# адрес контроллера
nova_metadata_host = 192.168.100.128
metadata_proxy_shared_secret = openstack

Поскольку Neutron ожидает, что настройки основного подключаемого модуля задаются в файлах директории /etc/neutron/, нужно создать символическую ссылку на конфигурационный файл подключаемого модуля ML2:

1
$ sudo ln -s /etc/neutron/plugins/ml2/ml2_conf.ini /etc/neutron/plugin.ini

Активируем и запускаем Open vSwitch:

1
$ sudo systemctl enable openvswitch; sudo systemctl start openvswitch

Создаём мост br-ex, к которому подключаем второй, пока ещё не настроенный адаптер (узнать его название - ip a):

1
2
$ ovs-vsctl add-br br-ex
$ ovs-vsctl add-port br-ex enp7s0

Если интерфейс не получил настройки сам, то можно запросить их принудительно:

1
2
$ sudo yum -y install dhclient
$ dhclient -v enp7s0

Проверяем получение настроек:

1
2
3
4
5
$ ip a
3: enp7s0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
    link/ether 52:54:00:5f:a4:52 brd ff:ff:ff:ff:ff:ff
    inet 10.100.1.242/24 brd 10.100.1.255 scope global dynamic enp7s0
       valid_lft 3646sec preferred_lft 3646sec

Создаём конфигурационные файлы сетевых интерфейсов. Файл /etc/sysconfig/network-scripts/ifcfg-enp1s0:

1
2
3
4
5
6
7
8
9
10
11
12
TYPE="Ethernet"
BOOTPROTO="none"
DEFROUTE="yes"
IPV6INIT="no"
NAME="enp1s0"
ONBOOT="yes"
HWADDR="52:54:00:3d:c6:ac"
IPADDR0="192.168.100.134"
PREFIX0="24"
GATEWAY="192.168.100.1"
DNS1="192.168.122.1"
NM_CONTROLLED=no

Файл /etc/sysconfig/network-scripts/ifcfg-enp7s0:

1
2
3
4
5
6
DEVICE=enp7s0
TYPE=Ethernet
ONBOOT=yes
BOOTPROTO=none
NAME=enp7s0
NM_CONTROLLED=no

Файл, описывающий конфигурацию моста br-ex - /etc/sysconfig/network-scripts/ifcfg-br-ex:

1
2
3
4
5
6
7
8
9
10
DEVICE=br-ex
DEVICETYPE=ovs
TYPE=OVSBridge
BOOTPROTO=static
ONBOOT=yes
IPADDR=10.100.1.204
NETMASK=255.255.255.0
GATEWAY=10.100.1.1
DNS1=8.8.8.8
NM_CONTROLLED=no

Отключаем сервис NetworkManager и отключаем его запуск после загрузки; включаем network:

1
2
$ sudo systemctl stop NetworkManager; sudo systemctl disable NetworkManager
$ sudo systemctl enable network; sudo systemctl start network

Проверяем конфигурацию Open vSwitch:

1
2
3
4
5
6
7
8
9
$ sudo ovs-vsctl show
c85d6e4b-a349-4dc9-a278-0647dfdafb1f
    Bridge br-ex
        Port br-ex
            Interface br-ex
                type: internal
        Port enp7s0
            Interface enp7s0
    ovs_version: "3.1.8-159.el9s"

Запускаем сервисы:

1
2
$ sudo systemctl enable neutron-openvswitch-agent neutron-l3-agent neutron-dhcp-agent neutron-metadata-agent neutron-ovs-cleanup
$ sudo systemctl start neutron-openvswitch-agent neutron-l3-agent neutron-dhcp-agent neutron-metadata-agent

Убеждаемся, что все агенты запустились и работают:

1
2
3
4
5
6
7
8
9
10
11
12
13
$ source keystone_admin 

$ openstack network agent list
+--------------------------------------+--------------------+-----------+-------------------+-------+-------+---------------------------+
| ID                                   | Agent Type         | Host      | Availability Zone | Alive | State | Binary                    |
+--------------------------------------+--------------------+-----------+-------------------+-------+-------+---------------------------+
| 23add11f-96a9-4ca4-8991-b6f98924d0cd | Open vSwitch agent | compute-2 | None              | :-)   | UP    | neutron-openvswitch-agent |
| 27190536-ae33-4b8c-a46b-9ca05b090d50 | Metadata agent     | network   | None              | :-)   | UP    | neutron-metadata-agent    |
| 3da6a5cf-51d0-4e55-841c-1ed58ce51cbf | L3 agent           | network   | nova              | :-)   | UP    | neutron-l3-agent          |
| 8010f402-0f82-4591-adfe-a2e5aca93f3b | Open vSwitch agent | network   | None              | :-)   | UP    | neutron-openvswitch-agent |
| b1b3fca0-d033-4bf9-a050-0019d0440fac | DHCP agent         | network   | nova              | :-)   | UP    | neutron-dhcp-agent        |
| c3734b04-c728-4d15-894a-010072a5466e | Open vSwitch agent | compute-1 | None              | :-)   | UP    | neutron-openvswitch-agent |
+--------------------------------------+--------------------+-----------+-------------------+-------+-------+---------------------------+

Horizon

Общие сведения

Horizon - графический веб-интерфейс OpenStack. Написано с использованием Django.

Установка

Horizon можно вынести на отдельную виртуальную машину, а можно на контроллере. Устанавливаем пакеты на контроллер:

1
$ sudo yum install -y openstack-dashboard memcached python3-memcached

Вносим изменения в конфигурацию /etc/openstack-dashboard/local_settings (часть информации из Bug#1947295):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# изменить строки
ALLOWED_HOSTS = ['*'] # перечень адресов, которым доступен Horizon
OPENSTACK_HOST = "controller" # IP сервера с Keystone
OPENSTACK_KEYSTONE_URL = "http://%s:5000/identity/v3" % OPENSTACK_HOST
SESSION_ENGINE = 'django.contrib.sessions.backends.cache'

CACHES = {
    'default': {
        'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache',
        'LOCATION': 'controller:11211',
    },
}

# также нужно добавить отсутствующую строку
WEBROOT = '/dashboard/'

Редактируем файл /etc/httpd/conf.d/openstack-dashboard.conf:

1
2
3
4
5
6
7
8
9
# добавляем в начало строку
WSGIApplicationGroup %{GLOBAL}

# из-за бага нужно внести изменения:
#WSGIScriptAlias /dashboard /usr/share/openstack-dashboard/openstack_dashboard/wsgi/django.wsgi заменить на
WSGIScriptAlias /dashboard /usr/share/openstack-dashboard/openstack_dashboard/wsgi.py

# <Directory /usr/share/openstack-dashboard/openstack_dashboard/wsgi заменить на
<Directory /usr/share/openstack-dashboard/openstack_dashboard

Включаем memcached и перезапускаем сервисы

1
2
$ sudo systemctl enable --now memcached
$ sudo systemctl restart httpd.service memcached.service

После перезагрузки Horizon будет доступен по адресу http://controller/dashboard.

Heat

Общие сведения

Службы Heat позволяют автоматизировать управление жизненным циклом наборов облачных сервисов как единым целым, объединяя их в стеки (stack). Задачи могут быть простыми (например развёртывание виртуальной машины), так и более сложными, например, старт комплексного приложения из многих машин и его масштабирование в зависимости от информации, передаваемой модулем телеметрии. Для описания стеков используются специальные, одновременно легко читаемые человеком и дружественные к обработке машиной форматы ресурсов, их ограничений, зависимостей и параметров:

  • HOT (Heart Orchestration Template) - формат, предназначенный исключительно для OpenStack. Представляет собой документ YAML;
  • CFT (AWS CloudFormation) - документы JSON в формате, совместимом с шаблонами сервиса Amazon CloudFormation.

К числу основных компонентов службы оркестрации относятся:

  • openstack-heat-engine - основной сервис, обеспечивающий обработку шаблонов и отправляющий события пользователя API;
  • openstack-heat-api - сервис, отвечающий за предоставление основного REST API Heat. Сервис взаимодействует с openstack-heat-engine через вызовы RPC;
  • openstack-heat-api-cfn - аналогичен предыдущему сервису, но обеспечивает работу с API, совместимым с AWS CloudFormation;
  • клиент командной строки Heat - интерфейс взаимодействия с Heat API. Включает также REST API.

Установка Heat

Устанавливаем пакеты на контроллер:

1
$ sudo yum install -y openstack-heat-api openstack-heat-api-cfn openstack-heat-engine python-heatclient openstack-heat-ui

Создаём базу данных:

1
$ sudo mysql -u root -popenstack
1
2
3
CREATE DATABASE heat;
GRANT ALL PRIVILEGES ON heat.* TO 'heat'@'localhost' IDENTIFIED BY 'heat';
GRANT ALL PRIVILEGES ON heat.* TO 'heat'@'%' IDENTIFIED BY 'heat';

Создаём пользователя heat в сервисе Keystone и добавляем ему роль admin в проекте service:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
$ source keystone_admin

$ openstack user create --domain default --password openstack heat
+---------------------+----------------------------------+
| Field               | Value                            |
+---------------------+----------------------------------+
| domain_id           | default                          |
| enabled             | True                             |
| id                  | 39e4c014d89740e7bccaa9fd9234e084 |
| name                | heat                             |
| options             | {}                               |
| password_expires_at | None                             |
+---------------------+----------------------------------+

$ openstack role add --project service --user heat admin

Для сервиса оркестрации также понадобится домен, который будет содержать проекты и пользователей стека. В новом домене понадобиться пользователь heat_domain_admin, который будет управлять проектами и пользователями:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
$ openstack domain create --description "Stack projects and users" heat
+-------------+----------------------------------+
| Field       | Value                            |
+-------------+----------------------------------+
| description | Stack projects and users         |
| enabled     | True                             |
| id          | 380aaae6276342d5b61197d51eae1380 |
| name        | heat                             |
| options     | {}                               |
| tags        | []                               |
+-------------+----------------------------------+

$ openstack user create --domain heat --password openstack heat_domain_admin
+---------------------+----------------------------------+
| Field               | Value                            |
+---------------------+----------------------------------+
| domain_id           | 380aaae6276342d5b61197d51eae1380 |
| enabled             | True                             |
| id                  | f20626e3d7fb4f939d6e42b3701973d2 |
| name                | heat_domain_admin                |
| options             | {}                               |
| password_expires_at | None                             |
+---------------------+----------------------------------+

$ openstack role add --domain heat --user-domain heat --user heat_domain_admin admin

Теперь создаём роль владельца стека и добавляем ему роль в проект и пользователю demo, тем самым дав ему возможность управлять стеками:

1
2
3
4
5
6
7
8
9
10
11
12
$ openstack role create heat_stack_owner
+-------------+----------------------------------+
| Field       | Value                            |
+-------------+----------------------------------+
| description | None                             |
| domain_id   | None                             |
| id          | 9ae18aae43c048d48827f72acb5b1cf9 |
| name        | heat_stack_owner                 |
| options     | {}                               |
+-------------+----------------------------------+

$ openstack role add --project demo --user demo heat_stack_owner

Также нам понадобится роль пользователя стека, который будет получать данные о прогрессе выполнения операций. Сервис оркестрации будет автоматически добавлять роль heat_stack_user пользователям, запускающим стек во время его запуска:

1
2
3
4
5
6
7
8
9
10
$ openstack role create heat_stack_user
+-------------+----------------------------------+
| Field       | Value                            |
+-------------+----------------------------------+
| description | None                             |
| domain_id   | None                             |
| id          | 3a4cc3d2249c432dad8d23ce8842e3bf |
| name        | heat_stack_user                  |
| options     | {}                               |
+-------------+----------------------------------+

Создаём сервисы и точки входа для heat-api и heat-api-cfn:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
$ openstack service create --name heat --description "Orchestration" orchestration
+-------------+----------------------------------+
| Field       | Value                            |
+-------------+----------------------------------+
| description | Orchestration                    |
| enabled     | True                             |
| id          | 6610736708c34063a91131d524423f4c |
| name        | heat                             |
| type        | orchestration                    |
+-------------+----------------------------------+

$ openstack service create --name heat-cfn --description "Orchestration" cloudformation
+-------------+----------------------------------+
| Field       | Value                            |
+-------------+----------------------------------+
| description | Orchestration                    |
| enabled     | True                             |
| id          | e2b7ba8a932044a8bf214f450f3e2f98 |
| name        | heat-cfn                         |
| type        | cloudformation                   |
+-------------+----------------------------------+

$ openstack endpoint create --region RegionOne orchestration public http://controller:8004/v1/%\(tenant_id\)s
+--------------+-----------------------------------------+
| Field        | Value                                   |
+--------------+-----------------------------------------+
| enabled      | True                                    |
| id           | 8557691d5f3443d5830dda846cd4a0c3        |
| interface    | public                                  |
| region       | RegionOne                               |
| region_id    | RegionOne                               |
| service_id   | 6610736708c34063a91131d524423f4c        |
| service_name | heat                                    |
| service_type | orchestration                           |
| url          | http://controller:8004/v1/%(tenant_id)s |
+--------------+-----------------------------------------+

$ openstack endpoint create --region RegionOne orchestration internal http://controller:8004/v1/%\(tenant_id\)s
+--------------+-----------------------------------------+
| Field        | Value                                   |
+--------------+-----------------------------------------+
| enabled      | True                                    |
| id           | a86c6cbc944a42c982a79124ba6545be        |
| interface    | internal                                |
| region       | RegionOne                               |
| region_id    | RegionOne                               |
| service_id   | 6610736708c34063a91131d524423f4c        |
| service_name | heat                                    |
| service_type | orchestration                           |
| url          | http://controller:8004/v1/%(tenant_id)s |
+--------------+-----------------------------------------+

$ openstack endpoint create --region RegionOne orchestration admin http://controller:8004/v1/%\(tenant_id\)s
+--------------+-----------------------------------------+
| Field        | Value                                   |
+--------------+-----------------------------------------+
| enabled      | True                                    |
| id           | ca1afab2be664aafa8c03f36d0bec70a        |
| interface    | admin                                   |
| region       | RegionOne                               |
| region_id    | RegionOne                               |
| service_id   | 6610736708c34063a91131d524423f4c        |
| service_name | heat                                    |
| service_type | orchestration                           |
| url          | http://controller:8004/v1/%(tenant_id)s |
+--------------+-----------------------------------------+

$ openstack endpoint create --region RegionOne cloudformation public http://controller:8000/v1
+--------------+----------------------------------+
| Field        | Value                            |
+--------------+----------------------------------+
| enabled      | True                             |
| id           | d5a5db947aef490e931bb6432e3d2596 |
| interface    | public                           |
| region       | RegionOne                        |
| region_id    | RegionOne                        |
| service_id   | e2b7ba8a932044a8bf214f450f3e2f98 |
| service_name | heat-cfn                         |
| service_type | cloudformation                   |
| url          | http://controller:8000/v1        |
+--------------+----------------------------------+

$ openstack endpoint create --region RegionOne cloudformation internal http://controller:8000/v1
+--------------+----------------------------------+
| Field        | Value                            |
+--------------+----------------------------------+
| enabled      | True                             |
| id           | 3cc0877c94354073939080732d316ead |
| interface    | internal                         |
| region       | RegionOne                        |
| region_id    | RegionOne                        |
| service_id   | e2b7ba8a932044a8bf214f450f3e2f98 |
| service_name | heat-cfn                         |
| service_type | cloudformation                   |
| url          | http://controller:8000/v1        |
+--------------+----------------------------------+

$ openstack endpoint create --region RegionOne cloudformation public http://controller:8000/v1
+--------------+----------------------------------+
| Field        | Value                            |
+--------------+----------------------------------+
| enabled      | True                             |
| id           | 7845643a0fab4e1e92f35278a119ee11 |
| interface    | public                           |
| region       | RegionOne                        |
| region_id    | RegionOne                        |
| service_id   | e2b7ba8a932044a8bf214f450f3e2f98 |
| service_name | heat-cfn                         |
| service_type | cloudformation                   |
| url          | http://controller:8000/v1        |
+--------------+----------------------------------+

Настраиваем Heat в файле /etc/heat/heat.conf:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
[DEFAULT]
transport_url = rabbit://openstack:openstack@controller
heat_metadata_server_url = http://controller:8000
heat_waitcondition_server_url = http://controller:8000/v1/waitcondition
stack_domain_admin = heat_domain_admin
stack_domain_admin_password = openstack
stack_user_domain_name = heat

[database]
connection = mysql+pymysql://heat:heat@controller/heat

[keystone_authtoken]
auth_uri = http://controller:5000
auth_url = http://controller:5000
auth_type = password
project_domain_name = default
user_domain_name = default
project_name = service
username = heat
password = openstack

[trustee]
auth_type = password
auth_url = http://controller:5000
username = heat
password = openstack
user_domain_name = default

[clients_keystone]
auth_uri = http://controller:5000

Заполняем базу данных; включаем сервисы:

1
2
3
4
$ sudo su -s /bin/sh -c "heat-manage db_sync" heat

$ sudo systemctl enable openstack-heat-api openstack-heat-api-cfn openstack-heat-engine
$ sudo systemctl start openstack-heat-api openstack-heat-api-cfn openstack-heat-engine

Проверяем сервисы:

1
2
3
4
5
6
7
8
9
$ openstack orchestration service list
+------------+-------------+--------------------------------------+------------+--------+----------------------------+--------+
| Hostname   | Binary      | Engine ID                            | Host       | Topic  | Updated At                 | Status |
+------------+-------------+--------------------------------------+------------+--------+----------------------------+--------+
| controller | heat-engine | b3eef86b-6a60-447d-a94f-97134b51cebe | controller | engine | 2025-07-30T11:57:09.000000 | up     |
| controller | heat-engine | 730b0f02-8608-4582-a9e7-7bee0360b6b0 | controller | engine | 2025-07-30T11:57:09.000000 | up     |
| controller | heat-engine | c37b364b-95a4-41ec-ad7a-4c2010ddd07c | controller | engine | 2025-07-30T11:57:09.000000 | up     |
| controller | heat-engine | 7cb66d4e-2032-46d0-ac3c-bc012656072c | controller | engine | 2025-07-30T11:57:09.000000 | up     |
+------------+-------------+--------------------------------------+------------+--------+----------------------------+--------+

Работа с виртуальными машинами

Создание внешней и пользовательской сети

Создаём “внешнюю” сеть и подсеть:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
$ source keystone_admin 

$ openstack network create --external --share --provider-network-type flat --provider-physical-network external ext-net
+---------------------------+--------------------------------------+
| Field                     | Value                                |
+---------------------------+--------------------------------------+
| admin_state_up            | UP                                   |
| availability_zone_hints   |                                      |
| availability_zones        |                                      |
| created_at                | 2025-07-30T12:02:06Z                 |
| description               |                                      |
| dns_domain                | None                                 |
| id                        | d7c5cc1d-e86a-4e7e-a723-14386f24951b |
| ipv4_address_scope        | None                                 |
| ipv6_address_scope        | None                                 |
| is_default                | False                                |
| is_vlan_transparent       | None                                 |
| mtu                       | 1500                                 |
| name                      | ext-net                              |
| port_security_enabled     | False                                |
| project_id                | 7120a6037766473c8cf4db4e68e5258f     |
| provider:network_type     | flat                                 |
| provider:physical_network | external                             |
| provider:segmentation_id  | None                                 |
| qos_policy_id             | None                                 |
| revision_number           | 1                                    |
| router:external           | External                             |
| segments                  | None                                 |
| shared                    | True                                 |
| status                    | ACTIVE                               |
| subnets                   |                                      |
| tags                      |                                      |
| updated_at                | 2025-07-30T12:02:06Z                 |
+---------------------------+--------------------------------------+

$ openstack subnet create --network ext-net --no-dhcp --allocation-pool start=10.100.1.100,end=10.100.1.200 --gateway 10.100.1.1 --subnet-range 10.100.1.0/24 ext-subnet
+----------------------+--------------------------------------+
| Field                | Value                                |
+----------------------+--------------------------------------+
| allocation_pools     | 10.100.1.100-10.100.1.200            |
| cidr                 | 10.100.1.0/24                        |
| created_at           | 2025-07-30T12:02:20Z                 |
| description          |                                      |
| dns_nameservers      |                                      |
| dns_publish_fixed_ip | None                                 |
| enable_dhcp          | False                                |
| gateway_ip           | 10.100.1.1                           |
| host_routes          |                                      |
| id                   | a33ef1d6-cbd0-4681-94bf-bc63bb05a191 |
| ip_version           | 4                                    |
| ipv6_address_mode    | None                                 |
| ipv6_ra_mode         | None                                 |
| name                 | ext-subnet                           |
| network_id           | d7c5cc1d-e86a-4e7e-a723-14386f24951b |
| project_id           | 7120a6037766473c8cf4db4e68e5258f     |
| revision_number      | 0                                    |
| segment_id           | None                                 |
| service_types        |                                      |
| subnetpool_id        | None                                 |
| tags                 |                                      |
| updated_at           | 2025-07-30T12:02:20Z                 |
+----------------------+--------------------------------------+

Создаём пользовательскую внутреннюю сеть и подсеть для неё:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
$ source keystone_demo

$ neutron net-create demo-net
neutron CLI is deprecated and will be removed in the Z cycle. Use openstack CLI instead.
Created a new network:
+-------------------------+--------------------------------------+
| Field                   | Value                                |
+-------------------------+--------------------------------------+
| admin_state_up          | True                                 |
| availability_zone_hints |                                      |
| availability_zones      |                                      |
| created_at              | 2025-07-30T12:02:33Z                 |
| description             |                                      |
| id                      | 25378caa-f890-409b-af61-6a482e8211aa |
| ipv4_address_scope      |                                      |
| ipv6_address_scope      |                                      |
| is_default              | False                                |
| mtu                     | 1458                                 |
| name                    | demo-net                             |
| project_id              | 000aca557baf409db7b14b884c639d13     |
| revision_number         | 1                                    |
| router:external         | False                                |
| shared                  | False                                |
| status                  | ACTIVE                               |
| subnets                 |                                      |
| tags                    |                                      |
| tenant_id               | 000aca557baf409db7b14b884c639d13     |
| updated_at              | 2025-07-30T12:02:33Z                 |
+-------------------------+--------------------------------------+

$ neutron subnet-create demo-net --name demo-subnet --gateway 172.16.0.1 172.16.0.0/24
neutron CLI is deprecated and will be removed in the Z cycle. Use openstack CLI instead.
Created a new subnet:
+-------------------+------------------------------------------------+
| Field             | Value                                          |
+-------------------+------------------------------------------------+
| allocation_pools  | {"start": "172.16.0.2", "end": "172.16.0.254"} |
| cidr              | 172.16.0.0/24                                  |
| created_at        | 2025-07-30T12:02:43Z                           |
| description       |                                                |
| dns_nameservers   |                                                |
| enable_dhcp       | True                                           |
| gateway_ip        | 172.16.0.1                                     |
| host_routes       |                                                |
| id                | 78c8a6c3-4018-4249-a4f6-05060948787f           |
| ip_version        | 4                                              |
| ipv6_address_mode |                                                |
| ipv6_ra_mode      |                                                |
| name              | demo-subnet                                    |
| network_id        | 25378caa-f890-409b-af61-6a482e8211aa           |
| project_id        | 000aca557baf409db7b14b884c639d13               |
| revision_number   | 0                                              |
| service_types     |                                                |
| subnetpool_id     |                                                |
| tags              |                                                |
| tenant_id         | 000aca557baf409db7b14b884c639d13               |
| updated_at        | 2025-07-30T12:02:43Z                           |
+-------------------+------------------------------------------------+

Создаём маршрутизатор для этой сети и подключим интерфейс маршрутизатора demo-router к подсети demo-subnet; устанавливаем роутеру в качестве шлюза внешнюю сеть:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
$ openstack router create demo-router
+-------------------------+--------------------------------------+
| Field                   | Value                                |
+-------------------------+--------------------------------------+
| admin_state_up          | UP                                   |
| availability_zone_hints |                                      |
| availability_zones      |                                      |
| created_at              | 2025-07-30T12:02:52Z                 |
| description             |                                      |
| external_gateway_info   | null                                 |
| flavor_id               | None                                 |
| id                      | 26e0e20b-efe7-40ed-a11b-047a875b1eae |
| name                    | demo-router                          |
| project_id              | 000aca557baf409db7b14b884c639d13     |
| revision_number         | 1                                    |
| routes                  |                                      |
| status                  | ACTIVE                               |
| tags                    |                                      |
| updated_at              | 2025-07-30T12:02:52Z                 |
+-------------------------+--------------------------------------+

$ openstack router add subnet demo-router demo-subnet

$ neutron router-gateway-set demo-router ext-net
neutron CLI is deprecated and will be removed in the Z cycle. Use openstack CLI instead.
Set gateway for router demo-router

Порт - это логическое подключение ресурса, например виртуальной машины или маршрутизатора, к подсети. Посмотреть информацию о конкретном порте можно при помощи команды neutron port-show или openstack port show.

Подготовка к запуску виртуальной машины

Для экземпляра виртуальной машины нужен флейвор - это тип создаваемой машины. Раньше некоторые флейворы создавались автоматически; сейчас их все нужно создавать самостоятельно. Ранее предустановленные типы выглядели так:

1
2
3
4
5
6
7
8
9
10
$ nova flavor-list
+----+-----------+--------+------+-----+------+-------+-------------+-----------+
| ID | Name      | Mem_MB | Disk | Eph | Swap | VCPUs | RXTX_Factor | Is_Public |
+----+-----------+--------+------+-----+------+-------+-------------+-----------+
| 1  | m1.tiny   | 512    | 1    | 0   |      | 1     | 1.0         | True      |
| 2  | m1.small  | 2048   | 20   | 0   |      | 1     | 1.0         | True      |
| 3  | m1.medium | 4096   | 40   | 0   |      | 2     | 1.0         | True      |
| 4  | m1.large  | 8192   | 80   | 0   |      | 4     | 1.0         | True      |
| 5  | m1.xlarge | 16384  | 160  | 0   |      | 8     | 1.0         | True      |
+----+-----------+--------+------+-----+------+-------+-------------+-----------+

Из важных параметров здесь:

  • Ephemeral - размер второго временного диска, данные которого, как и первого, теряются при выключении виртуальной машины;
  • Swap - размер опционального swap-раздела;
  • RXTX_Factor - позволяет изменять пропускную способность сети. Значение по умолчанию (1.0) обозначает пропускную способность как у подключенной сети. Данный параметр используется только в драйвере гипервизора Xen.

Создадим простейшую публичную конфигурацию с 1 Гб диска, 1 vCPU и 300 Мб RAM:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
$ source keystone_admin

$ openstack flavor create --ram 300 --disk 1 --vcpu 1 --public m2.tiny # альтернативная команда: nova flavor-create --is-public true m2.tiny auto 300 1 1
+----------------------------+--------------------------------------+
| Field                      | Value                                |
+----------------------------+--------------------------------------+
| OS-FLV-DISABLED:disabled   | False                                |
| OS-FLV-EXT-DATA:ephemeral  | 0                                    |
| description                | None                                 |
| disk                       | 1                                    |
| id                         | d3db6534-1b79-4211-ae47-391b233447d9 |
| name                       | m2.tiny                              |
| os-flavor-access:is_public | True                                 |
| properties                 |                                      |
| ram                        | 300                                  |
| rxtx_factor                | 1.0                                  |
| swap                       |                                      |
| vcpus                      | 1                                    |
+----------------------------+--------------------------------------+

Просмотреть все доступные флейворы можно так:

1
2
3
4
5
6
$ openstack flavor list # или nova flavor-list
+--------------------------------------+---------+-----+------+-----------+-------+-----------+
| ID                                   | Name    | RAM | Disk | Ephemeral | VCPUs | Is Public |
+--------------------------------------+---------+-----+------+-----------+-------+-----------+
| d3db6534-1b79-4211-ae47-391b233447d9 | m2.tiny | 300 |    1 |         0 |     1 | True      |
+--------------------------------------+---------+-----+------+-----------+-------+-----------+

Просмотр информации о конкретном флейворе:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
$ openstack flavor show d3db6534-1b79-4211-ae47-391b233447d9
+----------------------------+--------------------------------------+
| Field                      | Value                                |
+----------------------------+--------------------------------------+
| OS-FLV-DISABLED:disabled   | False                                |
| OS-FLV-EXT-DATA:ephemeral  | 0                                    |
| access_project_ids         | None                                 |
| description                | None                                 |
| disk                       | 1                                    |
| id                         | d3db6534-1b79-4211-ae47-391b233447d9 |
| name                       | m2.tiny                              |
| os-flavor-access:is_public | True                                 |
| properties                 |                                      |
| ram                        | 300                                  |
| rxtx_factor                | 1.0                                  |
| swap                       |                                      |
| vcpus                      | 1                                    |
+----------------------------+--------------------------------------+

Сервер метаданных может передавать те или иные параметры экземпляру виртуальной машины (например, публичный ключ для ssh). Создадим и сохраним закрытый ключ в файл:

1
2
3
$ source keystone_demo

$ openstack keypair create demokey1 > ~/demokey1 # альтернативная команда: nova keypair_add demokey1 > ~/demokey1

Список доступных ключей можно проверить командой:

1
2
3
4
5
6
$ openstack keypair list
+----------+-------------------------------------------------+------+
| Name     | Fingerprint                                     | Type |
+----------+-------------------------------------------------+------+
| demokey1 | b2:4b:3c:fe:89:00:f4:54:8e:f2:04:1d:88:3c:57:d6 | ssh  |
+----------+-------------------------------------------------+------+

Создаём виртуальную машину:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
$ openstack server create --image Cirros --flavor m2.tiny --key-name demokey1 --nic net-id=demo-net myinstance1 # nova boot flavor m2.tiny --image Cirros-From-Swift --key-name demokey1 myinstance1
+-----------------------------+------------------------------------------------+
| Field                       | Value                                          |
+-----------------------------+------------------------------------------------+
| OS-DCF:diskConfig           | MANUAL                                         |
| OS-EXT-AZ:availability_zone |                                                |
| OS-EXT-STS:power_state      | NOSTATE                                        |
| OS-EXT-STS:task_state       | scheduling                                     |
| OS-EXT-STS:vm_state         | building                                       |
| OS-SRV-USG:launched_at      | None                                           |
| OS-SRV-USG:terminated_at    | None                                           |
| accessIPv4                  |                                                |
| accessIPv6                  |                                                |
| addresses                   |                                                |
| adminPass                   | R8CDL2g83CvP                                   |
| config_drive                |                                                |
| created                     | 2025-07-30T12:21:04Z                           |
| flavor                      | m2.tiny (d3db6534-1b79-4211-ae47-391b233447d9) |
| hostId                      |                                                |
| id                          | 24e83e0c-ca68-4506-a1f5-249d2d161d55           |
| image                       | Cirros (20120ae4-d320-421e-b8c9-1b95549a3995)  |
| key_name                    | demokey1                                       |
| name                        | myinstance1                                    |
| progress                    | 0                                              |
| project_id                  | 000aca557baf409db7b14b884c639d13               |
| properties                  |                                                |
| security_groups             | name='default'                                 |
| status                      | BUILD                                          |
| updated                     | 2025-07-30T12:21:04Z                           |
| user_id                     | c1e0d27f36f746b79aa38c92d58ad600               |
| volumes_attached            |                                                |
+-----------------------------+------------------------------------------------+

Виртуальная машина может создаться с ошибкой: unsupported configuration: domain configuration does not support video model 'virtio'. Ошибка возникает из-за изменений в демоне libvirtd (подробнее - по ссылке bugs.launchpad.net/nova/+bug/2018172. Для её решения достаточно указать специальные метаданные образу и пересоздать виртуальную машину:

1
2
$ source keystone_admin
$ openstack image set --property hw_video_model=vga Cirros

Можно подключиться к гипервизору и посмотреть список виртуальных машин на нём или характеристики конкретной машины:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
$ sudo virsh list
 ID   Имя                 Состояние
-------------------------------------
 1    instance-00000002   работает

$ sudo virsh dumpxml 1
<domain type='kvm' id='1'>
  <name>instance-00000002</name>
  <uuid>24e83e0c-ca68-4506-a1f5-249d2d161d55</uuid>
  <metadata>
    <nova:instance xmlns:nova="http://openstack.org/xmlns/libvirt/nova/1.1">
      <nova:package version="25.3.0-1.el9s"/>
      <nova:name>myinstance1</nova:name>
      <nova:creationTime>2025-07-30 12:21:05</nova:creationTime>
      <nova:flavor name="m2.tiny">
        <nova:memory>300</nova:memory>
        <nova:disk>1</nova:disk>
        <nova:swap>0</nova:swap>
        <nova:ephemeral>0</nova:ephemeral>
        <nova:vcpus>1</nova:vcpus>
      </nova:flavor>
      <nova:owner>
        <nova:user uuid="c1e0d27f36f746b79aa38c92d58ad600">demo</nova:user>
        <nova:project uuid="000aca557baf409db7b14b884c639d13">demo</nova:project>
      </nova:owner>
      <nova:root type="image" uuid="20120ae4-d320-421e-b8c9-1b95549a3995"/>
      <nova:ports>
        <nova:port uuid="f39579c3-f26e-487f-a161-4a61641147d0">
          <nova:ip type="fixed" address="172.16.0.168" ipVersion="4"/>
        </nova:port>
      </nova:ports>
    </nova:instance>
  </metadata>
  <memory unit='KiB'>307200</memory>
  <currentMemory unit='KiB'>307200</currentMemory>
  <vcpu placement='static'>1</vcpu>
  <resource>
    <partition>/machine</partition>
  </resource>
  <sysinfo type='smbios'>
    <system>
      <entry name='manufacturer'>RDO</entry>
      <entry name='product'>OpenStack Compute</entry>
      <entry name='version'>25.3.0-1.el9s</entry>
      <entry name='serial'>24e83e0c-ca68-4506-a1f5-249d2d161d55</entry>
      <entry name='uuid'>24e83e0c-ca68-4506-a1f5-249d2d161d55</entry>
      <entry name='family'>Virtual Machine</entry>
    </system>
  </sysinfo>
  <os>
    <type arch='x86_64' machine='pc-i440fx-rhel7.6.0'>hvm</type>
    <boot dev='hd'/>
    <smbios mode='sysinfo'/>
  </os>
  <features>
    <acpi/>
    <apic/>
    <vmcoreinfo state='on'/>
  </features>
  <cpu mode='custom' match='exact' check='full'>
    <model fallback='forbid'>SierraForest</model>
    <vendor>Intel</vendor>
    <topology sockets='1' dies='1' clusters='1' cores='1' threads='1'/>
    <feature policy='require' name='vmx'/>
    <feature policy='require' name='hypervisor'/>
    <feature policy='require' name='ss'/>
    <feature policy='require' name='tsc_adjust'/>
    <feature policy='require' name='waitpkg'/>
    <feature policy='require' name='movdiri'/>
    <feature policy='require' name='movdir64b'/>
    <feature policy='require' name='md-clear'/>
    <feature policy='require' name='stibp'/>
    <feature policy='require' name='flush-l1d'/>
    <feature policy='require' name='ibpb'/>
    <feature policy='require' name='ibrs'/>
    <feature policy='require' name='amd-stibp'/>
    <feature policy='require' name='amd-ssbd'/>
    <feature policy='require' name='gds-no'/>
    <feature policy='require' name='rfds-clear'/>
    <feature policy='require' name='vmx-activity-wait-sipi'/>
    <feature policy='require' name='vmx-tsc-scaling'/>
    <feature policy='require' name='vmx-enable-user-wait-pause'/>
    <feature policy='disable' name='bus-lock-detect'/>
    <feature policy='disable' name='cmpccxadd'/>
    <feature policy='disable' name='avx-ifma'/>
    <feature policy='disable' name='avx-vnni-int8'/>
    <feature policy='disable' name='avx-ne-convert'/>
    <feature policy='disable' name='mcdt-no'/>
    <feature policy='disable' name='wbnoinvd'/>
    <feature policy='disable' name='pbrsb-no'/>
    <feature policy='disable' name='vmx-exit-load-perf-global-ctrl'/>
    <feature policy='disable' name='vmx-entry-load-perf-global-ctrl'/>
  </cpu>
  <clock offset='utc'>
    <timer name='pit' tickpolicy='delay'/>
    <timer name='rtc' tickpolicy='catchup'/>
    <timer name='hpet' present='no'/>
  </clock>
  <on_poweroff>destroy</on_poweroff>
  <on_reboot>restart</on_reboot>
  <on_crash>destroy</on_crash>
  <devices>
    <emulator>/usr/libexec/qemu-kvm</emulator>
    <disk type='file' device='disk'>
      <driver name='qemu' type='qcow2' cache='none'/>
      <source file='/var/lib/nova/instances/24e83e0c-ca68-4506-a1f5-249d2d161d55/disk' index='1'/>
      <backingStore type='file' index='2'>
        <format type='raw'/>
        <source file='/var/lib/nova/instances/_base/5ff71c087aa0f09df04e095484cb406e53b9874d'/>
        <backingStore/>
      </backingStore>
      <target dev='vda' bus='virtio'/>
      <alias name='virtio-disk0'/>
      <address type='pci' domain='0x0000' bus='0x00' slot='0x04' function='0x0'/>
    </disk>
    <controller type='usb' index='0' model='piix3-uhci'>
      <alias name='usb'/>
      <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x2'/>
    </controller>
    <controller type='pci' index='0' model='pci-root'>
      <alias name='pci.0'/>
    </controller>
    <interface type='bridge'>
      <mac address='fa:16:3e:72:34:1f'/>
      <source bridge='qbrf39579c3-f2'/>
      <target dev='tapf39579c3-f2'/>
      <model type='virtio'/>
      <mtu size='1458'/>
      <alias name='net0'/>
      <address type='pci' domain='0x0000' bus='0x00' slot='0x03' function='0x0'/>
    </interface>
    <serial type='pty'>
      <source path='/dev/pts/1'/>
      <log file='/var/lib/nova/instances/24e83e0c-ca68-4506-a1f5-249d2d161d55/console.log' append='off'/>
      <target type='isa-serial' port='0'>
        <model name='isa-serial'/>
      </target>
      <alias name='serial0'/>
    </serial>
    <console type='pty' tty='/dev/pts/1'>
      <source path='/dev/pts/1'/>
      <log file='/var/lib/nova/instances/24e83e0c-ca68-4506-a1f5-249d2d161d55/console.log' append='off'/>
      <target type='serial' port='0'/>
      <alias name='serial0'/>
    </console>
    <input type='tablet' bus='usb'>
      <alias name='input0'/>
      <address type='usb' bus='0' port='1'/>
    </input>
    <input type='mouse' bus='ps2'>
      <alias name='input1'/>
    </input>
    <input type='keyboard' bus='ps2'>
      <alias name='input2'/>
    </input>
    <graphics type='vnc' port='5900' autoport='yes' listen='0.0.0.0'>
      <listen type='address' address='0.0.0.0'/>
    </graphics>
    <audio id='1' type='none'/>
    <video>
      <model type='vga' vram='16384' heads='1' primary='yes'/>
      <alias name='video0'/>
      <address type='pci' domain='0x0000' bus='0x00' slot='0x02' function='0x0'/>
    </video>
    <memballoon model='virtio'>
      <stats period='10'/>
      <alias name='balloon0'/>
      <address type='pci' domain='0x0000' bus='0x00' slot='0x05' function='0x0'/>
    </memballoon>
    <rng model='virtio'>
      <backend model='random'>/dev/urandom</backend>
      <alias name='rng0'/>
      <address type='pci' domain='0x0000' bus='0x00' slot='0x06' function='0x0'/>
    </rng>
  </devices>
  <seclabel type='dynamic' model='dac' relabel='yes'>
    <label>+107:+107</label>
    <imagelabel>+107:+107</imagelabel>
  </seclabel>
</domain>

Список гипервизоров можно посмотреть командой:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
$ source keystone_admin

$ nova hypervisor-list
+--------------------------------------+---------------------+-------+---------+
| ID                                   | Hypervisor hostname | State | Status  |
+--------------------------------------+---------------------+-------+---------+
| 8703c883-8363-4f00-82ee-f527f582f984 | compute-1           | up    | enabled |
| 02d2ea3c-26df-479a-877b-b185be68a4b7 | compute-2           | up    | enabled |
+--------------------------------------+---------------------+-------+---------+

$ nova hypervisor-servers compute
+--------------------------------------+-------------------+--------------------------------------+---------------------+
| ID                                   | Name              | Hypervisor ID                        | Hypervisor Hostname |
+--------------------------------------+-------------------+--------------------------------------+---------------------+
| 24e83e0c-ca68-4506-a1f5-249d2d161d55 | instance-00000002 | 02d2ea3c-26df-479a-877b-b185be68a4b7 | compute-2           |
+--------------------------------------+-------------------+--------------------------------------+---------------------+

Найти конкретную виртуальную машину можно через базу данных:

1
$ sudo mysql -unova -pnova
1
2
3
4
5
6
7
USE nova;
SELECT uuid,host,launched_on,created_at FROM instances WHERE uuid='24e83e0c-ca68-4506-a1f5-249d2d161d55';
+--------------------------------------+-----------+-------------+---------------------+
| uuid                                 | host      | launched_on | created_at          |
+--------------------------------------+-----------+-------------+---------------------+
| 24e83e0c-ca68-4506-a1f5-249d2d161d55 | compute-2 | compute-2   | 2025-07-30 12:21:04 |
+--------------------------------------+-----------+-------------+---------------------+

Суммарную статистику для каждого проекта можно проверить командой:

1
2
3
4
5
6
7
$ nova usage-list
Usage from 2025-06-21 to 2025-07-20:
+----------------------------------+---------+---------------+-----------+----------------+
| Tenant ID                        | Servers | RAM MiB-Hours | CPU Hours | Disk GiB-Hours |
+----------------------------------+---------+---------------+-----------+----------------+
| 000aca557baf409db7b14b884c639d13 | 1       | 7.60          | 0.03      | 0.03           |
+----------------------------------+---------+---------------+-----------+----------------+

Если виртуальная машина в статусе ACTIVE (openstack server list), то можно получить ссылку к консоли:

1
2
3
4
5
6
7
8
9
10
$ source keystone_demo

$ openstack console url show myinstance1 # альтернативная команда: nova get-vnc-console myinstance1 novnc
+----------+------------------------------------------------------------------------------------------------+
| Field    | Value                                                                                          |
+----------+------------------------------------------------------------------------------------------------+
| protocol | vnc                                                                                            |
| type     | novnc                                                                                          |
| url      | http://192.168.100.128:6080/vnc_auto.html?path=%3Ftoken%3D12a51296-1e7e-47b3-afae-5a82552c14ea |
+----------+------------------------------------------------------------------------------------------------+

Далее нужно создать и применить к виртуальной машине группы безопасности - набор правил брандмауэра, разрешающих доступ к тем или иным портам виртуальной машины. По умолчанию в каждом проекте существует одна группа безопасности default, не содержащая ни одного правила для входящего трафика. Правила можно добавлять в существующую группу или в новую.

Создадим правило demo-sgroup и добавим в него правила для ssh и ICMP:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
$ openstack security group create demo-sgroup
+-----------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Field           | Value                                                                                                                                                                                                                      |
+-----------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| created_at      | 2025-07-30T12:23:01Z                                                                                                                                                                                                       |
| description     | demo-sgroup                                                                                                                                                                                                                |
| id              | 6f9820aa-230f-46f6-8b2c-f684de6b6794                                                                                                                                                                                       |
| name            | demo-sgroup                                                                                                                                                                                                                |
| project_id      | 000aca557baf409db7b14b884c639d13                                                                                                                                                                                           |
| revision_number | 1                                                                                                                                                                                                                          |
| rules           | created_at='2025-07-30T12:23:01Z', direction='egress', ethertype='IPv4', id='8230dd4b-70b4-41b1-a347-1a5b42c0a099', standard_attr_id='30', tenant_id='000aca557baf409db7b14b884c639d13', updated_at='2025-07-30T12:23:01Z' |
|                 | created_at='2025-07-30T12:23:01Z', direction='egress', ethertype='IPv6', id='b8ae504c-1608-408d-b513-c134ceb81c3f', standard_attr_id='31', tenant_id='000aca557baf409db7b14b884c639d13', updated_at='2025-07-30T12:23:01Z' |
| stateful        | True                                                                                                                                                                                                                       |
| tags            | []                                                                                                                                                                                                                         |
| updated_at      | 2025-07-30T12:23:01Z                                                                                                                                                                                                       |
+-----------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+

$ openstack security group rule create --protocol tcp --dst-port 22 demo-sgroup
+-------------------------+--------------------------------------+
| Field                   | Value                                |
+-------------------------+--------------------------------------+
| created_at              | 2025-07-30T12:23:14Z                 |
| description             |                                      |
| direction               | ingress                              |
| ether_type              | IPv4                                 |
| id                      | 22cb3abb-63b6-4918-9691-c7361dc8e57e |
| name                    | None                                 |
| port_range_max          | 22                                   |
| port_range_min          | 22                                   |
| project_id              | 000aca557baf409db7b14b884c639d13     |
| protocol                | tcp                                  |
| remote_address_group_id | None                                 |
| remote_group_id         | None                                 |
| remote_ip_prefix        | 0.0.0.0/0                            |
| revision_number         | 0                                    |
| security_group_id       | 6f9820aa-230f-46f6-8b2c-f684de6b6794 |
| tags                    | []                                   |
| tenant_id               | 000aca557baf409db7b14b884c639d13     |
| updated_at              | 2025-07-30T12:23:14Z                 |
+-------------------------+--------------------------------------+

$ openstack security group rule create --protocol icmp demo-sgroup
+-------------------------+--------------------------------------+
| Field                   | Value                                |
+-------------------------+--------------------------------------+
| created_at              | 2025-07-30T12:23:25Z                 |
| description             |                                      |
| direction               | ingress                              |
| ether_type              | IPv4                                 |
| id                      | d9562e85-63af-47f9-8cd7-1834bd86b930 |
| name                    | None                                 |
| port_range_max          | None                                 |
| port_range_min          | None                                 |
| project_id              | 000aca557baf409db7b14b884c639d13     |
| protocol                | icmp                                 |
| remote_address_group_id | None                                 |
| remote_group_id         | None                                 |
| remote_ip_prefix        | 0.0.0.0/0                            |
| revision_number         | 0                                    |
| security_group_id       | 6f9820aa-230f-46f6-8b2c-f684de6b6794 |
| tags                    | []                                   |
| tenant_id               | 000aca557baf409db7b14b884c639d13     |
| updated_at              | 2025-07-30T12:23:25Z                 |
+-------------------------+--------------------------------------+

Просмотр списка групп безопасности:

1
2
3
4
5
6
7
$ openstack security group list # nova secgroup-list
+--------------------------------------+-------------+----------------------------+----------------------------------+------+
| ID                                   | Name        | Description                | Project                          | Tags |
+--------------------------------------+-------------+----------------------------+----------------------------------+------+
| 2eacbdb9-0449-4284-a3f1-85661fd3bfe0 | default     | Группа защиты по умолчанию | 000aca557baf409db7b14b884c639d13 | []   |
| 6f9820aa-230f-46f6-8b2c-f684de6b6794 | demo-sgroup | demo-sgroup                | 000aca557baf409db7b14b884c639d13 | []   |
+--------------------------------------+-------------+----------------------------+----------------------------------+------+

Просмотреть правила конкретной группы:

1
2
3
4
5
6
7
8
9
10
11
12
13
$ openstack security group rule list # nova secgroup-list-rules
+--------------------------------------+-------------+-----------+-----------+------------+-----------+--------------------------------------+----------------------+--------------------------------------+
| ID                                   | IP Protocol | Ethertype | IP Range  | Port Range | Direction | Remote Security Group                | Remote Address Group | Security Group                       |
+--------------------------------------+-------------+-----------+-----------+------------+-----------+--------------------------------------+----------------------+--------------------------------------+
| 22cb3abb-63b6-4918-9691-c7361dc8e57e | tcp         | IPv4      | 0.0.0.0/0 | 22:22      | ingress   | None                                 | None                 | 6f9820aa-230f-46f6-8b2c-f684de6b6794 |
| 2cdf228e-ab01-4270-9530-84bf4ef7d927 | None        | IPv4      | 0.0.0.0/0 |            | egress    | None                                 | None                 | 2eacbdb9-0449-4284-a3f1-85661fd3bfe0 |
| 59f0c0f5-33f5-4404-9095-90d8188dc3de | None        | IPv6      | ::/0      |            | ingress   | 2eacbdb9-0449-4284-a3f1-85661fd3bfe0 | None                 | 2eacbdb9-0449-4284-a3f1-85661fd3bfe0 |
| 8230dd4b-70b4-41b1-a347-1a5b42c0a099 | None        | IPv4      | 0.0.0.0/0 |            | egress    | None                                 | None                 | 6f9820aa-230f-46f6-8b2c-f684de6b6794 |
| b8ae504c-1608-408d-b513-c134ceb81c3f | None        | IPv6      | ::/0      |            | egress    | None                                 | None                 | 6f9820aa-230f-46f6-8b2c-f684de6b6794 |
| b8cf486b-e1f8-494c-bcb5-1cfbc5965166 | None        | IPv4      | 0.0.0.0/0 |            | ingress   | 2eacbdb9-0449-4284-a3f1-85661fd3bfe0 | None                 | 2eacbdb9-0449-4284-a3f1-85661fd3bfe0 |
| d7b11068-dd67-4122-96a7-b71b4bbf74eb | None        | IPv6      | ::/0      |            | egress    | None                                 | None                 | 2eacbdb9-0449-4284-a3f1-85661fd3bfe0 |
| d9562e85-63af-47f9-8cd7-1834bd86b930 | icmp        | IPv4      | 0.0.0.0/0 |            | ingress   | None                                 | None                 | 6f9820aa-230f-46f6-8b2c-f684de6b6794 |
+--------------------------------------+-------------+-----------+-----------+------------+-----------+--------------------------------------+----------------------+--------------------------------------+

Группы безопасности можно добавлять и удалять динамически:

1
2
$ openstack server add security group myinstance1 demo-sgroup
$ openstack server remove security group myinstance1 default

Создаём и добавляем к нашей виртуальной машине плавающий IP:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
$ openstack floating ip create ext-net
+---------------------+--------------------------------------+
| Field               | Value                                |
+---------------------+--------------------------------------+
| created_at          | 2025-07-30T12:24:04Z                 |
| description         |                                      |
| dns_domain          | None                                 |
| dns_name            | None                                 |
| fixed_ip_address    | None                                 |
| floating_ip_address | 10.100.1.177                         |
| floating_network_id | d7c5cc1d-e86a-4e7e-a723-14386f24951b |
| id                  | b8369a52-b778-4828-9fe5-f38316395510 |
| name                | 10.100.1.177                         |
| port_details        | None                                 |
| port_id             | None                                 |
| project_id          | 000aca557baf409db7b14b884c639d13     |
| qos_policy_id       | None                                 |
| revision_number     | 0                                    |
| router_id           | None                                 |
| status              | DOWN                                 |
| subnet_id           | None                                 |
| tags                | []                                   |
| updated_at          | 2025-07-30T12:24:04Z                 |
+---------------------+--------------------------------------+

$ openstack server add floating ip myinstance1 10.100.1.177

$ openstack server list # проверяем, что IP добавился
+--------------------------------------+-------------+--------+-------------------------------------+--------+---------+
| ID                                   | Name        | Status | Networks                            | Image  | Flavor  |
+--------------------------------------+-------------+--------+-------------------------------------+--------+---------+
| 24e83e0c-ca68-4506-a1f5-249d2d161d55 | myinstance1 | ACTIVE | demo-net=10.100.1.177, 172.16.0.168 | Cirros | m2.tiny |
+--------------------------------------+-------------+--------+-------------------------------------+--------+---------+

Теперь нам пригодится виртуальная машина test, которая создавалась вместе с машинами для OpenStack. Копируем туда приватный ключ demokey1 и пробуем подключиться в виртуальной машине myinstance1:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
$ ping -c 2 10.100.1.177
PING 10.100.1.177 (10.100.1.177) 56(84) bytes of data.
64 bytes from 10.100.1.177: icmp_seq=1 ttl=63 time=2.27 ms
64 bytes from 10.100.1.177: icmp_seq=2 ttl=63 time=1.58 ms

--- 10.100.1.177 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 1001ms
rtt min/avg/max/mdev = 1.583/1.924/2.265/0.341 ms

$ $ssh -i demokey1 cirros@10.100.1.177
The authenticity of host '10.100.1.177 (10.100.1.177)' can't be established.
ED25519 key fingerprint is SHA256:WwuMuG/PGYJc6cDZbaaq6Xi21//jlgun4OvJPfQz3zM.
This key is not known by any other names
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
Warning: Permanently added '10.100.1.177' (ED25519) to the list of known hosts.

$ whoami
cirros

$ ping -c 2 8.8.8.8
PING 8.8.8.8 (8.8.8.8) 56(84) bytes of data.
64 bytes from 8.8.8.8: icmp_seq=1 ttl=114 time=51.6 ms
64 bytes from 8.8.8.8: icmp_seq=2 ttl=114 time=51.8 ms

--- 8.8.8.8 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 1002ms
rtt min/avg/max/mdev = 51.608/51.698/51.788/0.090 ms

Моментальные снимки

Создать новую виртуальную машину можно из образа уже созданной:

1
2
3
$ source keystone_demo

$ nova image-create myinstance1 myinstance1_sn1

Проверяем создание:

1
2
3
4
5
6
7
$ openstack image list
+--------------------------------------+-----------------+--------+
| ID                                   | Name            | Status |
+--------------------------------------+-----------------+--------+
| 20120ae4-d320-421e-b8c9-1b95549a3995 | Cirros          | active |
| a7914969-d735-4c07-aee2-72f18be672f6 | myinstance1_sn1 | active |
+--------------------------------------+-----------------+--------+

Создаём виртуальную машину из нового образа:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
$ openstack server create --image myinstance1_sn1 --flavor m2.tiny --key-name demokey1 --nic net-id=demo-net myinstance2
+-----------------------------+--------------------------------------------------------+
| Field                       | Value                                                  |
+-----------------------------+--------------------------------------------------------+
| OS-DCF:diskConfig           | MANUAL                                                 |
| OS-EXT-AZ:availability_zone |                                                        |
| OS-EXT-STS:power_state      | NOSTATE                                                |
| OS-EXT-STS:task_state       | scheduling                                             |
| OS-EXT-STS:vm_state         | building                                               |
| OS-SRV-USG:launched_at      | None                                                   |
| OS-SRV-USG:terminated_at    | None                                                   |
| accessIPv4                  |                                                        |
| accessIPv6                  |                                                        |
| addresses                   |                                                        |
| adminPass                   | KdvwP8mDLZFn                                           |
| config_drive                |                                                        |
| created                     | 2025-07-30T12:28:07Z                                   |
| flavor                      | m2.tiny (d3db6534-1b79-4211-ae47-391b233447d9)         |
| hostId                      |                                                        |
| id                          | 60276c7e-d729-42cd-8114-b127747663e3                   |
| image                       | myinstance1_sn1 (a7914969-d735-4c07-aee2-72f18be672f6) |
| key_name                    | demokey1                                               |
| name                        | myinstance2                                            |
| progress                    | 0                                                      |
| project_id                  | 000aca557baf409db7b14b884c639d13                       |
| properties                  |                                                        |
| security_groups             | name='default'                                         |
| status                      | BUILD                                                  |
| updated                     | 2025-07-30T12:28:07Z                                   |
| user_id                     | c1e0d27f36f746b79aa38c92d58ad600                       |
| volumes_attached            |                                                        |
+-----------------------------+--------------------------------------------------------+

$ openstack server list
+--------------------------------------+-------------+--------+-------------------------------------+-----------------+---------+
| ID                                   | Name        | Status | Networks                            | Image           | Flavor  |
+--------------------------------------+-------------+--------+-------------------------------------+-----------------+---------+
| 60276c7e-d729-42cd-8114-b127747663e3 | myinstance2 | ACTIVE | demo-net=172.16.0.23                | myinstance1_sn1 | m2.tiny |
| 24e83e0c-ca68-4506-a1f5-249d2d161d55 | myinstance1 | ACTIVE | demo-net=10.100.1.177, 172.16.0.168 | Cirros          | m2.tiny |
+--------------------------------------+-------------+--------+-------------------------------------+-----------------+---------+

Настройка экземпляров виртуальных машин при помощи cloud-init

При помощи cloud-init экземпляры виртуальных машин при старте могут настраивать различные параметры, такие как имя узла, ssh-ключ, сетевые настройки и так далее. ВМ получают эту информацию во время загрузки, обращаясь на сервер метаданных Neutron - http://169.254.169.254. Агент метаданных проксирует запросы к nova-api при помощи пространства имён маршрутизатора или DHCP.

Конфигурационная информация передаётся в виртуальную машину при помощи параметров --user-data во время запуска. Также метаданные можно передать при старте ВМ из Horizon на вкладке Post-Creation.

Пример простого конфигурационного файла cloud-init:

1
2
3
4
#cloud-config
hostname: fedora42
fqdn: fedora42.test.local
manage_etc_hosts: true

Далее запускаем виртуальную машину, передав ей файл:

1
$ nova boot --flavor m1.small --image fedora-42.x86_64 --key-name demokey1 --user-data ./test.txt mytestvm

Создание виртуальной машины с помощью Heat

Нужно скачать архив с Яндекс.Диска автора книги (диск, блог) с примерами конфигурационных файлов и шаблонов.

Понадобится файл /config_files/HOT/test-server.yml - данный шаблон является одной из многих вариаций Hello World для Heat: создаётся стек, состоящий из одной виртуальной машины, которой во время старта передаётся скрипт, выводящий сообщений “Instance STARTED!” на стандартный вывод:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
heat_template_version: 2014-10-16
description: > 
  OpenStack. A practical introduction to the cloud operating system.
  Example of launching one VM

parameters:
  network:
    type: string
    description: VM instance network
    default: demo-net
  image:
    type: string
    description: Image for running VM
    default: Cirros

resources:
  my_server:
    type: OS::Nova::Server
    properties:
      flavor: m2.tiny
      key_name: demokey1
      networks:
      - network: { get_param: network }
      image: { get_param: image }
      user_data: |
        #!/bin/sh
        echo "Instance STARTED!"
      user_data_format: RAW

outputs:
  instance_name:
    description: VM instance name
    value: { get_attr: [my_server, name] }
  private_ip:
    description: IP in private network
    value: { get_attr: [ my_server, first_address ] }

Версия (heat_template_version) задаётся не произвольно, а строго в соответствии с релизом OpenStack (2014-10-16 - релиз Juno). Описание опционально. Далее следует три части шаблона:

  • parameters: здесь определяются параметры image и network, которые можно задать во время запуска стека. Оба параметра - строки; у каждого из них есть значение по умолчанию;
  • resources: описывает ресурсы шаблона; здесь должен быть описан как минимум 1 ресурс (например type: OS::Nova::Server). С properties задаётся флейвор, ключ и скрипт, который будет исполнен при старте при помощи cloud-init;
  • outputs: задаёт параметры, которые будут выводиться пользователю, когда шаблон отработает в выводе heat stack-show, в интерфейсе Horizon или при запросе через API. Данная секция является необязательной.

Запуск шаблона:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
$ source keystone_demo

$ openstack stack create --parameter network=demo-net --template test-server.yml teststack
+---------------------+------------------------------------------------------------------------------------------------+
| Field               | Value                                                                                          |
+---------------------+------------------------------------------------------------------------------------------------+
| id                  | bfbe8012-2ac1-4e5f-aaa0-2ca647809f78                                                           |
| stack_name          | teststack                                                                                      |
| description         | OpenStack. A practical introduction to the cloud operating system. Example of launching one VM |
|                     |                                                                                                |
| creation_time       | 2025-07-30T12:30:49Z                                                                           |
| updated_time        | None                                                                                           |
| stack_status        | CREATE_IN_PROGRESS                                                                             |
| stack_status_reason | Stack CREATE started                                                                           |
+---------------------+------------------------------------------------------------------------------------------------+

С помощью stack list можно следить за процессом отработки:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
$ openstack stack list
+--------------------------------------+------------+--------------------+----------------------+--------------+
| ID                                   | Stack Name | Stack Status       | Creation Time        | Updated Time |
+--------------------------------------+------------+--------------------+----------------------+--------------+
| bfbe8012-2ac1-4e5f-aaa0-2ca647809f78 | teststack  | CREATE_IN_PROGRESS | 2025-07-30T15:29:24Z | None         |
+--------------------------------------+------------+--------------------+----------------------+--------------+

# ...

+--------------------------------------+------------+-----------------+----------------------+--------------+
| ID                                   | Stack Name | Stack Status    | Creation Time        | Updated Time |
+--------------------------------------+------------+-----------------+----------------------+--------------+
| bfbe8012-2ac1-4e5f-aaa0-2ca647809f78 | teststack  | CREATE_COMPLETE | 2025-07-30T12:30:49Z | None         |
+--------------------------------------+------------+-----------------+----------------------+--------------+

Можно посмотреть подробную информацию про конкретный стек:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
$ openstack stack show teststack
+-----------------------+--------------------------------------------------------------------------------------------------------------------------+
| Field                 | Value                                                                                                                    |
+-----------------------+--------------------------------------------------------------------------------------------------------------------------+
| id                    | bfbe8012-2ac1-4e5f-aaa0-2ca647809f78                                                                                     |
| stack_name            | teststack                                                                                                                |
| description           | OpenStack. A practical introduction to the cloud operating system. Example of launching one VM                           |
|                       |                                                                                                                          |
| creation_time         | 2025-07-30T12:30:49Z                                                                                                     |
| updated_time          | None                                                                                                                     |
| stack_status          | CREATE_COMPLETE                                                                                                          |
| stack_status_reason   | Stack CREATE completed successfully                                                                                      |
| parameters            | OS::project_id: 000aca557baf409db7b14b884c639d13                                                                         |
|                       | OS::stack_id: bfbe8012-2ac1-4e5f-aaa0-2ca647809f78                                                                       |
|                       | OS::stack_name: teststack                                                                                                |
|                       | image: Cirros                                                                                                            |
|                       | network: demo-net                                                                                                        |
|                       |                                                                                                                          |
| outputs               | - description: IP in private network                                                                                     |
|                       |   output_key: private_ip                                                                                                 |
|                       |   output_value: 172.16.0.152                                                                                             |
|                       | - description: VM instance name                                                                                          |
|                       |   output_key: instance_name                                                                                              |
|                       |   output_value: teststack-my_server-6bfy7i5tsqqa                                                                         |
|                       |                                                                                                                          |
| links                 | - href: http://controller:8004/v1/000aca557baf409db7b14b884c639d13/stacks/teststack/bfbe8012-2ac1-4e5f-aaa0-2ca647809f78 |
|                       |   rel: self                                                                                                              |
|                       |                                                                                                                          |
| deletion_time         | None                                                                                                                     |
| notification_topics   | []                                                                                                                       |
| capabilities          | []                                                                                                                       |
| disable_rollback      | True                                                                                                                     |
| timeout_mins          | None                                                                                                                     |
| stack_owner           | demo                                                                                                                     |
| parent                | None                                                                                                                     |
| stack_user_project_id | 6828adaa3fa34fcaa979042190f7cd44                                                                                         |
| tags                  | []                                                                                                                       |
|                       |                                                                                                                          |
+-----------------------+--------------------------------------------------------------------------------------------------------------------------+

Убеждаемся в наличии сервера (имя для него формируются из имени стека и имени ресурса) и проверяем отработку скрипта:

1
2
3
4
5
6
7
8
9
10
11
$ openstack server list
+--------------------------------------+----------------------------------+--------+-------------------------------------+-----------------+---------+
| ID                                   | Name                             | Status | Networks                            | Image           | Flavor  |
+--------------------------------------+----------------------------------+--------+-------------------------------------+-----------------+---------+
| bfe65104-47ae-416e-b5a9-76d352aa5afd | teststack-my_server-6bfy7i5tsqqa | ACTIVE | demo-net=172.16.0.152               | Cirros          | m2.tiny |
| 60276c7e-d729-42cd-8114-b127747663e3 | myinstance2                      | ACTIVE | demo-net=172.16.0.23                | myinstance1_sn1 | m2.tiny |
| 24e83e0c-ca68-4506-a1f5-249d2d161d55 | myinstance1                      | ACTIVE | demo-net=10.100.1.177, 172.16.0.168 | Cirros          | m2.tiny |
+--------------------------------------+----------------------------------+--------+-------------------------------------+-----------------+---------+

$ openstack console log show teststack-my_server-6bfy7i5tsqqa | grep STARTED
Instance STARTED!

Можно просмотреть список событий при создании стека:

1
2
3
4
5
$ openstack stack event list teststack
2025-07-29 17:04:24Z [teststack]: CREATE_IN_PROGRESS  Stack CREATE started
2025-07-29 17:04:24Z [teststack.my_server]: CREATE_IN_PROGRESS  state changed
2025-07-29 17:04:35Z [teststack.my_server]: CREATE_COMPLETE  state changed
2025-07-29 17:04:35Z [teststack]: CREATE_COMPLETE  Stack CREATE completed successfully

Для просмотра также доступен шаблон, из которого был создан стек:

1
$ openstack stack template show teststack

На этом установка базовых компонентов OpenStack завершена.

Публикация защищена лицензией CC BY 4.0 .
Содержание