本文尚未完成。
由于本人能力有限,文章及部分观点仅供参考。如有不正确或可改进之处,欢迎读者批评指正。
前言
去年,我在家里部署了一个三节点的 Proxmox Virtual Environment(PVE)集群,配以 Ceph 存储集群组成超融合集群(原文)。在这一平台上我创建了很多的 LXC/VM,用以部署我的各种服务,以及一些计算任务。
同时我也向我有需要的朋友们提供了一些 VM,供他们使用我集群中的计算和存储资源。我在 PVE 上为他们创建账号,然后我使用 Cloud-Init 复制提前准备好的模板 VM 至一个给他们专用的 VM,随后配置对应用户权限,将初始用户账密提供给我的朋友。
但是这一过程中我遇到了许多并不十分方便的场景,例如我的朋友们难以直接使用我 Proxmox Backup Server(PBS)进行的每日备份的备份结果,对他们的虚拟机进行回滚。如果我需要支持这一点,我需要为他们再创建 PBS 的独立账户,并且设置对应的权限。也包括 vmid 需要刻意编排避免冲突的小需求,让我不是十分满意。我希望能够有一个平台,能够让我的朋友在上面以更强的主动权管理他的资源,包括虚拟机、备份一类,而不是像现在仅由我创建并分发给他们。
在进行了一些搜索后,我意识到 PVE 虽然因为其轻量部署设计而非常适用于 HomeLab 或 DevOps 等小型场景,但是面对我当前的多租户需求,它并不能够提供很好的支持。
在一定的搜索之后,我关注到了 OpenStack,一个被广泛应用的开源的云计算平台。OpenStack 更适合于大型集群,其部署复杂度相当复杂,并且需要非常高的硬件资源支持。但是 OpenStack 能够提供满足我的需求的功能,创建一个类似于公有云平台的体验。
部署思路
OpenStack 平台的构建需要用到十余个基础组件,包括 DB、RabbitMQ、Memcached、HAProxy 以及 OpenStack 用于管理计算、存储、网络等等各个组件。其中所有服务大致可以分为两类:管理服务和计算服务。计算服务即 OpenStack Nova,用于创建、管理宿主机上的虚拟机;管理服务则为除计算服务以外的所有服务。
出于对 OpenStack 平台可用性的保障,上述所有服务都需要以高可用的方式部署。实现高可用服务的方式大致有两类:
- 集群部署:例如数据库等服务,我们可以通过在多个节点上部署服务,以集群形式向外部提供服务。在集群之前可能需要提供一个高可用的负载均衡节点。服务可以使用服务器节点的本地存储,和集群多个节点的算力,拥有更高的性能,适用于数据库等高性能需求的服务。
- HA 部署:例如 OpenStack Dashboard 等服务,我们可以在共享存储上创建一个虚拟机运行该服务,当节点宕机时自动迁移至其他存活节点,保证服务下线时间极短。由于服务使用共享存储,和仅单个节点的算力,其拥有相对较低的性能,但是复杂度大幅降低,适用于对性能无较高需求的服务。
计算服务的部署显然以集群的形式,我们在多个服务器上部署计算服务,让用户的虚拟机能够在这些服务器上自由迁移。当一个服务器宕机时,原位于此服务器上的所有虚拟机能够自动迁移到其他仍然存活的计算服务节点上。管理服务十余个组件则需要分别根据不同的方式进行部署,这为管理带来了一定的挑战。
传统的部署 OpenStack 的方式,是在服务器集群中选出若干台服务器作为管理服务器,高可用地在管理服务器中部署管理服务。另外有一些存储服务器,组建一个高可用的存储集群,为用户的高可用虚拟机提供存储服务。剩余的服务器均为计算服务器,计算服务器仅需要系统盘即可,不需要额外的数据存储盘,基于共享存储集群在其上运行用户的虚拟机,用户的虚拟机则能在各个计算服务器上在线迁移,实现高可用。
我原拥有一个 PVE 集群,根据传统做法应当移除 PVE 集群,并在之上依据如上的架构重新部署 OpenStack 集群。因为 OpenStack 作为一个云计算平台,它需要直接管理服务器上的虚拟机服务,会与 PVE 产生一定的管理冲突,不能直接在服务器上共存。
但是直接在服务器上部署 OpenStack 集群的方案极大地增加了管理难度。PVE 集群的部署本十分轻量,不依赖任何服务,可认为在服务器健康的情况下,PVE 集群是始终健康的。但是 OpenStack 拥有大量基础组件,任何组件的故障均会导致难以正常运行 OpenStack 平台。这会让我难以在异地修复故障。另外,我在 PVE 上本有一系列服务,全部迁移至 OpenStack 并不十分方便。
为此,一个想法是,我们可以仍以 PVE 直接管理宿主机,在其上运行虚拟机,在虚拟机中部署 OpenStack 集群。鉴于两层虚拟化可能会带来过大的开销,我们可以在 PVE 层使用 LXC,在 OpenStack 层继续使用 VM,从逻辑上硬件资源仅有一层虚拟化开销。
也就是说,我们能够继续以习惯的方式,在 PVE 上创建一系列独立的 LXC 容器,运行 OpenStack 所需要的各个服务。如服务为 HA 部署方式,也可以很方便地使用 PVE 的 HA 管理。另外,还可以继续使用现有的 PBS 对这些基础服务进行备份。这使得我们能够使用一种简洁且习惯的方式完成 OpenStack 的部署,且带来较小的额外性能开销。
OpenStack 官方推荐的部署方式基于 Ansible 进行自动化部署,是一个高效且广泛使用的优秀方案。但是无奈有一定学习成本,我暂时还不会使用,且目前集群规模尚小。因此我选择了手动部署各个服务,在本文中我们会依次对各个服务进行部署,最终构建完整的 OpenStack 平台。
硬件资源
部署结构
HAProxy 集群部署
HAProxy 是一个可以提供高可用性、负载均衡的代理软件。由于下面的一些集群部署的服务都需要进行高可用负载均衡,因此我们先对 HAProxy 集群进行部署。
在这里,我们使用 HAProxy + Keepalived 的组合。我们使用 Keepalived 将三个容器绑定到同一个虚拟 IP(VIP) 上。其中一个容器将真正绑定到该 VIP 上,另外两个容器则进行热备。当绑定 VIP 的容器宕机时,热备的容器会启用,绑定至该 VIP。这样可以使得使用该 VIP 时能够以高可用的方式访问到一个 HAProxy 实例。
容器部署
在三台服务器上各创建一个 LXC 进行部署。LXC 配置为:2C1G,8G 磁盘位于本地 SSD 存储。
安装 HAProxy 和 Keepalived:
apt install haproxy keepalived -y
HAProxy 配置位于 /etc/haproxy/haproxy.cfg
,我们暂时不进行更改,后续部署集群服务时我们会相应地在文件结尾增加集群配置。
Keepalived 配置位于 /etc/keepalived/keepalived.conf
,默认不创建,可以添加下面的配置至该文件。在此处的规划中,未来每一个集群服务均会有一个接入的独立 IP,添加至 virtual_ipaddress
的 ...
处即可。
vrrp_instance VI_1 {
state MASTER
interface eth1 # 提供服务的 LXC 网卡
virtual_router_id 51
priority 150 # 推荐每个节点各不相同
advert_int 1
authentication {
auth_type PASS
auth_pass 123456 # 自行生成密钥
}
virtual_ipaddress {
... # 请在此处填入所有绑定的 IP,一行一个
nopreempt
}
}
配置完成后,在 systemctl
启用两个服务即可。HAProxy 即配置完成。
MariaDB Galera 集群部署
MariaDB Galera Cluster 是一套开源的数据库集群高可用方案,实现了数据零丢失,是一个 MariaDB 同步多主机集群方案。
容器部署
在三台服务器上各自创建一个 LXC。LXC 配置为:2C4G,配以 20G 本地 SSD 磁盘。此处使用 VIP 10.2.0.10/16
,三个节点的 IP 为 10.2.x.10/16
。
开放 LXC 端口 3306/tcp
,4567/tcp
,4567/udp
,4568/tcp
,4444/tcp
。其中 3306/tcp
向 HAProxy 使用的 VIP 开放,其余端口向集群内部节点开放即可。
安装 MariaDB + Galera + rsync:
apt install mariadb-server galera-4 rsync -y
创建配置文件 /etc/mysql/conf.d/galera.cnf
:
[mysqld]
bind-address = 10.2.1.10 # 更改为绑定 IP
proxy-protocol-networks = 10.2.0.10
binlog_format = ROW
default_storage_engine = InnoDB
innodb_autoinc_lock_mode = 2
wsrep_on = ON
wsrep_provider = /usr/lib/galera/libgalera_smm.so
wsrep_cluster_name = "galera_cluster"
wsrep_cluster_address= "gcomm://10.2.1.10,10.2.2.10,10.2.3.10" # 更改为所有节点 IP
wsrep_node_name = "node1" # 每个节点互不相同
wsrep_node_address = "10.2.1.10" # 此节点 IP
为支持外部访问,还需要将 /etc/mysql/50-server.cnf
中的 127.0.0.1
换为 0.0.0.0
,支持外部访问。
完成配置后先执行 systemctl stop mariadb
,停止集群运行,在完成集群完整配置后再统一启动。
完成三节点的配置后,选择一个节点,在其上运行 galera_new_cluster
,随后在其他两个节点运行 systemctl start mariadb
,即可完成集群构建。
需要注意的是,如果未来出现单节点甚至双节点的宕机,重启并且使 mariadb
服务自行启动即可。但是三个集群节点若全部宕机,需要手动寻找最晚结束的 mariadb
,从它执行 galera_new_cluster
并重新恢复集群。
负载均衡部署
随后配置 HAProxy 集群连接 MariaDB Galera 集群。
首先配置 Keepalived,添加 VIP 10.2.0.10
作为 MariaDB Galera 集群入口。
随后配置 HAProxy 配置,为了避免集群内同用户密集读写被分散至不同节点导致同步错误,需要开启会话粘性:
frontend mariadb_frontend
bind 10.2.0.10:3306
mode tcp
default_backend mariadb_backend
backend mariadb_backend
mode tcp
balance leastconn
stick-table type ip size 200k expire 30m
stick on src
option tcpka
option mysql-check user haproxy
source 10.2.0.10
timeout connect 10s
timeout server 90s
server node1 10.2.1.10:3306 check
server node2 10.2.2.10:3306 check
server node3 10.2.3.10:3306 check
同时需要在 MariaDB 中创建对应的账户用于检查:
CREATE USER 'haproxy'@'10.2.0.10';
另外,若需要在 MariaDB 端根据请求来源 Host 来对用户进行鉴权,还需要开启 HAProxy 的 PROXY
协议。
在此功能下,需要在 /etc/mysql/50-server.cnf
中添加:
proxy-protocol-networks = 10.2.0.10/16 # 即 VIP
同时修改 HAProxy 配置添加 send-proxy
,即在 mariadb_backend
的每一个 server
行的最后添加 send-proxy
。
RabbitMQ 集群部署
容器部署
在三台服务器上各创建一个 LXC 用于运行 RabbitMQ 实例,LXC 配置:2C8G,配以 16GB 本地 SSD 存储作为磁盘。
开放 LXC 端口 5672/tcp
向 VIP;4369/tcp
,25672/tcp
向 RabbitMQ 集群内节点。此处使用 VIP 10.2.0.15/16
,三个节点的 IP 为 10.2.x.15/16
。
安装 RabbitMQ,这里使用 此处 提供的脚本使用 Cloudsmith 镜像进行安装:
sudo apt-get install curl gnupg apt-transport-https -y
## Team RabbitMQ's main signing key
curl -1sLf "https://keys.openpgp.org/vks/v1/by-fingerprint/0A9AF2115F4687BD29803A206B73A36E6026DFCA" | sudo gpg --dearmor | sudo tee /usr/share/keyrings/com.rabbitmq.team.gpg > /dev/null
## Community mirror of Cloudsmith: modern Erlang repository
curl -1sLf https://github.com/rabbitmq/signing-keys/releases/download/3.0/cloudsmith.rabbitmq-erlang.E495BB49CC4BBE5B.key | sudo gpg --dearmor | sudo tee /usr/share/keyrings/rabbitmq.E495BB49CC4BBE5B.gpg > /dev/null
## Community mirror of Cloudsmith: RabbitMQ repository
curl -1sLf https://github.com/rabbitmq/signing-keys/releases/download/3.0/cloudsmith.rabbitmq-server.9F4587F226208342.key | sudo gpg --dearmor | sudo tee /usr/share/keyrings/rabbitmq.9F4587F226208342.gpg > /dev/null
## Add apt repositories maintained by Team RabbitMQ
sudo tee /etc/apt/sources.list.d/rabbitmq.list <<EOF
## Provides modern Erlang/OTP releases
##
deb [arch=amd64 signed-by=/usr/share/keyrings/rabbitmq.E495BB49CC4BBE5B.gpg] https://ppa1.rabbitmq.com/rabbitmq/rabbitmq-erlang/deb/ubuntu noble main
deb-src [signed-by=/usr/share/keyrings/rabbitmq.E495BB49CC4BBE5B.gpg] https://ppa1.rabbitmq.com/rabbitmq/rabbitmq-erlang/deb/ubuntu noble main
# another mirror for redundancy
deb [arch=amd64 signed-by=/usr/share/keyrings/rabbitmq.E495BB49CC4BBE5B.gpg] https://ppa2.rabbitmq.com/rabbitmq/rabbitmq-erlang/deb/ubuntu noble main
deb-src [signed-by=/usr/share/keyrings/rabbitmq.E495BB49CC4BBE5B.gpg] https://ppa2.rabbitmq.com/rabbitmq/rabbitmq-erlang/deb/ubuntu noble main
## Provides RabbitMQ
##
deb [arch=amd64 signed-by=/usr/share/keyrings/rabbitmq.9F4587F226208342.gpg] https://ppa1.rabbitmq.com/rabbitmq/rabbitmq-server/deb/ubuntu noble main
deb-src [signed-by=/usr/share/keyrings/rabbitmq.9F4587F226208342.gpg] https://ppa1.rabbitmq.com/rabbitmq/rabbitmq-server/deb/ubuntu noble main
# another mirror for redundancy
deb [arch=amd64 signed-by=/usr/share/keyrings/rabbitmq.9F4587F226208342.gpg] https://ppa2.rabbitmq.com/rabbitmq/rabbitmq-server/deb/ubuntu noble main
deb-src [signed-by=/usr/share/keyrings/rabbitmq.9F4587F226208342.gpg] https://ppa2.rabbitmq.com/rabbitmq/rabbitmq-server/deb/ubuntu noble main
EOF
## Update package indices
sudo apt-get update -y
## Install Erlang packages
sudo apt-get install -y erlang-base \
erlang-asn1 erlang-crypto erlang-eldap erlang-ftp erlang-inets \
erlang-mnesia erlang-os-mon erlang-parsetools erlang-public-key \
erlang-runtime-tools erlang-snmp erlang-ssl \
erlang-syntax-tools erlang-tftp erlang-tools erlang-xmerl
## Install rabbitmq-server and its dependencies
sudo apt-get install rabbitmq-server -y --fix-missing
完成安装后即可用 systemctl
管理服务 rabbitmq-server
。
检查 /var/lib/rabbitmq/.erlang.cookie
,该文件需存在,权限为 400,属于 rabbitmq:rabbitmq
,该文件内有一些内容,需要复制,保持三个节点均相同。
在 /etc/rabbitmq/rabbitmq-env.conf
中写入 NODENAME=rabbit@<hostname>
,其中 hostname
为 LXC 主机名。
修改 /etc/hosts
,添加各节点名称与 IP 的对应关系:
10.2.1.15 RabbitMQ-1
10.2.2.15 RabbitMQ-2
10.2.3.15 RabbitMQ-3
完成后启动服务:
systemctl enable rabbitmq-server
systemctl start rabbitmq-server
完成三个节点的启动后,我们在二三两个 LXC 运行下面的命令加入一节点的集群:
rabbitmqctl stop_app
rabbitmqctl reset
rabbitmqctl join_cluster rabbit@RabbitMQ-1
rabbitmqctl start_app
负载均衡部署
然后配置 HAProxy 为 RabbitMQ 集群提供负载均衡。
还是先配置 Keepalived,将 VIP 10.2.0.15
分配给该节点。
HAProxy 配置如下:
frontend rabbitmq_frontend
bind 10.2.0.15:5672
mode tcp
default_backend rabbitmq_backend
backend rabbitmq_backend
mode tcp
balance roundrobin
source 10.2.0.15
server RabbitMQ-1 10.2.1.15:5672 check
server RabbitMQ-2 10.2.2.15:5672 check
server RabbitMQ-3 10.2.3.15:5672 check
完成后集群即连接完毕。随后登录任一节点,设置所有队列镜像同步:
rabbitmqctl set_policy ha-all "" '{"ha-mode":"all"}'
调优可参考 此文。
Memcached 集群部署
实际上 Memcached 无原生集群机制,但是单 LXC 的高可用依赖 Ceph HDD 作为存储,可能带来额外的延迟。为此此处仍使用三节点伪集群配置,以利用每台宿主机上的原生 SSD。
此处集群 IP 为 10.2.x.17/16
。
容器部署
在三台服务器上各创建一个 LXC,配置 2C1G,磁盘 8G 本地 SSD 存储。
开放 11211/tcp
向使用 Memcached 的服务的 IP 即可。
安装 Memcached:
apt install memcached
修改配置 /etc/memcached.conf
如下几行:
-l 10.2.1.17 # 监听 IP
-m 512 # 最大使用内存 MB
-c 2048 # 最大并发连接数
-t 2 # 工作线程数,推荐 CPU 核数
修改完成后使用 systemctl 管理服务即可:
systemctl enable memcached
systemctl restart memcached
这里 Memcached 不再配置负载均衡同一接口,而是由客户端直连集群多节点。
Keystone 集群部署
Keystone 是 OpenStack 控制面的第一个核心服务,用于提供身份认证服务。所有组件都依赖它进行 token 认证。它需要使用 Galera 和 Memcached。它是一个完全无状态的服务,因此非常适合做多副本部署。
此处集群 IP 为 10.2.x.160/16
,VIP 为 10.2.0.160/16
。
容器部署
在三台服务器上各创建一个 LXC,配置 2C2G,使用 8G 硬盘。Keystone 服务对本地硬盘无性能需求,可使用 Ceph 作为存储。
开放 LXC 端口 5000/tcp
向 VIP 即可。
首先在 MariaDB Galera 集群内创建数据库 Keystone
,并创建对应 Keystone 账户并赋予对应权限。
随后对每个 Keystone 节点进行下面的操作。
安装系统环境:
apt install python3-openstackclient apache2 libapache2-mod-wsgi-py3 mariadb-client keystone
配置 Keystone /etc/keystone/keystone.conf
(包含部分调优参数):
[database]
connection = mysql+pymysql://Keystone:<DB_PASSWORD>@10.2.0.10/Keystone
[token]
provider = fernet
expiration = 3600
cache_on_issue = true
[cache]
enabled = true
backend = dogpile.cache.memcached
memcache_servers = 10.2.1.17:11211,10.2.2.17:11211,10.2.3.17:11211
memcache_dead_retry = 30
memcache_socket_timeout = 1.0
memcache_pool_maxsize = 20
memcache_pool_unused_timeout = 60
[oslo_middleware]
max_request_body_size = 114688
[DEFAULT]
admin_token = <ADMIN_TOKEN>
其中最后一项配置 ADMIN_TOKEN
仅在首次部署时使用,用于在服务尚未创建完全时进行身份认证。在完成部署后则需要移除。
随后初始化 Keystone 数据库(在一个节点运行即可):
su -s /bin/bash keystone -c "keystone-manage db_sync"
随后配置 Fernet 密钥同步(在一个节点执行,其他节点复制):
keystone-manage fernet_setup --keystone-user keystone --keystone-group keystone
keystone-manage credential_setup --keystone-user keystone --keystone-group keystone
将 /etc/keystone/fernet-keys/
和 /etc/keystone/credential-keys/
拷贝到其他节点。
随后引导身份服务,在其中一个节点上运行:
keystone-manage bootstrap --bootstrap-password <ADMIN_PASS> \
--bootstrap-admin-url http://10.2.0.160:5000/v3/ \
--bootstrap-internal-url http://10.2.0.160:5000/v3/ \
--bootstrap-public-url http://10.2.0.160:5000/v3/ \
--bootstrap-region-id RegionOne
配置 Apache,修改 /etc/apache2/apache2.conf
:
ServerName 10.2.1.160
可在 Apache 配置 /etc/apache2/sites-enabled/keystone.conf
内调整线程数(processes
)至 CPU 核心数:
WSGIDaemonProcess keystone-public processes=2 threads=10 user=keystone group=keystone display-name=%{GROUP}
随后用 systemctl 管理 Apache:
systemctl enable apache2
systemctl restart apache2
负载均衡部署
在这里我们先将 VIP 10.2.0.160
添加至 Keepalived,并配置 HAProxy:
frontend keystone_frontend
bind 10.2.0.160:5000
mode tcp
default_backend keystone_backend
backend keystone_backend
mode tcp
balance roundrobin
option httpchk GET /v3
source 10.2.0.160
server Keystone-1 10.2.1.160:5000 check
server Keystone-2 10.2.2.160:5000 check
server Keystone-3 10.2.3.160:5000 check
完成上述操作后可在任意容器上运行如下命令进行验证:
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://10.2.0.160:5000/v3
export OS_IDENTITY_API_VERSION=3
openstack token issue
如显示 token 信息,则表示部署成功。
可将此处的所有 export
命令写入 admin-openrc.sh
中,方便之后使用 OpenStack 命令。
Glance 集群部署
Glance 是 OpenStack 用于维护虚拟机镜像的集中式仓库。此处我们使用 Ceph RBD 作为 Glance 的存储后端,用于存储镜像。
Glance 本身也为无状态服务,支持多副本横向扩展,因此此处仍使用多副本集群部署 Glance。
此处集群 IP 为 10.2.x.161/16
,VIP 为 10.2.0.161/16
。
预配置
在 MariaDB Galera 集群中创建数据库 Glance 和对应账户,赋予该数据库内权限。
对于 RabbitMQ,为 Glance 新建一个 vhost,并创建对应用户,授予该 vhost 权限。
通过 Keystone 创建 Glance 账户:
openstack user create --domain default --password <glance_PASS> glance
openstack role add --project service --user glance admin
openstack service create --name glance --description "OpenStack Image" image
openstack endpoint create --region RegionOne image public http://10.2.0.161:9292
openstack endpoint create --region RegionOne image internal http://10.2.0.161:9292
openstack endpoint create --region RegionOne image admin http://10.2.0.161:9292
在 Ceph 中创建一个存储池,此处名为 OpenStack-Glance
。随后创建对应用户:
ceph auth get-or-create client.glance mon 'profile rbd' osd 'profile rbd pool=OpenStack-Glance' -o /etc/ceph/ceph.client.glance.keyring
chmod 600 /etc/ceph/ceph.client.glance.keyring
容器部署
在三台服务器上各创建一个 LXC,配置 2C2G,使用 8G 系统盘,无性能要求,可以使用 Ceph RBD。
防火墙开放 9292/tcp
向 VIP 即可。
安装组件:
apt install glance python3-openstackclient ceph-common
配置 Glance /etc/glance/glance-api.conf
:
[DEFAULT]
enabled_backends = ceph:rbd
bind_host = 10.2.1.161
bind_port = 9292
log_dir = /var/log/glance/
transport_url = rabbit://Glance:aX8ZzoFidQiWYfuu@10.2.0.15:5672/Glance
[api]
workers = 2
enable_v1_api = false
enable_v2_api = true
[glance_store]
default_backend = ceph
stores = rbd
[ceph]
rbd_store_pool = OpenStack-Glance
rbd_store_user = glance
rbd_store_ceph_conf = /etc/ceph/ceph.conf
store_description = "Ceph RBD Backend"
[database]
connection = mysql+pymysql://Glance:<Glance_DBPASS>@10.2.0.10/Glance
[keystone_authtoken]
www_authenticate_uri = http://10.2.0.160:5000
auth_url = http://10.2.0.160:5000
memcached_servers = 10.2.1.17:11211,10.2.2.17:11211,10.2.3.17:11211
auth_type = password
project_domain_name = Default
user_domain_name = Default
project_name = service
username = glance
password = <GLANCE_PASS>
service_token_roles_required = True
region_name = RegionOne
interface = internal
[paste_deploy]
flavor = keystone
在任意节点运行一次初始化数据库:
su -s /bin/bash glance -c "glance-manage db_sync"
随后可用 systemctl 管理:
systemctl enable glance-api
systemctl start glance-api
负载均衡配置
首先为 Keepalived 添加 VIP 10.2.0.161
,随后添加如下的 HAProxy 配置:
frontend glance_frontend
bind 10.2.0.161:9292
mode tcp
default_backend glance_backend
backend glance_backend
mode tcp
balance roundrobin
option httpchk GET /versions
source 10.2.0.161
server Glance-1 10.2.1.161:9292 check
server Glance-2 10.2.2.161:9292 check
server Glance-3 10.2.3.161:9292 check
完成后可运行下方命令检测是否正常运行:
glance stores-info
进一步地,可上传 CirrOS 镜像测试 Glance 服务是否正确运行:
wget http://download.cirros-cloud.net/0.6.3/cirros-0.6.3-x86_64-disk.img
openstack image create "cirros-0.6.3-x86_64" \
--file cirros-0.6.3-x86_64-disk.img \
--disk-format qcow2 --container-format bare \
--public
openstack image list
Placement 集群部署
Placement 是 OpenStack 中的一个独立的 REST API 服务,用于追踪、查询、报告 OpenStack 的资源提供者(计算、共享存储、IP 池等)。我们这里仍使用三节点集群进行部署。
集群的 IP 设定为 10.2.x.162/16
,VIP 为 10.2.0.162/16
。
预配置
在数据库中创建数据库 Placement,创建账号 Placement@10.2.%.162
并授予对应权限。
通过 Keystone 注册 Placement 账户:
openstack user create --domain default --password <PLACEMENT_PASS> placement
openstack role add --project service --user placement admin
openstack service create --name placement --description "Placement API" placement
openstack endpoint create --region RegionOne placement public http://10.2.0.162:8778
openstack endpoint create --region RegionOne placement internal http://10.2.0.162:8778
openstack endpoint create --region RegionOne placement admin http://10.2.0.162:8778
容器部署
在三节点上各自创建一个 LXC,配置 1C1G 即可,配以 8G 硬盘,可以使用低速系统盘。
防火墙向 VIP 开启 8778/tcp
。
安装 Placement 组件:
apt install placement-api python3-pymysql python3-openstackclient
随后配置 Placement /etc/placement/placement.conf
:
[DEFAULT]
debug = false
[api]
auth_strategy = keystone
[keystone_authtoken]
www_authenticate_uri = http://10.2.0.160:5000
auth_url = http://10.2.0.160:5000
memcached_servers = 10.2.1.17:11211,10.2.2.17:11211,10.2.3.17:11211
auth_type = password
project_domain_name = Default
user_domain_name = Default
project_name = service
username = placement
password = <PLACEMENT_PASS>
service_token_roles_required = True
region_name = RegionOne
interface = internal
[placement_database]
connection = mysql+pymysql://Placement:<PLACEMENT_DBPASS>@10.2.0.10/Placement
可在 Apache 配置 /etc/apache2/sites-enabled/placement-api.conf
内调整线程数(processes
)至 CPU 核心数:
WSGIDaemonProcess placement-api processes=1 threads=1 user=placement group=placement display-name=%{GROUP}
完成后在一个节点上运行下面的命令初始化数据库:
su -s /bin/sh -c "placement-manage db sync" placement
完成后通过 systemctl 管理 Apache2 提供服务:
systemctl enable apache2
systemctl restart apache2
在配置完成 Nova 后会显示信息。
负载均衡配置
添加 VIP 10.2.0.162
至 Keepalived,随后配置 HAProxy:
frontend placement_frontend
bind 10.2.0.162:8778
mode tcp
default_backend placement_backend
backend placement_backend
mode tcp
balance roundrobin
option httpchk GET /placement
source 10.2.0.162
server Placement-1 10.2.1.162:8778 check
server Placement-2 10.2.2.162:8778 check
server Placement-3 10.2.3.162:8778 check
可通过执行下面的命令验证是否运行正常:
openstack resource provider list
Nova 控制面集群部署
Nova 为 OpenStack 中控制 VM 生命周期的组件,但是在此阶段我们仅部署 Nova 控制面,包含以下四个组件:
- nova-api:接受用户,服务的 API 请求。
- nova-scheduler:根据资源调度计算节点。
- nova-conductor:与数据库通信,解耦计算端。
- nova-novncproxy:提供 Web 控制台(VNC)访问。
这些组件均可进行多副本部署。
此处集群使用 IP 10.2.x.163/16
,VIP 为 10.2.0.163
。
预配置
创建数据库 Nova
,Nova_api
,与 Nova_cell0
。创建账号 Nova@10.2.%.163
同时授权三个数据库即可。
RabbitMQ 创建 vhost /Nova
并创建对应权限账号。
通过 Keystone 创建 Nova 账户:
openstack user create --domain default --pasword <Nova_PASS> nova
openstack role add --project service --user nova admin
openstack service create --name nova --description "OpenStack Compute" compute
openstack endpoint create --region RegionOne compute public http://10.2.0.163:8774/v2.1
openstack endpoint create --region RegionOne compute internal http://10.2.0.163:8774/v2.1
openstack endpoint create --region RegionOne compute admin http://10.2.0.163:8774/v2.1
容器部署
在三个节点上各创建一个 LXC,配置 4C4G,磁盘 20G,可使用慢速磁盘。
防火墙开放端口 8774/tcp
至 VIP。
安装服务:
apt install nova-api nova-conductor nova-novncproxy nova-scheduler neutron-common python3-neutronclient
配置 Nova /etc/nova/nova.conf
:
[DEFAULT]
my_ip = 10.2.1.163
transport_url = rabbit://Nova:<NOVA_RMQPASS>@10.2.0.15:5672/Nova
[api_database]
connection = mysql+pymysql://Nova:<NOVA_DBPASS>@10.2.0.10/Nova_api
[database]
connection = mysql+pymysql://Nova:<NOVA_DBPASS>@10.2.0.10/Nova
[api]
auth_strategy = keystone
[keystone_authtoken]
www_authenticate_uri = http://10.2.0.160:5000
auth_url = http://10.2.0.160:5000
memcached_servers = 10.2.1.17:11211,10.2.2.17:11211,10.2.3.17:11211
auth_type = password
project_domain_name = Default
user_domain_name = Default
project_name = service
username = nova
password = <NOVA_PASS>
[service_user]
send_service_user_token = true
[vnc]
enabled = true
server_listen = 10.2.1.163
server_proxyclient_address = 10.2.1.163
[glance]
api_servers = http://10.2.0.161:9292
[placement]
auth_url = http://10.2.0.160:5000
auth_type = password
region_name = RegionOne
project_domain_name = Default
user_domain_name = Default
project_name = service
username = placement
password = <PLACEMENT_PASS>
# 先提供对 neutron 的集成,正确运行可能需要在完成 neutron 的部署之后
[neutron]
auth_url = http://10.2.0.160:5000
auth_type = password
region_name = RegionOne
project_domain_name = Default
user_domain_name = Default
project_name = service
username = neutron
password = <NEUTRON_PASS>
url = http://10.2.0.164:9696
service_metadata_proxy = true
metadata_proxy_shared_secret = <METADATA_SECRET>
[cinder]
os_region_name = RegionOne
[oslo_concurrency]
lock_path = /var/lib/nova/tmp
初始化各个数据库(在一个节点上运行):
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
最后重启所有服务:
systemctl restart nova-api
systemctl restart nova-scheduler
systemctl restart nova-conductor
systemctl restart nova-novncproxy
负载均衡配置
添加 VIP 10.2.0.163
至 Keepalived,随后配置 HAProxy:
frontend nova_api_frontend
bind 10.2.0.163:8774
mode tcp
default_backend nova_api_backend
backend nova_api_backend
mode tcp
balance roundrobin
option httpchk GET /v2.1
source 10.2.0.163
server Nova-Controller-1 10.2.1.163:8774 check
server Nova-Controller-2 10.2.2.163:8774 check
server Nova-Controller-3 10.2.3.163:8774 check
完成后可以运行下面的命令,应当可以见到类似这样的输出:
# 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:****@10.2.0.10/Nova_cell0 | False |
| cell1 | 458b85fa-28d2-478f-a563-91390471324c | rabbit://Nova:****@10.2.0.15:5672/ | mysql+pymysql://Nova:****@10.2.0.10/Nova | False |
+-------+--------------------------------------+------------------------------------+------------------------------------------------+----------+
Neutron 控制面集群部署
Neutron 为 OpenStack 中负责管理网络的组件,其同样分为两部分,即控制面与计算面。在这里我们先仅部署控制面。
Neutron 的部署可以选择两种方式:一种是简单的架构,仅将虚拟机实例连接到外部网络;另一种额外添加了 L3 服务,支持将虚拟机连接到一些内部构建的网络中。此处我们选择使用第二种方式部署。
集群使用 IP 10.2.x.164/16
,VIP 为 10.2.0.164/16
。
预配置
创建数据库 Neutron
,并创建对应用户,赋予权限。
在 RabbitMQ 上创建 vhost /Neutron
,并创建对应权限用户。
通过 Keystone 创建 Neutron 用户:
openstack user create --domain default --password <NEUTRON_PASS> neutron
openstack role add --project service --user neutron admin
openstack service create --name neutron --description "OpenStack Networking" network
openstack endpoint create --region RegionOne network public http://10.2.0.164:9696
openstack endpoint create --region RegionOne network internal http://10.2.0.164:9696
openstack endpoint create --region RegionOne network admin http://10.2.0.164:9696
虚拟机部署
在三台服务器上各创建一个虚拟机,配置 4C4G,配以 16G 磁盘,可以使用低速盘。由于 Neutron 需要对网络设备的高权限操作,因此我们这里使用虚拟机而非继续使用容器。
防火墙开启 9696/tcp
向 VIP 放通。
容器开启 nesting=1,keyctl=1,fuse=1
。
安装组件:
apt install neutron-server neutron-plugin-ml2 neutron-openvswitch-agent neutron-l3-agent neutron-dhcp-agent neutron-metadata-agent
修改 Neutron 配置 /etc/neutron/neutron.conf
:
[DEFAULT]
core_plugin = ml2
service_plugins = router
transport_url = rabbit://Neutron:<NEUTRON_RMQPASS>@10.2.0.15/Neutron
notify_nova_on_port_status_changes = true
notify_nova_on_port_data_changes = true
[database]
connection = mysql+pymysql://Neutron:<NEUTRON_DBPASS>@10.2.0.10/Neutron
[keystone_authtoken]
www_authenticate_uri = http://10.2.0.160:5000
auth_url = http://10.2.0.160:5000
memcached_servers = 10.2.1.17:11211,10.2.2.17:11211,10.2.3.17:11211
auth_type = password
project_domain_name = Default
user_domain_name = Default
project_name = service
username = neutron
password = <NEUTRON_PASS>
[nova]
auth_url = http://10.2.0.160:5000
auth_type = password
region_name = RegionOne
project_domain_name = Default
user_domain_name = Default
project_name = service
username = nova
password = <NOVA_PASS>
[oslo_concurrency]
lock_path = /var/lib/neutron/tmp
随后配置 ML2 插件 /etc/neutron/plugins/ml2/ml2_conf.ini
:
[ml2]
type_drivers = flat,vlan,vxlan
tenant_network_types = vxlan
mechanism_drivers = openvswitch,l2population
extension_drivers = port_security
[ml2_type_flat]
flat_networks = provider
[ml2_type_vxlan]
vni_ranges = 11:1000
创建 OVS Bridge 连接到 Provider Network。此处不打算为 OpenStack 虚拟机提供更上一层的网络,因此直接桥接到该虚拟机的公网接口即可:
ovs-vsctl add-br br-www
ovs-vsctl add-port br-www eth0
配置 Open vSwitch /etc/neutron/plugins/ml2/openvswitch_agent.ini
:
[ovs]
bridge_mappings = provider:br-www
local_ip = 10.2.1.164
[agent]
tunnel_types = vxlan
l2_population = true
[securitygroup]
enable_security_group = true
firewall_driver = openvswitch
随后修改 /etc/neutron/dhcp_agent.ini
配置 Dnsmasq DHCP 驱动程序和隔离元数据:
[DEFAULT]
dhcp_driver = neutron.agent.linux.dhcp.Dnsmasq
enable_isolated_metadata = true
配置元数据代理 /etc/neutron/metadata_agent.ini
:
[DEFAULT]
nova_metadata_host = 10.2.0.163
metadata_proxy_shared_secret = <METADATA_SECRET>
最后,初始化数据库:
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
最后重启所有服务即可:
systemctl restart neutron-server
systemctl restart neutron-openvswitch-agent
systemctl restart neutron-dhcp-agent
systemctl restart neutron-metadata-agent
systemctl restart neutron-l3-agent
负载均衡配置
添加 VIP 10.2.0.164
至 Keepalived,随后 HAProxy 添加如下配置:
frontend neutron_frontend
bind 10.2.0.164:9696
mode tcp
default_backend neutron_backend
backend neutron_backend
mode tcp
balance roundrobin
option httpchk GET /
source 10.2.0.164
server Neutron-1 10.2.1.164:9696 check
server Neutron-2 10.2.2.164:9696 check
server Neutron-3 10.2.3.164:9696 check
完成后可以测试如下命令验证是否正常运行:
openstack network agent list
Cinder 控制节点集群部署
Cinder 是 OpenStack 的块存储服务。通常将 Cinder 的部署分为三个部分:Controller,Storage 和 Backup。这里我们先部署 Controller。
集群 IP 为 10.2.x.165/16
,VIP 为 10.2.0.165/16
。
预配置
创建数据库 Cinder
,创建对应用户并配置权限。
配置 RabbitMQ vhost /Cinder
并创建对应用户和配置对应权限。
在 Keystone 创建 Cinder 用户:
openstack user create --domain default --password <CINDER_PASS> cinder
openstack role add --project service --user cinder admin
openstack service create --name cinderv3 --description "OpenStack Block Storage" volumev3
openstack endpoint create --region RegionOne volumev3 public http://10.2.0.165:8776/v3/%\(project_id\)s
openstack endpoint create --region RegionOne volumev3 internal http://10.2.0.165:8776/v3/%\(project_id\)s
openstack endpoint create --region RegionOne volumev3 admin http://10.2.0.165:8776/v3/%\(project_id\)s
容器配置
在每台服务器上创建一个 LXC,配置 2C2G,磁盘 10G,可以使用低速存储。
防火墙开放 8776/tcp
向 VIP。
安装依赖:
apt install cinder-api cinder-scheduler
修改 Cinder 配置 /etc/cinder/cinder.conf
:
[DEFAULT]
my_ip = 10.2.1.165
auth_strategy = keystone
transport_url = rabbit://Cinder:<CINDER_RMQPASS>@10.2.0.15/Cinder
[database]
connection = mysql+pymysql://Cinder:<CINDER_DBPASS>@10.2.0.10/Cinder
[keystone_authtoken]
www_authenticate_uri = http://10.2.0.160:5000
auth_url = http://10.2.0.160:5000
memcached_servers = 10.2.1.17:11211,10.2.2.17:11211,10.2.3.17:11211
auth_type = password
project_domain_name = Default
user_domain_name = Default
project_name = service
username = cinder
password = <CINDER_PASS>
[oslo_concurrency]
lock_path = /var/lib/cinder/tmp
完成后初始化数据库:
su -s /bin/sh -c "cinder-manage db sync" cinder
随后 systemctl 重启应用配置即可:
systemctl restart cinder-scheduler
systemctl restart apache2
负载均衡配置
frontend cinder_controller_frontend
bind 10.2.0.165:8776
mode tcp
default_backend cinder_controller_backend
backend cinder_controller_backend
mode tcp
balance roundrobin
option httpchk GET /
source 10.2.0.165
server Cinder-Controller-1 10.2.1.165:8776 check
server Cinder-Controller-2 10.2.2.165:8776 check
server Cinder-Controller-3 10.2.3.165:8776 check
Cinder 存储节点集群部署
Cinder 存储节点负责管理和创建块设备,此处连接 Ceph RBD 后端。
此处集群 IP 10.2.x.166/16
。
预配置
在 Ceph 创建一个存储池 OpenStack-Cinder
,随后创建对应账户:
ceph auth get-or-create client.cinder mon 'profile rbd' osd 'profile rbd pool=OpenStack-Cinder' -o /etc/ceph/ceph.client.cinder.keyring
chmod 600 /etc/ceph/ceph.client.cinder.keyring
容器部署
在三个节点上各自创建一个 LXC,配置 2C4G,使用 10G SSD 作为存储盘。
安装依赖:
apt install ceph-common
apt install cinder-volume --no-install-recommends
配置 /etc/cinder/cinder.conf
:
[DEFAULT]
my_ip = 10.2.1.166
auth_strategy = keystone
transport_url = rabbit://Cinder:<CINDER_RMQPASS>@10.2.0.15/Cinder
enabled_backends = ceph
[ceph]
volume_driver = cinder.volume.drivers.rbd.RBDDriver
rbd_pool = OpenStack-Cinder
rbd_user = cinder
rbd_ceph_conf = /etc/ceph/ceph.conf
rbd_secret_uuid = <UUID> # 可以使用 uuidgen 生成 UUID
volume_backend_name = ceph
[database]
connection = mysql+pymysql://Cinder:<CINDER_DBPASS>@10.2.0.10/Cinder
[keystone_authtoken]
www_authenticate_uri = http://10.2.0.160:5000
auth_url = http://10.2.0.160:5000
memcached_servers = 10.2.1.17:11211,10.2.2.17:11211,10.2.3.17:11211
auth_type = password
project_domain_name = Default
user_domain_name = Default
project_name = service
username = cinder
password = <CINDER_PASS>
[oslo_concurrency]
lock_path = /var/lib/cinder/tmp
完成后使用 systemctl 管理:
systemctl restart cinder-volume
Horizon 集群部署
最后,我们需要完成 OpenStack 仪表盘服务 Horizon 的部署。这里我们还是使用三节点的集群方案。
集群 IP 10.2.x.167/16
,VIP 10.2.0.167/16
。
容器部署
在三节点上各创建一个 LXC,配置 2C2G,10G 磁盘,对磁盘性能无高要求。
安装组件:
apt install openstack-dashboard
编辑 Horizon 配置 /etc/openstack-dashboard/local_settings.py
:
OPENSTACK_HOST = "10.2.0.160"
OPENSTACK_KEYSTONE_URL = "http://%s:5000/identity/v3" % OPENSTACK_HOST
ALLOWED_HOSTS = ['one.example.com', 'two.example.com']
SESSION_ENGINE = 'django.contrib.sessions.backends.cache'
CACHES = {
'default': {
'BACKEND': 'django.core.cache.backends.memcached.PyMemcacheCache',
'LOCATION': [
'10.2.1.17:11211',
'10.2.2.17:11211',
'10.2.3.17:11211'
]
},
}
OPENSTACK_KEYSTONE_MULTIDOMAIN_SUPPORT = True
OPENSTACK_KEYSTONE_DEFAULT_DOMAIN = "Default"
TIME_ZONE = "Asia/Shanghai"
随后重启 apache2 即可:
systemctl reload apache2
负载均衡配置
添加 VIP 10.2.0.167
至 Keepalived,随后配置 HAProxy:
frontend horizon_frontend
bind 10.2.0.167:9898
mode tcp
default_backend horizon_backend
backend horizon_backend
mode tcp
balance roundrobin
option httpchk GET /horizon/
source 10.2.0.167
http-request set-header Host %[req.hdr(Host)]
http-request set-header X-Forwarded-Proto https
http-request set-header X-Forwarded-For %[src]
server Horizon-1 10.2.1.167:80 check
server Horizon-2 10.2.2.167:80 check
server Horizon-3 10.2.3.167:80 check
Comments | NOTHING