cloudstack-4.1.5版本最全入门笔记【2022】

cloudstack简介

CloudStack是一个开源的具有高可用性及扩展性的云计算平台。目前Cloudstack支持管理大部分主流的hypervisors,如KVM,XenServer,VMware,Oracle VM,Xen等。同时CloudStack是一个开源云计算解决方案。可以加速高伸缩性的公共和私有云(IaaS)的部署、管理、配置。使用CloudStack作为基础,数据中心操作者可以快速方便的通过现存基础架构创建云服务。

cloudstack概念架构

1614317659268

  • 用户:通过网络访问属于“我”的虚拟机、存储空间、管理“我”的个人模板。
  • 管理员:部署配置,管理账户,监控资源,安排作业,排除故障。
  • 开发人员:开发计费、监控、统计报表等功能模块,定制图形界面、工作流。

cloudstack部署架构

1614318138954

上图中的各个组件介绍如下:

  • Regions:为了提高云的可靠性,可以选择将资源分为多个地理区域。区域是CloudStack部署中最大的可用组织单位。一个区域由几个可用性zones组成,其中每个zone大致相当于一个数据中心。每个Regions均由其在一个zone中运行的管理服务器集群控制。regions中的zones通常相隔非常近。Regions 是用于提供容错和灾难恢复的有用技术。

  • Zone:Zone 对应于现实中的一个数据中心。

  • Pod:Pod 对应着一个机架。同一个 pod 中的机器在同一个子网(网段)中。

  • Cluster:Cluster 是多个主机组成的一个集群。同一个 cluster 中的主机有相同的硬件,相同的 Hypervisor,和共用同样的存储。同一个 cluster 中的虚拟机,可以实现无中断服务地从一个主机迁移到另外一个上。

  • Host:Host 就是运行虚拟机(VM)的主机。

  • CloudStack存储按用途分为主存储(Primary Storage)二级存储(Secondary Storage),主存储用来存储虚拟机的卷,二级存储用来存放虚拟机的模板,ISO镜像和快照
  • Primary storage:一级存储与 cluster 关联,它为该 cluster 中的主机的全部虚拟机提供磁盘卷。一个 cluster 至少有一个一级存储,且在部署时位置要临近主机以提供高性能。

  • Secondary storage:二级存储与 zone 关联,它存储模板文件,ISO 镜像和磁盘卷快照。

    • 模板:可以启动虚拟机的操作系统镜像,也包括了诸如已安装应用的其余配置信息。
    • ISO 镜像:包含操作系统数据或启动媒质的磁盘镜像。
    • 磁盘卷快照:虚拟机数据的已储存副本,能用于数据恢复或者创建新模板。

即从包含关系上来说,一个regions包含多个zone,一个 zone 包含多个 pod,一个 pod 包含多个 cluster,一个 cluster 包含多个 host。

cloudstack和kvm一起部署的架构

1614319012106

如上所述:在每个kvm的宿主机上都需要部署agent程序。

如果部署vmware的产品就必须部署vcenter server。

cloudstack部署实践

关于这部分内容,请阅读官方文档

主要是介绍cloudstack支持的存储协议、架构模式、机器配置等建议。

cloudstack和openstack比较

难易度 适合规模 参考资料 是否开源 市场占有率
cloudstack 组件少,较易 小、中、大 较少
openstack 组件多,较难 中、大 较多

部署cloudstack

环境准备

OS 主机名 IP rules services explain
cenots 7.7 management 10.10.10.5 管理节点 chronyd、cloudstack-management、mariadb、nginx 用于管理整个cloudstack,最少2c4g
cenots 7.7 kvm1 10.10.10.88 计算节点 kvm 用于运行租户创建的虚拟机,建议4c4g
cenots 7.7 nfs 10.10.10.87 存储节点 nfs 提供主存储、二级存储,最少2g1c,一块100G磁盘

系统初始化

系统初始化这一小节,如果没有特别说明,均需在所有节点执行。

修改主机名


$ hostnamectl set-hostname management

$ hostnamectl set-hostname kvm1

$ hostnamectl set-hostname nfs
source /etc/profile

关闭防火墙及selinux

在生产环境中,建议防火墙放行内网网段即可。selinux设置为permissive模式。(视频资料中说selinux设置为disable会有问题,具体待验证。)


$ systemctl stop firewalld && systemctl disable firewalld

setenforce 0

sed -i 's#^SELINUX=.*#SELINUX=permissive#g' /etc/selinux/config

sed -i 's#^SELINUX=.*#SELINUX=permissive#g' /etc/sysconfig/selinux

配置yum源

这一步主要是将默认的国外yum源配置为国内阿里的yum,如果你有自己内网的yum源服务器,请跳过此步骤。

# 更换为阿里云源
wget -O /etc/yum.repos.d/CentOS-Base.repo https://mirrors.aliyun.com/repo/Centos-7.repo
wget -O /etc/yum.repos.d/epel.repo http://mirrors.aliyun.com/repo/epel-7.repo
cat > /etc/yum.repos.d/cloudstack.repo << 'EOF'
[cloudstack]
name=cloudstack
baseurl=http://download.cloudstack.org/centos/$releasever/4.15/
enabled=1
gpgcheck=0
EOF

配置nfs服务

(此步骤在nfs节点执行)

 yum -y install nfs-utils

cat >> /etc/exports << EOF

/export/secondary *(rw,async,no_root_squash,no_subtree_check)

/export/primary *(rw,async,no_root_squash,no_subtree_check)

EOF
# 创建共享目录
mkdir /export/{primary,secondary}
# 启动nfs
systemctl enable rpcbind nfs
systemctl start rpcbind nfs
exportfs -a 表示将所有的更新
其他任意节点确保可查看到共享目录:
showmount -e 10.10.10.87

安装cloudstack-management

yum install -y cloudstack-management cloudstack-common

导入数据库(此处使用已有的mysql作为存储)


# 可通过 cloudstack-setup-databases --help 查看其他命令选项及其含义
cloudstack-setup-databases cloud:password00038@10.10.10.5:3306 --deploy-as=usertest:password00038
# cloud:password00038:表示执行成功后,mysql数据库将创建一个密码为password00038的cloud用户供管理节点使用。
# --deploy-as:指定你本次使用哪个数据库用户导入数据

额外提下:如果server要做高可用,在另一节点只需要执行cloudstack-setup-databases cloud:password00038@10.10.10.5:3306不要加不要加不要加--deploy-as参数

输出如下信息,表示数据库初始化成功:

1614335594963

启动manager server

# 第一次启动请这样启动

$ cloudstack-setup-management

# 执行后将输出如下信息,则表示启动成功:

Starting to configure CloudStack Management Server:

Configure Firewall ... [OK]

Configure CloudStack Management Server ...[OK]

CloudStack Management Server setup is Done!
# 后续启动方式请使用
$ systemctl restart cloudstack-management

访问dashboard

访问management的8080端口,可以看到如下界面,则表示management安装成功(默认用户名/密码:admin/password):

image-20220210170709372

上传系统虚拟机模板

可参考管理服务器安装 — 文档 (apache.org)

此处使用单独的 NFS 服务器,在server上执行挂载

mount -t nfs 10.10.10.87:/export/secondary /mnt/secondary

cloudstack默认依赖几个虚机运行,当cloudstack添加区域后,他将自动启动相关虚机,所以还需要将镜像导入到二级存储中。

下载虚拟机系统模板,放到二级存储目录上

#官方下载地址http://cloudstack.apt-get.eu/systemvm/4.15/
wget http://cloudstack.apt-get.eu/systemvm/4.15/systemvmtemplate-4.15.0-kvm.qcow2.bz2 
wget http://cloudstack.apt-get.eu/systemvm/4.15/systemvmtemplate-4.15.0-vmware.ova
wget http://cloudstack.apt-get.eu/systemvm/4.15/systemvmtemplate-4.15.0-ovm.raw.bz2
wget http://cloudstack.apt-get.eu/systemvm/4.15/systemvmtemplate-4.15.0-xen.vhd.bz2
wget http://cloudstack.apt-get.eu/systemvm/4.15/systemvmtemplate-4.15.0-hyperv.vhd.zip

#kvm
/usr/share/cloudstack-common/scripts/storage/secondary/cloud-install-sys-tmplt \
-m /export/secondary  -f /root/systemvmtemplate-4.15.0-kvm.qcow2.bz2  -h kvm -F

#vmware
/usr/share/cloudstack-common/scripts/storage/secondary/cloud-install-sys-tmplt \
-m /export/secondary  -f /root/systemvmtemplate-4.15.0-vmware.ova  -h vmware -F

输出如下,则表示上传成功:

1614339908396

如果您使用的是单独的 NFS 服务器,请务必执行此步骤,不然下次重启server时候会报错卡主

# 卸载辅助存储并删除创建的目录
umount /mnt/secondary
rmdir /mnt/secondary

报错如下:

 [o.a.c.s.NfsMountManager] (main:null) (logid:) Clean up mounted NFS mount points used in current session.

配置计算节点

注:此步骤只需在计算节点上执行。

修改网络配置

主要是生成一个网桥设备,以便VM都可以连接到此网桥。

# 备份源网卡配置文件
$ cp /etc/sysconfig/network-scripts/ifcfg-ens33{,_$(date +%F_%H).bak}
# 修改网卡配置文件
cat > /etc/sysconfig/network-scripts/ifcfg-ens33 << EOF
TYPE=Ethernet
DEVICE=ens33
ONBOOT=yes
BRIDGE=cloudbr0
EOF

cat > /etc/sysconfig/network-scripts/ifcfg-cloudbr0 << EOF
DEVICE=cloudbr0
TYPE=Bridge
ONBOOT=yes
BOOTPROTO=static
IPADDR=10.10.10.22
GATEWAY=10.10.10.1
DNS1=223.5.5.5
EOF
# 修改完成后,务必检查是否修改正确,网卡名称、IP地址与你的实际环境是否一致
# 确认无误后,重启网络服务

$ systemctl restart network
安装cloudstack-agent
yum -y install cloudstack-agent cloudstack-common
确认加载kvm模块
$ lsmod | grep kvm # 输出如下,则表示已加载
[root@WT-TEST-10-22 ~]# lsmod | grep kvm
kvm_intel             188688  15 
kvm                   636969  1 kvm_intel
irqbypass              13503  21 kvm
[root@WT-TEST-10-22 ~]# 
安装ibvirt

yum -y install qemu-kvm libvirt python-virtinst bridge-utils

修改libvirt默认配置

修改vnc默认监听地址

sed -i 's/^#vnc_listen =.*/vnc_listen = "0.0.0.0"/g' /etc/libvirt/qemu.conf

# 指定cloudstack-management地址
sed -i "s/host=.*/host=10.10.10.5/g" /etc/cloudstack/agent/agent.properties
# 重启libvirt
systemctl restart libvirtd
启动cloudstack-agent并加入开机自启

$ systemctl start cloudstack-agent && systemctl enable cloudstack-agent

规划cloustack网络

在cloudstack中,提供了两种网络:基本网络和高级网络。这篇博文将基于基本网络进行配置,如果要配置高级网络,那么这篇博文不用继续往下看了,移步即可。

基本网络

基本网络模式采用传统扁平网络,与现有网络完美兼容,其网络通信拓扑如下:

1614324293753

基础网络模式只提供了简单的网络模型,管理网络、来宾网络、存储网络、V-Route(只提供了DNS、dhcp,并不提供网关服务)等。

高级网络

高级网络模式中,每个租户获得一个或多个来宾网络,每个网络属于独立的VLAN,由虚拟路由器为这些来宾网络提供网关服务。

虚拟路由器(系统虚拟机提供)在高级网络中十分重要,它将成为租户私有网络与公共网络之间的接口,并未租户私有网络提供各种网络服务,包括NAT、静态NAT、DHCP、DNS、Load Balancing、Port Forwording、Firewalls、Site-to-Site 虚拟专用网、VPC等。

高级网络架构图如下:1614324480867

两种不同的网络,对来宾网络(Guest Network)采用的隔离方式不同,在基本模式下,采用安全组(Security Group)方式进行隔离;而在高级网络中,采用VLAN方式进行隔离。

具体网络规划(内网实验用)

角色 网络
management+nfs 10.10.10.5
kvm1 10.10.10.22
虚拟机(来宾网络) 10.10.10.150-10.10.10.160
创建zone

登录到cloudstack-management的管理控制台,进行如下操作,以便添加第一个zone:

1、网络选择基本的:
image-20211126114504059
2、资源域详细信息:

网络方案介绍:

  • DefaultSharedNetworkOfferingWithSGService:带有安全组的网络方案,推荐选择此选项。

  • DefaultSharedNetworkOffering:不带安全组功能。

  • DefaultSharedNetscalerEIPandELBNetworkOffering:如果你在CLOUDSTACK内安装了Citrix NetScaler应用,并且你需要Elastic IP和Elastic Load Balancing这些功能的话,那就选择这个选项。EIP 和ELB技术在安全组启用的情况下,可以提供1:1的NAT映射和负载均衡功能。此功能需要citrix硬件支持,一般很少用。

  • QuickCloudNoServices:表示什么都不用,新增选项,不建议使用。

image-20220211100054911

3、网络

image-20211126114526260

4、添加提供点

image-20220211100245480

5、设置来宾网络

image-20211126114424578

6、设置群集名称

image-20220211100614341

7、添加kvm主机节点

image-20220211100749497

8、配置主存储

image-20220211101037328

9、配置二级存储

image-20220211101119055

11、启用资源域

激动人心的时刻到了,这一步,将检验你之前所有的操作是否正确。

image-20220211101612943

验证cloudstack可用性

至此,你必须保证下面的任意资源都为“UP” 状态,如下:

1、资源域状态为“Enabled”

2、提供点状态状态为“Enabled”

3、群集状态“Enabled”

4、主机状态必须为 “Up”

5、主存储状态必须为 “Up”

6、二级存储状态必须为 “Up”

7、系统VM必须正常状态必须为 “Up”

至此,可以说你的集群完全可用了,但虚拟路由器现在数量为 “0”,当我们创建第一个实例后,虚拟路由器就被创建了。

注册ISO

现在,我们就来启动一个实例进行验证。需要自行准备一张系统盘。最好是centos的。附:centos镜像下载链接

注册ISO镜像支持两种方式,一种是从本地上传,一种是从一个URL主机,为了速度考虑,建议自行准备http服务器,然后配置为文件服务器,进行注册ISO(本地上传功能不靠谱)。

1、安装nginx

任意节点安装即可,既然博文开头规划在了management节点,那就在这个节点吧。

server {
	listen 80;
	server_name  10.10.10.5;
location / {
root /data;
autoindex on;
autoindex_exact_size off;
autoindex_localtime on;
}
}
#可以看到在正常下载即可:
wget http://10.10.10.5/CentOS-7-x86_64-DVD-2009.iso

2、定义允许哪些网络可以访问二级存储(不配置iso安装的时候会拒绝

secstorage.allowed.internal.sites

image-20220211140151997

3、重启cloudstack-management生效

systemctl restart cloudstack-management

重启后,需要稍等片刻,待8080端口在监听,才可以继续访问控制台:

4、注册ISO

访问控制台,进行如下操作:

image-20220211110611827

查看镜像上传进度:

自行刷新页面,直至完成:

稍等片刻,看到镜像状态如下,则表示成功:

image-20220210174132652

修改下全局配置

  • cpu.overprovisioning.factor

    CPU超配倍数 一般设置3-4倍,内存超配倍数,如果准备运行虚拟机大多是Linux无界面系统,可以设置2倍,如果运行Windows等有图形界面的。最好选择不修改,因为经过个人测试,图形界面虚拟机相应的qemu进程真的会占用宿主机分配的那么多内存。当然,这有可能是因为我使用kvm 作为虚拟机管理程序的原因,Xenserver或者VMware可能会好一点。

  • mem.overprovisioning.factor

    内存超配倍数

  • secstorage.allowed.internal.sites
    允许下载模板或ISO的网段。。。可以设置成0.0.0.0/0表示允许所有网段,或者设置成 自己网络所在网段如 192.168.199.0/24

  • kvm.snapshot.enabled

    是否启用KVM 的VM快照功能

  • expunge.delay

    删除vm后,卷清理等待时间

  • enable.dynamic.scale.vm
    配置动态 CPU 和内存扩展

创建vm虚拟机

网页捕获_10-2-2022_181546_10.10.10.5

启动VM后,进入虚机控制台,则可以和正常一样装系统了

image-20220211111151250

此处省略一万字...............

取消附加ISO

当装完系统后,重启VM,默认还会进入装系统的界面,我们需要进行如下操作,才可以正常使用虚机,如下(需在VM关机状态下执行):

image-20220211112640542

安装centos系统后 ,没有IP地址

  • 配置网卡及初始化系统
#必须要修改网络接口的配置文件,编辑/etc/sysconfig/network-scripts/ifcfg-eth0文件
TYPE=Ethernet
BOOTPROTO=dhcp
NAME=eth0
DEVICE=eth0
ONBOOT=yes
DNS1=223.5.5.5
PEERDNS="no"  #该配置可以禁用dhclient-script更新 resolv.conf文件,否则手动修改dns后重启系统后被改回虚拟路由器的地址,还有另外一种方法见https://forums.centos.org/viewtopic.php?t=24741#p116748
#----------系统初始化操作可以放在此处---------------------
#移除udev持久设备规则
rm -f /etc/udev/rules.d/70*
rm -f /var/lib/dhclient/*
#移除SSH Keys这步是为了确认所有要作为模板的VMs的SSH Keys都不相同,否则这样会降低虚拟机的安全性。
rm -f /etc/ssh/*key*
#清除日志文件,从主模板移除旧的日志文件是一个好习惯。
cat /dev/null > /var/log/audit/audit.log 2>/dev/null1
cat /dev/null > /var/log/wtmp 2>/dev/null
logrotate -f /etc/logrotate.conf 2>/dev/null
rm -f /var/log/*-* /var/log/*.gz 2>/dev/null
#清除用户历史bash命令。
history -c
unset HISTFILE
#关闭selinux和防火墙
sed -i "s/SELINUX=enforcing/SELINUX=disable/g" /etc/selinux/config
systemctl stop firewalld.service;systemctl disable firewalld.service

  • 关闭VM
  • 基于关闭vm的模板并且创建新模板

从当前实例进来,点击**卷**

image-20220211135258662

基于卷创建模板

image-20220211135335267

image-20220211135414820

等待最终模板的状态是"Download Complete"

image-20220211140055511

从此可以使用"tmp_centos7"模板创建虚拟机了

API操作

官网

#!/usr/bin/env python
# -*- coding:utf-8 -*-
# @Time    : 2022/2/11 14:41
# @Author  : XuLiLiang
# @Email   : xuliliang@epailive.com
# @File    : cloudstack-api.py
import base64
import hashlib
import hmac
import json
import urllib

import httpx

import requests
from urllib import parse

baseurl = 'http://10.10.10.5:8080/client/api?'
api_key = '6QAhoFguQkIo-pxyggaaVRlsiSAD--Xrg18_5SDB4xptddp1PEcNCe5RcryXLhUKXox6Rujlcun4A8kRcbX23g'
secret_key = 'kVN31BNvJzl-60KgI2Y_n9DDk13Loe2PMn85g2VZoM8R6LgKYqZ5XOszjTAiENgSnsacjkmLMoX2f0754Z38eA'


class CloudApi:
    def __init__(self):
        self.baseurl = baseurl
        self.api_key = api_key
        self.secret_key = secret_key

    def GetSing(self, params,args=None):
        """
         封装request
        """

        params['response'] = 'json'
        params['apikey'] = self.api_key
        request_str = '&'.join(['='.join([k, parse.quote_plus(params[k])]) for k in params.keys()])
        sig_url = urllib.parse.urlencode(params)
        sig_str = '&'.join(['='.join([k.lower(), parse.quote_plus(params[k].lower().replace('+', '%20'))]) for k in
                            sorted(params.keys())])
        # sig1 = hmac.new(self.secret_key, sig_str, hashlib.sha1).digest()
        # sig2 = base64.encodebytes(hmac.new(self.secret_key, sig_str, hashlib.sha1).digest())
        # sig3 = base64.encodebytes(hmac.new(self.secret_key, sig_str, hashlib.sha1).digest()).strip()
        sig = parse.quote_plus(base64.b64encode(hmac.new(self.secret_key.encode('utf-8'), sig_str.encode('utf-8'), hashlib.sha1).digest()).strip())
        req = self.baseurl + request_str +args + '&signature=' + sig
        return req

    def listVirtualMachines(self,name=''):
        """
        列出vms
        """
        params = {
            'command': 'listVirtualMachines',
            'name':name
        }
        req = self.GetSing(params)
        s = requests.get(req).content.decode("utf-8")
        res = json.loads(s)
        intances=[]
        if not res['listvirtualmachinesresponse']['virtualmachine']:
            print("VM is \033[31mnot exist\033[0m!")
            return False
        else:
            if name:
                for instance in res['listvirtualmachinesresponse']['virtualmachine']:
                    try:
                        if name==instance['name']:
                            instance_info = [instance['id'], instance['name'], instance['nic'][0]['ipaddress'],
                                             instance['state']]
                            intances.append(instance_info)
                            break
                    except Exception as e:
                        raise e
            else:
                for instance in res['listvirtualmachinesresponse']['virtualmachine']:
                    if instance['state'] != 'Error' :
                        instance_info = [instance['id'], instance['name'],instance['nic'][0]['ipaddress'],
                                     instance['state']]
                        intances.append(instance_info)
        # print(intances)
        return intances


    def listTemplates(self):
        """
        获取模板列表
        """
        args_dict = {
            'command': 'listTemplates',
            'templatefilter': 'all',
        }
        req = self.GetSing(args_dict)
        httpx.AsyncClient()
        s = httpx.get(req)
        response = json.loads(s.content.decode("utf-8"))['listtemplatesresponse']['template']
        for x in response:
            print(x['id'], x['name'])

    def getZones(self):
        """
        获取zones
        """
        args_dict = {
            'command': 'listZones',
        }
        req = self.GetSing(args_dict)
        s = requests.get(req)
        response = json.loads(s.content.decode("utf-8"))['listzonesresponse']['zone']
        for x in response:
            print (x['id'])
            return (x['id'])

    def listServiceOfferings(self):
        """
        列出计算方案
        """
        args_dict = {
            'command': 'listServiceOfferings',
        }
        req = self.GetSing(args_dict)
        s = requests.get(req)
        response = json.loads(s.content.decode("utf-8"))['listserviceofferingsresponse']['serviceoffering']
        for x in response:
            print(x['id'], x['name'])
        # print(response)

    def listDiskOfferings(self):
        """
        列出所有磁盘方案
        """
        args_dict = {
            'command': 'listDiskOfferings',
        }
        req = self.GetSing(args_dict)
        try:
            with httpx.Client() as client:
                s = client.get(req, timeout=10)
                response = json.loads(s.content.decode("utf-8"))
                print(response)
        except Exception as e:
            raise e


    def deployVirtualMachine(self):
        """
        创建vm
        """
        import uuid
        suid = str(uuid.uuid4())
        vm_name = f"VM-{suid}"
        filepath = 'init.sh'
        with open(filepath, 'rb') as f1:
            base64_str = base64.encodebytes(f1.read())
            u_data = base64_str.decode('utf-8')
            # print(u_data)

        # user_data = """#!/bin/bash
        # env
        # echo "export AAAAAA=1234567890" >> ~/.bashrc
        # echo "export BBBBBB=0123456789" >> ~/.bashrc
        # source ~/.bashrc
        # env
        # """
        # bs = str(base64.b64encode(user_data.encode("utf-8")), "utf-8")
        # print(bs)
        args_dict = {
            'command': 'deployVirtualMachine',
            "diskofferingid": '6f17d452-b307-4005-93db-5f4e9060f1af',
            "name": vm_name,
            "serviceofferingid": '7e792106-53f6-402d-a671-80e86cc00486',
            "templateid": '4ecb75d3-c060-4ccf-af88-717e2987389e',
            "zoneid": '2d6c3c0a-6c42-4c10-8273-5879bf02cc70',

        }
        data=f"&userdata={u_data}"

        req = self.GetSing(args_dict,data)
        try:
                s = requests.get(req)
                response = json.loads(s.content.decode("utf-8"))
                print(response)
        except Exception as e:
            raise e

    def actionVirtualMachine(self, id, action):
        status = {
            'destroy': 'destroy',
            'recover': 'recover',
            'start': 'start',
            'stop': 'stop',
            'reboot': 'reboot',
            'restore':'restore',
            'running':'running',
        }
        host_info=self.listVirtualMachines(id)
        print(host_info)
        if host_info[0][3] == status[action]:
            print("The \033[36m%s\033[0m Status is \033[33m%s\033[0m !")
            import sys
            sys.exit(500)

        args_dict = {
            'command': status[action]+'VirtualMachine',
            'id': host_info[0][0],
        }
        req = self.GetSing(args_dict)
        try:
            s = requests.get(req)
            res = json.loads(s.content.decode("utf-8"))
            print(res)
        except Exception as e:
            raise e

    def queryAsyncJobResult(self,id):
        args_dict={
            'command': 'queryAsyncJobResult',
            'jobid':id,
        }
        req = self.GetSing(args_dict)
        try:
            with httpx.Client() as client:
                s = client.get(req, timeout=10)
                response = json.loads(s.content.decode("utf-8"))
                print(response)
                return response
        except Exception as e:
            raise e
    def listNetworks(self):
        args_dict={
            'command': 'listNetworks',
        }
        req = self.GetSing(args_dict)
        try:
            with httpx.Client() as client:
                s = client.get(req, timeout=10)
                response = json.loads(s.content.decode("utf-8"))
                print(response)
                return response
        except Exception as e:
            raise e


if __name__ == '__main__':
    api = CloudApi()
    # 0 - Job表示程序还在进行
    # 1 - Job表示成功地完成了
    # 2 - Job表示执行失败
    # api.listVirtualMachines()
    # api.actionVirtualMachine('centos','destroy')
    # api.listClusters()
    # api.listServiceOfferings()
    # api.listTemplates()
    # api.getZones()
    api.deployVirtualMachine()
    # api.listDiskOfferings()
    # api.listNetworks()
    # api.queryAsyncJobResult('cedd5f88-dfba-4356-9df3-c13e1d3fe47b')

cloud-init实战

在云平台中,创建云主机的时候希望能够对主机进行一些初始化操作,如配置ip,主机名,密码,ssh登录等。openstack或cloudstack上可以使用cloud-init进行初始化。

cloud-init官方文档
阿里云官方文档 安装cloud-init

前提条件
• 一台KVM机器,用于制作初始的centos7镜像
• 已为Linux云服务器绑定弹性IP。
• 已登录Linux云服务器。
• Linux云服务器的网卡属性为DHCP方式。

以下均在模板机器上配置

1. 下载cloud-init
wget -O /etc/yum.repos.d/epel.repo http://mirrors.aliyun.com/repo/epel-7.repo
yum install cloud-init -y 
cloud-init init --local
#设置开机自启动
systemctl enable cloud-init-local.service cloud-init.service cloud-config.service cloud-final.service
2. 安装相应的包
# ACPI服务是控制重启和关闭实例
yum -y install acpid
systemctl enable acpid
# 安装cloud-utils-growpart 允许分区调整
yum -y install cloud-utils-growpart
3. 配置Cloud-Init工具
  1. 用户可以根据需要根据用户类型配置登录云服务器的用户权限。使用root帐户登录,需要开启root用户的ssh权限,并开启密码远程登录。
  • 若用户选择注入密码,则通过自己注入的密码进行远程SSH或noVNC登录。
  • 若用户选择注入密钥,则通过自己注入的密钥进行远程SSH登录。

配置ssh文件

vim /etc/ssh/sshd_config
PasswordAuthentication yes

2 . 编辑配置文件/etc/cloud/cloud.cfg

在cloud.cfg文件增加该配置之后,cloud-init不会管理/etc/sysconfig/network-scripts/下网络配置,需要自行管理。
建议提前配置好网卡配置文件为dhcp获取,否则在私有云上创建的实例可能会导致获取不到IP地址;原因是cloud-init中的自动配置网卡文件可能会导致mac地址不一致

network:
  config: disabled

最终配置如下

users:
  - name: root
    ssh_authorized_keys: #配置远程控制节点的ssh-keygen,
      - ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAvGQtIxNSwb3DqHJuDqBW0Gz6uc/B1gc4Un+7tQgMEcBbsOtaeLlmfF8D0DT4Tk349f2wmP12TyjqG+fekXB4HvrcXq/xVzloWalN0bzXNhVhy4ymXTq4lc6vYEkXLIyWN57FFp6NHbiKHBWkKHAYraYnf5a7wWOpPTq20bdHaIi4Pw9ADxWpQMVxyeMhBW9ZvBgPr4aGpkrKmARZShmLwEWpSHxRJymErnL6p/64s3xfRY4L9YdVLGBZfrzsoNVD20tTw1ctDswEkvTp46SNLK8BcM3qIk0WUpMEcNus7WtG4pQr9cob3qVAiMYGUP5KOiDa4PdjccvWP+bkDTjzsQ== root@kaifa-dev02

disable_root: 0
ssh_pwauth: 1
preserve_hostname: flase
manage_etc_hosts: true

manage_resolv_conf: true
resolv_conf:
  nameservers:
    - 8.8.8.8
    - 8.8.4.4
  options:
    rotate: true
    timeout: 1
network:
  config: disabled
runcmd:
  - [ sh, -c, echo "=========Welcome To cloudstack'=========" > /root/runcmd.log ]
cloud_init_modules:
 - ssh
 - migrator
 - bootcmd
 - write-files
 - growpart
 - resizefs
 #- set_hostname
 #- update_hostname
 - update_etc_hosts
 - rsyslog
 - users-groups

cloud_config_modules:
 - mounts
 - locale
 - set-passwords
 - yum-add-repo
 - package-update-upgrade-install
 - timezone
 - puppet
 - chef
 - salt-minion
 - mcollective
 - disable-ec2-metadata
 - runcmd
 - ntp-conf

cloud_final_modules:
 - rightscale_userdata
 - scripts-per-once
 - scripts-per-boot
 - scripts-per-instance
 - scripts-user
 - ssh-authkey-fingerprints
 - keys-to-console
 - phone-home
 - final-message
 - power-state-change

system_info:
   distro: centos
   paths:
      cloud_dir: /var/lib/cloud/
      templates_dir: /etc/cloud/templates/
   ssh_svcname: sshd

chpasswd:
   list: |
     root:123456
   expire: False
timezone: Asia/Shanghai
packages: 
  - wget
  - zip
  - iftop
  - htop
  - curl
  - bind-utils

日志输出路径配置文件

#日志处理方式handlers**
#文件路径:/etc/cloud/cloud.cfg.d/05_logging.cfg
[logger_cloudinit]
   level=DEBUG
   qualname=cloudinit
   handlers=cloudLogHandler
   propagate=1
#最后一行增加输出的日志文件
output: {all: '| tee -a /var/log/cloud-init-output.log'}   

image-20220216172801332

检查Cloud-Init工具相关配置是否成功

执行以下命令,无错误发生,说明Cloud-Init配置成功

[Docker][root VM-438178de-b93e-400a-8981-581bfdcba864 ~]$ cloud-init init --local
Cloud-init v. 19.4 running 'init-local' at Wed, 16 Feb 2022 09:29:47 +0000. Up 1026.33 seconds.
[Docker][root VM-438178de-b93e-400a-8981-581bfdcba864 ~]$ 

设置完成后关闭虚拟机,准备下一阶段生成镜像

history -c
shutdown -h now

基于此卷创建模板

基于HAproxy高可用

安装

yum -y install haproxy

/etc/haproxy/haproxy.cfg完整配置文件如下

global
    # to have these messages end up in /var/log/haproxy.log you will
    # need to:
    #
    # 1) configure syslog to accept network log events.  This is done
    #    by adding the '-r' option to the SYSLOGD_OPTIONS in
    #    /etc/sysconfig/syslog
    #
    # 2) configure local2 events to go to the /var/log/haproxy.log
    #   file. A line like the following can be added to
    #   /etc/sysconfig/syslog
    #
    #    local2.*                       /var/log/haproxy.log
    #
    log         127.0.0.1 local2

    chroot      /var/lib/haproxy
    pidfile     /var/run/haproxy.pid
    maxconn     4000
    user        haproxy
    group       haproxy
    daemon

    # turn on stats unix socket
    stats socket /var/lib/haproxy/stats

defaults
    mode                    http
    log                     global
    option                  httplog
    option                  dontlognull
    option http-server-close
    option forwardfor       except 127.0.0.0/8
    option                  redispatch
    retries                 3
    timeout http-request    10s
    timeout queue           1m
    timeout connect         10s
    timeout client          1m
    timeout server          1m
    timeout http-keep-alive 10s
    timeout check           10s
    maxconn                 3000


listen web-ui-80
		bind *:80
		option httpchk OPTIONS /client
		log global
		mode http
		option httplog
		option forwardfor
		balance source
		cookie JSESSIONID insert preserve  
		server msg01 10.10.10.5:8080 cookie JSESSIONID_SERVER_1  check inter 50000 rise 2 fall 5
		server msg02 10.10.10.68:8080 cookie JSESSIONID_SERVER_1  check inter 50000 rise 2 fall 5
 
listen web-ui-8080
		bind *:8080
		option httpchk OPTIONS /client
		log global
		mode http
		option httplog
		option forwardfor
		balance source
		cookie JSESSIONID insert preserve  
		server msg01 10.10.10.5:8080 cookie JSESSIONID_SERVER_1  check inter 50000 rise 2 fall 5
		server msg02 10.10.10.68:8080 cookie JSESSIONID_SERVER_1  check inter 50000 rise 2 fall 5


重启haproxy

systemctl restart haproxy

访问 本机ip 即可进入CloudStack的UI界面 ,修改 全局设置 host 值为 本机ip

密码管理

CloudStack提供可选的密码重置功能,允许用户设置临时的admin或root密码,也可以从CloudStack UI中重置现有的admin或root密码。
要启用重置密码功能,您需要下载一个附加脚本来给模板打补丁

模板vm中执行

    #下载脚本
    wget https://download.cloudstack.org/templates/4.2/bindir/cloud-set-guest-password.in 
    mv cloud-set-guest-password.in cloud-set-guest-password
    mv cloud-set-guest-password /etc/init.d/
    chmod +x /etc/init.d/cloud-set-guest-password
    #加到开机自启动
    chkconfig --add cloud-set-guest-password

模板中启用密码功能

基于此卷创建模板时启动密码功能

image.png

posted @ 2022-02-11 17:40  51运维com  阅读(629)  评论(0编辑  收藏  举报