Ubuntu20.04 搭建W版本OpenStack平台

目录

一、基础环境配置

1.controller、compute配置网卡地址

2.配置域名解析

3.NTP时间同步

二、添加OpenStack-wallaby软件包及基本环境

1、OpenStack 服务的所有节点上添加软件包

2、Mysql数据库

3、Rabbitmq消息队列

4、Memcached

5、etcd环境部署

三、keystone服务

四、glance镜像服务

五、Placement环境搭建

六、Nova计算服务

七、Neutron网络服务

八、Dashboard搭建

九、访问Dashboard并实例发放


主机名 ens33 ens34
conttroller 192.168.100.10 192.168.200.10
compute 192.168.100.20 192.168.200.10

一、基础环境配置

1.controller、compute配置网卡地址

2.配置域名解析

将节点的主机名设置为controller、compute.

controller、compute编辑/etc/hosts文件以包含以下内容:

192.168.100.10 controller

192.168.100.20 compute

3.NTP时间同步

controller节点

#安装chrony软件包
$sudo apt install -y chrony


#编辑/etc/chrony/chrony.conf文件:
server 192.168.100.10 iburst
allow 192.168.100.0/24

#重启NTP服务:
$ sudo systemctl start chronyd

compute节点

#安装软件包。
$sudo apt install chrony

#配置/etc/chrony/chrony.conf文件:
server controller iburst
#pool 2.debian.pool.ntp.org offline iburst

#重启NTP服务。
$ sudo systemctl start chronyd

二、添加OpenStack-wallaby软件包及基本环境

1、OpenStack 服务的所有节点上添加软件包

$ sudo add-apt-repository cloud-archive:wallaby
$ sudo apt install python3-openstackclient

2、Mysql数据库

安装mariadb以及对应的依赖包
$sudo apt install mariadb-server python3-pymysql

创建和编辑/etc/mysql/mariadb.conf.d/99-openstack.cnf文件:
添加[mysqld]section字段
[mysqld]
bind-address = 192.168.100.10
default-storage-engine = innodb
innodb_file_per_table = on
max_connections = 4096
collation-server = utf8_general_ci
character-set-server = utf8


重启数据库服务:
$ sudo systemctl restart mysql
通过运行mysql_secure_installation 脚本来保护数据库服务。并进行为数据库root帐户初始化密码 :(设置数据库密码为000000)
$ sudo mysql_secure_installation

3、Rabbitmq消息队列

controller节点配置rabbitmq消息队列

$sudo apt install rabbitmq-server

添加openstack用户:
$sudo rabbitmqctl add_user openstack 000000
Creating user "openstack" ...

允许用户的配置、写入和读取访问权限 openstack:
$sudo rabbitmqctl set_permissions openstack ".*" ".*" ".*"
Setting permissions for user "openstack" in vhost "/" ...

4、Memcached

sudo apt install memcached python3-memcache

编辑/etc/memcached.conf文件进行访问修改:
-l 192.168.100.10


重启 Memcached 服务:
$ sudo systemctl status memcached

5、etcd环境部署

$sudo apt install etcd

编辑该/etc/default/etcd文件:
将ETCD_INITIAL_CLUSTER, ETCD_INITIAL_ADVERTISE_PEER_URLS, ETCD_ADVERTISE_CLIENT_URLS, 设置为ETCD_LISTEN_CLIENT_URLS控制器节点的管理 IP 地址,以允许其他节点通过管理网络访问:
ETCD_NAME="controller"
ETCD_DATA_DIR="/var/lib/etcd"
ETCD_INITIAL_CLUSTER_STATE="new"
ETCD_INITIAL_CLUSTER_TOKEN="etcd-cluster-01"
ETCD_INITIAL_CLUSTER="controller=http://192.168.100.10:2380"
ETCD_INITIAL_ADVERTISE_PEER_URLS="http://192.168.100.10:2380"
ETCD_ADVERTISE_CLIENT_URLS="http://192.168.100.10:2379"
ETCD_LISTEN_PEER_URLS="http://0.0.0.0:2380"
ETCD_LISTEN_CLIENT_URLS="http://192.168.100.10:2379"


启用并重启 etcd 服务:
$sudo systemctl enable etcd
$sudo systemctl restart etcd

三、keystone服务

$sudo mysql –uroot –p000000

创建keystone数据库:
MariaDB [(none)]> CREATE DATABASE keystone;

授予对keystone数据库访问权限:(设置keystone用户密码为000000)
MariaDB [(none)]> GRANT ALL PRIVILEGES ON keystone.* TO 'keystone'@'localhost' \
IDENTIFIED BY '000000';
MariaDB [(none)]> GRANT ALL PRIVILEGES ON keystone.* TO 'keystone'@'%' \
IDENTIFIED BY '000000';


安装软件包:
$sudo apt install keystone

编辑/etc/keystone/keystone.conf文件:
在该[database]字段部分中进行配置,配置数据库访问:
[database]
# ...
connection = mysql+pymysql://keystone:000000@controller/keystone

在[token]字段部分中,配置 Fernet 令牌提供程序:
[token]
# ...
provider = fernet

填充身份服务数据库:
$sudo su -s /bin/sh -c "keystone-manage db_sync" keystone
初始化 Fernet 密钥库:
$sudo keystone-manage fernet_setup --keystone-user keystone --keystone-group keystone
$sudo keystone-manage credential_setup --keystone-user keystone --keystone-group keystone


引导身份服务:
$sudo keystone-manage bootstrap --bootstrap-password 000000 \
  --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

配置 Apache HTTP 服务器
编辑/etc/apache2/apache2.conf文件并配置 
修改ServerName字段以引用控制器节点:
ServerName controller
(如果该ServerName条目尚不存在,则需要添加该条目)


重启Apache服务:
$sudo systemctl restart apache2

通过设置适当的环境变量来配置管理帐户:
$ export OS_USERNAME=admin
$ export OS_PASSWORD=000000
$ 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




创建域、项目、用户和角色
Identity 服务为每个 OpenStack 服务提供身份验证服务。身份验证服务使用域、项目、用户和角色的组合。
$ openstack domain create --description "An Example Domain" example
+-------------+----------------------------------+
| Field       | Value                            |
+-------------+----------------------------------+
| description | An Example Domain                |
| enabled     | True                             |
| id          | 2f4f80574fd84fe6ba9067228ae0a50c |
| name        | example                          |
| tags        | []                               |
+-------------+----------------------------------+

本指南使用一个服务项目,该项目包含您添加到环境中的每个服务的唯一用户。创建service 项目:
$ openstack project create --domain default --description "Service Project" service
+-------------+----------------------------------+
| Field       | Value                            |
+-------------+----------------------------------+
| description | Service Project                  |
| domain_id   | default                          |
| enabled     | True                             |
| id          | 24ac7f19cd944f4cba1d77469b2a73ed |
| is_domain   | False                            |
| name        | service                          |
| parent_id   | default                          |
| tags        | []                               |
+-------------+----------------------------------+

创建myproject项目:
$ openstack project create --domain default \
  --description "Demo Project" myproject
+-------------+----------------------------------+
| Field       | Value                            |
+-------------+----------------------------------+
| description | Demo Project                     |
| domain_id   | default                          |
| enabled     | True                             |
| id          | 231ad6e7ebba47d6a1e57e1cc07ae446 |
| is_domain   | False                            |
| name        | myproject                        |
| parent_id   | default                          |
| tags        | []                               |
+-------------+----------------------------------+

创建myuser用户:(用户密码设置为000000)
$ openstack user create --domain default --password-prompt myuser
User Password:
Repeat User Password:
+---------------------+----------------------------------+
| Field               | Value                            |
+---------------------+----------------------------------+
| domain_id           | default                          |
| enabled             | True                             |
| id                  | aeda23aa78f44e859900e22c24817832 |
| name                | myuser                           |
| options             | {}                               |
| password_expires_at | None                             |
+---------------------+----------------------------------+

创建myrole角色:
$ openstack role create myrole
+-----------+----------------------------------+
| Field     | Value                            |
+-----------+----------------------------------+
| domain_id | None                             |
| id        | 997ce8d05fc143ac97d83fdfb5998552 |
| name      | myrole                           |
+-----------+----------------------------------+

将myrole角色添加到myproject项目和myuser用户:
$ openstack role add --project myproject --user myuser myrole
此命令不提供任何输出。

$unset OS_AUTH_URL OS_PASSWORD
$openstack --os-auth-url http://controller:5000/v3 \
  --os-project-domain-name Default --os-user-domain-name Default \
  --os-project-name admin --os-username admin token issue

Password:   
+------------+-----------------------------------------------------------------+
| Field      | Value                                                           |
+------------+-----------------------------------------------------------------+
| expires    | 2016-02-12T20:14:07.056119Z                                     |
| id         | gAAAAABWvi7_B8kKQD9wdXac8MoZiQldmjEO643d-e_j-XXq9AmIegIbA7UHGPv |
|            | atnN21qtOMjCFWX7BReJEQnVOAj3nclRQgAYRsfSU_MrsuWb4EDtnjU7HEpoBb4 |
|            | o6ozsA_NmFWEpLeKy0uNn_WeKbAhYygrsmQGA49dclHVnz-OMVLiyM9ws       |
| project_id | 343d245e850143a096806dfaefa9afdc                                |
| user_id    | ac3377633149401296f6c0d92d79dc16                                |
+------------+-----------------------------------------------------------------+

$openstack --os-auth-url http://controller:5000/v3 \
  --os-project-domain-name Default --os-user-domain-name Default \
  --os-project-name myproject --os-username myuser token issue

Password:   
+------------+-----------------------------------------------------------------+
| Field      | Value                                                           |
+------------+-----------------------------------------------------------------+
| expires    | 2016-02-12T20:15:39.014479Z                                     |
| id         | gAAAAABWvi9bsh7vkiby5BpCCnc-JkbGhm9wH3fabS_cY7uabOubesi-Me6IGWW |
|            | yQqNegDDZ5jw7grI26vvgy1J5nCVwZ_zFRqPiz_qhbq29mgbQLglbkq6FQvzBRQ |
|            | JcOzq3uwhzNxszJWmzGC7rJE_H0A_a3UFhqv8M4zMRYSbS2YF0MyFmp_U       |
| project_id | ed0b60bf607743088218b0a533d5943f                                |
| user_id    | 58126687cbcc4888bfa9ab73a2256f27                                |
+------------+-----------------------------------------------------------------+

2、创建 OpenStack 客户端环境脚本
创建并编辑admin-openrc文件并添加以下内容:
export OS_PROJECT_DOMAIN_NAME=Default
export OS_USER_DOMAIN_NAME=Default
export OS_PROJECT_NAME=admin
export OS_USERNAME=admin
export OS_PASSWORD=000000
export OS_AUTH_URL=http://controller:5000/v3
export OS_IDENTITY_API_VERSION=3
export OS_IMAGE_API_VERSION=2

创建并编辑demo-openrc文件并添加以下内容:
export OS_PROJECT_DOMAIN_NAME=Default
export OS_USER_DOMAIN_NAME=Default
export OS_PROJECT_NAME=myproject
export OS_USERNAME=myuser
export OS_PASSWORD=000000
export OS_AUTH_URL=http://controller:5000/v3
export OS_IDENTITY_API_VERSION=3
export OS_IMAGE_API_VERSION=2


使用脚本
加载admin-openrc文件以使用身份服务的位置以及admin项目和用户凭据填充环境变量:
$ . admin-openrc

请求身份验证令牌:
$ openstack token issue
+------------+-----------------------------------------------------------------+
| Field      | Value                                                           |
+------------+-----------------------------------------------------------------+
| expires    | 2016-02-12T20:44:35.659723Z                                     |
| id         | gAAAAABWvjYj-Zjfg8WXFaQnUd1DMYTBVrKw4h3fIagi5NoEmh21U72SrRv2trl |
|            | JWFYhLi2_uPR31Igf6A8mH2Rw9kv_bxNo1jbLNPLGzW_u5FC7InFqx0yYtTwa1e |
|            | eq2b0f6-18KZyQhs7F3teAta143kJEWuNEYET-y7u29y0be1_64KYkM7E       |
| project_id | 343d245e850143a096806dfaefa9afdc                                |
| user_id    | ac3377633149401296f6c0d92d79dc16                                |
+------------+-----------------------------------------------------------------+

四、glance镜像服务

$sudo mysql –uroot –p000000

创建glance数据库:
MariaDB [(none)]> CREATE DATABASE glance;

授予对glance数据库访问权限:
MariaDB [(none)]> GRANT ALL PRIVILEGES ON glance.* TO 'glance'@'localhost' \
  IDENTIFIED BY '000000';
MariaDB [(none)]> GRANT ALL PRIVILEGES ON glance.* TO 'glance'@'%' \
  IDENTIFIED BY '000000';



$ . admin-openrc
创建glance服务凭证

创建glance用户:
$ openstack user create --domain default --password-prompt glance
User Password:
Repeat User Password:
+---------------------+----------------------------------+
| Field               | Value                            |
+---------------------+----------------------------------+
| domain_id           | default                          |
| enabled             | True                             |
| id                  | 3f4e777c4062483ab8d9edd7dff829df |
| name                | glance                           |
| options             | {}                               |
| password_expires_at | None                             |
+---------------------+----------------------------------+

将admin角色添加到glance用户和 service项目:
$ openstack role add --project service --user glance admin


创建glance服务实体:
$ openstack service create --name glance --description "OpenStack Image" image
+-------------+----------------------------------+
| Field       | Value                            |
+-------------+----------------------------------+
| description | OpenStack Image                  |
| enabled     | True                             |
| id          | 8c2c7f1b9b5049ea9e63757b5533e6d2 |
| name        | glance                           |
| type        | image                            |
+-------------+----------------------------------+

创建镜像服务 API 端点:
$ openstack endpoint create --region RegionOne image public http://controller:9292
+--------------+----------------------------------+
| Field        | Value                            |
+--------------+----------------------------------+
| enabled      | True                             |
| id           | 340be3625e9b4239a6415d034e98aace |
| interface    | public                           |
| region       | RegionOne                        |
| region_id    | RegionOne                        |
| service_id   | 8c2c7f1b9b5049ea9e63757b5533e6d2 |
| 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           | a6e4b153c2ae4c919eccfdbb7dceb5d2 |
| interface    | internal                         |
| region       | RegionOne                        |
| region_id    | RegionOne                        |
| service_id   | 8c2c7f1b9b5049ea9e63757b5533e6d2 |
| 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           | 0c37ed58103f4300a84ff125a539032d |
| interface    | admin                            |
| region       | RegionOne                        |
| region_id    | RegionOne                        |
| service_id   | 8c2c7f1b9b5049ea9e63757b5533e6d2 |
| service_name | glance                           |
| service_type | image                            |
| url          | http://controller:9292           |
+--------------+----------------------------------+


安装软件包:
$sudo apt install glance

编辑/etc/glance/glance-api.conf文件:
[database]字段部分中,配置数据库访问:
[database]
# ...
connection = mysql+pymysql://glance:000000@controller/glance


在[keystone_authtoken]和[paste_deploy]部分,配置身份服务访问:
[keystone_authtoken]
# ...
www_authenticate_uri = http://controller:5000
auth_url = http://controller:5000
memcached_servers = controller:11211
auth_type = password
project_domain_name = Default
user_domain_name = Default
project_name = service
username = glance
password = 000000


[paste_deploy]
# ...
flavor = keystone

在该[glance_store]部分中,配置本地文件系统存储和镜像文件的位置:
[glance_store]
# ...
stores = file,http
default_store = file
filesystem_store_datadir = /var/lib/glance/images/

填充镜像服务数据库:
$sudo su -s /bin/sh -c "glance-manage db_sync" glance


重新启动镜像服务:
$ sudo systemctl restart glance-api

使用QCOW2磁盘格式、裸容器格式和公开可见性将镜像上传到 glance Image 服务 ,以便所有项目都可以访问它:
上传cirros-0.4.0-x86_64-disk.img
$ glance image-create --name "cirros" --file cirros-0.4.0-x86_64-disk.img --disk-format qcow2 --container-format bare --visibility=public
+------------------+------------------------------------------------------+
| Field            | Value                                                |
+------------------+------------------------------------------------------+
| checksum         | 133eae9fb1c98f45894a4e60d8736619                     |
| container_format | bare                                                 |
| created_at       | 2015-03-26T16:52:10Z                                 |
| disk_format      | qcow2                                                |
| file             | /v2/images/cc5c6982-4910-471e-b864-1098015901b5/file |
| id               | cc5c6982-4910-471e-b864-1098015901b5                 |
| min_disk         | 0                                                    |
| min_ram          | 0                                                    |
| name             | cirros                                               |
| owner            | ae7a98326b9c455588edd2656d723b9d                     |
| protected        | False                                                |
| schema           | /v2/schemas/image                                    |
| size             | 13200896                                             |
| status           | active                                               |
| tags             |                                                      |
| updated_at       | 2015-03-26T16:52:10Z                                 |
| virtual_size     | None                                                 |
| visibility       | public                                               |
+------------------+------------------------------------------------------+

$ glance image-list
+--------------------------------------+--------+--------+
| ID                                   | Name   | Status |
+--------------------------------------+--------+--------+
| 38047887-61a7-41ea-9b49-27987d5e8bb9 | cirros | active |
+--------------------------------------+--------+--------+

五、Placement环境搭建

$sudo mysql –uroot –p000000

创建placement数据库:
MariaDB [(none)]> CREATE DATABASE placement;

授予对数据库的适当访问权限:
MariaDB [(none)]> GRANT ALL PRIVILEGES ON placement.* TO 'placement'@'localhost' \
  IDENTIFIED BY '000000';
MariaDB [(none)]> GRANT ALL PRIVILEGES ON placement.* TO 'placement'@'%' \
  IDENTIFIED BY '000000';

配置用户和端点
$ . admin-openrc

$ openstack user create --domain default --password-prompt placement
User Password:
Repeat User Password:
+---------------------+----------------------------------+
| Field               | Value                            |
+---------------------+----------------------------------+
| domain_id           | default                          |
| enabled             | True                             |
| id                  | fa742015a6494a949f67629884fc7ec8 |
| name                | placement                        |
| options             | {}                               |
| password_expires_at | None                             |
+---------------------+----------------------------------+

将 Placement 用户添加到具有 admin 角色的服务项目:
$ openstack role add --project service --user placement admin


在服务目录中创建 Placement API 条目:
$ openstack service create --name placement --description "Placement API" placement
+-------------+----------------------------------+
| Field       | Value                            |
+-------------+----------------------------------+
| description | Placement API                    |
| enabled     | True                             |
| id          | 2d1a27022e6e4185b86adac4444c495f |
| name        | placement                        |
| type        | placement                        |
+-------------+----------------------------------+

创建 Placement API 服务端点:
$ openstack endpoint create --region RegionOne placement public http://controller:8778
+--------------+----------------------------------+
| Field        | Value                            |
+--------------+----------------------------------+
| enabled      | True                             |
| id           | 2b1b2637908b4137a9c2e0470487cbc0 |
| interface    | public                           |
| region       | RegionOne                        |
| region_id    | RegionOne                        |
| service_id   | 2d1a27022e6e4185b86adac4444c495f |
| 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           | 02bcda9a150a4bd7993ff4879df971ab |
| interface    | internal                         |
| region       | RegionOne                        |
| region_id    | RegionOne                        |
| service_id   | 2d1a27022e6e4185b86adac4444c495f |
| 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           | 3d71177b9e0f406f98cbff198d74b182 |
| interface    | admin                            |
| region       | RegionOne                        |
| region_id    | RegionOne                        |
| service_id   | 2d1a27022e6e4185b86adac4444c495f |
| service_name | placement                        |
| service_type | placement                        |
| url          | http://controller:8778           |
+--------------+----------------------------------+


安装软件包:
$sudo apt install placement-api
编辑/etc/placement/placement.conf文件:
在该[placement_database]部分中,配置数据库访问:
[placement_database]
# ...
connection = mysql+pymysql://placement:000000@controller/placement

在[api]和[keystone_authtoken]部分,配置身份服务访问:
[api]
# ...
auth_strategy = keystone


[keystone_authtoken]
# ...
auth_url = http://controller:5000/v3
memcached_servers = controller:11211
auth_type = password
project_domain_name = Default
user_domain_name = Default
project_name = service
username = placement
password = 000000


填充placement数据库:
$sudo su -s /bin/sh -c "placement-manage db sync" placement


重启apache web服务。
$ sudo systemctl restart apache2


$ . admin-openrc
执行placement状态检查:
$sudo placement-status upgrade check
+----------------------------------+
| Upgrade Check Results            |
+----------------------------------+
| Check: Missing Root Provider IDs |
| Result: Success                  |
| Details: None                    |
+----------------------------------+
| Check: Incomplete Consumers      |
| Result: Success                  |
| Details: None                    |
+----------------------------------+

六、Nova计算服务

controller完成Nova服务搭建

$sudo mysql –uroot –p000000

创建nova_api,nova和nova_cell0数据库:
MariaDB [(none)]> CREATE DATABASE nova_api;
MariaDB [(none)]> CREATE DATABASE nova;
MariaDB [(none)]> CREATE DATABASE nova_cell0;

授予对数据库的访问权限:
MariaDB [(none)]> GRANT ALL PRIVILEGES ON nova_api.* TO 'nova'@'localhost' \
  IDENTIFIED BY '000000';
MariaDB [(none)]> GRANT ALL PRIVILEGES ON nova_api.* TO 'nova'@'%' \
  IDENTIFIED BY '000000';

MariaDB [(none)]> GRANT ALL PRIVILEGES ON nova.* TO 'nova'@'localhost' \
  IDENTIFIED BY '000000';
MariaDB [(none)]> GRANT ALL PRIVILEGES ON nova.* TO 'nova'@'%' \
  IDENTIFIED BY '000000';

MariaDB [(none)]> GRANT ALL PRIVILEGES ON nova_cell0.* TO 'nova'@'localhost' \
  IDENTIFIED BY '000000';
MariaDB [(none)]> GRANT ALL PRIVILEGES ON nova_cell0.* TO 'nova'@'%' \
  IDENTIFIED BY '000000';


$ . admin-openrc
创建计算服务凭证:

$ openstack user create --domain default --password-prompt nova
User Password:
Repeat User Password:
+---------------------+----------------------------------+
| Field               | Value                            |
+---------------------+----------------------------------+
| domain_id           | default                          |
| enabled             | True                             |
| id                  | 8a7dbf5279404537b1c7b86c033620fe |
| name                | nova                             |
| options             | {}                               |
| password_expires_at | None                             |
+---------------------+----------------------------------+

admin为nova用户添加角色:
$ openstack role add --project service --user nova admin

创建nova服务实体:
$ openstack service create --name nova --description "OpenStack Compute" compute
+-------------+----------------------------------+
| Field       | Value                            |
+-------------+----------------------------------+
| description | OpenStack Compute                |
| enabled     | True                             |
| id          | 060d59eac51b4594815603d75a00aba2 |
| name        | nova                             |
| type        | compute                          |
+-------------+----------------------------------+

创建 Compute API 服务端点:
$ openstack endpoint create --region RegionOne \
 compute public http://controller:8774/v2.1
+--------------+-------------------------------------------+
| Field        | Value                                     |
+--------------+-------------------------------------------+
| enabled      | True                                      |
| id           | 3c1caa473bfe4390a11e7177894bcc7b          |
| interface    | public                                    |
| region       | RegionOne                                 |
| region_id    | RegionOne                                 |
| service_id   | 060d59eac51b4594815603d75a00aba2          |
| 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           | e3c918de680746a586eac1f2d9bc10ab          |
| interface    | internal                                  |
| region       | RegionOne                                 |
| region_id    | RegionOne                                 |
| service_id   | 060d59eac51b4594815603d75a00aba2          |
| 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           | 38f7af91666a47cfb97b4dc790b94424          |
| interface    | admin                                     |
| region       | RegionOne                                 |
| region_id    | RegionOne                                 |
| service_id   | 060d59eac51b4594815603d75a00aba2          |
| service_name | nova                                      |
| service_type | compute                                   |
| url          | http://controller:8774/v2.1               |
+--------------+-------------------------------------------+

安装 Placement 服务并配置用户和端点:
安装软件包:
$sudo apt install nova-api nova-conductor nova-novncproxy nova-scheduler
编辑/etc/nova/nova.conf文件:
在[api_database]和[database]部分,配置数据库访问:
[api_database]
# ...
connection = mysql+pymysql://nova:000000@controller/nova_api

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

[DEFAULT]部分,配置RabbitMQ消息队列访问:
[DEFAULT]
# ...
transport_url = rabbit://openstack:000000@controller:5672/



在[api]和[keystone_authtoken]部分,配置身份服务访问:
[api]
# ...
auth_strategy = keystone

[keystone_authtoken]
# ...
www_authenticate_uri = http://controller:5000/
auth_url = http://controller:5000/
memcached_servers = controller:11211
auth_type = password
project_domain_name = Default
user_domain_name = Default
project_name = service
username = nova
password = 000000

[DEFAULT]部字段中,配置my_ip选项以使用控制器节点的管理接口 IP 地址:
[DEFAULT]
# ...
my_ip = 192.168.100.10

配置/etc/nova/nova.conf的
[vnc]部分中,将 VNC 代理配置为使用控制器节点的管理接口 IP 地址:

[vnc]
enabled = true
# ...
server_listen = $my_ip
server_proxyclient_address = $my_ip
在该[glance]部分中,配置 Image 服务 API 的位置:

[glance]
# ...
api_servers = http://controller:9292
在该[oslo_concurrency]部分中,配置锁定路径:

[oslo_concurrency]
# ...
lock_path = /var/lib/nova/tmp
由于打包错误,请log_dir从该[DEFAULT]部分中删除该选项 。

在[placement]部分中,配置对 Placement 服务的访问:
[placement]
# ...
region_name = RegionOne
project_domain_name = Default
project_name = service
auth_type = password
user_domain_name = Default
auth_url = http://controller:5000/v3
username = placement
password = 000000
填充nova-api数据库:
$sudo su -s /bin/sh -c "nova-manage api_db sync" nova

注册cell0数据库:
$sudo su -s /bin/sh -c "nova-manage cell_v2 map_cell0" nova

创建cell1单元格:
$sudo su -s /bin/sh -c "nova-manage cell_v2 create_cell --name=cell1 --verbose" nova

填充 nova 数据库:
$sudo su -s /bin/sh -c "nova-manage db sync" nova

验证 nova cell0 和 cell1 是否正确注册:
$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?charset=utf8 |  False   |
| cell1 | f690f4fd-2bc5-4f15-8145-db561a7b9d3d | rabbit://openstack:****@controller:5672/nova_cell1 | mysql+pymysql://nova:****@controller/nova_cell1?charset=utf8 |  False   |
+-------+--------------------------------------+----------------------------------------------------+--------------------------------------------------------------+----------+


重新启动计算服务:
$ service nova-api restart
$ service nova-scheduler restart
$ service nova-conductor restart
$ service nova-novncproxy restart

compute节点完成Nova服务搭建

$sudo apt install nova-compute

编辑/etc/nova/nova.conf文件并完成以下操作:
在该[DEFAULT]部分,配置RabbitMQ消息队列访问:
[DEFAULT]
# ...
transport_url = rabbit://openstack:000000@controller

在[api]和[keystone_authtoken]部分,配置身份服务访问:
[api]
# ...
auth_strategy = keystone

[keystone_authtoken]
# ...
www_authenticate_uri = http://controller:5000/
auth_url = http://controller:5000/
memcached_servers = controller:11211
auth_type = password
project_domain_name = Default
user_domain_name = Default
project_name = service
username = nova
password = 000000

在该[DEFAULT]部分中,配置my_ip选项:
[DEFAULT]
# ...
my_ip = MANAGEMENT_INTERFACE_IP_ADDRESS(192.168.100.20)


配置/etc/nova/nova.conf的[neutron]部分。 
在[vnc]部分中,启用和配置远程控制台访问:

[vnc]
# ...
enabled = true
server_listen = 0.0.0.0
server_proxyclient_address = $my_ip
novncproxy_base_url = http://controller:6080/vnc_auto.html


在该[glance]部分中,配置 Image 服务 API 的位置:
[glance]
# ...
api_servers = http://controller:9292

在该[oslo_concurrency]部分中,配置锁定路径:
[oslo_concurrency]
# ...
lock_path = /var/lib/nova/tmp

在[placement]部分中,配置 Placement API:
[placement]
# ...
region_name = RegionOne
project_domain_name = Default
project_name = service
auth_type = password
user_domain_name = Default
auth_url = http://controller:5000/v3
username = placement
password = 000000


确定计算节点是否支持虚拟机的硬件加速:
$ egrep -c '(vmx|svm)' /proc/cpuinfo
如果此命令返回值,则您的计算节点支持硬件加速,这通常不需要额外配置。one or greater
如果此命令返回值zero,则您的计算节点不支持硬件加速,您必须配置libvirt为使用 QEMU 而不是 KVM。
编辑文件中的[libvirt]部分,/etc/nova/nova-compute.conf如下所示:
[libvirt]
# ...
virt_type = qemu

重启计算服务:
$ service nova-compute restart
 	

将计算节点添加到cell数据库中

在控制器节点上执行发现计算节点资源操作
$ . admin-openrc

$ openstack compute service list --service nova-compute
+----+-------+--------------+------+-------+---------+----------------------------+
| ID | Host  | Binary       | Zone | State | Status  | Updated At                 |
+----+-------+--------------+------+-------+---------+----------------------------+
| 1  | node1 | nova-compute | nova | up    | enabled | 2017-04-14T15:30:44.000000 |
+----+-------+--------------+------+-------+---------+----------------------------+

发现计算主机:
$sudo su -s /bin/sh -c "nova-manage cell_v2 discover_hosts --verbose" nova
Found 2 cell mappings.
Skipping cell0 since it does not contain hosts.
Getting compute nodes from cell 'cell1': ad5a5985-a719-4567-98d8-8d148aaae4bc
Found 1 computes in cell: ad5a5985-a719-4567-98d8-8d148aaae4bc
Checking host mapping for compute host 'compute': fe58ddc1-1d65-4f87-9456-bc040dc106b3
Creating host mapping for compute host 'compute': fe58ddc1-1d65-4f87-9456-bc040dc106b3

添加新计算节点时,您必须在控制器节点上运行以注册这些新计算节点。或者,可以在/etc/nova/nova.conf中设置适当的间隔 :
[scheduler]
discover_hosts_in_cells_interval = 300

验证操作:
在控制器节点上执行。
$ . admin-openrc
列出服务组件以验证每个进程的成功启动和注册:
$ openstack compute service list
+----+--------------------+------------+----------+---------+-------+----------------------------+
| Id | Binary             | Host       | Zone     | Status  | State | Updated At                 |
+----+--------------------+------------+----------+---------+-------+----------------------------+
|  1 | nova-scheduler     | controller | internal | enabled | up    | 2016-02-09T23:11:15.000000 |
|  2 | nova-conductor     | controller | internal | enabled | up    | 2016-02-09T23:11:16.000000 |
|  3 | nova-compute       | compute1   | nova     | enabled | up    | 2016-02-09T23:11:20.000000 |
+----+--------------------+------------+----------+---------+-------+----------------------------+

七、Neutron网络服务

controller节点完成neutron服务搭建

$sudo mysql -u root –p000000

创建neutron数据库:
MariaDB [(none)] CREATE DATABASE neutron;

授予对neutron数据库的访问权限,
MariaDB [(none)]> GRANT ALL PRIVILEGES ON neutron.* TO 'neutron'@'localhost' \
  IDENTIFIED BY '000000';
MariaDB [(none)]> GRANT ALL PRIVILEGES ON neutron.* TO 'neutron'@'%' \
  IDENTIFIED BY '000000';


$ . admin-openrc
要创建服务凭证
创建neutron用户:
$ openstack user create --domain default --password-prompt neutron
User Password:
Repeat User Password:
+---------------------+----------------------------------+
| Field               | Value                            |
+---------------------+----------------------------------+
| domain_id           | default                          |
| enabled             | True                             |
| id                  | fdb0f541e28141719b6a43c8944bf1fb |
| name                | neutron                          |
| options             | {}                               |
| password_expires_at | None                             |
+---------------------+----------------------------------+

admin为neutron用户添加角色:
$ openstack role add --project service --user neutron admin

创建neutron服务实体:
$ openstack service create --name neutron \
  --description "OpenStack Networking" network
+-------------+----------------------------------+
| Field       | Value                            |
+-------------+----------------------------------+
| description | OpenStack Networking             |
| enabled     | True                             |
| id          | f71529314dab4a4d8eca427e701d209e |
| name        | neutron                          |
| type        | network                          |
+-------------+----------------------------------+

创建网络服务 API 端点:
$ openstack endpoint create --region RegionOne \
  network public http://controller:9696
+--------------+----------------------------------+
| Field        | Value                            |
+--------------+----------------------------------+
| enabled      | True                             |
| id           | 85d80a6d02fc4b7683f611d7fc1493a3 |
| interface    | public                           |
| region       | RegionOne                        |
| region_id    | RegionOne                        |
| service_id   | f71529314dab4a4d8eca427e701d209e |
| 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           | 09753b537ac74422a68d2d791cf3714f |
| interface    | internal                         |
| region       | RegionOne                        |
| region_id    | RegionOne                        |
| service_id   | f71529314dab4a4d8eca427e701d209e |
| 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           | 1ee14289c9374dffb5db92a5c112fc4e |
| interface    | admin                            |
| region       | RegionOne                        |
| region_id    | RegionOne                        |
| service_id   | f71529314dab4a4d8eca427e701d209e |
| service_name | neutron                          |
| service_type | network                          |
| url          | http://controller:9696           |
+--------------+----------------------------------+


安装组件
$sudo apt install neutron-server neutron-plugin-ml2 \
  neutron-linuxbridge-agent neutron-l3-agent neutron-dhcp-agent \
  neutron-metadata-agent

配置服务器组件
编辑/etc/neutron/neutron.conf文件:
在该[database]部分中,配置数据库访问:
[database]
# ...
connection = mysql+pymysql://neutron:000000@controller/neutron

在[DEFAULT]部分中,启用模块化第 2 层 (ML2) 插件、路由器服务和重叠 IP 地址:
[DEFAULT]
# ...
core_plugin = ml2
service_plugins = router
allow_overlapping_ips = true

在该[DEFAULT]部分,配置RabbitMQ 消息队列访问:
[DEFAULT]
# ...
transport_url = rabbit://openstack:000000@controller

在[DEFAULT]和[keystone_authtoken]部分,配置身份服务访问:
[DEFAULT]
# ...
auth_strategy = keystone

[keystone_authtoken]
# ...
www_authenticate_uri = http://controller:5000
auth_url = http://controller:5000
memcached_servers = controller:11211
auth_type = password
project_domain_name = default
user_domain_name = default
project_name = service
username = neutron
password = 000000

在[DEFAULT]和[nova]部分中,配置 Networking 以通知 Compute 网络拓扑更改:
[DEFAULT]
# ...
notify_nova_on_port_status_changes = true
notify_nova_on_port_data_changes = true

[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 = 000000

在该[oslo_concurrency]部分中,配置锁定路径:
[oslo_concurrency]
# ...
lock_path = /var/lib/neutron/tmp

配置模块化第 2 层 (ML2) 插件
ML2 插件使用 Linux 桥接机制为实例构建第 2 层(桥接和交换)虚拟网络基础设施。
编辑/etc/neutron/plugins/ml2/ml2_conf.ini文件:
在[ml2]部分中,启用平面、VLAN 和 VXLAN 网络:
[ml2]
# ...
type_drivers = flat,vlan,vxlan

在该[ml2]部分中,启用 VXLAN 自助网络:
[ml2]
# ...
tenant_network_types = vxlan

在[ml2]部分中,启用 Linux 桥接和二层填充机制:
[ml2]
# ...
mechanism_drivers = linuxbridge,l2population

配置 ML2 插件后,删除type_drivers选项中的值 可能会导致数据库不一致。
Linux 网桥代理仅支持 VXLAN 覆盖网络。

在[ml2]部分中,启用端口安全扩展驱动程序:
[ml2]
# ...
extension_drivers = port_security

在[ml2_type_flat]部分中,将提供者虚拟网络配置为平面网络:
[ml2_type_flat]
# ...
flat_networks = provider

在该[ml2_type_vxlan]部分中,配置自助网络的 VXLAN 网络标识符范围:
[ml2_type_vxlan]
# ...
vni_ranges = 1:1000

在该[securitygroup]部分中,启用ipset以提高安全组规则的效率:
[securitygroup]
# ...
enable_ipset = true

配置 Linux 网桥代理
Linux 桥接代理为实例构建第 2 层(桥接和交换)虚拟网络基础架构并处理安全组。
编辑/etc/neutron/plugins/ml2/linuxbridge_agent.ini文件:
在[linux_bridge]部分中,
[linux_bridge]
physical_interface_mappings = provider:PROVIDER_INTERFACE_NAME(ens34)

替换PROVIDER_INTERFACE_NAME为底层提供者物理网络接口的名称。

在该[vxlan]部分中,启用VXLAN覆盖网络,配置处理覆盖网络的物理网络接口的IP地址,并启用第2层填充:
[vxlan]
enable_vxlan = true
local_ip = OVERLAY_INTERFACE_IP_ADDRESS(192.168.100.10)
l2_population = true

替换OVERLAY_INTERFACE_IP_ADDRESS为处理覆盖网络的底层物理网络接口的 IP 地址。示例架构使用管理接口将流量隧道传输到其他节点。因此,替换OVERLAY_INTERFACE_IP_ADDRESS为控制器节点的管理 IP 地址。

在该[securitygroup]部分中,启用安全组并配置 Linux 网桥 iptables 防火墙驱动程序:
[securitygroup]
# ...
enable_security_group = true
firewall_driver = neutron.agent.linux.iptables_firewall.IptablesFirewallDriver


通过验证以下所有sysctl值都设置为,确保您的 Linux 操作系统内核支持网桥过滤器:
net.bridge.bridge-nf-call-iptables
net.bridge.bridge-nf-call-ip6tables
要启用网络桥接支持,通常br_netfilter需要加载内核模块。


配置三层代理
第 3 层 (L3) 代理为自助服务虚拟网络提供路由和 NAT 服务。
编辑/etc/neutron/l3_agent.ini文件:
在该[DEFAULT]部分中,配置 Linux 桥接接口驱动程序:
[DEFAULT]
# ...
interface_driver = linuxbridge

配置 DHCP 代理
DHCP 代理为虚拟网络提供 DHCP 服务。
编辑/etc/neutron/dhcp_agent.ini文件:
在该[DEFAULT]部分中,配置 Linux 桥接接口驱动程序、Dnsmasq DHCP 驱动程序,并启用隔离元数据,以便提供商网络上的实例可以通过网络访问元数据:
[DEFAULT]
# ...
interface_driver = linuxbridge
dhcp_driver = neutron.agent.linux.dhcp.Dnsmasq
enable_isolated_metadata = true

配置元数据代理
编辑/etc/neutron/metadata_agent.ini文件并完成以下操作:
在该[DEFAULT]部分中,配置元数据主机和共享密钥:
[DEFAULT]
# ...
nova_metadata_host = controller
metadata_proxy_shared_secret = 000000


配置 Compute 服务以使用 Networking 服务
编辑/etc/nova/nova.conf文件:
在该[neutron]部分中,配置访问参数,启用元数据代理,并配置密钥:
[neutron]
# ...
auth_url = http://controller:5000
auth_type = password
project_domain_name = default
user_domain_name = default
region_name = RegionOne
project_name = service
username = neutron
password = 000000
service_metadata_proxy = true
metadata_proxy_shared_secret = 000000
替换METADATA_SECRET为您为元数据代理选择的机密。


填充数据库:
$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


重启计算 API 服务:
$service nova-api restart

重新启动网络服务。
$ service neutron-server restart
$ service neutron-linuxbridge-agent restart
$ service neutron-dhcp-agent restart
$ service neutron-metadata-agent restart

对于网络选项 2,还要重新启动第 3 层服务:
$ service neutron-l3-agent restart

compute节点搭建Neutron服务

$sudo apt install neutron-linuxbridge-agent


编辑/etc/neutron/neutron.conf文件:
在该[database]部分中,注释掉所有connection选项,因为计算节点不直接访问数据库。
在该[DEFAULT]部分,配置RabbitMQ 消息队列访问:
[DEFAULT]
# ...
transport_url = rabbit://openstack:000000@controller

在[DEFAULT]和[keystone_authtoken]部分,配置身份服务访问:
[DEFAULT]
# ...
auth_strategy = keystone

[keystone_authtoken]
# ...
www_authenticate_uri = http://controller:5000
auth_url = http://controller:5000
memcached_servers = controller:11211
auth_type = password
project_domain_name = default
user_domain_name = default
project_name = service
username = neutron
password = 000000

注释掉或删除该[keystone_authtoken]部分中的任何其他选项 。

在该[oslo_concurrency]部分中,配置锁定路径:
[oslo_concurrency]
# ...
lock_path = /var/lib/neutron/tmp


配置 Linux 网桥代理
Linux 桥接代理为实例构建第 2 层(桥接和交换)虚拟网络基础架构并处理安全组。
编辑/etc/neutron/plugins/ml2/linuxbridge_agent.ini文件:
在该[linux_bridge]部分中,将提供者虚拟网络映射到提供者物理网络接口:
[linux_bridge]
physical_interface_mappings = provider:PROVIDER_INTERFACE_NAME(ens34)
替换PROVIDER_INTERFACE_NAME为底层提供者物理网络接口的名称。

在该[vxlan]部分中,启用VXLAN覆盖网络,配置处理覆盖网络的物理网络接口的IP地址,并启用第2层填充:
[vxlan]
enable_vxlan = true
local_ip = OVERLAY_INTERFACE_IP_ADDRESS(192.168.100.20)
l2_population = true
替换OVERLAY_INTERFACE_IP_ADDRESS为处理覆盖网络的底层物理网络接口的 IP 地址。
示例架构使用管理接口将流量隧道传输到其他节点。因此,替换OVERLAY_INTERFACE_IP_ADDRESS为计算节点的管理IP地址。

在该[securitygroup]部分中,启用安全组并配置 Linux 网桥 iptables 防火墙驱动程序:
[securitygroup]
# ...
enable_security_group = true
firewall_driver = neutron.agent.linux.iptables_firewall.IptablesFirewallDriver


通过验证以下所有sysctl值都设置为,确保您的 Linux 操作系统内核支持网桥过滤器:
net.bridge.bridge-nf-call-iptables
net.bridge.bridge-nf-call-ip6tables
要启用网络桥接支持,通常br_netfilter需要加载内核模块。


配置 Compute 服务以使用 Networking 服务
编辑/etc/nova/nova.conf文件并完成以下操作:
在该[neutron]部分,配置访问参数:
[neutron]
# ...
auth_url = http://controller:5000
auth_type = password
project_domain_name = default
user_domain_name = default
region_name = RegionOne
project_name = service
username = neutron
password = 000000


重启计算服务:
$ service nova-compute restart

重启 Linux 网桥代理:
$ service neutron-linuxbridge-agent restart

八、Dashboard搭建

$sudo apt install openstack-dashboard

编辑 /etc/openstack-dashboard/local_settings.py 文件:
配置仪表板以在controller节点上使用 OpenStack 服务 :
OPENSTACK_HOST = "controller"

在仪表板配置部分,允许您的主机访问仪表板:
ALLOWED_HOSTS = ['*']
ALLOWED_HOSTS也可以['*']接受所有主机。这可能对开发工作有用,但可能不安全,不应在生产中使用。

配置memcached会话存储服务:
SESSION_ENGINE = 'django.contrib.sessions.backends.cache'

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

启用身份 API 版本 3:
OPENSTACK_KEYSTONE_URL = "http://%s/identity/v3" % OPENSTACK_HOST

启用对域的支持:
OPENSTACK_KEYSTONE_MULTIDOMAIN_SUPPORT = True

配置 API 版本:
OPENSTACK_API_VERSIONS = {
    "identity": 3,
    "image": 2,
    "volume": 3,
}

配置Default为您通过仪表板创建的用户的默认域:
OPENSTACK_KEYSTONE_DEFAULT_DOMAIN = "Default"

配置user为您通过仪表板创建的用户的默认角色:
OPENSTACK_KEYSTONE_DEFAULT_ROLE = "user"

(可选)配置时区:
TIME_ZONE = "TIME_ZONE"
替换TIME_ZONE为适当的时区标识符。



/etc/apache2/conf-available/openstack-dashboard.conf如果不包括,则添加以下行 。
WSGIApplicationGroup %{GLOBAL}


重新加载 Web 服务器配置:
$ systemctl reload apache2.service

九、访问Dashboard并实例发放

Ubuntu20.04 搭建W版本OpenStack平台_第1张图片

创建网络

Ubuntu20.04 搭建W版本OpenStack平台_第2张图片

Ubuntu20.04 搭建W版本OpenStack平台_第3张图片

创建云主机类型

Ubuntu20.04 搭建W版本OpenStack平台_第4张图片

创建实例

Ubuntu20.04 搭建W版本OpenStack平台_第5张图片

Ubuntu20.04 搭建W版本OpenStack平台_第6张图片

 点击Launch Instance

Ubuntu20.04 搭建W版本OpenStack平台_第7张图片

云服务器发放成功

Ubuntu20.04 搭建W版本OpenStack平台_第8张图片 Ubuntu20.04 搭建W版本OpenStack平台_第9张图片

运维就像是绿叶,没有绿叶的衬托,花儿始终是残缺的美!

没有Error就是最好的消息。

你可能感兴趣的:(openstack,ubuntu,云计算)