ECS部署场景升级最佳实践

使用ECS进行部署是计算巢服务常用的部署场景,在服务完成部署以后,怎么进行升级是经常被忽略的问题,本实践将针对常见的两种部署方式如何升级进行说明,ISV在使用时可以具体场景具体分析,决定使用哪种部署方式,进而选择不同的升级方式。

部署方式介绍

  • ECS镜像部署方式:ECS镜像部署方式为将应用部署所需的软件包、容器镜像等依赖内容提前打包到ECS镜像中,适用于比较复杂的部署场景。优势是部署稳定快速,缺点是数据和软件应用同在系统盘中,在升级时直接替换系统盘会有数据覆盖问题,需要挂载数据盘来解决。

  • RunCommand命令部署方式:RunCommand命令部署方式不依赖ECS镜像,主要应用部署通过Shell命令完成,适用于相对简单的部署场景。优势是进行部署升级时都是通过RunCommand中的命令执行来完成,不需要进行系统盘更换,升级时没有数据问题,整体操作更简单,缺点是命令执行在某些情况下会存在不兼容的情况,比如ECS实例未开公网,拉取不下来文件等问题。

ECS镜像部署方式升级

镜像部署具有很多优势,适用于比较复杂或有卡点的部署场景,如docker部署场景不存在docker镜像无法拉取,所有的文件都已经事先准备好,不会出现命令式部署由于网络、环境等原因出现部署失败的情况,整体来说稳定而又快速,目前是我们ECS场景部署服务的最佳实践,在服务部署方面应用比较广泛。

升级存在问题

但在升级方面,ECS镜像部署存在数据和应用耦合的问题,ECS镜像进行升级操作会直接更换系统盘,用户的历史数据会被覆盖掉,解决方式是让用户自己备份数据,等升级完再进行倒入恢复,操作较麻烦,体验不好。

推荐解决方案

目前推荐的方式是ECS挂载数据盘,应用相关数据保存到数据盘中,实现软件应用和数据的分离。在服务进行升级时,进行系统盘更换也不会覆盖数据盘中的数据,用户数据不会丢失,系统盘更换后数据盘重新进行挂载,原有的应用数据还在。

具体过程如下图所示:

image.png

服务部署需要做以下改造

  1. 创建ECS实例时进行数据盘挂载。

  2. 将软件应用数据存放路径改为数据盘挂载目录,有初始数据需要提前复制到数据盘中。

创建服务通过精选模板创建服务中的ECS镜像部署为例,以下为ECS挂载数据盘和修改应用数据存放路径的代码示例。

InstanceGroup:
  Type: ALIYUN::ECS::InstanceGroup
  Properties:
    # 这里省去部分无关属性
    SystemDiskCategory: cloud_essd
    SystemDiskSize: 200
    InternetMaxBandwidthOut: 1
    IoOptimized: optimized
    MaxAmount: 1
    DiskMappings:
      - Category: cloud_essd
        Size: 200
    # 数据盘初始化和挂载
    UserData: |
      #cloud-config
      bootcmd:
        - |
          #!/bin/bash
          function init_and_mount_data_disk() {
              disk_device="/dev/vdb"
              parted_disk_device="/dev/vdb1"
              mount_point="/data"
              # 已初始化的磁盘,跳过初始化,直接挂载
              if blkid -o value -s TYPE $disk_device &>/dev/null; then
                echo "Disk is already initialized."
              else
                echo "Disk is not initialized, initializing..."
                cat >> /root/InitDataDisk.sh << "EOF"
          #!/bin/bash
          echo "p
          n
          p
      
      
      
          w
          " |  fdisk -u /dev/vdb
          EOF
                /bin/bash /root/InitDataDisk.sh
                rm -f /root/InitDataDisk.sh
                mkfs -t ext4 $parted_disk_device
              fi
      
              cp /etc/fstab /etc/fstab.bak
              mkdir $mount_point
              echo `blkid $parted_disk_device | awk '{print $2}' | sed 's/\\\"//g'` $mount_point ext4 defaults 0 0 >> /etc/fstab
              mount -a
          }
          init_and_mount_data_disk
RunInstallCommand:
  Type: ALIYUN::ECS::RunCommand
  Properties:
    InstanceIds:
      Fn::GetAtt:
      - InstanceGroup
      - InstanceIds
    Type: RunShellScript
    Sync: true
    Timeout: 3600
    CommandContent:
      Fn::Sub:
        - |
          #!/bin/bash
          function save_log_to_data_disk() {
            mkdir -p /data/logs
            chmod -R 666 /data/logs
            # 使用数据盘目录存放日志,避免升级Ecs镜像时数据丢失
            sed -i 's/LOG_DIR/\/data/g' /home/admin/application/deploy.sh
          }
          # 用于触发版本升级
          echo "当前时间:${CurTime}"
          cd /home/admin/application
          /bin/bash deploy.sh stop
          save_log_to_data_disk
          /bin/bash deploy.sh start
        - AccountId:
            Ref: ALIYUN::TenantId
          CurTime:
            Ref: CurTime
完整服务可以参考创建服务时,通过精选模板创建服务中的ECS镜像部署。image.png

RunCommand部署方式升级

RunCommand部署方式适用于较简单的部署场景,主要通过执行Shell命令的方式去进行软件部署。

升级存在问题

RunCommand方式存在部分限制,如命令执行不能有卡点;部署在中国内地的ECS实例,不能拉取中国境外的容器镜像;不能拉取github上的文件等。

推荐解决方案

这种部署方式进行服务升级时比较简单,不涉及到系统盘的变更,不存在数据丢失的问题,新老服务版本的不同主要是RunCommand命令的内容不同,升级时通过执行新服务版本的RunCommand命令来完成升级。这种方式的RunCommand命令一般要执行以下三个步骤:

  1. 关闭原有应用。

  2. 更新应用部署内容(拉取软件包、容器镜像等)。

  3. 启动新版应用。

创建服务通过精选模板创建服务中的ECS软件包部署为例,以下为RunCommand命令实现的代码示例。

RunInstallCommand:
  Type: ALIYUN::ECS::RunCommand
  Properties:
    InstanceIds:
      Fn::GetAtt:
      - InstanceGroup
      - InstanceIds
    Type: RunShellScript
    Sync: true
    Timeout: 3600
    CommandContent:
      Fn::Sub:
        - |
          #!/bin/bash
          function stop_application() {
            if [ -f "/home/admin/application/deploy.sh" ]; then
              /bin/bash /home/admin/application/deploy.sh stop
            fi
          }

          function start_application() {
            yum install -y java
            mkdir -p /home/admin/application
            cd /home/admin/application
            # 2. 拉取新版的软件包
            wget '{{ computenest::file::springboot }}' -O package.tgz
            tar xvf package.tgz
            # 3. 启动新版应用
            /bin/bash deploy.sh start
          }
          # 1. 关闭原有应用
          stop_application
          start_application
        - AccountId:
            Ref: ALIYUN::TenantId
完整服务可以参考创建服务时,通过精选模板创建服务中的ECS软件包部署和 ECS容器部署。image.png