【OpenStack】创建系统(VM)实例镜像及实例创建方法
@TOC
推荐超级课程:

在最后的 post 中,我们回顾了项目的设计,并设置了项目环境。在这篇文章中,我们将开始设置项目的工作组件并开始测试。
创建计算镜像
对于一些人来说,这是一个可能会让人感到困惑的练习部分,因为提供解决方案的方法有很多种。由于镜像生成的方式很多,而且可以支持的格式也多种多样 ,我会专注于使用可复现的过程部署 VM 镜像。我不会考虑容器,因为这需要 Magnum 容器编排器 或者 Zun 容器服务器 ,但在另一个系列中值得一看。
考虑到 OpenStack 是一个组织技术(类似于 Kubernetes,但用于虚拟机),您可以开始理解 [Nova(计算组件)作为一个像 QEMU、VirtualBox 或 Xen 这样的虚拟机控制器。这意味着您可以像在本地机器上启动 VM 一样在 OpenStack 上运行 VM。让我们看看其中的一些方式。
加载基本镜像
在开始本节中的任何内容之前,所有选项都需要在某个时候上传一个新镜像。首先从流行的发行版中准备准备镜像。OpenStack 提供了一个可以支持的流行选项列表
。未来自动化的一个重要考虑因素是在基本包中包含 cloud-init
。有一种方式可以自动完成这个(通过 DevStack 的 local.conf 文件),当我们第一次设置实例时。
在此项目中,我将使用 Debian Buster 云映像 ,因为其简单性和稳定性。
- 前往上面的链接,找到最新版本。从列表中下载
debian-10-openstack-amd64.qcow2文件。 - 下载完毕后,在 OpenStack Dashboard 中打开 Project 部分,选择 Images。选择“Create Image”以打开创建镜像对话框。
- 在新对话框中指定以下选项:
- Image Name:
debian-buster - 文件:查找下载的文件(
debian-10-openstack-amd64.qcow2) - 格式:
QCOW2 - 最小磁盘(GB):
3。如果您想要在将来避免麻烦,可以将其设置为此值。 - Visibility:(可选)设置为
Public。这将允许跨所有项目访问。在维基中可以查看更多信息:Glance V2 Community Image Visibility Design
- Image Name:

- 点击 Create Image 上传镜像到 Glance。
上传完成后,镜像即可使用。对于接下来的部分,按照相同的步骤为其他镜像类型进行操作。
预建镜像
由于实际上是在 OpenStack 中构建 VM,所以可以在准备就绪后创建 VM 镜像并加载到 OpenStack。由于我们不会按照这些步骤操作,我会跳过很多内容。
例如,在 Linux 上使用 QEMU/Virtual Manager,我可以准备一个 VM,使用 Ubuntu 20.04,带有一个 10GB(未填充)的磁盘,在控制台上按照指示安装 PostgreSQL 13(从 PostgreSQL APT 存储库中)。

一旦将镜像设置为您想要的状态并可以自动启动所有所需的服务,关闭实例并将 QCOW2(或其他磁盘格式)的 VM 上传到 OpenStack。从 Project 部分,打开 Images 并为您刚刚创建的镜像点击“Create Image”。
可用后,“Launch Instance” 将准备此镜像为磁盘卷,以供在 VM 中运行并启动。选择磁盘大小,实例规格(例如 m1.medium),然后启动实例。这将使用镜像创建磁盘,将 VM 配置到可用网络并启动。

现在使用这种加载方式存在一些问题:
- 如果要存储一个 2-5GB 大小的镜像,则占用更多内存。加载较大的镜像也会存在问题,因为该服务可能在上传过程中出现超时错误。
- 如果要部署多个相同的镜像实例,将需要配置网络接口为自动 DHCP。
- 需要为每个实例特定地配置每个镜像。
手动实例创建
改进此过程的一种方法是使用 OpenStack 环境作为您的虚拟机控制器,在无需每次上传新镜像的情况下配置您的实例。这将大大减少要维护的镜像数量,并节省管理这些实例所需的时间。
与之前一样,与其选择任意控制器中创建 VM,不如选择一个基本镜像启动新实例(我们已经上传了一个)并进行配置。
我不会详细讨论,但步骤基本上与之前相同,只是顺序稍有不同(在 OpenStack 中启动实例后设置镜像,而不是之前)。这将大大提高磁盘使用情况和节省时间,允许对每个实例进行非常自定义的配置。
但它仍然存在一些问题:
- 为任何大型应用程序设置需要很长时间
- 许多手动交互意味着有很多人为错误的可能性
cloud-init 搭救
cloud-init 是一个独立的软件包,其中包含在基本镜像中安装的脚本和应用程序,这些脚本和应用程序在首次引导时运行并等待提供配置。这些配置定义系统配置的所有方面和运行设置实例的命令。这些配置很容易保存和管理在 Git 存储库或其他位置。如果发生任何问题或意外,您可以使用可用的配置快速启动新实例。
OpenStack 通过符合 EC2 的 Metadata Service 提供对 cloud-init UserData 的访问,以在启动过程中允许您包含定义实例的配置需求。这意味着在启动了基本实例后,您可以登录到具有所有 OS 配置、创建的用户帐户和安装的应用程序的实例。
在此练习中,我们希望创建一个数据库主机,使用 PostgreSQL 14 存储我们的对象元数据和查询功能,并在以后实现扩展/多服务器配置。
使用 cloud-init 配置启动实例
Cloud-Init 有许多部分可用于配置实例。其中一些部分可以“植入”到基本镜像中,而其他部分可以通过 Metadata Service 提供。我们要提供的是 cloud-config(或用户数据)部分,它将允许我们创建用户、在初始化后设置 OS,并开始安装应用程序并将其设置。
由于我们的项目包含两个节点,我们将首先从需要我们开始构建应用程序的节点,即数据库服务器开始。我们将按照定义启动实例的相同步骤进行操作,但在完成之前,我们还要在“Configuration”部分包括所需的配置。在这里,我们可以包含一个配置文件(通常作为 YAML 文件),其中包含我们要设置的内容。

- 详细信息:将 实例名称 设置为
db - 来源:
- 大小(GB):
5 - 分配
debian-buster镜像
- 大小(GB):
- 规格:
- 分配
ds2G
- 分配
- 配置:在 自定义脚本 下包含以下代码:
#cloud-config
users:
- name: app
ssh-authorized-keys:
- $SSH_PUBLIC_KEY
sudo: ['ALL=(ALL) NOPASSWD:ALL']
groups: sudo
shell: /bin/bash
growpart:
mode: auto
device: ["/"]
ignore_growroot_disabled: False
package_update: true
package_upgrade: true
runcmd:
- apt install -y curl ca-certificates gnupg
- curl https://www.postgresql.org/media/keys/ACCC4CF8.asc | gpg --dearmor | tee /etc/apt/trusted.gpg.d/apt.postgresql.org.gpg >/dev/null
- echo "deb http://apt.postgresql.org/pub/repos/apt buster-pgdg main" > /etc/apt/sources.list.d/pgdg.list
- apt update
- apt install -qy postgresql-14
- echo "host all all 0.0.0.0/0 scram-sha-256" > /etc/postgresql/14/main/pg_hba.conf
- sed -i "s/^#listen_addresses = 'localhost'/listen_addresses = '*'/g" /etc/postgresql/14/main/postgresql.conf
- systemctl restart postgresql
- sudo -u postgres createuser app
- sudo -u postgres createdb app
- sudo -u postgres psql -c "alter user app with encrypted password '$APP_PASSWORD';"
- sudo -u postgres psql -c "grant all privileges on database app to app;"
此 YAML 配置包含 cloud-init 特定于的配置(如创建用户帐户和各种 OS 更改)。runcmd 部分列出了我想要在设置完成后运行的所有命令,以满足我需要的所有内容。
注意:请记得用相关值替换
$SSH_PUBLIC_KEY和$APP_PASSWORD。您的公共 SSH 密钥(通常在您的主目录中,如".ssh/id_rsa.pub")将允许您SSH 登录到新的实例而无需密码。如果您打算从多台计算机连接,请甚至可以提供多个 SSH 密钥。对于数据库密码,请使用一个独特的内容,因为这将由我们的应用程序用来连接到数据库。
输入完毕后,点击 Create Instance 创建新实例并加载其配置。在 Log 标签中,将显示在系统上生成的最近日志的缩略输出。即使系统已经完成启动,cloud-init 任务可能仍在运行。当您看到 "Reached target Cloud-init target" 时,表示任务已完成。尽管我们有访问 Console 标签的权限,使得我们可以虚拟查看新实例,但由于我们的用户帐户没有密码,所以无法从这里登录到实例。稍后我们将处理这个问题。

连接到您的新实例
现在您有一个正在运行的数据库实例,我们希望使用它来测试连接并开始开发。这需要一些设置,我们将在这里进行:
- Floating IP:用于访问我们的实例,即使是临时的,也可以在云外部访问。
- SSH 隧道:这将允许我们在 DevStack 主机和我们的数据库服务器之间创建一个端口隧道。我们将使用它来测试我们的连接并开发我们的代码。
为实例分配 Floating IP
在我们的最后一篇文章中,我们已经创建了一个 Floating IP,但认为应该在这里更详细解释一下它的作用。
Floating IP 是用于将内部网络打开到公共网络的接口(或网关,或隧道),只要指定了路由器。与其把公共网络看作必须路由到的网络,最好将其视为我们可以保留的公共地址池。其他项目也会使用这个“池”,因此很可能,您将受到可以创建的 Floating IP 数量的限制。
例如,一个具有 CIDR 为 172.24.0.0/27 的公共网络,位范围为 5(32 - 27),这意味着有 29 个接口(25 - 1 网络地址 - 1 网关,如果使用 - 1 广播地址),为您提供一个 172.24.0.2 - 172.24.0.30 的地址池。如果在托管的 OpenStack 中工作,管理员可能会对每个项目能够创建多少个 Floating IP 设置很多限制,从而为每个项目保留一组固定数量的地址。
另外,一个 Floating IP 是一个进入我们项目的接口。在生产环境中,这将成为一个攻击向量和安全风险,因此我们必须限制项目使用的 Floating IP 数量。即使对于我们自己的私有云,使用太多 Floating IP 也会有限制。向项目提供无限数量的 Floating IP 很容易,但我们的硬件资源现在需要处理通过这些接口的所有流量规则(安全组)。
对于我们的项目目的,我们将设置一个专门用于测试我们数据库的 Floating IP(将来,我们将使用一个 跳板主机 来执行此任务)。
继续我们从新的 db 实例开始的工作,单击右上角的下拉菜单。这将提供一个可以对我们的实例执行的操作的长列表。在我们的练习中,我们要选择“关联浮动IP”。

将会出现一个对话框,提示您分配一个现有IP,我们有生成新IP的选项(使用+按钮),但我们已经有一个可用。在对话框中选择下拉列表,将IP分配给此实例。

创建SSH隧道
到目前为止,如果您做得没错,您应该已经有一个带有PostgreSQL数据库的VM实例,在该实例上启动了OpenSSH服务器,并具有可以公开访问(或至少可以在OpenStack之外访问)的IP地址。让我们来使用它吧!
首先,我们将测试对我们的新实例的访问权限。由于这是在我们的DevStack VM上,我们首先需要SSH进入该VM。如果您是在带有桌面的VM上使用,请登录到其图形控制台。
ssh stack@my_devstack_vm
接下来,我们将需要SSH进入我们的新PostgreSQL VM。由于我们分配了一个浮动IP,我们将使用它访问我们的数据库。
ssh app@172.24.0.196 # 或者您生成的浮动IP。
确认系统的SSH指纹后,您现在应该在新的VM上了。这就像是任何其他系统一样。您可以在这个系统上进行一些操作,但我们有工作要做。由于这将是我们应用程序的数据库,我们应该访问该数据库。
psql -d app -U app
q # 退出
从这里,您可以运行一些命令来验证当前可用的内容,但除了数据库和用户之外,还没有配置任何数据库。我们将在下一篇文章中处理这个问题。但让我们来到关键部分,创建一个SSH隧道。
由于我们的SSH密钥已在这个新实例上识别,我们可以在我们的DevStack主机和这个DB之间创建一个隧道。这将在我们的DevStack主机上打开一个端口,将所有流量传输到我们的DB,使其看起来像我们的DB在主机上本身。从DevStack主机执行此命令如下:
ssh <user>@<host_address> -L [<bind_address>:]<local_port>:<target_address>:<target_port>
关于这个命令的简短说明是:
- host_address 是我们将要SSH进入的地址。这是隧道的另一端将会存在的地方。
- local_port 是将打开以处理流量的本地端口号。
- target_address 是流量将被推送到的地址。在这种情况下,因为我们正在创建一个隧道进入我们的数据库,这将是
localhost。此命令也可以与跳转主机和target_address将任何跳转主机将可以访问的地址一起使用。 - target_port 将连接的
target_address上的端口号。 - 可选的 bind_address 告诉谁将具有对此端口的访问权限。默认情况下,它只会创建一个本地套接字(您只能从本地机器访问它)。添加绑定地址可以允许您的网络上的其他系统连接。
返回到我们的设置,我们已经在DevStack主机上的SSH实例中。从这里,我们将直接创建一个隧道到我们的PostgreSQL DB实例。这将使我们的命令如下:
ssh app@172.24.0.196 -L 0.0.0.0:5432:localhost:5432
这将在您的控制台中打开一个SSH连接,但在后台,DevStack主机上的端口5432也会被打开。只要这个连接保持打开状态,这个端口就会处于活动状态。
测试一下,如果我们打开一个新的控制台(并且您在本地安装了psql命令,或者某个配置了PostgreSQL驱动程序的IDE),您应该可以访问到这个数据库。例如,这里是从我的本地PyCharm实例发起的连接:

结论
这是一个很大的文章,但我们在这里涵盖了很多内容:
- 将基础映像添加到我们的OpenStack项目
- 使用
cloud-init创建一个新实例来设置我们的账户,复制SSH密钥,安装数据库并开始配置数据库。 - 为了开发目的,为我们的数据库创建并关联一个外部可用的浮动IP。
- 使用新的浮动IP,介绍了如何使用SSH隧道从本地计算机连接到我们的数据库。
项目正在逐渐形成,下一篇文章中我们将涵盖工作的编码组件。不用担心,我已经做了所有的工作,您只需要部署它。但这也应该让您对OpenStack提供的一些功能有一个较为全面的了解,包括内部网络通信、与OpenStack的STaaS(存储作为服务)Swift对象存储的交互,以及部署应用程序。