使用ROS CDK部署Nginx服务

本文以TypeScript语言为例,为您介绍如何使用ROS CDK部署Nginx服务。

步骤一:初始化工程

执行以下命令,创建工程目录并初始化工程。

mkdir demo
cd demo
ros-cdk init --language=typescript --generate-only=true

步骤二:配置阿里云凭证信息

  1. 执行以下命令,配置阿里云凭证信息。

    ros-cdk config
  2. 根据界面提示输入配置信息。

    ros-cdk config
    endpoint(optional, default:https://ros.aliyuncs.com):
    defaultRegionId(optional, default:cn-hangzhou):cn-beijing
    
    [1] AK
    [2] StsToken
    [3] RamRoleArn
    [4] EcsRamRole
    [0] CANCEL
    
    Authenticate mode [1...4 / 0]: 1
    accessKeyId:************************
    accessKeySecret:******************************
    
     ✅ Your cdk configuration has been saved successfully!

步骤三:安装依赖

  1. 修改package.json文件,添加ECS依赖包(ros-cdk-ecs)。

    {
      "name": "demo",
      "version": "0.1.0",
      "bin": {
        "demo": "bin/demo.js"
      },
      "scripts": {
        "build": "tsc",
        "test": "jest"
      },
      "devDependencies": {
        "@types/jest": "^25.2.1",
        "@types/node": "10.17.5",
        "typescript": "^3.9.7",
        "jest": "^25.5.0",
        "ts-jest": "^25.3.1",
        "ts-node": "^8.1.0",
        "babel-jest": "^26.6.3",
        "@babel/core": "^7.12.9",
        "@babel/preset-env": "7.12.7",
        "@babel/preset-typescript": "^7.12.7",
        "@alicloud/ros-cdk-assert": "^1.0.0"
      },
      "dependencies": {
        "@alicloud/ros-cdk-core": "^1.0.5",
        "@alicloud/ros-cdk-ecs": "^1.0.3",
        "@alicloud/ros-cdk-ros": "1.0.0"
      }
    }
  2. 执行以下命令,安装依赖。

    npm install

步骤四:管理资源栈

  1. 修改lib/demo-stack.ts文件,创建ECS实例并安装Nginx服务。

    下列提供多语言的示例代码供您参考。

    TypeScript示例

    import * as ros from '@alicloud/ros-cdk-core';
    import * as ecs from '@alicloud/ros-cdk-ecs';
    import * as ROS from '@alicloud/ros-cdk-ros';
    
    export class DemoStack extends ros.Stack {
        constructor(scope: ros.Construct, id: string, props?: ros.StackProps) {
            super(scope, id, props);
            new ros.RosInfo(this, ros.RosInfo.description, "This is the simple ros cdk app example.");
            // The code that defines your stack goes here
            const nginxDefaultPort = new ros.RosParameter(this, 'NginxDefaultPort', {
                type: ros.RosParameterType.STRING,
            });
            const ecsInstanceType = new ros.RosParameter(this, 'EcsInstanceType', {
                type: ros.RosParameterType.STRING,
            });
            const systemDiskCategory = new ros.RosParameter(this, 'SystemDiskCategory', {
                type: ros.RosParameterType.STRING,
            });
            const vpc = new ecs.Vpc(this, 'vpc-from-ros-cdk', {
                vpcName: 'test-ros-cdk-vpc',
                cidrBlock: '10.0.0.0/8',
                description: 'This is ros cdk test'
            });
    
            const vsw = new ecs.VSwitch(this, `vsw-from-ros-cdk`, {
                vpcId: vpc.attrVpcId,
                // zoneId: ros.Fn.select(0, ros.Fn.getAzs(ros.Fn.ref('ALIYUN::Region'))),
                zoneId: 'cn-beijing-h',
                vSwitchName: 'test-ros-cdk-vsw',
                cidrBlock: '10.0.0.0/16',
            });
    
            const sg = new ecs.SecurityGroup(this, 'ros-cdk-test-sg',{
                vpcId: vpc.attrVpcId,
                securityGroupName: 'test-ros-cdk-sg',
                securityGroupIngress: [{'portRange':'22/22','nicType':'intranet','ipProtocol':'tcp','sourceCidrIp':'0.0.0.0/0'},
                    {'portRange':'80/80','nicType':'intranet','ipProtocol':'tcp','sourceCidrIp':'0.0.0.0/0'}]
            });
    
            const ecsWaitConditionHandle = new ROS.WaitConditionHandle(this,'RosWaitConditionHandle',{
                count: 1
            })
    
            const ecsWaitCondition = new ROS.WaitCondition(this,'RosWaitCondition',{
                timeout: 300,
                handle: ros.Fn.ref('RosWaitConditionHandle'),
                count: 1
            })
            let NginxDefaultPort = nginxDefaultPort.valueAsString
            const ecsGroups = new ecs.InstanceGroup(this,'ros-cdk-test-ecs',{
                vpcId: vpc.attrVpcId,
                vSwitchId: vsw.attrVSwitchId,
                imageId: 'centos_7',
                maxAmount: 1,
                securityGroupId: sg.attrSecurityGroupId,
                instanceType: ecsInstanceType.valueAsString,
                systemDiskCategory: systemDiskCategory.valueAsString,
                instanceName: 'test-ros-cdk-ecs',
                userData: ros.Fn.replace({ NOTIFY: ecsWaitConditionHandle.attrCurlCli }, `#!/bin/bash\nyum install -y nginx\nsed -i \'s/listen       80;/listen       ${NginxDefaultPort};/\' /etc/nginx/nginx.conf \nsystemctl restart nginx\n NOTIFY`),
            });
        }
    }

    Java示例

    package com.myorg;
    
    import com.aliyun.ros.cdk.core.*;
    
    import com.aliyun.ros.cdk.ecs.*;
    
    import com.aliyun.ros.cdk.ros.WaitConditionHandle;
    import com.aliyun.ros.cdk.ros.WaitCondition;
    
    import java.util.Arrays;
    import java.util.Map;
    import java.util.HashMap;
    import java.util.List;
    
    public class DemoStack extends Stack {
        public DemoStack(final Construct scope, final String id) {
            this(scope, id, null);
        }
    
        public DemoStack(final Construct scope, final String id, final StackProps props) {
            super(scope, id, props);
    
            // The code that defines your stack goes here
            List<Object> list1 = Arrays.asList();
            Map<String, String> Port22 = new HashMap<>();
            Map<String, String> Port80 = new HashMap<>();
            Map<String, Object> NOTIFY = new HashMap<>();
            Port22.put("PortRange", "22/22");
            Port22.put("SourceCidrIp", "0.0.0.0/0");
            Port22.put("IpProtocol", "tcp");
            Port22.put("NicType", "intranet");
            Port80.put("NicType", "intranet");
            Port80.put("SourceCidrIp", "0.0.0.0/0");
            Port80.put("IpProtocol", "tcp");
            Port80.put("PortRange", "80/80");
            list1.add(Port22);
            list1.add(Port80);
            RosParameter NginxDefaultPort = RosParameter.Builder.create(this, "NginxDefaultPort").type(RosParameterType.STRING).build();
            RosParameter EcsInstanceType = RosParameter.Builder.create(this, "EcsInstanceType").type(RosParameterType.STRING).build();
            RosParameter SystemDiskCategory = RosParameter.Builder.create(this, "SystemDiskCategory").type(RosParameterType.STRING).build();
            String str1 = "#!/bin/bash\\nyum install -y nginx\\nsed -i \\'s/listen       80;/listen       ";
            String nginx_default_port = NginxDefaultPort.getValueAsString();
            String str2 = ";/\\' /etc/nginx/nginx.conf \\nsystemctl restart nginx\\n NOTIFY";
            String user_data_str = str1 + nginx_default_port + str2;
            Vpc vpc = Vpc.Builder.create(this, "vpc-from-ros-cdk").vpcName("test-ros-cdk-vpc").
                    cidrBlock("10.0.0.0/8").description("This is ros cdk test").build();
            VSwitch vswitch = VSwitch.Builder.create(this, "vsw-from-ros-cdk").vpcId(vpc.getAttrVpcId()).
                    cidrBlock("10.0.0.0/16").vSwitchName("test-ros-cdk-vsw").zoneId("cn-beijing-h").build();
            SecurityGroup sg = SecurityGroup.Builder.create(this, "ros-cdk-test-sg").vpcId(vpc.getAttrVpcId())
                    .securityGroupIngress(list1).securityGroupName("test-ros-cdk-sg").build();
            WaitConditionHandle waitConditionHandle = WaitConditionHandle.Builder.create(this, "RosWaitConditionHandle").count(1).build();
            WaitCondition waitCondition = WaitCondition.Builder.create(this, "RosWaitCondition").
                    count(1).handle(Fn.ref("RosWaitConditionHandle")).timeout(300).build();
            NOTIFY.put("NOTIFY", waitConditionHandle.getAttrCurlCli());
            InstanceGroup.Builder.create(this, "ros-cdk-test-ecs").vpcId(vpc.getAttrVpcId()).
                    vSwitchId(vswitch.getAttrVSwitchId()).maxAmount(1).securityGroupId(sg.getAttrSecurityGroupId()).
                    instanceType(EcsInstanceType.getValueAsString()).userData(Fn.replace(NOTIFY, user_data_str)).
                    instanceName("test-ros-cdk-ecs").imageId("centos_7").systemDiskCategory(SystemDiskCategory.getValueAsString()).build();
    
        }
    }

    Python示例

    import ros_cdk_core as core
    import ros_cdk_ecs as ecs
    import ros_cdk_ros as ros
    
    
    class DemoStack(core.Stack):
    
        def __init__(self, scope: core.Construct, construct_id: str, **kwargs) -> None:
            super().__init__(scope, construct_id, **kwargs)
    
            # The code that defines your stack goes here
            nginx_default_port = core.RosParameter(self, "NginxDefaultPort",
                                                   type=core.RosParameterType.STRING)
    
            ecs_instance_type = core.RosParameter(self, "EcsInstanceType", type=core.RosParameterType.STRING)
    
            system_disk_category = core.RosParameter(self, "SystemDiskCategory", type=core.RosParameterType.STRING)
    
            vpc = ecs.Vpc(self, "vpc-from-ros-cdk", ecs.VPCProps(
                cidr_block="10.0.0.0/8",
                vpc_name="vpc-from-ros-cdk",
                description="This is ros cdk test"
            ))
    
            vswitch = ecs.VSwitch(self, "vsw-from-ros-cdk", ecs.VSwitchProps(
                cidr_block="10.0.0.0/16",
                zone_id="cn-beijing-h",
                vpc_id=vpc.attr_vpc_id,
                v_switch_name="test-ros-cdk-vsw"
            ))
    
            sg = ecs.SecurityGroup(self, "ros-cdk-test-sg", ecs.SecurityGroupProps(
                vpc_id=vpc.attr_vpc_id,
                security_group_name="test-ros-cdk-sg",
                security_group_ingress=[
                    {'portRange': '22/22', 'nicType': 'intranet', 'ipProtocol': 'tcp', 'sourceCidrIp': '0.0.0.0/0'},
                    {'portRange': '80/80', 'nicType': 'intranet', 'ipProtocol': 'tcp', 'sourceCidrIp': '0.0.0.0/0'}]
            ))
    
            wait_condition_handle = ros.WaitConditionHandle(self, "RosWaitConditionHandle", ros.WaitConditionHandleProps(
                count=1
            ))
    
            wait_condition = ros.WaitCondition(self, "RosWaitCondition", ros.WaitConditionProps(
                timeout=300,
                count=1,
                handle=core.Fn.ref("RosWaitConditionHandle")
            ))
    
            ecs.InstanceGroup(self, "ros-cdk-test-ecs", ecs.InstanceGroupProps(
                vpc_id=vpc.attr_vpc_id,
                v_switch_id=vswitch.attr_v_switch_id,
                security_group_id=sg.attr_security_group_id,
                max_amount=1,
                instance_type=ecs_instance_type.value_as_string,
                instance_name="test-ros-cdk-ecs",
                system_disk_category=system_disk_category.value_as_string,
                image_id="centos_7",
                user_data=core.Fn.replace({"NOTIFY": wait_condition_handle.attr_curl_cli},
                                          "#!/bin/bash\nyum install -y nginx\nsed -i \'s/listen       80;/listen       "
                                          + nginx_default_port.value_as_string +
                                          ";/\' /etc/nginx/nginx.conf \nsystemctl restart nginx\n NOTIFY")
            ))

    C#示例

    using System.Collections.Generic;
    using AlibabaCloud.SDK.ROS.CDK.Core;
    using AlibabaCloud.SDK.ROS.CDK.Ecs;
    using AlibabaCloud.SDK.ROS.CDK.Ros;
    using IStackProps = AlibabaCloud.SDK.ROS.CDK.Core.IStackProps;
    using Stack = AlibabaCloud.SDK.ROS.CDK.Core.Stack;
    
    namespace Demo
    {
        public class DemoStack : Stack
        {
            public DemoStack(Construct scope, string id, IStackProps props = null) : base(scope, id, props)
            {
                // The code that defines your stack goes here
                IDictionary<string, object> notifyObj = new Dictionary<string, object>();
                Dictionary<string, string> port22Obj = new Dictionary<string, string>();
                Dictionary<string, string> port80Obj = new Dictionary<string, string>();
                port22Obj.Add("PortRange", "22/22");
                port22Obj.Add("SourceCidrIp", "0.0.0.0/0");
                port22Obj.Add("IpProtocol", "tcp");
                port22Obj.Add("NicType", "intranet");
                port80Obj.Add("PortRange", "80/80");
                port80Obj.Add("SourceCidrIp", "0.0.0.0/0");
                port80Obj.Add("IpProtocol", "tcp");
                port80Obj.Add("NicType", "intranet");
    
                object[] RegionArray = new object[2] {port22Obj, port80Obj};
    
                var NginxDefaultPort = new RosParameter(this, "NginxDefaultPort", new RosParameterProps
                {
                    Type = RosParameterType.STRING,
                });
    
                var EcsInstanceType = new RosParameter(this, "EcsInstanceType", new RosParameterProps
                {
                    Type = RosParameterType.STRING
                });
    
                var SystemDiskCategory = new RosParameter(this, "SystemDiskCategory", new RosParameterProps
                {
                    Type = RosParameterType.STRING
                });
                
                var Vpc = new Vpc(this, "vpc-from-ros-cdk", new VPCProps
                {
                    CidrBlock = "10.0.0.0/8",
                    VpcName = "test-ros-cdk-vpc",
                    Description = "This is ros cdk test"
                });
                
                var VSwitch = new VSwitch(this, "vsw-from-ros-cdk", new VSwitchProps
                {
                    CidrBlock = "10.0.0.0/16",
                    ZoneId = "cn-beijing-h",
                    VpcId = Vpc.AttrVpcId,
                    VSwitchName = "test-ros-cdk-vsw"
                });
    
                var sg = new SecurityGroup(this, "ros-cdk-test-sg", new SecurityGroupProps
                {
                    VpcId = Vpc.AttrVpcId,
                    SecurityGroupName = "test-ros-cdk-sg",
                    SecurityGroupIngress = RegionArray,
                });
    
                var wait_condition_handle = new WaitConditionHandle(this, "RosWaitConditionHandle", new WaitConditionHandleProps
                {
                    Count = 1
                });
    
                var wait_condition = new WaitCondition(this, "RosWaitCondition", new WaitConditionProps
                {
                    Timeout = 300,
                    Count = 1,
                    Handle = Fn.Ref("RosWaitConditionHandle")
                });
                
                string str1 = "#!/bin/bash\nyum install -y nginx\nsed -i \'s/listen       80;/listen       ";
    
                string str2 = ";/\' /etc/nginx/nginx.conf \nsystemctl restart nginx\n NOTIFY";
    
                string str3 = NginxDefaultPort.ValueAsString;
                
                string result = str1+str3+ str2;
                
                notifyObj.Add("NOTIFY", wait_condition_handle.AttrCurlCli);
                var ecs = new InstanceGroup(this, "ros-cdk-test-ecs", new InstanceGroupProps
                {
                    VpcId = Vpc.AttrVpcId,
                    VSwitchId = VSwitch.AttrVSwitchId,
                    SecurityGroupId = sg.AttrSecurityGroupId,
                    MaxAmount = 1,
                    InstanceType = EcsInstanceType.ValueAsString,
                    InstanceName = "test-ros-cdk-ecs",
                    ImageId = "centos_7",
                    SystemDiskCategory = SystemDiskCategory.ValueAsString,
                    UserData = Fn.Replace(notifyObj, result)
                });
            }
        }
    }

  2. 执行以下命令,生成模板文件。

    ros-cdk synth --json

    执行命令后,输出以下内容:

    {
      "Description": "This is the simple ros cdk app example.",
      "Metadata": {
        "ALIYUN::ROS::Interface": {
          "TemplateTags": [
            "Create by ROS CDK"
          ]
        }
      },
      "ROSTemplateFormatVersion": "2015-09-01",
      "Parameters": {
        "NginxDefaultPort": {
          "Type": "String"
        },
        "EcsInstanceType": {
          "Type": "String"
        },
        "SystemDiskCategory": {
          "Type": "String"
        }
      },
      "Resources": {
        "vpc-from-ros-cdk": {
          "Type": "ALIYUN::ECS::VPC",
          "Properties": {
            "CidrBlock": "10.0.0.0/8",
            "Description": "This is ros cdk test",
            "EnableIpv6": false,
            "VpcName": "test-ros-cdk-vpc"
          }
        },
        "vsw-from-ros-cdk": {
          "Type": "ALIYUN::ECS::VSwitch",
          "Properties": {
            "CidrBlock": "10.0.0.0/16",
            "VpcId": {
              "Fn::GetAtt": [
                "vpc-from-ros-cdk",
                "VpcId"
              ]
            },
            "ZoneId": "cn-beijing-h",
            "VSwitchName": "test-ros-cdk-vsw"
          }
        },
        "ros-cdk-test-sg": {
          "Type": "ALIYUN::ECS::SecurityGroup",
          "Properties": {
            "SecurityGroupIngress": [
              {
                "PortRange": "22/22",
                "SourceCidrIp": "0.0.0.0/0",
                "IpProtocol": "tcp",
                "NicType": "intranet"
              },
              {
                "PortRange": "80/80",
                "SourceCidrIp": "0.0.0.0/0",
                "IpProtocol": "tcp",
                "NicType": "intranet"
              }
            ],
            "SecurityGroupName": "test-ros-cdk-sg",
            "VpcId": {
              "Fn::GetAtt": [
                "vpc-from-ros-cdk",
                "VpcId"
              ]
            }
          }
        },
        "RosWaitConditionHandle": {
          "Type": "ALIYUN::ROS::WaitConditionHandle",
          "Properties": {
            "Count": 1,
            "Mode": "Full"
          }
        },
        "RosWaitCondition": {
          "Type": "ALIYUN::ROS::WaitCondition",
          "Properties": {
            "Handle": {
              "Ref": "RosWaitConditionHandle"
            },
            "Timeout": 300,
            "Count": 1
          }
        },
        "ros-cdk-test-ecs": {
          "Type": "ALIYUN::ECS::InstanceGroup",
          "Properties": {
            "ImageId": "centos_7",
            "InstanceType": {
              "Ref": "EcsInstanceType"
            },
            "MaxAmount": 1,
            "AllocatePublicIP": true,
            "AutoRenew": "False",
            "AutoRenewPeriod": 1,
            "InstanceChargeType": "PostPaid",
            "InstanceName": "test-ros-cdk-ecs",
            "InternetChargeType": "PayByTraffic",
            "InternetMaxBandwidthIn": 200,
            "InternetMaxBandwidthOut": 1,
            "IoOptimized": "optimized",
            "Period": 1,
            "PeriodUnit": "Month",
            "SecurityGroupId": {
              "Fn::GetAtt": [
                "ros-cdk-test-sg",
                "SecurityGroupId"
              ]
            },
            "SystemDiskCategory": {
              "Ref": "SystemDiskCategory"
            },
            "UserData": {
              "Fn::Replace": [
                {
                  "NOTIFY": {
                    "Fn::GetAtt": [
                      "RosWaitConditionHandle",
                      "CurlCli"
                    ]
                  }
                },
                {
                  "Fn::Join": [
                    "",
                    [
                      "#!/bin/bash\nyum install -y nginx\nsed -i 's/listen       80;/listen       ",
                      {
                        "Ref": "NginxDefaultPort"
                      },
                      ";/' /etc/nginx/nginx.conf \nsystemctl restart nginx\n NOTIFY"
                    ]
                  ]
                }
              ]
            },
            "VpcId": {
              "Fn::GetAtt": [
                "vpc-from-ros-cdk",
                "VpcId"
              ]
            },
            "VSwitchId": {
              "Fn::GetAtt": [
                "vsw-from-ros-cdk",
                "VSwitchId"
              ]
            }
          }
        }
      }
    }
  3. 执行以下命令,创建资源栈。

    ros-cdk deploy --parameters EcsInstanceType=ecs.c6e.large --parameters NginxDefaultPort=8080 --parameters SystemDiskCategory=cloud_essd --sync=true

    执行命令后,输出以下内容:

    DemoStack: deploying...
    |DemoStack               |2021-12-28T09:08:38 | CREATE_COMPLETE      | ALIYUN::ECS::SecurityGroup | sg-2ze515oc21n45wgs**** | ros-cdk-test-sg
    
    |DemoStack               |2021-12-28T09:08:38 | CREATE_COMPLETE      | ALIYUN::ECS::VSwitch    | vsw-2zeuuwgla2qqrw89**** | vsw-from-ros-cdk
    
    |DemoStack               |2021-12-28T09:08:38 | CREATE_COMPLETE      | ALIYUN::ROS::WaitConditionHandle |  | RosWaitConditionHandle
    
    |DemoStack               |2021-12-28T09:08:38 | CREATE_COMPLETE      | ALIYUN::ECS::VPC        | vpc-2zedbloxtm5jetdg**** | vpc-from-ros-cdk
    
    |DemoStack               |2021-12-28T09:08:38 | CREATE_COMPLETE      | ALIYUN::ECS::InstanceGroup | i-2ze6yjdmete88**** | ros-cdk-test-ecs
    
    |DemoStack               |2021-12-28T09:08:38 | CREATE_COMPLETE      | ALIYUN::ROS::WaitCondition |  | RosWaitCondition
    
    
     ✅ The deployment(sync deploy stack) has finished!
    status: CREATE_COMPLETE
    StatusReason: Stack CREATE completed successfully
    StackId: f7ddd89b-914a-44a4-aac9-80derdg****
  4. 可选:删除资源栈。

    1. 执行以下命令:

      ros-cdk destroy --sync=true
    2. 根据界面提示,确认删除。

      The following stack(s) will be destroyed(Only deployed stacks will be displayed).
      
      DemoStack
      
      Please confirm.(Y/N)
      y

      执行命令后,输出以下内容:

      DemoStack: destroying...
      |DemoStack               | DELETE_COMPLETE      | ALIYUN::ECS::SecurityGroup |  | ros-cdk-test-sg
      
      |DemoStack               | DELETE_COMPLETE      | ALIYUN::ECS::VSwitch    |  | vsw-from-ros-cdk
      
      |DemoStack               | DELETE_COMPLETE      | ALIYUN::ROS::WaitConditionHandle |  | RosWaitConditionHandle
      
      |DemoStack               | DELETE_COMPLETE      | ALIYUN::ECS::VPC        |  | vpc-from-ros-cdk
      
      |DemoStack               | DELETE_COMPLETE      | ALIYUN::ECS::InstanceGroup |  | ros-cdk-test-ecs
      
      |DemoStack               | DELETE_COMPLETE      | ALIYUN::ROS::WaitCondition |  | RosWaitCondition
      
      
       ✅ The task(sync destroy stack) has finished!
      status: DELETE_COMPLETE
      StatusReason: Stack DELETE completed successfully
      StackId: f7ddd89b-914a-44a4-aac9-80derdg****