使用 Ceph 和 OpenStack 构建公共 AMI
为了向人们展示 OpenStack 和 Ceph 如何协同工作,我决定构建一个用于其 Elastic Compute Cloud (EC2) 的 Amazon Machine Image (AMI)。这将使人们能够展示集成,最终用户获得一个可用的示例,以及开发人员获得一个潜在的易于启动的环境来构建。当然,我不是一个 devops 专家,所以许多假设和 init 脚本可能会让经验丰富的专家感到不舒服并咬牙切齿。请记住,补丁欢迎! ![]()
对于那些喜欢跳到故事结尾的人,请随时前往 Amazon 并搜索公共镜像中的‘ceph-openstack’或 AMI ID ‘ami-2fbf3746’并使用以下限制启动
- m1.xlarge 实例大小
- 创建一个新的或使用现有的 ssh 密钥
- 创建一个相对宽松的安全组(我只是将其对所有端口开放)
以下所有详细信息都包含在一个文本文件中,位于 /home/ubuntu/。其余的人可以阅读我对 EC2 提出的一些挑战的 hacky 解决方案。其中一些问题是
- 静态主机名(ec2 默认情况下不太好玩,但像 rabbitMQ 这样的服务更喜欢静态主机名)
- 动态 IP(Ceph MON 不喜欢 IP 更改)
- 干净的 OpenStack 安装(DevStack 对于此非常棒,但必须进行一些修改)
- 预构建的可启动 Ceph 卷(Ceph/OpenStack 能够从 Ceph 卷启动是关键点之一)
每个问题都由我创建的 /usr/local/ec2/ 中的 init 脚本处理,并添加到 rc.local。现在进入正题!
使您的 EC2 主机名静态 ¶
虽然 EC2 通常会根据几个标准(看起来像 domU- 或 ip-)为您提供一个主机名,但我想要一个我可以控制的静态主机名,以便一些服务可以很好地协同工作。幸运的是,Amazon 提供了一个方便的 API,您可以使用它来动态获取某些信息。我创建了一个 /usr/local/ec2/ec2-hostname.sh 脚本,它将使用适当的信息更新 /etc/hostname 和 /etc/hosts。完成的脚本如下
#!/bin/bash
从 Amazon API 获取 FQDN
DOMAIN=`/usr/bin/curl -s http://169.254.169.254/latest/meta-data/public-hostname`
HOSTNAME='cephdemo' IPV4=`/usr/bin/curl -s http://169.254.169.254/latest/meta-data/public-ipv4`
设置主机名
hostname $HOSTNAME echo $HOSTNAME > /etc/hostname
将 fqdn 添加到 hosts 文件
cat< /etc/hosts
此文件由 ec2-hostname 脚本自动生成
127.0.0.1 localhost $IPV4 $DOMAIN $HOSTNAME
以下行适用于支持 IPv6 的主机
::1 ip6-localhost ip6-loopback fe00::0 ip6-localnet ff00::0 ip6-mcastprefix ff02::1 ip6-allnodes ff02::2 ip6-allrouters ff02::3 ip6-allhosts EOF
这将为我们提供一个主机名为‘cephdemo’,它使用 IPv4 地址和公共主机名(例如:ec2-23-20-118-120.compute-1.amazonaws.com)来解析。这应该为我们提供一个良好的基础,开始安装其他服务,从 Ceph 开始。
安装 Ceph ¶
由于这是一个简单的演示,所有内容都在一台机器上运行,我选择遵循 5 分钟快速入门指南 在 Ceph.com 上。您应该拥有所有需要的资料。此演示框的唯一更改是删除了 /etc/ceph/ceph.conf 中的 MDS,因为我们不会安装任何元数据服务器。
使 Ceph MON IP 动态 ¶
当您启动 Ceph 集群的监视器时,它们期望一个静态 IP,因此我必须进行一些杂技表演,以确保当您启动新的 AMI(具有新的 IP)时,它将使用功能正常的 monmap 启动 Ceph。为此,我们需要获取当前 IP 地址并将其注入到我们的 Ceph 集群中的替换 monmap。幸运的是,Ceph 有一个 monmaptool 可以帮助我们做到这一点。生成的 /usr/local/ec2/update_mon_ip.sh 脚本如下
#!/bin/bash
NEWIP=$(/sbin/ifconfig eth0 | grep 'inet addr:' | cut -d: -f2 | awk '{ print $1}') LATEST=$(/bin/cat /var/lib/ceph/mon/ceph-a/monmap/last_committed)
/bin/sed -i "s/mon addr =.*:/mon addr = $NEWIP:/" /etc/ceph/ceph.conf
mkdir -p /tmp/oldmonmap cp /var/lib/ceph/mon/ceph-a/monmap/$LATEST /tmp/oldmonmap/
/usr/bin/monmaptool --rm a /tmp/oldmonmap/$LATEST /usr/bin/monmaptool --add a $NEWIP:6789 /tmp/oldmonmap/$LATEST
service ceph stop /usr/bin/ceph-mon -i a --inject-monmap /tmp/oldmonmap/$LATEST service ceph start
/bin/rm -rf /tmp/oldmonmap
这将更新 /etc/ceph/ceph.conf,以便客户端知道如何访问 monmap,删除旧的 mon.a 并使用新的 IP 重新添加它,注入新的 monmap,然后重新启动 Ceph。现在,我们应该在需要重新启动时都可以拥有一个正在运行的 Ceph 集群。
安装 OpenStack ¶
为了这个演示,我想要一个干净的 OpenStack,它在创建每个新实例时都会安装和运行。来自 Rackspace Cloud Builder 团队的 DevStack 工作对于快速而肮脏的 OpenStack 安装来说绝对棒极了。它并非设计用于启动生产环境,但它在短时间内让我熟悉并舒适地使用 OpenStack。获取 DevStack 的最简单方法是使用 git,所以我继续安装了它
#> sudo apt-get install git -y
现在我们可以克隆到 devstack
#> cd ~/ #> git clone git://github.com/openstack-dev/devstack.git
在运行魔术安装脚本之前,只需要进行一些设置工作,所以我们导航到 ~/devstack 并创建一个 localrc 文件,其中将包含 IP 范围、网络信息和所有服务密码。最终它应该看起来像这样
FLOATING_RANGE=192.168.1.224/27 FIXED_RANGE=10.0.0.0/24 FIXED_NETWORK_SIZE=256 FLAT_INTERFACE=eth0 ADMIN_PASSWORD=supersecret MYSQL_PASSWORD=iheartdatabases RABBIT_PASSWORD=flopsymopsy SERVICE_PASSWORD=iheartksl
唯一的其他更改是对 stack.sh 安装脚本的轻微调整,以用于我们的自定义 EC2 主机名工作。我希望它使用完全限定域名(ec2 公共 DNS)而不是仅仅使用 IP。这样,当我们使用基于 Web 的仪表板中的 VNC 功能时,它将能够正确解析。因此,编辑 ~/devstack/stack.sh,找到以下两行,并替换 $(hostname –fqdn) 位
NOVNCPROXY_URL=${NOVNCPROXY_URL:-"http://$(hostname --fqdn):6080/vnc_auto.html"} XVPVNCPROXY_URL=${XVPVNCPROXY_URL:-"http://$(hostname --fqdn):6081/console"}
配置完成后,我们就可以让 DevStack 发挥它的魔力了。请记住,它不能以 root 用户身份运行,所以我只是以默认的 ubuntu 用户身份运行它
#> ./stack.sh
您应该看到大量的设置飞速掠过,但完成后,您应该拥有一个正在运行的 OpenStack 安装。现在我们需要配置它以使用 Ceph。
配置 Ceph ¶
由于此设置基于 OpenStack 的 Folsom 版本和 Ceph 的 Argonaut 版本,因此这是一个相当简单的设置。我决定为 Cinder 和 Glance 创建专用的 RBD 池。
#> ceph osd pool create volumes 128 #> ceph osd pool create images 128
我们还需要 python-ceph 客户端库
#> sudo apt-get install python-ceph
下一步是设置池权限,为 cinder 和 glance 创建一对用户帐户,并为每个帐户创建密钥环。
#> ceph auth get-or-create client.volumes mon 'allow r' osd 'allow rwx pool=volumes, allow rx pool=images' #> ceph auth get-or-create client.images mon 'allow r' osd 'allow rwx pool=images'
#> sudo useradd glance #> sudo useradd cinder
#> ceph auth get-or-create client.images | sudo tee /etc/ceph/ceph.client.images.keyring #> sudo chown glance:glance /etc/ceph/ceph.client.images.keyring #> ceph auth get-or-create client.volumes | sudo tee /etc/ceph/ceph.client.volumes.keyring #> sudo chown cinder:cinder /etc/ceph/ceph.client.volumes.keyring
这应该处理 glance 和 cinder 的 Ceph 身份验证,剩下的就是确保 libvirt 可以与 Ceph 通信。不幸的是,libvirt 通过一个密钥来处理身份验证,所以我们必须做一些稍微不同的事情
#> ceph auth get-key client.volumes | tee /home/ubuntu/client.volumes.key
#> cat > secret.xml <<EOF
#> sudo virsh secret-define --file secret.xml
secret 的 UUID 在此处输出,应该如下所示:df92844f-410f-6411-771e-cb65223ecb2e
#> sudo virsh secret-set-value --secret {secret 的 UUID} --base64 $(cat client.volumes.key) && rm client.volumes.key secret.xml
好了,我们应该处理所有身份验证部分。现在我们只需要告诉 OpenStack 使用 Ceph。
配置 OpenStack ¶
为了让 OpenStack 使用 Ceph,我们只需要更改所需的 conf 文件中的几行。我们将通过编辑 /etc/glance/glance-api.conf 和 /etc/cinder/cinder.conf 文件并进行以下更改来执行此操作
编辑 glance-api.conf 中的现有行
#> sudo vi /etc/glance/glance-api.conf
default_store=rbd rbd_store_user=images rbd_store_pool=images
在 cinder.conf 中添加以下行
#> sudo vi /etc/cinder/cinder.conf
volume_driver=cinder.volume.driver.RBDDriver rbd_pool=volumes
rbd_user=volumes rbd_secret_uuid=df92844f-410f-6411-771e-cb65223ecb2e
重新启动 OpenStack 应该是剩下的全部。不幸的是,DevStack 没有安装服务或任何永久内容,而是选择在一系列屏幕窗口中运行所有内容。但是,他们制作了一个 rejoin-stack 脚本,该脚本将根据您的安装重新启动屏幕会话。因此,重新启动 devstack 安装应该如下所示
#> screen -dR ctrl-a :quit #> cd ~/devstack #> ./rejoin-stack.sh ctrl-a d
欢迎来到您的 Ceph 支持的 OpenStack 安装!剩下的工作是准备一个可启动的卷,备份 conf 文件以供将来安装,并创建启动脚本,以便在创建新实例时自动执行所有设置。
创建可启动卷 ¶
为了手动创建可启动卷,现在我们已经连接到 Ceph RBD,我需要启动一个实例并附加一个空白卷。不幸的是,使用 Folsom,我们始终需要存储在 Glance 中的镜像,该镜像与我们想要启动的任何卷相同。OpenStack 存储所有元数据的方式意味着您不能“只是”从卷启动,即使在启动时它不会从镜像中获取任何内容。这正在发生变化,但对于我用于构建此演示的版本,情况仍然如此。
创建可启动卷的步骤如下
登录到 OpenStack 仪表板
http://ec2-107-22-25-74.compute-1.amazonaws.com(您的公共 ec2 地址)用户名:admin 密码:supersecret(在安装 devstack 时在 localrc 中设置)
对于这个例子,我启动了包含的 CirrOS 镜像,这样我就不需要导入新的卷了,但任何镜像都可以使用,无论是 Ubuntu 镜像还是你当前喜欢的镜像。 记住,你需要在下面的 init 脚本中包含步骤,以从 glance CLI 重现镜像,这样你才能拥有示例卷所需的元数据。
创建卷
"项目选项卡" -> 卷 启动卷的空白卷 存储镜像的空白卷
附加卷
“项目选项卡” -> 卷 “编辑附件” 启动卷位于 /dev/vdb 镜像存储位于 /dev/vdc
SSH 到新实例并成为 root
(从 ec2 盒子) #> ssh cirros@10.0.0.2 密码: cubswin:) #> sudo su
在新卷上创建文件系统
#> mkfs.ext3 -b 1024 /dev/vdb 1048576 #> mkfs.ext3 -b 1024 /dev/vdc 1048576
挂载卷
#> mkdir /tmp/stage #> mount /dev/vdb /tmp/stage
#> mkdir /tmp/cirros #> mount /dev/vdc /tmp/cirros
获取并挂载 CirrOS 镜像
(从 ec2 盒子) #> wget https://launchpad.net/cirros/trunk/0.3.0/+download/cirros-0.3.0-x86_64-rootfs.img.gz #> scp cirros-0.3.0-x86_64-rootfs.img.gz cirros@10.0.0.2:/home/cirros/
(从 cirros) #> mv /home/cirros/cirros-0.3.0-x86_64-rootfs.img.gz /tmp/cirros/ #> gunzip cirros-0.3.0-x86_64-rootfs.img.gz #> mkdir /tmp/cirros/mnt #> mount /tmp/cirros/cirros-0.3.0-x86_64-rootfs.img.gz /tmp/cirros/mnt
将镜像复制到卷
#> cp -pr /tmp/cirros/mnt/* /tmp/stage
清理
#> umount /tmp/cirros/mnt #> sync #> umount /tmp/stage
(从 OpenStack 控制台) 取消附加两个卷 删除镜像存储卷
终止 CirrOS 镜像
现在我们有一个存储在 Ceph 中的可启动卷。 你应该能够查看卷信息,或者从 ec2 命令行运行“#> rbd ls -p volumes”,以查看我们稍后在构建 init 脚本时将使用的“黄金”卷的名称。
自动化启动 ¶
现在我们已经设置并运行了所有内容,我们只需要自动化启动过程。 首先,我们需要获取当前的 cinder 和 glance 配置文件,因为它们将在我们将在启动时安装的新安装中被覆盖
#> mkdir /home/ubuntu/backup #> cp /etc/glance/glance-api.conf /home/ubuntu/backup/glance-api.conf #> cp /etc/cinder/cinder.conf /home/ubuntu/backup/cinder.conf
我们应该拥有创建 OpenStack 的一个全新、可用的副本并将其重新连接到 Ceph(Ceph 身份验证信息不会在新 OpenStack 安装中被擦除)所需的一切。 我创建了一个 /usr/local/ec2/restack.sh 脚本来为我执行此操作
#!/bin/bash
#清理进程并重启 rabbit ps -eo pid,command | grep 'erl --' | grep -v grep | awk '{print $1}' | xargs kill -9 service rabbitmq-server restart
#清理 devstack su ubuntu -c 'cd /home/ubuntu/devstack && ./stack.sh'
sleep 10
#复制启用 Ceph 的配置文件 cp -f /home/ubuntu/backup/cinder.conf /etc/cinder/cinder.conf cp -f /home/ubuntu/backup/glance-api.conf /etc/glance/glance-api.conf
#重启 OpenStack 以应用更改 killall screen su ubuntu -c 'cd /home/ubuntu/devstack && ./rejoin-stack.sh' touch /home/ubuntu/restack.done
使用我们的全新 OpenStack 安装,我们需要创建一个卷并将我们的“黄金”卷复制到其中,以便我们的演示实例可以拥有一个可启动卷来使用。 我通过一个 /usr/local/ec2/create_volume.sh 脚本来执行此操作,但不得不编写一个等待以确保 DevStack 安装完成
#!/bin/bash
while : do if pgrep -f cinder-api > /dev/null; then if [ -f /home/ubuntu/restack.done ]; then export OS_USERNAME=admin export OS_PASSWORD=supersecret export OS_TENANT_NAME=admin export OS_AUTH_URL=https://:5000/v2.0
VOL_NAME="volumes-$(openssl rand -hex 4)" /usr/local/bin/cinder create --display_name $VOL_NAME --display_description "cirros bootable volume" 1 VOL_ID=`/usr/local/bin/cinder list | /bin/grep $VOL_NAME | head -1 | /bin/sed -e 's/^| //g;s/ |.*$//g'` /usr/bin/rbd cp -p volumes volume-7fd881f8-c834-4f79-9f92-c570e4995c58 volume-$VOL_ID rm /home/ubuntu/restack.done break fi fi sleep 10 done
剩下的就是告诉我们的系统在启动时运行这四个脚本并发布 AMI。 现在,一个致命的缺陷立即引起我的注意是:“如果我重启机器,它会继续创建新的 Ceph 卷而不清理它们。” 因此,你可能需要手动删除它们(如果你决心多次重启此盒子),或者只是销毁机器并从 AMI 启动一个干净的机器。 将脚本添加到启动中只是对 rc.local 的简单编辑,如下所示
#> sudo chmod o+x /usr/local/ec2/* #> sudo vi /etc/rc.local
/usr/local/ec2/ec2-hostname.sh /usr/local/ec2/update_mon_ip.sh /usr/local/ec2/restack.sh /usr/local/ec2/create_volume.sh
从这里,我只是从 EC2 控制台创建了 AMI 并使权限公开。 随意在 Ceph 和 OpenStack 中四处探索,并通过 邮件列表或 IRC 向我们提出任何 Ceph 问题。 快乐 Ceph-ing。
scuttlemonkey 结束

