ROS 中使用 Chef 部署应用

    xiaoxiao2026-01-09  9

    资源编排ROS 是一种简单易用的云计算资源管理和自动化运维服务。用户通过模板描述多个云计算资源的依赖关系、配置等,并自动完成所有资源的创建和配置,以达到自动化部署、运维等目的。 了解更多

    通过阿里云的资源编排服务,ROS,可以很方便的创建一组资源。但是创建资源只是第一步,接下来我们需要把应用部署上去,有两种方式供你使用,ROS 的 UserData 脚本或者集成配置管理工具,例如 Chef 或Puppet。本文将重点讲述ROS 集成 Chef 实现应用的部署与配置。关于使用 UserData 脚本的方式,大家可以参考《基于资源编排一键交付连接RDS的应用》。

    通过 Chef,你可以自动实现在 ECS 上的部署配置应用而不用手动构建各种脚本。通过把 Chef 和 ROS 集成,这样能更方便的把生产资源和部署应用集成到一块,并且通过ROS的模板,可以实现随时随地无限次的搭建相同应用环境,很轻松的把搭建环境集成到 DevOps 中去。

    本文将以部署 WordPress 为例,讲解如何通过 ROS 去构建一个高可用的 Web Server 环境,最后通过执行 Chef 的 Recipe 在高可用的 Web Server 基础设施环境中安装配置 WordPress 。通过最终的这个 ROS模板,你可以简洁快速的获取一个 WordPress 应用。当然你还可以通过 Git 或 SVN 管理这个 ROS 的模板,实现对自己 WordPress 应用环境的版本控制。

    ROS 安装部署 WordPress 架构概览

    此模板讲创建一个高可用的带有负载均衡能力的 WordPress 环境,并通过阿里云的 RDS 提供后端的数据存储。基本的架构如下图所示:

    在上面的架构图里面,通过 ROS 的 ALIYUN::ECS::InstanceGroup 创建多个 ECS 节点,这样就可以保证 WordPress 有多个实例,提高 WordPress 的高可用性。在 ECS 的前面部署了一个 SLB, 来保证均衡后端 ECS 的负载,给用户暴露唯一的 WordPress 访问地址,同时能够在添加或减少后端 ECS 服务器的时候,用户无感知。SLB 通过 ALIYUN::SLB::LoadBalancer 创建。通过 ALIYUN::SLB::Listener 配置SLB监听那些端口, ALIYUN::SLB::BackendServerAttachment 把后端服务器 ECS 加入到SLB监听列表中。通过使用 RDS 提供 WordPress 的后端数据存储能力。ROS 通过 ALIYUN::RDS::DBInstance 创建 RDS 实例配置数据库。以上所有的资源都部署在一个安全组里面,通过安全组控制数据出入规则,提高安全性。

    最终,当 ECS 实例启动的时候,ROS 通过利用 Chef 的本地模式安装和配置 WordPress。 Chef 的本地模式是使用本地的 Chef 仓库来管理 cookbook 而不用通过 Chef Server。

    WordPress 一键部署

    一键部署>>>

    点击一键部署后,默认会在华北2 region 部署 WordPress。 如果你需要调整 region,请点击页面右下角的【上一步】,然后重新选择 region,接着点击【下一步】,你只需要填入如下图中必填的信息或者根据你的需求调整信息后,点击【创建】按钮就可以部署一套 WordPress 高可用环境。

    模板详解

    创建 VPC 网络

    在本例中,所有资源的都处于VPC网络下,保证网络的隔离性和安全性。为了保证 ECS 能够访问外网,获取到 Chef 的安装包,下载到 WordPress 的 cookbook,我们配置了 VPC 的 SNAT 网关。请参考《新玩法,ROS帮你一键搭建NatGateway让VPC与Internet的互访》,了解如何详细的配置你的 VPC 网络。

    "SNatEntry": { "Type": "ALIYUN::ECS::SNatEntry", "DependsOn": "WPLoadBalancer", "Properties": { "SNatIp": { "Fn::Select": [ "0", { "Fn::GetAtt": [ "NatGateway", "BandwidthPackageIps" ] } ] }, "SourceVSwitchId": { "Fn::GetAtt": [ "VSwitch", "VSwitchId" ] }, "SNatTableId": { "Fn::GetAtt": [ "NatGateway", "SNatTableId" ] } } }, "NatGateway": { "Type": "ALIYUN::ECS::NatGateway", "Properties": { "Spec": "Small", "NatGatewayName": "NatGateway", "BandwidthPackage": [ { "IpCount": 1, "Bandwidth": 5 } ], "VSwitchId": { "Ref": "VSwitch" }, "VpcId": { "Fn::GetAtt": [ "Vpc", "VpcId" ] } } }, "Vpc": { "Type": "ALIYUN::ECS::VPC", "Properties": { "CidrBlock": "192.168.0.0/16" } }, "VSwitch": { "Type": "ALIYUN::ECS::VSwitch", "Properties": { "CidrBlock": "192.168.33.0/24", "ZoneId": { "Fn::Select": [ "0", { "Fn::GetAZs": { "Ref": "ALIYUN::Region" } } ] }, "VpcId": { "Fn::GetAtt": [ "Vpc", "VpcId" ] } } }

    创建安全组

    在本例中,所有的ECS都加入到一个默认安全组。同时,给安全组资源配置允许外部用户可通过80和22端口访问 WordPress 部署环境。

    "DefaultSecurityGroup": { "Type": "ALIYUN::ECS::SecurityGroup", "Properties": { "Description": "DDC default security group", "SecurityGroupIngress": [ { "SourceCidrIp": "0.0.0.0/0", "IpProtocol": "tcp", "NicType": "intranet", "PortRange": "22/22" }, { "SourceCidrIp": "0.0.0.0/0", "IpProtocol": "tcp", "NicType": "intranet", "PortRange": "443/443" }, { "SourceCidrIp": "0.0.0.0/0", "IpProtocol": "tcp", "NicType": "intranet", "PortRange": "80/80" } ], "SecurityGroupEgress": [ { "IpProtocol": "all", "DestCidrIp": "0.0.0.0/0", "NicType": "intranet", "PortRange": "-1/-1", "Priority": 1 } ], "VpcId": { "Ref": "Vpc" } } }

    创建 ECS 实例

    本例中,创建了两种 ECS 实例,一种是用 ALIYUN::ECS::InstanceGroup 创建用来部署 WordPress 的 ECS实例,这个资源可以通过 MaxAmount 来指定一次创建多少台 ECS 实例。一个是用 ALIYUN::ECS::Instance 创建一台运维使用的跳板机。跳板机也部署在相同的 VPC 网络中,但是给跳板机分配了公网 IP。

    "WPEcsInstance": { "Type": "ALIYUN::ECS::InstanceGroup", "DependsOn": "SNatEntry", "Properties": { "IoOptimized": { "Ref": "WPEcsIoOptimized" }, "ImageId": { "Ref": "WPEcsImageId" }, "SecurityGroupId": { "Fn::GetAtt": [ "DefaultSecurityGroup", "SecurityGroupId" ] }, "Password": { "Ref": "WPEcsInstancePassword" }, "MinAmount": { "Ref": "WPEcsMaxAmount" }, "AllocatePublicIP": "false", "SystemDiskCategory": { "Ref": "WPEcsSystemDiskCategory" }, "UserData": { "Fn::Replace": [ { "ros-notify": { "Fn::GetAtt": [ "WPEcsConditionHandle", "CurlCli" ] } }, { "Fn::Join": [ "", [ "#!/bin/sh\n", "apt-get update\n", "apt-get install -y rails\n", "apt-get install -y unzip\n", "\n", "wget -P /tmp http://ros-om-dependence.oss-cn-shanghai.aliyuncs.com/chef-ubuntu-64/chef_12.18.31-1_amd64.deb\n", "dpkg -i /tmp/chef_12.18.31-1_amd64.deb\n", "wget -P /tmp http://ros-om-dependence.oss-cn-shanghai.aliyuncs.com/chef-ubuntu-64/chefdk_1.2.22-1_amd64.deb\n", "dpkg -i /tmp/chefdk_1.2.22-1_amd64.deb\n", "\n", "mkdir -p /var/chef/chef-repo/.chef\n", "# chef local repo setting\n", "# wget -P /tmp http://github.com/opscode/chef-repo/tarball/master/chef-boneyard-chef-repo-605eeda.tar.gz\n", "wget -P /tmp http://ros-om-dependence.oss-cn-shanghai.aliyuncs.com/chef-ubuntu-64/chef-boneyard-chef-repo-605eeda.tar.gz\n", "tar -xzf /tmp/chef-boneyard-chef-repo-605eeda.tar.gz -C /var/chef/chef-repo\n", "cp -rf /var/chef/chef-repo/chef-boneyard-chef-repo-605eeda/* /var/chef/chef-repo\n", "rm -rf /var/chef/chef-repo/chef-boneyard-chef-repo-605eeda\n", "echo install chef > /tmp/log\n", "# set default knife.rb\n", "echo \"cookbook_path [ '/var/chef/chef-repo/cookbooks' ]\" > /var/chef/chef-repo/.chef/knife.rb\n", "echo \"node_path [ '/var/chef/chef-repo/nodes' ]\" >> /var/chef/chef-repo/.chef/knife.rb\n", "\n", "# set default client.rb\n", "echo \"cookbook_path [ '/var/chef/chef-repo/cookbooks' ]\" > /var/chef/chef-repo/.chef/client.rb\n", "echo \"node_path [ '/var/chef/chef-repo/nodes' ]\" >> /var/chef/chef-repo/.chef/client.rb\n", "\n", "# set init chef conf\n", "orig_home=$HOME\n", "export HOME='/var/chef'\n", "\n", "# create node list\n", "cd /var/chef/chef-repo\n", "chef-client -z -c /var/chef/chef-repo/.chef/client.rb\n", "echo config chef repo >> /tmp/log\n", "\n", "\n", "# download wordpress cookbook\n", "wget -P /tmp http://ros-om-dependence.oss-cn-shanghai.aliyuncs.com/chef-ubuntu-64/wordpress.tar.gz\n", "tar -xzf /tmp/wordpress.tar.gz -C /var/chef/chef-repo/cookbooks\n", "\n", "# set default knife.rb\n", "echo \"cookbook_path [ '/var/chef/chef-repo/cookbooks/wordpress/berks-cookbooks' ]\" > /var/chef/chef-repo/.chef/knife.rb\n", "echo \"node_path [ '/var/chef/chef-repo/nodes' ]\" >> /var/chef/chef-repo/.chef/knife.rb\n", "\n", "# set default client.rb\n", "echo \"cookbook_path [ '/var/chef/chef-repo/cookbooks/wordpress/berks-cookbooks' ]\" > /var/chef/chef-repo/.chef/client.rb\n", "echo \"node_path [ '/var/chef/chef-repo/nodes' ]\" >> /var/chef/chef-repo/.chef/client.rb\n", "echo config wordpress cookbook >> /tmp/log\n", "\n", "\n", "# set wordpress datebase conf\n", "echo \"normal['wordpress']['db']['pass'] = '", { "Ref": "WPDBPassword" }, "'\" > /var/chef/chef-repo/cookbooks/wordpress/berks-cookbooks/wordpress/attributes/aliyun_rds_config.rb\n", "echo \"normal['wordpress']['db']['user'] = '", { "Ref": "WPDBUser" }, "'\" >> /var/chef/chef-repo/cookbooks/wordpress/berks-cookbooks/wordpress/attributes/aliyun_rds_config.rb\n", "echo \"normal['wordpress']['db']['host'] = '", { "Fn::GetAtt": [ "WPDBDatabase", "InnerConnectionString" ] }, "'\" >> /var/chef/chef-repo/cookbooks/wordpress/berks-cookbooks/wordpress/attributes/aliyun_rds_config.rb\n", "echo \"normal['wordpress']['db']['name'] = '", { "Ref": "WPDBName" }, "'\" >> /var/chef/chef-repo/cookbooks/wordpress/berks-cookbooks/wordpress/attributes/aliyun_rds_config.rb\n", "\n", "\n", "echo run install wordpress cookbook >> /tmp/log\n", "knife node run_list add -z `knife node list -z` recipe[wordpress]\n", "\n", "chef-client -z -c /var/chef/chef-repo/.chef/client.rb | tee -a /tmp/chef_runing_log\n", "ros-notify\n" ] ] } ] }, "MaxAmount": { "Ref": "WPEcsMaxAmount" }, "VSwitchId": { "Ref": "VSwitch" }, "VpcId": { "Ref": "Vpc" }, "InstanceType": { "Ref": "WPEcsInstanceType" } } }, "JumpHost": { "Type": "ALIYUN::ECS::Instance", "Properties": { "IoOptimized": "optimized", "ImageId": { "Ref": "WPEcsImageId" }, "SecurityGroupId": { "Fn::GetAtt": [ "DefaultSecurityGroup", "SecurityGroupId" ] }, "Password": { "Ref": "WPEcsInstancePassword" }, "AllocatePublicIP": "true", "SystemDiskCategory": "cloud_efficiency", "VSwitchId": { "Ref": "VSwitch" }, "VpcId": { "Ref": "Vpc" }, "InstanceType": { "Ref": "WPEcsInstanceType" } } },

    ROS 通过 UserData 集成了 Chef, 首先安装 Chef 所依赖的 ruby 环境。由于网络原因,我们把 Chef 的安装包,本地仓库和相应的 cookbook 都做了镜像,方便大家在国内访问。然后配置 Chef 的 knife.rb 和 client.rb 文件指向本地仓库中的 cookbook。调用 chef-client -z 指定本地模式生成 node list。然后添加RDS实例中的数据库名称,用户名,密码和机器名称到 WordPress cookbook 的 attributes 中,保证 Chef 能正确配置 WordPress 数据库属性。最后调用下面的 Chef 命令,在本机上安装配置 WordPress 实例。

    knife node run_list add -z `knife node list -z` recipe[wordpress] chef-client -z -c /var/chef/chef-repo/.chef/client.rb

    SLB

    要高可用的环境,SLB 是必不可少的一个资源。通过 SLB 即可均衡分配请求到后端服务,更可以做用户无感知地增加,减少或者替换有问题的后端 ECS 实例。同时,通过 SLB 可以给用户提供一个唯一的WordPress 访问地址。本例中,创建 SLB 后,配置了 SLB 监听后端的 ECS 的80端口。

    "WPLoadBalancerListener80": { "Type": "ALIYUN::SLB::Listener", "DependsOn": "WPLoadBalancer", "Properties": { "Persistence": { "StickySession": "on", "PersistenceTimeout": 600 }, "HealthCheck": { "Timeout": "2", "Port": "80", "Interval": "5", "HealthyThreshold": "2", "UnhealthyThreshold": "4" }, "LoadBalancerId": { "Ref": "WPLoadBalancer" }, "BackendServerPort": "80", "Protocol": "tcp", "Bandwidth": -1, "ListenerPort": "80" } }, "WPSLBAttachment": { "Type": "ALIYUN::SLB::BackendServerAttachment", "Properties": { "BackendServerList": { "Fn::GetAtt": [ "WPEcsInstance", "InstanceIds" ] }, "LoadBalancerId": { "Ref": "WPLoadBalancer" } } }, "WPLoadBalancer": { "Type": "ALIYUN::SLB::LoadBalancer", "Properties": { "LoadBalancerName": "WordPressLoadBalancer", "AddressType": "internet" } },

    RDS

    WordPress 需要存储用户的博文和评论,后端数据库是必不可少的一个组件。阿里云 RDS 资源是一个很好的选择。通过 ROS 可以简便的把创建 RDS 实例和配置数据库一步搞定。

    "WPDBDatabase": { "Type": "ALIYUN::RDS::DBInstance", "DependsOn": "SNatEntry", "Properties": { "DBInstanceClass": { "Ref": "WPDBInstanceClass" }, "DBMappings": [ { "DBName": { "Ref": "WPDBName" }, "CharacterSetName": "utf8" } ], "ZoneId": { "Fn::Select": [ "0", { "Fn::GetAZs": { "Ref": "ALIYUN::Region" } } ] }, "DBInstanceStorage": { "Ref": "WPDBInstanceStorage" }, "VSwitchId": { "Ref": "VSwitch" }, "Engine": { "Ref": "WPDBEngine" }, "MasterUserPassword": { "Ref": "WPDBPassword" }, "MasterUsername": { "Ref": "WPDBUser" }, "PreferredBackupPeriod": [ "Monday", "Wednesday" ], "VPCId": { "Ref": "Vpc" }, "EngineVersion": { "Ref": "WPDBEngineVersion" }, "PreferredBackupTime": "23:00Z-24:00Z", "SecurityIPList": "0.0.0.0/0" } },

    总结

    从本例来看,不仅通过 ROS 能安装配置应用,也可以通过集成第三方的官配工具实现相同的目的。本例以Chef 为例相大家展示了 ROS 如何通过集成 第三方配管工具。希望通过这个例子,大家通过 Chef 不光能部署 WordPress ,更能部署自己的应用。关于 ROS 的详细指导请参考这里。

    资源编排ROS 是一种简单易用的云计算资源管理和自动化运维服务。用户通过模板描述多个云计算资源的依赖关系、配置等,并自动完成所有资源的创建和配置,以达到自动化部署、运维等目的。 了解更多 相关资源:python入门教程(PDF版)
    最新回复(0)