首页 > 其他分享 >基于 ROS 的 Terraform 托管服务轻松部署同城容灾应用

基于 ROS 的 Terraform 托管服务轻松部署同城容灾应用

时间:2024-07-15 18:01:10浏览次数:16  
标签:原生 网关 部署 同城容灾 Terraform 集群 ROS 资源

介绍

企业对在线的关键业务应用存在容灾需求,同城主机房发生故障,流量能切换到备机房,备机房具备实时接管能力。本方案介绍了通过阿里云的NLB、MSE、ACK等产品组合能力,实现应用同城多活的方案。

资源编排服务(Resource Orchestration Service, ROS)是阿里云提供基于基础设施即代码(Infrastructure as Code, IaC) 理念的自动化部署服务,我们可以通过定义一个 Terraform 模板,轻松部署一套云上的同城多活应用。

方案架构

本方案基于云原生网关+MSE注册中心实现应用同城多活,通过云原生网关的主动健康检查机制可以实现秒级故障自动转移。云原生网关支持管理多套ACK集群,通过对多个集群的同名服务合并的能力,可以实现非对等部署状态下的全局流量负载均衡。通过每个集群部署一套注册中心实现微服务调用可用区闭环以后,可以配合云原生网关的多种流量路由能力实现蓝绿和灰度等发布策略。

实施步骤

  1. 登录ROS控制台:通过MSE实现应用同城容灾部署页面

  2. 配置模板参数:选择 ECS 实例的可用区、实例类型等

  3. 点击【下一步】,然后【创建】,等待资源栈创建完成。ROS 能够快速完成两套可用区的ACK集群以及MSE网关的部署。

  4. 云原生网关创建来源
    登录 MSE 控制台,在云原生网关中创建两个来源,关联您在两个可用区的容器集群。

  5. 云原生网关创建服务
    在云原生网关中创建服务,选择对应命名空间下的服务。

    云原生网关支持跨集群的服务统一管理,下文中所创建的服务会自动的把两套Kubernetes集群中相同命名空间下的同名服务进行合并。

  6. 云原生网关创建路由
    创建路由,设置域名和匹配规则

    选择目标服务后保存并上线路由

  7. 切流效果验证
    云原生网关可根据后端集群的工作负载数及健康状态动态的调整流量,下文分别演示两个集群工作负载数量对等部署、非对等部署、机房故障场景下的云原生网关自动切流效果。
    可以启动下方的shell脚本,循环对网关发起请求

#!/bin/bash
for (( i = 1; i < 100; i++ )); do
      curl http://{ip}/helloDuohuo     # ip 需要替换成您网关的公网IP
      sleep 1
      echo
done
  1. 两套集群工作负载数量对等部署
    两套集群中工作负载的副本保持一致

    通过上文的shell脚本发起请求,得到以下输出

    输出表明,流量被负载均衡到可用区G和可用区I,两个可用区的集群各承担了50%的流量。

  2. 两个集群工作负载数量非对等部署
    可用区I的集群副本数量缩容为0

    得到以下输出

    输出表明,可用区G的集群承担了全部的流量

部署原理

我们可以看到通过 ROS 可以非常快捷地部署阿里云上的各种云资源(比如 alicloud_vpc、alicloud_vswitch、alicloud_instance 实例等)。如果想了解是如何做到的,那么可以阅读此章节。

  1. 编写 Terraform 模板。在如下模板中定义了:
  • resource:定义了 VPC、VSwitch、K8S、MSE 网关等资源。
  • variable:定义了常用的参数,比如可用区、ECS 实例类型类型。
  • output:定义了自定义输出,比如 MSE 网关的公网IP
  1. 在 ROS 控制台中使用此模板创建资源栈。ROS 提供的 Terraform 托管服务会自动解析出模板中资源的依赖关系,按照资源依赖顺序创建云资源。如果资源间没有依赖,则会并发创建,从而提升部署效率。ROS 会把这次创建的所有资源存放到一个“资源栈”中,后续可以方便地管理这组资源集合。比如:
  • 将新模板应用到这个“资源栈”中,从而更新里面的资源。
  • 删除这个“资源栈”,从而把所有的资源删掉。
ROSTemplateFormatVersion: '2015-09-01'
Transform: Aliyun::Terraform-v1.5
Workspace:
  main.tf: |-
    variable "zone_id1" {
      type        = string
      description = <<EOT
      {
        "AssociationProperty": "ZoneId",
        "Label": {
            "zh-cn": "可用区ID1"
        }
      }
      EOT
      default     = "cn-hangzhou-g"
    }

    variable "zone_id2" {
      type        = string
      description = <<EOT
      {
        "AssociationProperty": "ZoneId",
        "Label": {
            "zh-cn": "可用区ID2"
        }
      }
      EOT
      default     = "cn-hangzhou-i"
    }


    variable "instance_type1" {
      description = <<EOT
      {
        "AssociationProperty": "ALIYUN::ECS::Instance::InstanceType",
        "AssociationPropertyMetadata": {
          "ZoneId": "$${zone_id1}"
        },
        "Label": {
            "zh-cn": "ECS实例规格1"
        }
      }
      EOT
      default     = "ecs.g5.xlarge"
    }

    variable "instance_type2" {
      description = <<EOT
      {
        "AssociationProperty": "ALIYUN::ECS::Instance::InstanceType",
        "AssociationPropertyMetadata": {
          "ZoneId": "$${zone_id2}"
        },
        "Label": {
            "zh-cn": "ECS实例规格2"
        }
      }
      EOT
      default     = "ecs.g6e.xlarge"
    }

    resource random_string "s" {
      length    = 5
      lower     = true
      min_lower = 5
      special   = false
    }


    resource "alicloud_vpc" "vpc1" {
      vpc_name   = "duohuo-vpc1"
      cidr_block = "10.0.0.0/8"
    }

    resource "alicloud_vswitch" "vswitch1" {
      vpc_id     = alicloud_vpc.vpc1.id
      zone_id    = var.zone_id1
      cidr_block = "10.0.0.0/24"
    }

    resource "alicloud_vswitch" "vswitch2" {
      vpc_id     = alicloud_vpc.vpc1.id
      zone_id    = var.zone_id2
      cidr_block = "10.0.1.0/24"
    }


    resource "alicloud_cs_managed_kubernetes" "k8s1" {
      name               = format("duohuo_k8s1_%s", random_string.s.id)
      cluster_spec       = "ack.pro.small"
      version            = "1.28.9-aliyun.1"
      worker_vswitch_ids = [alicloud_vswitch.vswitch1.id]
      service_cidr       = "192.168.0.0/24"
      pod_cidr           = "192.168.1.0/24"
      node_cidr_mask     = 24
      new_nat_gateway    = true
    }

    resource "alicloud_cs_managed_kubernetes" "k8s2" {
      name               = format("duohuo_k8s2_%s", random_string.s.id)
      cluster_spec       = "ack.pro.small"
      version            = "1.28.9-aliyun.1"
      worker_vswitch_ids = [alicloud_vswitch.vswitch2.id]
      service_cidr       = "192.168.2.0/24"
      pod_cidr           = "192.168.3.0/24"
      node_cidr_mask     = 24
      new_nat_gateway    = true
      depends_on = [alicloud_cs_managed_kubernetes.k8s1]
    }

    resource "alicloud_cs_kubernetes_node_pool" "node_pool1" {
      name                 = "duohuo_node_pool1"
      cluster_id           = alicloud_cs_managed_kubernetes.k8s1.id
      vswitch_ids          = [alicloud_vswitch.vswitch1.id]
      instance_types       = [var.instance_type1]
      system_disk_category = "cloud_essd"
      system_disk_size     = 40
      desired_size         = 5
    }

    resource "alicloud_cs_kubernetes_node_pool" "node_pool2" {
      name                 = "duohuo_node_pool2"
      cluster_id           = alicloud_cs_managed_kubernetes.k8s2.id
      vswitch_ids          = [alicloud_vswitch.vswitch2.id]
      instance_types       = [var.instance_type2]
      system_disk_category = "cloud_essd"
      system_disk_size     = 40
      desired_size         = 5
    }


    resource "alicloud_mse_cluster" "mse1" {
      cluster_specification = "MSE_SC_1_2_60_c"
      cluster_type          = "Nacos-Ans"
      cluster_version       = "NACOS_2_0_0"
      instance_count        = 3
      net_type              = "privatenet"
      pub_network_flow      = "1"
      connection_type       = "slb"
      cluster_alias_name    = format("duohuo_mse1_%s", random_string.s.id)
      mse_version           = "mse_pro"
      vswitch_id            = alicloud_vswitch.vswitch1.id
      vpc_id                = alicloud_vpc.vpc1.id
    }

    resource "alicloud_mse_cluster" "mse2" {
      cluster_specification = "MSE_SC_1_2_60_c"
      cluster_type          = "Nacos-Ans"
      cluster_version       = "NACOS_2_0_0"
      instance_count        = 3
      net_type              = "privatenet"
      pub_network_flow      = "1"
      connection_type       = "slb"
      cluster_alias_name    = format("duohuo_mse2_%s", random_string.s.id)
      mse_version           = "mse_pro"
      vswitch_id            = alicloud_vswitch.vswitch2.id
      vpc_id                = alicloud_vpc.vpc1.id
    }

    data "alicloud_mse_clusters" "mse1" {
      ids = [alicloud_mse_cluster.mse1.id]
    }

    data "alicloud_mse_clusters" "mse2" {
      ids = [alicloud_mse_cluster.mse2.id]
    }


    locals {
      ros_tpl = file("${path.cwd}/ros_tpl")
    }

    resource "alicloud_ros_stack" "stack1" {
      stack_name    = format("duohuo1_%s", random_string.s.id)
      template_body = local.ros_tpl
      parameters {
        parameter_key   = "ClusterId"
        parameter_value = alicloud_cs_managed_kubernetes.k8s1.id
      }
      parameters {
        parameter_key   = "MseAddress"
        parameter_value = data.alicloud_mse_clusters.mse1.clusters.0.intranet_domain
      }
      parameters {
        parameter_key   = "Env"
        parameter_value = var.zone_id1
      }
      depends_on = [alicloud_cs_kubernetes_node_pool.node_pool1]
    }

    resource "alicloud_ros_stack" "stack2" {
      stack_name    = format("duohuo2_%s", random_string.s.id)
      template_body = local.ros_tpl
      parameters {
        parameter_key   = "ClusterId"
        parameter_value = alicloud_cs_managed_kubernetes.k8s2.id
      }
      parameters {
        parameter_key   = "MseAddress"
        parameter_value = data.alicloud_mse_clusters.mse2.clusters.0.intranet_domain
      }
      parameters {
        parameter_key   = "Env"
        parameter_value = var.zone_id2
      }
      depends_on = [alicloud_cs_kubernetes_node_pool.node_pool2]
    }

    resource "alicloud_mse_gateway" "gateway1" {
      gateway_name      = "duohuo_gateway1"
      replica           = 2
      spec              = "MSE_GTW_2_4_200_c"
      vswitch_id        = alicloud_vswitch.vswitch1.id
      vpc_id            = alicloud_vpc.vpc1.id
      internet_slb_spec = "slb.s1.small"
      timeouts {
        create = "1200s"
      }
    }

    output "public_ip" {
      value = alicloud_mse_gateway.gateway1.slb_list[0].slb_ip
    }
  ros_tpl: |-
    {
      "ROSTemplateFormatVersion": "2015-09-01",
      "Parameters": {
        "ClusterId": {
          "Type": "String"
        },
        "MseAddress": {
          "Type": "String"
        },
        "Env": {
          "Type": "String"
        }
      },
      "Resources": {
        "CSClusterApplication": {
          "Type": "ALIYUN::CS::ClusterApplication",
          "Properties": {
            "ClusterId": {
              "Ref": "ClusterId"
            },
            "YamlContent": {
              "Fn::Sub": "apiVersion: apps/v1\nkind: Deployment\nmetadata:\n  name: duohuo-provider\n  labels:\n    app: duohuo-provider\nspec:\n  replicas: 2\n  selector:\n    matchLabels:\n      app: duohuo-provider\n  template:\n    metadata:\n      labels:\n        app: duohuo-provider\n    spec:\n      containers:\n        - env:\n            - name: nacos_address\n              value: '${MseAddress}:8848' \n            - name: env\n              value: ${Env}\n          image: 'registry.cn-hangzhou.aliyuncs.com/jinfengdocker/mse-duohuo-provider:v1'\n          imagePullPolicy: Always\n          name: duohuo-provider\n          ports:\n            - containerPort: 8080\n              protocol: TCP\n          resources:\n            limits:\n              cpu: '2'\n              memory: 1Gi\n            requests:\n              cpu: '0.5'\n              memory: 0.1Gi\n---\napiVersion: apps/v1         \nkind: Deployment\nmetadata:\n  name: duohuo-consumer\n  labels:\n    app: duohuo-consumer\nspec:\n  replicas: 2\n  selector:\n    matchLabels:\n      app: duohuo-consumer\n  template:\n    metadata:\n      labels:\n        app: duohuo-consumer\n    spec:\n      containers:\n        - env:\n            - name: nacos_address\n              value: '${MseAddress}:8848' \n            - name: env\n              value: ${Env}\n          image: 'registry.cn-hangzhou.aliyuncs.com/jinfengdocker/mse-duohuo-consumer:v1'\n          imagePullPolicy: Always\n          name: duohuo-consumer\n          ports:\n            - containerPort: 8080\n              protocol: TCP\n          resources:\n            limits:\n              cpu: '2'\n              memory: 1Gi\n            requests:\n              cpu: '0.5'\n              memory: 0.1Gi\n---\napiVersion: v1\nkind: Service\nmetadata:\n  name: duohuo-consumer-service\nspec:\n  ports:\n    - name: http\n      port: 8080\n      protocol: TCP\n      targetPort: 8080\n  selector:\n    app: duohuo-consumer\n  sessionAffinity: None\n  type: ClusterIP\nDefaultNamespace: default"
            }
          }
        }
      }
    }
  .metadata: |-
    {
      "ALIYUN::ROS::Interface": {
        "ParameterGroups": [
          {
            "Parameters": [
              "zone_id1",
              "zone_id2"
            ],
            "Label": {
              "default": {
                "zh-cn": "可用区配置",
                "en": "Zone Configuration"
              }
            }
          },
          {
            "Parameters": [
              "instance_type1",
              "instance_type2"
            ],
            "Label": {
              "default": {
                "zh-cn": "Ecs实例类型配置",
                "en": "Ecs InstanceType Configuration"
              }
            }
          }
        ],
        "TemplateTags": [
          "acs:integrate:landing_zone:mse_disaster_tolerance"
        ]
      }
    }
Metadata:
  ALIYUN::ROS::Interface:
    ParameterGroups:
      - Parameters:
          - zone_id1
          - zone_id2
        Label:
          default:
            zh-cn: 可用区配置
            en: Zone Configuration
      - Parameters:
          - instance_type1
          - instance_type2
        Label:
          default:
            zh-cn: Ecs实例类型配置
            en: Ecs InstanceType Configuration
    TemplateTags:
      - acs:integrate:landing_zone:mse_disaster_tolerance

总结

基于 IaC 的理念,通过定义一个模板,使用 ROS 提供的 Terraform 托管服务进行自动化部署,可以非常高效快捷地部署任意云资源和应用(比如部署同城容灾应用)。相比于手动部署或者通过 API、SDK 的部署方式,有着高效、稳定等诸多优势,也是服务上云的最佳实践。

标签:原生,网关,部署,同城容灾,Terraform,集群,ROS,资源
From: https://www.cnblogs.com/alicloudros/p/18303659

相关文章

  • Turtlebot3在ROS Gazebo中使用OpenCV检测并跟踪球体
    原文链接:https://www.youtube.com/watch?v=Rw6ATkORRG8   一个小巧的机器人在虚拟世界中敏捷地追踪着一个滚动的球体。Turtlebot3,一个搭载ROS操作系统的智能机器人,在Gazebo仿真环境中,利用OpenCV的神奇力量,展现出令人惊叹的视觉追踪能力。 Turtlebot3的"眼睛"是一台高清......
  • Microsoft Office 自定义安装部署工具 | Mocreak
    软件简介:Mocreak是一款一键自动化下载、安装、部署正版Office的办公增强工具。该工具完全免费、无广告、绿色、无毒、简约、高效、安全。软件特点:一键快速下载、安装、部署最新版MicrosoftOffice软件。提供简约、高效,且可自定义的图形界面,提升部署效率。支持将Office安......
  • ros2,功能包下使用自定义的msg,msg文件在定义在当前文件下
    1.创建功能包,参考ros官方方式Writingasimplepublisherandsubscriber(C++)—ROS2Documentation:Humbledocumentationros2pkgcreate--build-typeament_cmake--licenseApache-2.0cpp_pubsub2.创建msg在cpp_pubsub功能包下创建msg文件夹 ros2_ws/cpp_pubsub......
  • Tool-Cross-compilation-Toolchain-ARM-Linaro
    Tool-Cross-compilation-Toolchain-ARM-LinaroUbuntu上基于Arm的交叉编译工具链。引用:arm生态发展与交叉编译链选择-知乎arm-none-linux-gnueabi-gcc:是Codesourcery公司(目前已经被Mentor收购)基于GCC推出的的ARM交叉编译工具。可用于交叉编译ARM(32位)系统中所有环节的代码,包......
  • ROS学习笔记总结篇(基础篇梳理)
    在学习完一到十章节的ros后,我们的ros基础篇也迎来了结束,因此,在这章节,我会做一个总结,将一到十章的内容之串起来,实操一遍,接下来我们直接进入实操!一、创建一个工作空间首先,按下ctrl+shift+T打开终端,创建一个新的ros工作空间。#创建工作空间目录mkdir-psyj_ws/src#进入syj_......
  • 已解决——ROS2开发环境搭建,亚博智能小车
    在实现多机通讯时,官方教程讲的很模糊,具体细节实现主机(ROS2小车),从机(自己的电脑上的Ubuntu系统)首先打开两个terminal,左边的负责连接小车,右边的负责实现从机的接受话题主机terminal输入[email protected]进入后再输入./run_docker.sh然后就进入小车的docker了然后输入sud......
  • 解决Microsoft Visual C++ runtime package找不到问题
    使用了Dism++进行电脑清理,不小心选择了下面两个内容:尤其是第二个packagecache绝对不能清空,否则不知道哪个软件就不能运行了,报MicrosoftvisualC++runtime问题.然后再安装各个版本MicrosoftvisualC++redis仍会报同样的问题,死循环了.网上有各种解决方案,有......
  • Microsoft.WSMan.Management.Activities.dll文件丢失导致程序无法运行问题
    其实很多用户玩单机游戏或者安装软件的时候就出现过这种问题,如果是新手第一时间会认为是软件或游戏出错了,其实并不是这样,其主要原因就是你电脑系统的该dll文件丢失了或没有安装一些系统软件平台所需要的动态链接库,这时你可以下载这个Microsoft.WSMan.Management.Activities.dll......
  • Microsoft.Windows.StartLayout.Commands.dll文件丢失导致程序无法运行问题
    其实很多用户玩单机游戏或者安装软件的时候就出现过这种问题,如果是新手第一时间会认为是软件或游戏出错了,其实并不是这样,其主要原因就是你电脑系统的该dll文件丢失了或没有安装一些系统软件平台所需要的动态链接库,这时你可以下载这个Microsoft.Windows.StartLayout.Commands.dl......
  • Franka Ros2 主要节点及关系
     控制节点:1.franka_hw_node功能:与硬件接口通信,处理低级控制。订阅话题:/franka/control_commands发布话题:/franka/hardware_states /franka/state_feedback2.franka_control_node功能:处理机器人控制命令,管理控制模式。订阅话题:/franka/state_feedback发布话题:/frank......