OpenStack Train版

目录

一、安装基础环境&服务

1.1系统配置

1.2 ntp时间同步

1.3 关闭防火墙 selinux

1.4 安装train版yum源

2.安装客户端【controller节点】

3.安装数据库【controller节点】

4.安装消息队列服务【controller节点】

5.安装memcache【controller节点】

6.安装etcd【controller节点】

二、OpenStack Train版-2.安装keystone身份认证服务

1. 创建keystone数据库并授权

2. 安装keystone软件包

3. 修改配置文件

4. 填充数据库

5. 修改apache配置

 6. 初始化环境变量

 7. 创建服务所使用的项目、创建user角色、查看

三、OpenStack Train版-3.安装glance镜像服务

1. 创建数据库并授权

2. 创建glance用户 并授权

3. 创建glance服务实体、创建镜像服务API访问端点

5. 安装glance软件包

6. 编辑glance的配置文件

7. 填充glance数据库

8. 启动glance服务并设置开机自启

9.下载cirros镜像,验证glance的安装

四、OpenStack Train版-4.安装placement放置服务

1. 创建数据库授予数据库权限

2. 创建placement用户

3. 创建placement服务实体、创建placement服务访问端点

4. 安装placement软件包

5. 修改配置文件

6.填充placement数据库

7. 重启apache服务

8. 检查健康状态

五、OpenStack Train版-5.安装nova计算服务(控制节点)

1. 创建数据库并授权

2. 创建nova用户  向nova用户添加admin角色

4. 创建nova服务实体  创建Compute API服务端点

6. 安装软件包

7. 修改配置文件

8. 填充nova-api数据库

9. 数据库填充好之后,验证nova cell0和cell1是否正确注册:

10. 启动计算服务nova并将其配置为开机自启

六、OpenStack Train版-6.安装nova计算服务(计算节点)

1. 安装软件包

2. 修改计算节点的nova配置文件

3. 确定计算节点是否支持虚拟机硬件加速

4. 启动Compute服务及其相关服务,并设置开机自启

5. controller节点测试

6. 发现计算节点主机

7. 设置适当的发现时间间隔(可选)

8. 验证整个计算服务nova

七、OpenStack Train版-8.安装neutron网络服务(控制节点)

7. 修改 neutron 配置文件

(1)neutron server的配置文件neutron.conf

(2)ML2 plugin的配置文件ml2_conf.ini

8. 修改内核参数

9. dhcp agent配置文件dhcp_agent.ini

10. 配置元数据代理,以便和nova通讯

11. 修改nova的配置文件,也是为了和neutron进行交互

12. 初始数据库

13. 重新启动nova-api服务

14. 启动neutron服务和配置开机启动

八、OpenStack Train版-9.安装neutron网络服务(计算节点)

1. 安装组件

2. 修改配置文件

(1)修改neutron主配置文件

(2)配置Linux网桥代理

(3)sysctl.conf

3. 修改nova配置文件{compute01}

4. 重启nova计算服务

5. 启动neutron服务和设置开机自启动

6. 在控制节点(controller)执行以下命令验证neutron服务

九、OpenStack Train版-10.安装horizon服务(计算节点)

1、语言环境

2、可访问的keystone endpoint

3. 安装

4. 编辑配置文件/etc/openstack-dashboard/local_settings

5. 重建apache的dashboard配置文件

6. 备用机制

7. 重新启动计算节点(compute01)上apache服务

十、OpenStack Train版-11.启动实例(控制节点)

1、检查各个节点间的网络通讯ping

2、删除NetworkManager软件包    在控制节点和计算节点都执行

3. controller节点创建网络

4. controller节点创建子网

5. 控制节点创建硬件配置方案

6. 检查网络配置


一、安装基础环境&服务

1.1系统配置

系统开启内核虚拟化
https://jingyan.baidu.com/article/ab0b56305f2882c15afa7dda.html
https://jingyan.baidu.com/article/7c6fb42847fc1dc1652c905f.html

Centos7更改网卡名称eth0

https://jingyan.baidu.com/article/17bd8e524c76a285ab2bb8ff.html

关闭ipv6

https://www.cnblogs.com/mrway/p/10751819.html
echo "net.ipv6.conf.all.disable_ipv6=1" >>/etc/sysctl.conf
sysctl -p

系统地址解析
vim /etc/hosts
192.168.213.50  controller
192.168.231.51  compute1
系统更换阿里云源

1.2 ntp时间同步

yum install chrony -y

主节点配置

vim /etc/chrony.conf 
server ntp.aliyun.com iburst

allow 192.168.231.0/24

从节点
vim /etc/chrony.conf 
server 192.168.231.50 iburst

systemctl restart chronyd.service 
systemctl enable chronyd.service 

1.3 关闭防火墙 selinux


systemctl disable firewalld
systemctl stop firewalld
setenforce 0
sed -i '/^SELINUX=/ s/enforcing/disabled/'  /etc/selinux/config
编辑/etc/selinux/config 文件,将SELinux的默认值enforcing 改为 disabled,下次开机就不会再启动
注意:此时也不可以用setenforce 1 命令临时打开

1.4 安装train版yum源

yum install centos-release-openstack-train -y

2.安装客户端【controller节点】

yum install python-openstackclient -y

3.安装数据库【controller节点】

yum install mariadb mariadb-server python2-PyMySQL
cat > /etc/my.cnf.d/openstack.cnf << EOF
[mysqld]
bind-address = 192.168.231.50
 
default-storage-engine = innodb     #默认存储引擎
innodb_file_per_table = on          #每张表独立表空间文件
max_connections = 4096              #最大连接数
collation-server = utf8_general_ci   #默认字符集
character-set-server = utf8
EOF
systemctl enable mariadb.service
systemctl start mariadb.service
mysql_secure_installation
回车--->n--->一路y

4.安装消息队列服务【controller节点】

yum install rabbitmq-server -y
 
systemctl enable rabbitmq-server.service
systemctl start rabbitmq-server.service

rabbitmq-plugins enable rabbitmq_management

创建用户

rabbitmqctl add_user openstack RABBIT_PASS
rabbitmqctl set_permissions openstack ".*" ".*" ".*"

安装好之后,使用netstat -tnlup 查看   25672、15672和5672端口      访问web   15672   guest  guest

5.安装memcache【controller节点】

yum install memcached python-memcached -y

sed -i '/OPTIONS/c\OPTIONS="-l 0.0.0.0"' /etc/sysconfig/memcached
 
systemctl enable memcached.service
systemctl start memcached.service

安装和启动好之后,同样使用netstat -tnlup查看端口情况,看到11211端口有程序在侦听则表示memcache安装成功

6.安装etcd【controller节点】

yum install etcd -y

cp -a /etc/etcd/etcd.conf{,.bak}
cat > /etc/etcd/etcd.conf <<EOF 
#[Member]
ETCD_DATA_DIR="/var/lib/etcd/default.etcd"
ETCD_LISTEN_PEER_URLS="http://192.168.231.50:2380"
ETCD_LISTEN_CLIENT_URLS="http://192.168.231.50:2379"
ETCD_NAME="controller"
#[Clustering]
ETCD_INITIAL_ADVERTISE_PEER_URLS="http://192.168.231.50:2380"
ETCD_ADVERTISE_CLIENT_URLS="http://192.168.231.50:2379"
ETCD_INITIAL_CLUSTER="controller=http://192.168.231.50:2380"
ETCD_INITIAL_CLUSTER_TOKEN="etcd-cluster-01"
ETCD_INITIAL_CLUSTER_STATE="new"
EOF

systemctl enable etcd
systemctl start etcd

二、OpenStack Train版-2.安装keystone身份认证服务

1. 创建keystone数据库并授权

mysql
CREATE DATABASE keystone;
GRANT ALL PRIVILEGES ON keystone.* TO 'keystone'@'localhost' IDENTIFIED BY 'KEYSTONE_DBPASS';
GRANT ALL PRIVILEGES ON keystone.* TO 'keystone'@'%' IDENTIFIED BY 'KEYSTONE_DBPASS';
exit;

2. 安装keystone软件包


yum install openstack-keystone httpd mod_wsgi openstack-utils -y

3. 修改配置文件

cp -a /etc/keystone/keystone.conf{,.bak}
grep -Ev "^$|#" /etc/keystone/keystone.conf.bak > /etc/keystone/keystone.conf

openstack-config --set /etc/keystone/keystone.conf database connection  mysql+pymysql://keystone:KEYSTONE_DBPASS@controller/keystone
openstack-config --set /etc/keystone/keystone.conf token provider  fernet


4. 填充数据库

su -s /bin/sh -c "keystone-manage db_sync" keystone

初始化Fernet密钥存储库
这是新版本的OpenStack的新功能,在Train版本下,keystone不再使用简单的字符串作为临时token,而是使用下面创建的fernet的用户来运行keystone。

同时,keystone也不再对管理员用户和普通用户的服务端点区分使用不同的端口5000和35357,而是只使用5000端口不再使用35357端口。

keystone-manage fernet_setup --keystone-user keystone --keystone-group keystone
keystone-manage credential_setup --keystone-user keystone --keystone-group keystone
keystone-manage bootstrap --bootstrap-password ADMIN_PASS \
    --bootstrap-admin-url http://controller:5000/v3/ \
    --bootstrap-internal-url http://controller:5000/v3/ \
    --bootstrap-public-url http://controller:5000/v3/ \
    --bootstrap-region-id RegionOne

5. 修改apache配置

echo "ServerName controller" >> /etc/httpd/conf/httpd.conf
ln -s /usr/share/keystone/wsgi-keystone.conf /etc/httpd/conf.d/


启动和开机自启动apache
systemctl enable httpd.service
systemctl start httpd.service

 6. 初始化环境变量

cat >> ~/.bashrc << EOF
export OS_USERNAME=admin
export OS_PASSWORD=ADMIN_PASS
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
EOF
 
source ~/.bashrc 
测试
openstack token issue

 7. 创建服务所使用的项目、创建user角色、查看

openstack project create --domain default --description "Service Project" service
openstack role create user
openstack role list

三、OpenStack Train版-3.安装glance镜像服务

1. 创建数据库并授权

mysql
CREATE DATABASE glance;
GRANT ALL PRIVILEGES ON glance.* TO 'glance'@'localhost' IDENTIFIED BY 'GLANCE_DBPASS';
GRANT ALL PRIVILEGES ON glance.* TO 'glance'@'%' IDENTIFIED BY 'GLANCE_DBPASS';

2. 创建glance用户 并授权

openstack user create --domain default --password GLANCE_PASS glance
openstack role add --project service --user glance admin

3. 创建glance服务实体、创建镜像服务API访问端点

openstack service create --name glance --description "OpenStack Image" image
openstack endpoint create --region RegionOne image public http://controller:9292
openstack endpoint create --region RegionOne image internal http://controller:9292
openstack endpoint create --region RegionOne image admin http://controller:9292

5. 安装glance软件包

yum install openstack-glance -y

6. 编辑glance的配置文件

cp -a /etc/glance/glance-api.conf{,.bak}
cp -a /etc/glance/glance-registry.conf{,.bak}
grep -Ev '^$|#' /etc/glance/glance-api.conf.bak > /etc/glance/glance-api.conf
grep -Ev '^$|#' /etc/glance/glance-registry.conf.bak > /etc/glance/glance-registry.conf

openstack-config --set /etc/glance/glance-api.conf database connection  mysql+pymysql://glance:GLANCE_DBPASS@controller/glance
openstack-config --set /etc/glance/glance-api.conf keystone_authtoken www_authenticate_uri   http://controller:5000
openstack-config --set /etc/glance/glance-api.conf keystone_authtoken auth_url  http://controller:5000
openstack-config --set /etc/glance/glance-api.conf keystone_authtoken memcached_servers  controller:11211
openstack-config --set /etc/glance/glance-api.conf keystone_authtoken auth_type  password
openstack-config --set /etc/glance/glance-api.conf keystone_authtoken project_domain_name  Default
openstack-config --set /etc/glance/glance-api.conf keystone_authtoken user_domain_name  Default
openstack-config --set /etc/glance/glance-api.conf keystone_authtoken project_name  service
openstack-config --set /etc/glance/glance-api.conf keystone_authtoken username  glance
openstack-config --set /etc/glance/glance-api.conf keystone_authtoken password  GLANCE_PASS
openstack-config --set /etc/glance/glance-api.conf paste_deploy flavor  keystone
openstack-config --set /etc/glance/glance-api.conf glance_store stores  file,http
openstack-config --set /etc/glance/glance-api.conf glance_store default_store  file
openstack-config --set /etc/glance/glance-api.conf glance_store filesystem_store_datadir  /var/lib/glance/images/

7. 填充glance数据库

su -s /bin/sh -c "glance-manage db_sync" glance


8. 启动glance服务并设置开机自启

systemctl enable openstack-glance-api.service
systemctl start openstack-glance-api.service


 
启动好之后,查看端口情况,如果有9292端口,则表示glance启动成功。
[root@controller ~]# lsof -i:9292
COMMAND    PID   USER   FD   TYPE DEVICE SIZE/OFF NODE NAME
glance-ap 9333 glance    4u  IPv4  48361      0t0  TCP *:armtechdaemon (LISTEN)
glance-ap 9913 glance    4u  IPv4  48361      0t0  TCP *:armtechdaemon (LISTEN)
 

9.下载cirros镜像,验证glance的安装
 

wget http://download.cirros-cloud.net/0.4.0/cirros-0.4.0-x86_64-disk.img
openstack image create --file /root/cirros-0.4.0-x86_64-disk.img --disk-format qcow2 --container-format bare --public cirros
glance image-list

查看镜像的物理文件
[root@controller ~]# ll /var/lib/glance/images/
total 12420
-rw-r----- 1 glance glance 12716032 Jan  9 22:30 060d49e3-5346-4bbd-ba42-7247f2daead5

四、OpenStack Train版-4.安装placement放置服务

1. 创建数据库授予数据库权限

mysql
CREATE DATABASE placement;
GRANT ALL PRIVILEGES ON placement.* TO 'placement'@'localhost' IDENTIFIED BY 'PLACEMENT_DBPASS';
GRANT ALL PRIVILEGES ON placement.* TO 'placement'@'%' IDENTIFIED BY 'PLACEMENT_DBPASS';
exit

2. 创建placement用户

openstack user create --domain default --password PLACEMENT_PASS placement
openstack role add --project service --user placement admin


3. 创建placement服务实体、创建placement服务访问端点

openstack service create --name placement --description "Placement API" placement
openstack endpoint create --region RegionOne placement public http://controller:8778
openstack endpoint create --region RegionOne placement internal http://controller:8778
openstack endpoint create --region RegionOne placement admin http://controller:8778


4. 安装placement软件包

yum install openstack-placement-api -y

5. 修改配置文件


cp /etc/placement/placement.conf /etc/placement/placement.conf.bak
grep -Ev '^$|#' /etc/placement/placement.conf.bak > /etc/placement/placement.conf
openstack-config --set  /etc/placement/placement.conf placement_database connection mysql+pymysql://placement:PLACEMENT_DBPASS@controller/placement

vim /etc/placement/placement.conf
[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 = PLACEMENT_PASS


6.填充placement数据库

su -s /bin/sh -c "placement-manage db sync" placement


 
修改placement的apache配置文件(官方文档坑点之一,这个步骤官方文档没有提到,如果不做,后面计算服务检查时将会报错)


vim /etc/httpd/conf.d/00-placement-api.conf
.....
  <Directory /usr/bin>
   <IfVersion >= 2.4>
     Require all granted
  </IfVersion>
  <IfVersion < 2.4>
     Order allow,deny
     Allow from all
  </IfVersion>
 </Directory>
.....


7. 重启apache服务

systemctl restart httpd


 
检查服务是否启动成功,使用netstat -tnlup查看端口情况,如果存在8778的端口,表示placement服务启动成功。
[root@controller ~]# lsof -i:8778
COMMAND   PID   USER   FD   TYPE DEVICE SIZE/OFF NODE NAME
httpd   11116   root    6u  IPv6  53596      0t0  TCP *:8778 (LISTEN)
httpd   11125 apache    6u  IPv6  53596      0t0  TCP *:8778 (LISTEN)
httpd   11126 apache    6u  IPv6  53596      0t0  TCP *:8778 (LISTEN)
httpd   11127 apache    6u  IPv6  53596      0t0  TCP *:8778 (LISTEN)
httpd   11128 apache    6u  IPv6  53596      0t0  TCP *:8778 (LISTEN)
httpd   11129 apache    6u  IPv6  53596      0t0  TCP *:8778 (LISTEN)
 
进一步检查,使用命令:curl http://controller:8778,直接访问placement的API地址,看是否能返回json。
[root@controller ~]# curl http://controller:8778
{"versions": [{"status": "CURRENT", "min_version": "1.0", "max_version": "1.36", "id": "v1.0", "links": [{"href": "", "rel": "self"}]}]}

8. 检查健康状态

placement-status upgrade check

五、OpenStack Train版-5.安装nova计算服务(控制节点)

计算服务nova较之前的服务稍显复杂(但没有网络服务neutron复杂),它需要在控制节点和计算节点都安装
控制节点主要安装nova-api(nova主服务)、nova-scheduler(nova调度服务)、nova-conductor(nova数据库服务,提供数据库访问)、nova-novncproxy(nova的vnc服务,提供实例的控制台)等服务;


1. 创建数据库并授权

mysql
CREATE DATABASE nova_api;
CREATE DATABASE nova;
CREATE DATABASE nova_cell0;
GRANT ALL PRIVILEGES ON nova_api.* TO 'nova'@'localhost' IDENTIFIED BY 'NOVA_DBPASS';
GRANT ALL PRIVILEGES ON nova_api.* TO 'nova'@'%' IDENTIFIED BY 'NOVA_DBPASS';
GRANT ALL PRIVILEGES ON nova.* TO 'nova'@'localhost' IDENTIFIED BY 'NOVA_DBPASS';
GRANT ALL PRIVILEGES ON nova.* TO 'nova'@'%' IDENTIFIED BY 'NOVA_DBPASS';
GRANT ALL PRIVILEGES ON nova_cell0.* TO 'nova'@'localhost' IDENTIFIED BY 'NOVA_DBPASS';
GRANT ALL PRIVILEGES ON nova_cell0.* TO 'nova'@'%' IDENTIFIED BY 'NOVA_DBPASS';
exit;


2. 创建nova用户  向nova用户添加admin角色

openstack user create --domain default --password NOVA_PASS nova
openstack role add --project service --user nova admin


4. 创建nova服务实体  创建Compute API服务端点

openstack service create --name nova --description "OpenStack Compute" compute
openstack endpoint create --region RegionOne compute public http://controller:8774/v2.1
openstack endpoint create --region RegionOne compute internal http://controller:8774/v2.1
openstack endpoint create --region RegionOne compute admin http://controller:8774/v2.1


6. 安装软件包

yum install openstack-nova-api openstack-nova-conductor   openstack-nova-novncproxy openstack-nova-scheduler -y

7. 修改配置文件

cp -a /etc/nova/nova.conf{,.bak}
grep -Ev '^$|#' /etc/nova/nova.conf.bak > /etc/nova/nova.conf
 
openstack-config --set /etc/nova/nova.conf DEFAULT enabled_apis  osapi_compute,metadata
openstack-config --set /etc/nova/nova.conf DEFAULT my_ip  192.168.231.50
openstack-config --set /etc/nova/nova.conf DEFAULT use_neutron  true
openstack-config --set /etc/nova/nova.conf DEFAULT firewall_driver  nova.virt.firewall.NoopFirewallDriver
openstack-config --set /etc/nova/nova.conf DEFAULT transport_url  rabbit://openstack:RABBIT_PASS@controller
openstack-config --set /etc/nova/nova.conf api_database connection  mysql+pymysql://nova:NOVA_DBPASS@controller/nova_api
openstack-config --set /etc/nova/nova.conf database connection  mysql+pymysql://nova:NOVA_DBPASS@controller/nova
openstack-config --set /etc/nova/nova.conf placement_database connection  mysql+pymysql://placement:PLACEMENT_DBPASS@controller/placement

openstack-config --set /etc/nova/nova.conf api auth_strategy  keystone
openstack-config --set /etc/nova/nova.conf keystone_authtoken auth_url  http://controller:5000/v3
openstack-config --set /etc/nova/nova.conf keystone_authtoken memcached_servers  controller:11211
openstack-config --set /etc/nova/nova.conf keystone_authtoken auth_type  password
openstack-config --set /etc/nova/nova.conf keystone_authtoken project_domain_name  Default
openstack-config --set /etc/nova/nova.conf keystone_authtoken user_domain_name  Default
openstack-config --set /etc/nova/nova.conf keystone_authtoken project_name  service
openstack-config --set /etc/nova/nova.conf keystone_authtoken username  nova
openstack-config --set /etc/nova/nova.conf keystone_authtoken password  NOVA_PASS
 
openstack-config --set /etc/nova/nova.conf vnc enabled  true
openstack-config --set /etc/nova/nova.conf vnc server_listen  ' $my_ip'
openstack-config --set /etc/nova/nova.conf vnc server_proxyclient_address  ' $my_ip'
 
openstack-config --set /etc/nova/nova.conf glance api_servers  http://controller:9292
openstack-config --set /etc/nova/nova.conf oslo_concurrency lock_path  /var/lib/nova/tmp
openstack-config --set /etc/nova/nova.conf placement region_name  RegionOne
openstack-config --set /etc/nova/nova.conf placement project_domain_name  Default
openstack-config --set /etc/nova/nova.conf placement project_name  service
openstack-config --set /etc/nova/nova.conf placement auth_type  password
openstack-config --set /etc/nova/nova.conf placement user_domain_name  Default
openstack-config --set /etc/nova/nova.conf placement auth_url  http://controller:5000/v3
openstack-config --set /etc/nova/nova.conf placement username  placement
openstack-config --set /etc/nova/nova.conf placement password  PLACEMENT_PASS


8. 填充nova-api数据库

su -s /bin/sh -c "nova-manage api_db sync" nova
su -s /bin/sh -c "nova-manage cell_v2 map_cell0" nova
su -s /bin/sh -c "nova-manage cell_v2 create_cell --name=cell1 --verbose" nova
su -s /bin/sh -c "nova-manage db sync" nova

9. 数据库填充好之后,验证nova cell0和cell1是否正确注册:

su -s /bin/sh -c "nova-manage cell_v2 list_cells" nova


10. 启动计算服务nova并将其配置为开机自启

systemctl enable openstack-nova-api.service openstack-nova-scheduler.service openstack-nova-conductor.service openstack-nova-novncproxy.service
systemctl start openstack-nova-api.service openstack-nova-scheduler.service openstack-nova-conductor.service openstack-nova-novncproxy.service

同样,使用netstat -tnlup查看端口情况,如出现8774和8775端口则表示nova服务正常启动。

六、OpenStack Train版-6.安装nova计算服务(计算节点)

1. 安装软件包

yum install centos-release-openstack-train openstack-nova-compute openstack-utils-y

2. 修改计算节点的nova配置文件


cp -a /etc/nova/nova.conf{,.bak}
grep -Ev '^$|#' /etc/nova/nova.conf.bak > /etc/nova/nova.conf
 
openstack-config --set  /etc/nova/nova.conf DEFAULT enabled_apis  osapi_compute,metadata
openstack-config --set  /etc/nova/nova.conf DEFAULT transport_url  rabbit://openstack:RABBIT_PASS@controller
openstack-config --set  /etc/nova/nova.conf DEFAULT my_ip 192.168.231.51
openstack-config --set  /etc/nova/nova.conf DEFAULT use_neutron  true
openstack-config --set  /etc/nova/nova.conf DEFAULT firewall_driver  nova.virt.firewall.NoopFirewallDriver
openstack-config --set  /etc/nova/nova.conf api auth_strategy  keystone
openstack-config --set  /etc/nova/nova.conf keystone_authtoken auth_url  http://controller:5000/v3
openstack-config --set  /etc/nova/nova.conf keystone_authtoken memcached_servers  controller:11211
openstack-config --set  /etc/nova/nova.conf keystone_authtoken auth_type  password
openstack-config --set  /etc/nova/nova.conf keystone_authtoken project_domain_name  Default
openstack-config --set  /etc/nova/nova.conf keystone_authtoken user_domain_name  Default

openstack-config --set  /etc/nova/nova.conf keystone_authtoken project_name  service
openstack-config --set  /etc/nova/nova.conf keystone_authtoken username  nova
openstack-config --set  /etc/nova/nova.conf keystone_authtoken password  NOVA_PASS
openstack-config --set  /etc/nova/nova.conf vnc enabled  true
openstack-config --set  /etc/nova/nova.conf vnc server_listen  0.0.0.0
openstack-config --set  /etc/nova/nova.conf vnc server_proxyclient_address  ' $my_ip'
openstack-config --set  /etc/nova/nova.conf vnc novncproxy_base_url http://controller:6080/vnc_auto.html
openstack-config --set  /etc/nova/nova.conf glance api_servers  http://controller:9292
openstack-config --set  /etc/nova/nova.conf oslo_concurrency lock_path  /var/lib/nova/tmp
openstack-config --set  /etc/nova/nova.conf placement region_name  RegionOne
openstack-config --set  /etc/nova/nova.conf placement project_domain_name  Default

openstack-config --set  /etc/nova/nova.conf placement project_name  service
openstack-config --set  /etc/nova/nova.conf placement auth_type  password
openstack-config --set  /etc/nova/nova.conf placement user_domain_name  Default
openstack-config --set  /etc/nova/nova.conf placement auth_url  http://controller:5000/v3
openstack-config --set  /etc/nova/nova.conf placement username  placement
openstack-config --set  /etc/nova/nova.conf placement password  PLACEMENT_PASS
openstack-config --set  /etc/nova/nova.conf libvirt virt_type  qemu


3. 确定计算节点是否支持虚拟机硬件加速

egrep -c '(vmx|svm)' /proc/cpuinfo

如果此命令返回值不是0,则计算节点支持硬件加速,不需要加入下面的配置。
如果此命令返回值是0,则计算节点不支持硬件加速,并且必须配置libvirt为使用QEMU而不是KVM,需要编辑/etc/nova/nova.conf 文件中的[libvirt]部分:

[libvirt]
virt_type = qemu

4. 启动Compute服务及其相关服务,并设置开机自启

systemctl enable libvirtd.service openstack-nova-compute.service
systemctl start libvirtd.service openstack-nova-compute.service

5. controller节点测试

openstack compute service list --service nova-compute

6. 发现计算节点主机

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

7. 设置适当的发现时间间隔(可选


vim /etc/nova/nova.conf
[scheduler]
discover_hosts_in_cells_interval = 300
systemctl restart openstack-nova-api.service


8. 验证整个计算服务nova

openstack compute service list --service nova-compute
openstack compute service list
openstack catalog list
nova-status upgrade check

七、OpenStack Train版-8.安装neutron网络服务(控制节点)

1. 创建neutron数据库并授权

mysql 
CREATE DATABASE neutron;
GRANT ALL PRIVILEGES ON neutron.* TO 'neutron'@'localhost' IDENTIFIED BY 'NEUTRON_DBPASS';
GRANT ALL PRIVILEGES ON neutron.* TO 'neutron'@'%' IDENTIFIED BY 'NEUTRON_DBPASS';
exit;


2. 创建neutron用户 向neutron用户添加admin角色

openstack user create --domain default --password NEUTRON_PASS neutron
openstack role add --project service --user neutron admin


4. 创建neutron服务实体创建neutron服务端点

openstack service create --name neutron --description "OpenStack Networking" network
openstack endpoint create --region RegionOne network public http://controller:9696
openstack endpoint create --region RegionOne network internal http://controller:9696
openstack endpoint create --region RegionOne  network admin http://controller:9696

6. 安装软件包{配置二层网络}

yum install openstack-neutron openstack-neutron-ml2   openstack-neutron-linuxbridge ebtables -y

7. 修改 neutron 配置文件


(1)neutron server的配置文件neutron.conf

cp -a /etc/neutron/neutron.conf{,.bak}
grep -Ev '^$|#' /etc/neutron/neutron.conf.bak > /etc/neutron/neutron.conf
 
openstack-config --set  /etc/neutron/neutron.conf database connection  mysql+pymysql://neutron:NEUTRON_DBPASS@controller/neutron
openstack-config --set  /etc/neutron/neutron.conf DEFAULT core_plugin ml2
openstack-config --set  /etc/neutron/neutron.conf DEFAULT service_plugins 
openstack-config --set  /etc/neutron/neutron.conf DEFAULT transport_url  rabbit://openstack:RABBIT_PASS@controller
openstack-config --set  /etc/neutron/neutron.conf DEFAULT auth_strategy  keystone
openstack-config --set  /etc/neutron/neutron.conf DEFAULT notify_nova_on_port_status_changes  true
openstack-config --set  /etc/neutron/neutron.conf DEFAULT notify_nova_on_port_data_changes  true
openstack-config --set  /etc/neutron/neutron.conf keystone_authtoken www_authenticate_uri  http://controller:5000
openstack-config --set  /etc/neutron/neutron.conf keystone_authtoken auth_url  http://controller:5000
openstack-config --set  /etc/neutron/neutron.conf keystone_authtoken memcached_servers  controller:11211
openstack-config --set  /etc/neutron/neutron.conf keystone_authtoken auth_type  password
openstack-config --set  /etc/neutron/neutron.conf keystone_authtoken project_domain_name  default
openstack-config --set  /etc/neutron/neutron.conf keystone_authtoken user_domain_name  default
openstack-config --set  /etc/neutron/neutron.conf keystone_authtoken project_name  service
openstack-config --set  /etc/neutron/neutron.conf keystone_authtoken username  neutron
openstack-config --set  /etc/neutron/neutron.conf keystone_authtoken password  NEUTRON_PASS
openstack-config --set  /etc/neutron/neutron.conf oslo_concurrency lock_path  /var/lib/neutron/tmp
 
vim /etc/neutron/neutron.conf
[nova]([nova]自己加,加8行)
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 = NOVA_PASS

(2)ML2 plugin的配置文件ml2_conf.ini


cp -a /etc/neutron/plugins/ml2/ml2_conf.ini{,.bak}
grep -Ev '^$|#' /etc/neutron/plugins/ml2/ml2_conf.ini.bak > /etc/neutron/plugins/ml2/ml2_conf.ini
 
openstack-config --set /etc/neutron/plugins/ml2/ml2_conf.ini ml2 type_drivers  flat,vlan
openstack-config --set /etc/neutron/plugins/ml2/ml2_conf.ini ml2 tenant_network_types 
openstack-config --set /etc/neutron/plugins/ml2/ml2_conf.ini ml2 mechanism_drivers  linuxbridge
openstack-config --set /etc/neutron/plugins/ml2/ml2_conf.ini ml2 extension_drivers  port_security
openstack-config --set /etc/neutron/plugins/ml2/ml2_conf.ini ml2_type_flat flat_networks  provider
openstack-config --set /etc/neutron/plugins/ml2/ml2_conf.ini securitygroup enable_ipset  true


(3)linux bridge network provider的配置文件linuxbridge_agent.ini

cp -a /etc/neutron/plugins/ml2/linuxbridge_agent.ini{,.bak}
grep -Ev '^$|#' /etc/neutron/plugins/ml2/linuxbridge_agent.ini.bak > /etc/neutron/plugins/ml2/linuxbridge_agent.ini

openstack-config --set /etc/neutron/plugins/ml2/linuxbridge_agent.ini linux_bridge physical_interface_mappings  provider:eth0
openstack-config --set /etc/neutron/plugins/ml2/linuxbridge_agent.ini vxlan enable_vxlan  false
openstack-config --set /etc/neutron/plugins/ml2/linuxbridge_agent.ini securitygroup enable_security_group  true
openstack-config --set /etc/neutron/plugins/ml2/linuxbridge_agent.ini securitygroup firewall_driver  neutron.agent.linux.iptables_firewall.IptablesFirewallDriver
从配置文件中可以看出,INTERFACE_NAME指的是eth0,就是连接外部网络的那块网卡(provider interface)


8. 修改内核参数

echo 'net.bridge.bridge-nf-call-iptables=1
net.bridge.bridge-nf-call-ip6tables=1
net.ipv6.conf.all.disable_ipv6 = 1' >> /etc/sysctl.conf

modprobe br_netfilter
sysctl -p

9. dhcp agent配置文件dhcp_agent.ini


cp -a /etc/neutron/dhcp_agent.ini{,.bak}
grep -Ev '^$|#' /etc/neutron/dhcp_agent.ini.bak > /etc/neutron/dhcp_agent.ini

openstack-config --set  /etc/neutron/dhcp_agent.ini DEFAULT interface_driver linuxbridge
openstack-config --set  /etc/neutron/dhcp_agent.ini DEFAULT dhcp_driver neutron.agent.linux.dhcp.Dnsmasq
openstack-config --set  /etc/neutron/dhcp_agent.ini DEFAULT enable_isolated_metadata true


10. 配置元数据代理,以便和nova通讯

cp -a /etc/neutron/metadata_agent.ini{,.bak}
grep -Ev '^$|#' /etc/neutron/metadata_agent.ini.bak > /etc/neutron/metadata_agent.ini
 
openstack-config --set  /etc/neutron/metadata_agent.ini DEFAULT nova_metadata_host  controller
openstack-config --set  /etc/neutron/metadata_agent.ini DEFAULT metadata_proxy_shared_secret  METADATA_SECRET

11. 修改nova的配置文件,也是为了和neutron进行交互

openstack-config --set  /etc/nova/nova.conf neutron url  http://controller:9696
openstack-config --set  /etc/nova/nova.conf neutron auth_url  http://controller:5000
openstack-config --set  /etc/nova/nova.conf neutron auth_type  password
openstack-config --set  /etc/nova/nova.conf neutron project_domain_name  default
openstack-config --set  /etc/nova/nova.conf neutron user_domain_name  default
openstack-config --set  /etc/nova/nova.conf neutron region_name  RegionOne
openstack-config --set  /etc/nova/nova.conf neutron project_name  service
openstack-config --set  /etc/nova/nova.conf neutron username  neutron
openstack-config --set  /etc/nova/nova.conf neutron password  NEUTRON_PASS
openstack-config --set  /etc/nova/nova.conf neutron service_metadata_proxy  true
openstack-config --set  /etc/nova/nova.conf neutron metadata_proxy_shared_secret  METADATA_SECRET

12. 初始数据库

ln -s /etc/neutron/plugins/ml2/ml2_conf.ini /etc/neutron/plugin.ini
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

13. 重新启动nova-api服务

systemctl restart openstack-nova-api.service

14. 启动neutron服务和配置开机启动

systemctl enable neutron-server.service neutron-linuxbridge-agent.service neutron-dhcp-agent.service neutron-metadata-agent.service
systemctl start neutron-server.service neutron-linuxbridge-agent.service neutron-dhcp-agent.service neutron-metadata-agent.service

启动好之后,可以使用systemctl status命令查看各个服务运行的状态,使用netstat -tnlup查看是否有9696端口。
[root@controller ~]# netstat -lntup|grep 9696
tcp        0      0 0.0.0.0:9696            0.0.0.0:*               LISTEN      11930/server.log    

八、OpenStack Train版-9.安装neutron网络服务(计算节点)

1. 安装组件

yum install openstack-neutron-linuxbridge ebtables ipset -y


2. 修改配置文件


(1)修改neutron主配置文件

cp -a /etc/neutron/neutron.conf{,.bak}
grep -Ev '^$|#' /etc/neutron/neutron.conf.bak > /etc/neutron/neutron.conf
 
openstack-config --set  /etc/neutron/neutron.conf DEFAULT transport_url rabbit://openstack:RABBIT_PASS@controller
openstack-config --set  /etc/neutron/neutron.conf DEFAULT auth_strategy keystone 
openstack-config --set  /etc/neutron/neutron.conf keystone_authtoken www_authenticate_uri http://controller:5000
openstack-config --set  /etc/neutron/neutron.conf keystone_authtoken auth_url http://controller:5000
openstack-config --set  /etc/neutron/neutron.conf keystone_authtoken memcached_servers controller:11211
openstack-config --set  /etc/neutron/neutron.conf keystone_authtoken auth_type password
openstack-config --set  /etc/neutron/neutron.conf keystone_authtoken project_domain_name default
openstack-config --set  /etc/neutron/neutron.conf keystone_authtoken user_domain_name default
openstack-config --set  /etc/neutron/neutron.conf keystone_authtoken project_name service
openstack-config --set  /etc/neutron/neutron.conf keystone_authtoken username neutron
openstack-config --set  /etc/neutron/neutron.conf keystone_authtoken password NEUTRON_PASS 
openstack-config --set  /etc/neutron/neutron.conf oslo_concurrency lock_path /var/lib/neutron/tmp

(2)配置Linux网桥代理

cp -a /etc/neutron/plugins/ml2/linuxbridge_agent.ini{,.bak}
grep -Ev '^$|#' /etc/neutron/plugins/ml2/linuxbridge_agent.ini.bak > /etc/neutron/plugins/ml2/linuxbridge_agent.ini
 
openstack-config --set /etc/neutron/plugins/ml2/linuxbridge_agent.ini linux_bridge physical_interface_mappings  provider:eth0
openstack-config --set /etc/neutron/plugins/ml2/linuxbridge_agent.ini vxlan enable_vxlan  false
openstack-config --set /etc/neutron/plugins/ml2/linuxbridge_agent.ini securitygroup enable_security_group  true
openstack-config --set /etc/neutron/plugins/ml2/linuxbridge_agent.ini securitygroup firewall_driver  neutron.agent.linux.iptables_firewall.IptablesFirewallDriver


(3)sysctl.conf
 

echo 'net.bridge.bridge-nf-call-iptables=1
net.bridge.bridge-nf-call-ip6tables=1
net.ipv6.conf.all.disable_ipv6 = 1' >> /etc/sysctl.conf

modprobe br_netfilter
sysctl -p

3. 修改nova配置文件{compute01}

openstack-config --set  /etc/nova/nova.conf neutron auth_url http://controller:5000
openstack-config --set  /etc/nova/nova.conf neutron auth_type password
openstack-config --set  /etc/nova/nova.conf neutron project_domain_name default
openstack-config --set  /etc/nova/nova.conf neutron user_domain_name default
openstack-config --set  /etc/nova/nova.conf neutron region_name RegionOne
openstack-config --set  /etc/nova/nova.conf neutron project_name service
openstack-config --set  /etc/nova/nova.conf neutron username neutron
openstack-config --set  /etc/nova/nova.conf neutron password NEUTRON_PASS

4. 重启nova计算服务

systemctl restart openstack-nova-compute.service

5. 启动neutron服务和设置开机自启动

systemctl enable neutron-linuxbridge-agent.service
systemctl start neutron-linuxbridge-agent.service


6. 在控制节点(controller)执行以下命令验证neutron服务
 

openstack network agent list

九、OpenStack Train版-10.安装horizon服务(计算节点)

系统要求
安装Train版本的Horizon有以下要求:


1、语言环境


Python 2.7、3.6或3.7
Django 1.11、2.0和2.2
Django 2.0和2.2支持在Train版本中处于试验阶段。
Ussuri发行版(Train发行版之后的下一个发行版)将使用Django 2.2作为主要的Django版本。Django 2.0支持将被删除。


2、可访问的keystone endpoint

3. 安装

yum install openstack-dashboard -y

4. 编辑配置文件/etc/openstack-dashboard/local_settings

cp -a /etc/openstack-dashboard/local_settings{,.bak}
echo " " > /etc/openstack-dashboard/local_settings
import os
from django.utils.translation import ugettext_lazy as _
from openstack_dashboard.settings import HORIZON_CONFIG
DEBUG = False
ALLOWED_HOSTS = ['*']
LOCAL_PATH = '/tmp'
SECRET_KEY='60eeac4448ab9733b7d8'
SESSION_ENGINE = 'django.contrib.sessions.backends.cache'
CACHES = {
    'default': {
         'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache',
         'LOCATION': 'controller:11211',
    }
}
EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend'
OPENSTACK_HOST = "controller"
OPENSTACK_KEYSTONE_URL = "http://%s:5000/v3" % OPENSTACK_HOST
OPENSTACK_KEYSTONE_MULTIDOMAIN_SUPPORT = True
OPENSTACK_API_VERSIONS = {
    "identity": 3,
    "image": 2,
    "volume": 3,
}
OPENSTACK_KEYSTONE_DEFAULT_DOMAIN = "Default"
OPENSTACK_KEYSTONE_DEFAULT_ROLE = "user"
OPENSTACK_NEUTRON_NETWORK = {
    'enable_auto_allocated_network': False,
    'enable_distributed_router': False,
    'enable_fip_topology_check': False,
    'enable_ha_router': False,
    'enable_lb': False,
    'enable_firewall': False,
    'enable_vpn': False,
    'enable_ipv6': True,
    'enable_quotas': False,
    'enable_rbac_policy': True,
    'enable_router': False,
    'default_dns_nameservers': [],
    'supported_provider_types': ['*'],
    'segmentation_id_range': {},
    'extra_provider_types': {},
    'supported_vnic_types': ['*'],
    'physical_networks': [],
}
TIME_ZONE = "Asia/Shanghai"
LOGGING = {
    'version': 1,
    'disable_existing_loggers': False,
    'formatters': {
        'console': {
            'format': '%(levelname)s %(name)s %(message)s'
        },
        'operation': {
            'format': '%(message)s'
        },
    },
    'handlers': {
        'null': {
            'level': 'DEBUG',
            'class': 'logging.NullHandler',
        },
        'console': {
            'level': 'DEBUG' if DEBUG else 'INFO',
            'class': 'logging.StreamHandler',
            'formatter': 'console',
        },
        'operation': {
            'level': 'INFO',
            'class': 'logging.StreamHandler',
            'formatter': 'operation',
        },
    },
    'loggers': {
        'horizon': {
            'handlers': ['console'],
            'level': 'DEBUG',
            'propagate': False,
        },
        'horizon.operation_log': {
            'handlers': ['operation'],
            'level': 'INFO',
            'propagate': False,
        },
        'openstack_dashboard': {
            'handlers': ['console'],
            'level': 'DEBUG',
            'propagate': False,
        },
        'novaclient': {
            'handlers': ['console'],
            'level': 'DEBUG',
            'propagate': False,
        },
        'cinderclient': {
            'handlers': ['console'],
            'level': 'DEBUG',
            'propagate': False,
        },
        'keystoneauth': {
            'handlers': ['console'],
            'level': 'DEBUG',
            'propagate': False,
        },
        'keystoneclient': {
            'handlers': ['console'],
            'level': 'DEBUG',
            'propagate': False,
        },
        'glanceclient': {
            'handlers': ['console'],
            'level': 'DEBUG',
            'propagate': False,
        },
        'neutronclient': {
            'handlers': ['console'],
            'level': 'DEBUG',
            'propagate': False,
        },
        'swiftclient': {
            'handlers': ['console'],
            'level': 'DEBUG',
            'propagate': False,
        },
        'oslo_policy': {
            'handlers': ['console'],
            'level': 'DEBUG',
            'propagate': False,
        },
        'openstack_auth': {
            'handlers': ['console'],
            'level': 'DEBUG',
            'propagate': False,
        },
        'django': {
            'handlers': ['console'],
            'level': 'DEBUG',
            'propagate': False,
        },
        'django.db.backends': {
            'handlers': ['null'],
            'propagate': False,
        },
        'requests': {
            'handlers': ['null'],
            'propagate': False,
        },
        'urllib3': {
            'handlers': ['null'],
            'propagate': False,
        },
        'chardet.charsetprober': {
            'handlers': ['null'],
            'propagate': False,
        },
        'iso8601': {
            'handlers': ['null'],
            'propagate': False,
        },
        'scss': {
            'handlers': ['null'],
            'propagate': False,
        },
    },
}
SECURITY_GROUP_RULES = {
    'all_tcp': {
        'name': _('All TCP'),
        'ip_protocol': 'tcp',
        'from_port': '1',
        'to_port': '65535',
    },
    'all_udp': {
        'name': _('All UDP'),
        'ip_protocol': 'udp',
        'from_port': '1',
        'to_port': '65535',
    },
    'all_icmp': {
        'name': _('All ICMP'),
        'ip_protocol': 'icmp',
        'from_port': '-1',
        'to_port': '-1',
    },
    'ssh': {
        'name': 'SSH',
        'ip_protocol': 'tcp',
        'from_port': '22',
        'to_port': '22',
    },
    'smtp': {
        'name': 'SMTP',
        'ip_protocol': 'tcp',
        'from_port': '25',
        'to_port': '25',
    },
    'dns': {
        'name': 'DNS',
        'ip_protocol': 'tcp',
        'from_port': '53',
        'to_port': '53',
    },
    'http': {
        'name': 'HTTP',
        'ip_protocol': 'tcp',
        'from_port': '80',
        'to_port': '80',
    },
    'pop3': {
        'name': 'POP3',
        'ip_protocol': 'tcp',
        'from_port': '110',
        'to_port': '110',
    },
    'imap': {
        'name': 'IMAP',
        'ip_protocol': 'tcp',
        'from_port': '143',
        'to_port': '143',
    },
    'ldap': {
        'name': 'LDAP',
        'ip_protocol': 'tcp',
        'from_port': '389',
        'to_port': '389',
    },
    'https': {
        'name': 'HTTPS',
        'ip_protocol': 'tcp',
        'from_port': '443',
        'to_port': '443',
    },
    'smtps': {
        'name': 'SMTPS',
        'ip_protocol': 'tcp',
        'from_port': '465',
        'to_port': '465',
    },
    'imaps': {
        'name': 'IMAPS',
        'ip_protocol': 'tcp',
        'from_port': '993',
        'to_port': '993',
    },
    'pop3s': {
        'name': 'POP3S',
        'ip_protocol': 'tcp',
        'from_port': '995',
        'to_port': '995',
    },
    'ms_sql': {
        'name': 'MS SQL',
        'ip_protocol': 'tcp',
        'from_port': '1433',
        'to_port': '1433',
    },
    'mysql': {
        'name': 'MYSQL',
        'ip_protocol': 'tcp',
        'from_port': '3306',
        'to_port': '3306',
    },
    'rdp': {
        'name': 'RDP',
        'ip_protocol': 'tcp',
        'from_port': '3389',
        'to_port': '3389',
    },
}


5. 重建apache的dashboard配置文件

cd /usr/share/openstack-dashboard
python manage.py make_web_conf --apache > /etc/httpd/conf.d/openstack-dashboard.conf


6. 备用机制


若出现不能正常访问,请操作以下步骤:
建立策略文件(policy.json)的软链接,否则登录到dashboard将出现权限错误和显示混乱
ln -s /etc/openstack-dashboard /usr/share/openstack-dashboard/openstack_dashboard/conf


7. 重新启动计算节点(compute01)上apache服务

systemctl enable httpd.service
systemctl restart httpd.service


由于dashboard的运行机制是把网站下的所有文件删除之后再重新复制,所以重启httpd需要等待一段时间。
 
重新启动控制节点(controller)上的memcache服务

systemctl restart memcached.service


十、OpenStack Train版-11.启动实例(控制节点)

1、检查各个节点间的网络通讯ping

2、删除NetworkManager软件包    在控制节点和计算节点都执行

yum remove NetworkManager -y

3. controller节点创建网络

neutron net-create --shared --provider:physical_network provider --provider:network_type flat WAN

参数说明:
--share 指明所有项目都可以使用这个网络,否则只有创建者能使用
--external 指明是外部网络
--provider-physical-network provider 
指明物理网络的提供者,与下面neutron的配置文件对应,其中provider是标签,可以更改为其他,但是2个地方必须要统一。
[ml2_type_flat]
flat_networks = provider
 
--provider-network-type flat
指明这里创建的网络是flat类型,即实例连接到此网络时和物理网络是在同一个网段,无vlan等功能。
vm-network 网络名称


4. controller节点创建子网

neutron subnet-create --name subnet-wan --allocation-pool \
start=192.168.231.100,end=192.168.231.200 --dns-nameserver 114.114.114.114 \
--gateway 192.168.231.2 WAN 192.168.231.0/24

参数说明:
--network 指明父网络
--allocation-pool start=10.8.20.50,end=10.8.20.60 指明子网起始地址和终止地址
--dns-nameserver 指明dns服务器
--gateway 指明网关地址
--subnet-range 指明子网网段
 
vm-subnetwork 子网名称

5. 控制节点创建硬件配置方案

openstack flavor create --id 0 --vcpus 1 --ram 64 --disk 1 m1.nano

6. 检查网络配置
 

openstack network list
yum install bridge-utils -y
brctl show

https://blog.csdn.net/chengyinwu/article/details/103946226

猜你喜欢

转载自blog.csdn.net/kaikai136412162/article/details/112390253