使用ROS一键创建,分区,格式化和挂载数据盘

本文涉及的产品
资源编排,不限时长
简介: 对于每一个应用来说都有存储数据的需求,阿里云ECS针对不同的用户需求提供了三种类型的数据云盘,普通云盘,高效云盘和SSD云盘。通过ECS控制台可以为每个实例创建最多4块空数据盘或者根据已有数据盘的snapshot产生4块含有数据的云盘。但是根据上面的方式产生的数据云盘,不能直接使用,需用户登录EC.

对于每一个应用来说都有存储数据的需求,阿里云ECS针对不同的用户需求提供了三种类型的数据云盘,普通云盘,高效云盘和SSD云盘。通过ECS控制台可以为每个实例创建最多4块空数据盘或者根据已有数据盘的snapshot产生4块含有数据的云盘。但是根据上面的方式产生的数据云盘,不能直接使用,需用户登录ECS实例手动配置。对于空数据盘,用户登录ECS的实例手动分区,格式化,挂载;对于通过snapshot产生的数据盘,用户必须自己手动mount。这对于用户部署使用多台ECS实例,是一个繁重的体力活而且容易出错。

本文将为大家提供一个基于资源编排一键创建数据盘并通过UserData自动分区,格式化,化挂载数据盘的便捷方法。

创建数据盘

创建数据盘有两种方式:

  1. 作为ECS实例的属性

    DiskMappings

    DiskMappings是一个列表类型的属性,列表的每一个项就代表一个数据盘的定义,用户可以指定数据盘名称,大小,类型,以及源snapshotId。

  2. 作为stack的资源,再把disk资源关联到对应的ECS

    ALIYUN::ECS::Disk

    在模版指定这样的资源就说明需要创建一块数据盘,用户指定数据盘名称,大小,域,源snapshotId等等

    ALIYUN::ECS::DiskAttachment

    指定哪一块数据盘要和关联到哪一个ECS实例。必须指定的属性包括ALIYUN::ECS::Disk的Id和ECS实例的Id

    不管是上面那种方式创建带有源数据的云盘,源数据盘snapshot必须和将要创建的数据盘在同一个域。

利用UserData处理数据盘

ROS给用户提供了UserData机制,这样用户就可以在创建ECS的时候,通过指定UserData脚本给ECS在第一次启动的时候做一些配置和初始化的工作。用户可以根据自己的需要自由的编写UserData脚本。下面我将提供两个简单的例子说明到底如何利用ROS和UserData机制实现一键创建数据盘并自动分区,格式化和mount。

UserData脚处理空数据盘

这个例子创建一个ECS实例,并给实例创建2个空数据盘,让实例处于阿里云的专有网络,并且给这个实例分配弹性IP以便后续访问。我们使用的是DiskMappings实例属性来说明ROS怎么创建数据盘,这个例子中定义了数据盘的名称,大小。给UserData指定了一个简单的脚本,脚本中首先是通过fdisk命令分区数据盘,然后以ext4方式格式化数据盘,最后挂载数据盘,最后配置/etc/fstab保证每次启动ECS都能正确挂载数据盘。在这个例子中用户可以通过TotalDataDisk说明有多少块数据盘,MountPoint指定数据盘的挂载点。我也通过指定ROS的WaitCondition资源来得到UserData脚本的执行结果。WaitCondition的使用可以参考这里。下面是最终模版:

{
  "ROSTemplateFormatVersion": "2015-09-01",
  "Parameters": {
    "VpcName": {
      "MaxLength": 128,
      "Description": "VPC 名称",
      "Type": "String",
      "ConstraintDescription": "[2, 128] 英文或中文字符",
      "MinLength": 2
    },
    "SecurityGroupName": {
      "Description": "安全组名称",
      "Type": "String"
    },
    "VpcCidrBlock": {
      "Default": "10.0.0.0/8",
      "AllowedValues": [
        "192.168.0.0/16",
        "172.16.0.0/12",
        "10.0.0.0/8"
      ],
      "Type": "String"
    },
    "Password": {
      "NoEcho": true,
      "MaxLength": 30,
      "Description": "ECS登录密码.",
      "Type": "String",
      "ConstraintDescription": "8-30个字符,可以包含大、小写字母和特殊字符",
      "MinLength": 8
    },
    "DiskSize": {
      "Default": 40,
      "Type": "Number"
    },
    "TotalDataDisk": {
      "Description": "实例挂在数据盘的数量",
      "Type": "String"
    },
    "ZoneId": {
      "Description": "可用区 Id,  <a href='#/product/cn-shenzhen/list/zoneList' target='_blank'>查看可用区</a>",
      "Type": "String"
    },
    "DiskName": {
      "Type": "String"
    },
    "SystemDiskCategory": {
      "Default": "cloud",
      "AllowedValues": [
        "cloud",
        "cloud_efficiency",
        "cloud_ssd"
      ],
      "Description": "系统盘的磁盘种类, 普通云盘(cloud)、高效云盘(cloud_efficiency)或SSD云盘(cloud_ssd)",
      "Type": "String"
    },
    "MountPoint": {
      "Description": "数据盘的挂在点",
      "Type": "String"
    },
    "DestinationCidrBlock": {
      "Default": "192.168.1.0",
      "Description": "Route的目标网段,例如192.168.1.0/24或192.168.1.0",
      "Type": "String"
    },
    "VSwitchCidrBlock": {
      "Default": "10.0.10.0/24",
      "Description": "VSwitch网段,此网段必须属于VPC",
      "Type": "String"
    }
  },
  "Resources": {
    "VSwitch": {
      "Type": "ALIYUN::ECS::VSwitch",
      "Properties": {
        "CidrBlock": {
          "Ref": "VSwitchCidrBlock"
        },
        "ZoneId": {
          "Ref": "ZoneId"
        },
        "VpcId": {
          "Fn::GetAtt": [
            "Vpc",
            "VpcId"
          ]
        }
      }
    },
    "Vpc": {
      "Type": "ALIYUN::ECS::VPC",
      "Properties": {
        "CidrBlock": {
          "Ref": "VpcCidrBlock"
        },
        "VpcName": {
          "Ref": "VpcName"
        }
      }
    },
    "WaitCondition": {
      "Type": "ALIYUN::ROS::WaitCondition",
      "Properties": {
        "Handle": {
          "Ref": "WaitConHandle"
        },
        "Timeout": 200,
        "Count": 1
      }
    },
    "SecurityGroup": {
      "Type": "ALIYUN::ECS::SecurityGroup",
      "Properties": {
        "SecurityGroupName": {
          "Ref": "SecurityGroupName"
        },
        "VpcId": {
          "Ref": "Vpc"
        }
      }
    },
    "NewEip": {
      "Type": "ALIYUN::ECS::EIP",
      "Properties": {
        "InternetChargeType": "PayByTraffic",
        "Bandwidth": 1
      }
    },
    "SecurityGroupIngress": {
      "Type": "ALIYUN::ECS::SecurityGroupIngress",
      "Properties": {
        "SourceCidrIp": "0.0.0.0/0",
        "SecurityGroupId": {
          "Ref": "SecurityGroup"
        },
        "IpProtocol": "all",
        "NicType": "intranet",
        "PortRange": "-1/-1"
      }
    },
    "WebServer": {
      "Type": "ALIYUN::ECS::Instance",
      "Properties": {
        "IoOptimized": "optimized",
        "ImageId": "centos6u5_64_40G_cloudinit_20160427.raw",
        "SecurityGroupId": {
          "Ref": "SecurityGroup"
        },
        "Password": {
          "Ref": "Password"
        },
        "DiskMappings": [
          {
            "DiskName": {
              "Ref": "DiskName"
            },
            "Size": {
              "Ref": "DiskSize"
            }
          },
          {
            "Size": {
              "Ref": "DiskSize"
            }
          }
        ],
        "SystemDiskCategory": {
          "Ref": "SystemDiskCategory"
        },
        "UserData": {
          "Fn::Join": [
            "",
            [
              "#!/bin/sh\n",
              "logs=~/mount_logs\n",
              "i=1\n",
              "total=",
              {
                "Ref": "TotalDataDisk"
              },
              "\n",
              "mountpoint=",
              {
                "Ref": "MountPoint"
              },
              "\n",
              "while [ $i -le $total ]\n",
              "do\n",
              "    j=`echo $i|awk '{printf \"%c\", 97+$i}'`\n",
              "fdisk -S 56 /dev/vd$j <<ESXU\n",
              "n\n",
              "p\n",
              "1\n",
              "\n",
              "\n",
              "w\n",
              "ESXU\n",
              "    echo \"/dev/vd$j is fdisked!\" >> $logs\n",
              "    mkfs.ext4 /dev/vd${j}1\n",
              "    if [ $? -eq 0 ];then\n",
              "        echo \"/dev/vd${j}1 is formated!\" >> $logs\n",
              "    fi\n",
              "    touch ~/test_ftab\n",
              "    mkdir $mountpoint$i\n",
              "cat << ESXU > ~/test_ftab\n",
              "/dev/vd${j}1         $mountpoint$i       ext4       defaults        0 0\n",
              "ESXU\n",
              "    cat ~/test_ftab >> /etc/fstab\n",
              "    mount -a\n",
              "    chmod -R 777 $mountpoint$i\n",
              "    rm -rf ~/test_ftab\n",
              "    echo \"/dev/vd${j}1 is mounted!\" >> $logs\n",
              "    let i+=1\n",
              "done\n",
              "\n",
              {
                "Fn::GetAtt": [
                  "WaitConHandle",
                  "CurlCli"
                ]
              },
              " -d '{\"id\" : \"webserver\", \"data\" : \"mount disk\"}'\n"
            ]
          ]
        },
        "VSwitchId": {
          "Ref": "VSwitch"
        },
        "VpcId": {
          "Ref": "Vpc"
        },
        "InstanceType": "ecs.n1.small"
      }
    },
    "WaitConHandle": {
      "Type": "ALIYUN::ROS::WaitConditionHandle"
    },
    "EIPBind": {
      "Type": "ALIYUN::ECS::EIPAssociation",
      "Properties": {
        "InstanceId": {
          "Ref": "WebServer"
        },
        "AllocationId": {
          "Ref": "NewEip"
        }
      }
    },
    "SecurityGroupEgress": {
      "Type": "ALIYUN::ECS::SecurityGroupEgress",
      "Properties": {
        "SecurityGroupId": {
          "Ref": "SecurityGroup"
        },
        "IpProtocol": "all",
        "DestCidrIp": "0.0.0.0/0",
        "NicType": "intranet",
        "PortRange": "-1/-1"
      }
    }
  },
  "Outputs": {
    "Data": {
      "Value": {
        "Fn::GetAtt": [
          "WaitCondition",
          "Data"
        ]
      }
    },
    "PublicIp": {
      "Value": {
        "Fn::GetAtt": [
          "WebServer",
          "PublicIp"
        ]
      }
    },
    "InstanceId": {
      "Value": {
        "Fn::GetAtt": [
          "WebServer",
          "InstanceId"
        ]
      }
    },
    "CurlCli": {
      "Value": {
        "Fn::GetAtt": [
          "WaitConHandle",
          "CurlCli"
        ]
      }
    }
  }
}

UserData脚本处理带有源数据的数据盘

这个例子是根据源数据的snapshot创建数据盘,其它的都和上面的例子类似。这时候新的ECS实例的数据盘是已经分好区和格式化过的,我们只需要挂载数据盘到合适的挂载点就行。通过TotalDataDisk说明有多少块数据盘,MountPoint指定数据盘的挂载点,使用ROS的WaitCondition资源来得到UserData脚本的执行结果。下面是最终模版:

{
  "ROSTemplateFormatVersion": "2015-09-01",
  "Parameters": {
    "VpcName": {
      "MaxLength": 128,
      "Description": "VPC 名称",
      "Type": "String",
      "ConstraintDescription": "[2, 128] 英文或中文字符",
      "MinLength": 2
    },
    "DataDisk2SnapshotId": {
      "Description": "根据此快照创建数据盘2",
      "Type": "String"
    },
    "Password": {
      "NoEcho": true,
      "MaxLength": 30,
      "Description": "ECS登录密码.",
      "Type": "String",
      "ConstraintDescription": "8-30个字符,可以包含大、小写字母和特殊字符",
      "MinLength": 8
    },
    "DiskName": {
      "Type": "String"
    },
    "ZoneId": {
      "Description": "可用区 Id,  <a href='#/product/cn-shenzhen/list/zoneList' target='_blank'>查看可用区</a>",
      "Type": "String"
    },
    "DestinationCidrBlock": {
      "Default": "192.168.1.0",
      "Description": "Route的目标网段,例如192.168.1.0/24或192.168.1.0",
      "Type": "String"
    },
    "MountPoint": {
      "Description": "数据盘的挂在点",
      "Type": "String"
    },
    "VSwitchCidrBlock": {
      "Default": "10.0.10.0/24",
      "Description": "VSwitch网段,此网段必须属于VPC",
      "Type": "String"
    },
    "DataDisk1SnapshotId": {
      "Description": "根据此快照创建数据盘1",
      "Type": "String"
    },
    "SecurityGroupName": {
      "Description": "安全组名称",
      "Type": "String"
    },
    "VpcCidrBlock": {
      "Default": "10.0.0.0/8",
      "AllowedValues": [
        "192.168.0.0/16",
        "172.16.0.0/12",
        "10.0.0.0/8"
      ],
      "Type": "String"
    },
    "DiskSize": {
      "Default": 40,
      "Type": "Number"
    },
    "TotalDataDisk": {
      "Description": "实例挂在数据盘的数量",
      "Type": "String"
    },
    "SystemDiskCategory": {
      "Default": "cloud",
      "AllowedValues": [
        "cloud",
        "cloud_efficiency",
        "cloud_ssd"
      ],
      "Description": "系统盘的磁盘种类, 普通云盘(cloud)、高效云盘(cloud_efficiency)或SSD云盘(cloud_ssd)",
      "Type": "String"
    }
  },
  "Resources": {
    "VSwitch": {
      "Type": "ALIYUN::ECS::VSwitch",
      "Properties": {
        "CidrBlock": {
          "Ref": "VSwitchCidrBlock"
        },
        "ZoneId": {
          "Ref": "ZoneId"
        },
        "VpcId": {
          "Fn::GetAtt": [
            "Vpc",
            "VpcId"
          ]
        }
      }
    },
    "Vpc": {
      "Type": "ALIYUN::ECS::VPC",
      "Properties": {
        "CidrBlock": {
          "Ref": "VpcCidrBlock"
        },
        "VpcName": {
          "Ref": "VpcName"
        }
      }
    },
    "WaitCondition": {
      "Type": "ALIYUN::ROS::WaitCondition",
      "Properties": {
        "Handle": {
          "Ref": "WaitConHandle"
        },
        "Timeout": 200,
        "Count": 1
      }
    },
    "SecurityGroup": {
      "Type": "ALIYUN::ECS::SecurityGroup",
      "Properties": {
        "SecurityGroupName": {
          "Ref": "SecurityGroupName"
        },
        "VpcId": {
          "Ref": "Vpc"
        }
      }
    },
    "NewEip": {
      "Type": "ALIYUN::ECS::EIP",
      "Properties": {
        "InternetChargeType": "PayByTraffic",
        "Bandwidth": 1
      }
    },
    "SecurityGroupIngress": {
      "Type": "ALIYUN::ECS::SecurityGroupIngress",
      "Properties": {
        "SourceCidrIp": "0.0.0.0/0",
        "SecurityGroupId": {
          "Ref": "SecurityGroup"
        },
        "IpProtocol": "all",
        "NicType": "intranet",
        "PortRange": "-1/-1"
      }
    },
    "WebServer": {
      "Type": "ALIYUN::ECS::Instance",
      "Properties": {
        "IoOptimized": "optimized",
        "ImageId": "centos6u5_64_40G_cloudinit_20160427.raw",
        "SecurityGroupId": {
          "Ref": "SecurityGroup"
        },
        "Password": {
          "Ref": "Password"
        },
        "DiskMappings": [
          {
            "SnapshotId": {
              "Ref": "DataDisk1SnapshotId"
            },
            "DiskName": {
              "Ref": "DiskName"
            },
            "Size": {
              "Ref": "DiskSize"
            }
          },
          {
            "SnapshotId": {
              "Ref": "DataDisk2SnapshotId"
            },
            "Size": {
              "Ref": "DiskSize"
            }
          }
        ],
        "SystemDiskCategory": {
          "Ref": "SystemDiskCategory"
        },
        "UserData": {
          "Fn::Join": [
            "",
            [
              "#!/bin/sh\n",
              "logs=~/mount_logs\n",
              "i=1\n",
              "total=",
              {
                "Ref": "TotalDataDisk"
              },
              "\n",
              "mountpoint=",
              {
                "Ref": "MountPoint"
              },
              "\n",
              "while [ $i -le $total ]\n",
              "do\n",
              "    j=`echo $i|awk '{printf \"%c\", 97+$i}'`\n",
              "    touch ~/test_ftab\n",
              "    mkdir $mountpoint$i\n",
              "cat << ESXU > ~/test_ftab\n",
              "/dev/vd${j}1         $mountpoint$i       ext4       defaults        0 0\n",
              "ESXU\n",
              "    cat ~/test_ftab >> /etc/fstab\n",
              "    mount -a\n",
              "    chmod -R 777 $mountpoint$i\n",
              "    rm -rf ~/test_ftab\n",
              "    echo \"/dev/vd${j}1 is mounted!\" >> $logs\n",
              "    let i+=1\n",
              "done\n",
              "\n",
              {
                "Fn::GetAtt": [
                  "WaitConHandle",
                  "CurlCli"
                ]
              },
              " -d '{\"id\" : \"webserver\", \"data\" : \"mount disk\"}'\n"
            ]
          ]
        },
        "VSwitchId": {
          "Ref": "VSwitch"
        },
        "VpcId": {
          "Ref": "Vpc"
        },
        "InstanceType": "ecs.n1.small"
      }
    },
    "WaitConHandle": {
      "Type": "ALIYUN::ROS::WaitConditionHandle"
    },
    "EIPBind": {
      "Type": "ALIYUN::ECS::EIPAssociation",
      "Properties": {
        "InstanceId": {
          "Ref": "WebServer"
        },
        "AllocationId": {
          "Ref": "NewEip"
        }
      }
    },
    "SecurityGroupEgress": {
      "Type": "ALIYUN::ECS::SecurityGroupEgress",
      "Properties": {
        "SecurityGroupId": {
          "Ref": "SecurityGroup"
        },
        "IpProtocol": "all",
        "DestCidrIp": "0.0.0.0/0",
        "NicType": "intranet",
        "PortRange": "-1/-1"
      }
    }
  },
  "Outputs": {
    "Data": {
      "Value": {
        "Fn::GetAtt": [
          "WaitCondition",
          "Data"
        ]
      }
    },
    "PublicIp": {
      "Value": {
        "Fn::GetAtt": [
          "WebServer",
          "PublicIp"
        ]
      }
    },
    "InstanceId": {
      "Value": {
        "Fn::GetAtt": [
          "WebServer",
          "InstanceId"
        ]
      }
    },
    "CurlCli": {
      "Value": {
        "Fn::GetAtt": [
          "WaitConHandle",
          "CurlCli"
        ]
      }
    }
  }
}

注意

我们注意到以上两个例子都是使用DiskMappings属性,而不是使用ROS栈资源的方式创建数据盘,这是因为DiskMappings是ECS资源的属性,所以在创建启动ECS的时候,数据盘已经创建好了,并且和ECS实例做了关联。那么执行UserData就能完成分区,格式化和挂载。但是如果以ROS stack资源的方式创建数据盘,首先是创建ECS资源和Disk资源,最后才关联disk和ECS实例。那么当ECS实例启动的时候,数据盘还没有真正关联到相应的ECS,所以这种情况下执行UserData脚本就会找不到数据盘,分区,格式化,挂载也就无从谈起。如果大家要使用数据盘并想通过UserData自动挂载数据盘,则建议使用DiskMappings这中方式创建数据盘。

相关实践学习
使用ROS创建VPC和VSwitch
本场景主要介绍如何利用阿里云资源编排服务,定义资源编排模板,实现自动化创建阿里云专有网络和交换机。
阿里云资源编排ROS使用教程
资源编排(Resource Orchestration)是一种简单易用的云计算资源管理和自动化运维服务。用户通过模板描述多个云计算资源的依赖关系、配置等,并自动完成所有资源的创建和配置,以达到自动化部署、运维等目的。编排模板同时也是一种标准化的资源和应用交付方式,并且可以随时编辑修改,使基础设施即代码(Infrastructure as Code)成为可能。 产品详情:https://www.aliyun.com/product/ros/
目录
相关文章
|
弹性计算 Linux Perl
为ROS创建的资源自动挂载数据盘
通过脚本实现自有镜像自动挂在在阿里云申请的数据盘
2994 0
|
2月前
|
Ubuntu 机器人 Linux
|
1月前
|
自动驾驶 安全 机器人
ROS2:从初识到深入,探索机器人操作系统的进化之路
前言 最近开始接触到基于DDS的这个系统,是在稚晖君的机器人项目中了解和认识到。于是便开始自己买书学习起来,感觉挺有意思的,但是只是单纯的看书籍,总会显得枯燥无味,于是自己又开始在网上找了一些视频教程结合书籍一起来看,便让我对ROS系统有了更深的认识和理解。 ROS的发展历程 ROS诞生于2007年的斯坦福大学,这是早期PR2机器人的原型,这个项目很快被一家商业公司Willow Garage看中,类似现在的风险投资一样,他们投了一大笔钱给这群年轻人,PR2机器人在资本的助推下成功诞生。 2010年,随着PR2机器人的发布,其中的软件正式确定了名称,就叫做机器人操作系统,Robot Op
73 14
|
1月前
|
XML 算法 自动驾驶
ROS进阶:使用URDF和Xacro构建差速轮式机器人模型
【11月更文挑战第7天】本篇文章介绍的是ROS高效进阶内容,使用URDF 语言(xml格式)做一个差速轮式机器人模型,并使用URDF的增强版xacro,对机器人模型文件进行二次优化。
|
1月前
|
自动驾驶 安全 机器人
ROS2:从初识到深入,探索机器人操作系统的进化之路
【11月更文挑战第4天】ROS2的学习过程和应用,介绍DDS系统的框架和知识。
|
7月前
|
传感器 人工智能 算法
ROS机器人操作系统
ROS机器人操作系统
185 1
|
2月前
|
传感器 数据可视化 机器人
【ROS速成】半小时入门机器人ROS系统简明教程之可视化系统(三)
半小时入门机器人ROS系统简明教程之可视化系统
111 0
|
2月前
|
机器人
【ROS速成】半小时入门机器人ROS系统简明教程之安装测速(二)
半小时入门机器人ROS系统简明教程之安装测速
|
6月前
|
机器学习/深度学习 传感器 算法
强化学习(RL)在机器人领域的应用,尤其是结合ROS(Robot Operating System)和Gazebo(机器人仿真环境)
强化学习(RL)在机器人领域的应用,尤其是结合ROS(Robot Operating System)和Gazebo(机器人仿真环境)
300 2
|
6月前
|
机器人 定位技术 C++
技术笔记:ROS中测试机器人里程计信息
技术笔记:ROS中测试机器人里程计信息

推荐镜像

更多