【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对象存储的交互,以及部署应用程序。