本文是基于资源编排一键交付应用的进阶篇。
众所周知,许多 Web 应用都会涉及对数据库的访问,但出于对数据的保护,通常我们在构建应用时会将应用本身和其对应的数据库分别部署在不同的机器上,以实现数据与应用相隔离。同时,为了降低应用构建的复杂度,阿里云提供了稳定可靠、可弹性伸缩的在线数据库服务 RDS,实现了对数据库的快速部署,从而使得对应用的部署工作主要集中在应用本身,所以本文将讲解如何基于资源编排实现应用与 RDS 的连接。
基于资源编排一键交付连接 RDS 的应用的工作,主要包括以下两个方面:
- 熟悉 RDS 资源,并定义构建 RDS 资源的模板
- 将构建 RDS 资源的模板与构建应用的资源模板进行整合
为了便于说明,本文将以基于资源编排一键交付应用中构建的 WordPress 作为示例。与上篇不同的是,本文在构建应用是除了构建 WordPress 的运行环境 ECS 外,还要构建数据库资源 RDS,并且 RDS 的构建顺序要优先于 ECS,以便 ECS 资源可实现对 RDS 资源的连接访问。
同样,目前云资源构建的网络类型只支持 VPC,可选区域仅支持华南1、华北2和华东2,即RegionId
只支持cn-shenzhen
、cn-beijing
和cn-shanghai
。其它的 Region 和网络类型,我们也会尽快的上线。
定义构建RDS资源的模板
定义一个 RDS 资源编排模板,用于构建 RDS 资源。在模板中定义我们需要创建的资源:
-
ALIYUN::RDS::DBInstance
RDS 可支持 MySQL、SQL Server、PostgreSQL 和 PPAS 引擎,本文 RDS 用于搭建 WordPress 应用,所以使用常用的 MySQL 即可。除此之外,您还可以在模板中设置更多关于数据库的信息。
以下是利用已有 VPC 环境构建 RDS 资源的模板:
{
"ROSTemplateFormatVersion": "2015-09-01",
"Parameters": {
"DBName": {
"AllowedPattern": "[a-z]{1}[a-z0-9-_]*[a-z0-9]{1}",
"ConstraintDescription": "由 2~64 个字符的小写字母、数字、下划线或中划线组成,开头需为字母,结尾需为字母或数字。",
"Default": "wordpress",
"Description": "WordPress数据库名称",
"MaxLength": "64",
"MinLength": "2",
"Type": "String"
},
"DBPassword": {
"AllowedPattern": "[a-zA-Z0-9-_]*",
"ConstraintDescription": "由 6~32 个字符的字母、数字、中划线或下划线组成。",
"Default": "wpADMIN123",
"Description": "WordPress数据库密码",
"MaxLength": "32",
"MinLength": "6",
"Type": "String"
},
"DBUser": {
"AllowedPattern": "[a-z]{1}[a-z0-9_]*[a-z0-9]{1}",
"ConstraintDescription": "由 2~16 个字符的小写字母,数字或下划线组成、开头需为字母,结尾需为字母或数字。",
"Default": "wpuser",
"Description": "WordPress数据库用户名",
"MaxLength": "16",
"MinLength": "2",
"Type": "String"
},
"VSwitchId": {
"Description": "已创建的VSwitch的ID",
"Type": "String"
},
"VpcId": {
"Description": "已创建的vpc的ID",
"Type": "String"
}
},
"Resources": {
"Database": {
"Properties": {
"DBInstanceClass": "rds.mysql.t1.small",
"DBInstanceDescription": "ros",
"DBInstanceStorage": "50",
"DBMappings": [
{
"CharacterSetName": "utf8",
"DBName": {
"Ref": "DBName"
}
}
],
"Engine": "MySQL",
"EngineVersion": "5.6",
"MasterUserPassword": {
"Ref": "DBPassword"
},
"MasterUsername": {
"Ref": "DBUser"
},
"PreferredBackupPeriod": [
"Monday",
"Wednesday"
],
"PreferredBackupTime": "23:00Z-24:00Z",
"SecurityIPList": "0.0.0.0/0",
"VPCId": {
"Ref": "VpcId"
},
"VSwitchId": {
"Ref": "VSwitchId"
}
},
"Type": "ALIYUN::RDS::DBInstance"
}
},
"Outputs": {
"DBInstanceId": {
"Value": {
"Fn::GetAtt": [
"Database",
"DBInstanceId"
]
}
},
"InnerConnectionString": {
"Value": {
"Fn::GetAtt": [
"Database",
"InnerConnectionString"
]
}
}
}
}
整合RDS到WordPress的构建模板中
定义好 RDS 的模板后,需要将该模板整合到 WordPress 的构建模板中,以实现 WordPress 对 RDS 资源的直接访问。由于 WordPress 的运行环境ALIYUN::ECS::Instance
要直接访问资源ALIYUN::RDS::DBInstance
,因此在模板中定义ALIYUN::ECS::Instance
时要使用属性DependsOn作为支持,保证资源ALIYUN::RDS::DBInstance
优先于资源ALIYUN::ECS::Instance
创建。
ECS 实例是怎么连接到 RDS 的呢?这里用到的就是资源ALIYUN::RDS::DBInstance
的属性 InnerConnectionString。在 RDS 创建成功后,通过内部函数Fn::GetAtt获取 RDS 的 InnerConnectionString,并将其设置为 WordPress 的 DatabaseHost,自此就可以轻松访问 RDS 了。
以下是利用已有 VPC 资源整合资源 RDS 后的构建 WordPress 的模板:
{
"ROSTemplateFormatVersion": "2015-09-01",
"Parameters": {
"DBName": {
"AllowedPattern": "[a-z]{1}[a-z0-9-_]*[a-z0-9]{1}",
"ConstraintDescription": "由 2~64 个字符的小写字母、数字、下划线或中划线组成,开头需为字母,结尾需为字母或数字。",
"Default": "wordpress",
"Description": "WordPress数据库名称",
"MaxLength": "64",
"MinLength": "2",
"Type": "String"
},
"DBPassword": {
"AllowedPattern": "[a-zA-Z0-9-_]*",
"ConstraintDescription": "由 6~32 个字符的字母、数字、中划线或下划线组成。",
"Default": "wpADMIN123",
"Description": "WordPress数据库密码",
"MaxLength": "32",
"MinLength": "6",
"Type": "String"
},
"DBUser": {
"AllowedPattern": "[a-z]{1}[a-z0-9_]*[a-z0-9]{1}",
"ConstraintDescription": "由 2~16 个字符的小写字母,数字或下划线组成、开头需为字母,结尾需为字母或数字。",
"Default": "wpuser",
"Description": "WordPress数据库用户名",
"MaxLength": "16",
"MinLength": "2",
"Type": "String"
},
"InstancePassword": {
"AllowedPattern": "[a-zA-Z0-9]*",
"ConstraintDescription": "可包含大小写字母,数字和特殊字符",
"Default": "vmADMIN123",
"Description": "ECS实例的登录密码",
"MaxLength": "41",
"MinLength": "8",
"Type": "String"
},
"SecurityGroupName": {
"Description": "安全组名称",
"Type": "String"
},
"VSwitchId": {
"Description": "已创建的VSwitch的ID",
"Type": "String"
},
"VpcId": {
"Description": "已创建的vpc的ID",
"Type": "String"
},
"ZoneId": {
"Default": "cn-shenzhen-a",
"Description": "可用区 Id",
"Type": "String"
}
},
"Resources": {
"Database": {
"Properties": {
"DBInstanceClass": "rds.mysql.t1.small",
"DBInstanceDescription": "ros",
"DBInstanceStorage": "50",
"DBMappings": [
{
"CharacterSetName": "utf8",
"DBName": {
"Ref": "DBName"
}
}
],
"Engine": "MySQL",
"EngineVersion": "5.6",
"MasterUserPassword": {
"Ref": "DBPassword"
},
"MasterUsername": {
"Ref": "DBUser"
},
"PreferredBackupPeriod": [
"Monday",
"Wednesday"
],
"PreferredBackupTime": "23:00Z-24:00Z",
"SecurityIPList": "0.0.0.0/0",
"VPCId": {
"Ref": "VpcId"
},
"VSwitchId": {
"Ref": "VSwitchId"
}
},
"Type": "ALIYUN::RDS::DBInstance"
},
"EIPBind": {
"Properties": {
"AllocationId": {
"Ref": "NewEip"
},
"InstanceId": {
"Ref": "WebServer"
}
},
"Type": "ALIYUN::ECS::EIPAssociation"
},
"NewEip": {
"Properties": {
"Bandwidth": 1,
"InternetChargeType": "PayByTraffic"
},
"Type": "ALIYUN::ECS::EIP"
},
"SecurityGroup": {
"Properties": {
"SecurityGroupName": {
"Ref": "SecurityGroupName"
},
"VpcId": {
"Ref": "VpcId"
}
},
"Type": "ALIYUN::ECS::SecurityGroup"
},
"SecurityGroupIngress": {
"Properties": {
"IpProtocol": "all",
"PortRange": "-1/-1",
"SecurityGroupId": {
"Ref": "SecurityGroup"
},
"SourceCidrIp": "0.0.0.0/0"
},
"Type": "ALIYUN::ECS::SecurityGroupIngress"
},
"WebServer": {
"DependsOn": "Database",
"Properties": {
"ImageId": "centos6u5_64_40G_cloudinit_20160427.raw",
"InstanceType": "ecs.s2.large",
"IoOptimized": "optimized",
"Password": {
"Ref": "InstancePassword"
},
"SecurityGroupId": {
"Ref": "SecurityGroup"
},
"SystemDiskCategory": "cloud_ssd",
"UserData": {
"Fn::Replace": [
{
"print": "echo"
},
{
"Fn::Join": [
"",
[
"#!/bin/sh",
"\n",
"DatabaseUser=",
{
"Ref": "DBUser"
},
"\n",
"DatabasePwd=",
{
"Ref": "DBPassword"
},
"\n",
"DatabaseName=",
{
"Ref": "DBName"
},
"\n",
"DatabaseHost=",
{
"Fn::GetAtt": [
"Database",
"InnerConnectionString"
]
},
"\n",
"WebRootPath='/var/www/html'\n",
"ApacheIndex='Options Indexes FollowSymLinks'\n",
"ApacheIndexReplace='Options -Indexes FollowSymLinks'\n",
"yum install -y curl httpd mysql-server php php-common php-mysql\n",
"yum install -y php-gd php-imap php-ldap php-odbc php-pear php-xml php-xmlrpc\n",
"chkconfig httpd on\n",
"wget http://wordpress.org/latest.tar.gz\n",
"tar -xzvf latest.tar.gz\n",
"sed -i \"s/database_name_here/$DatabaseName/\" wordpress/wp-config-sample.php\n",
"sed -i \"s/username_here/$DatabaseUser/\" wordpress/wp-config-sample.php\n",
"sed -i \"s/password_here/${DatabasePwd:-$DatabasePwdDef}/\" wordpress/wp-config-sample.php\n",
"sed -i \"s/localhost/$DatabaseHost/\" wordpress/wp-config-sample.php\n",
"mv wordpress/wp-config-sample.php wordpress/wp-config.php\n",
"cp -a wordpress/* $WebRootPath\n",
"rm -rf wordpress*\n",
"service httpd stop\n",
"usermod -d $WebRootPath apache &>/dev/null\n",
"chown apache:apache -R $WebRootPath\n",
"sed -i \"s/$ApacheIndex/$ApacheIndexReplace/\" /etc/httpd/conf/httpd.conf\n",
"service httpd start\n"
]
]
}
]
},
"VSwitchId": {
"Ref": "VSwitchId"
},
"VpcId": {
"Ref": "VpcId"
}
},
"Type": "ALIYUN::ECS::Instance"
}
},
"Outputs": {
"DBInstanceId": {
"Value": {
"Fn::GetAtt": [
"Database",
"DBInstanceId"
]
}
},
"InnerConnectionString": {
"Value": {
"Fn::GetAtt": [
"Database",
"InnerConnectionString"
]
}
},
"InstanceId": {
"Value": {
"Fn::GetAtt": [
"WebServer",
"InstanceId"
]
}
},
"PublicIp": {
"Value": {
"Fn::GetAtt": [
"WebServer",
"PublicIp"
]
}
}
}
}
创建Stack资源
完成模板的创建后,根据 Stack 资源的创建步骤,输入必要的参数,点击创建
按钮,即可完成资源的创建以及应用的构建。
访问WordPress
资源创建完成后,根据资源创建的输出结果,在浏览器中输入http://[PublicIP]/wp-admin/install.php
即可访问搭建好的 WordPress 应用。