IBM Cloud Docs
使用 IAM,VPC,Transit Gateway 和 DNS 的基于团队的隐私

使用 IAM,VPC,Transit Gateway 和 DNS 的基于团队的隐私

本教程可能会发生成本。 使用“成本估算器”根据您的预计使用量生成成本估算。

微服务很受欢迎,因为它们允许企业围绕其提供的服务来组织其开发团队。 本教程将指导您完成为基于 IBM Cloud® Virtual Private Cloud (VPC) 的微服务体系结构创建基础结构的步骤。 在此体系结构中,VPC 使用 IBM Cloud® Transit Gateway相互连接。 通过在 IBM Cloud® DNS Services中注册的主机名来访问一组共享微服务。 每个 VPC 都由由 IBM Cloud® Identity and Access Management隔离的单独团队管理。 (可选) 可以使用 IBM Cloud® Load Balancer 来向外扩展共享微服务。

目标

  • 了解如何使用 IAM 和资源组隔离基础架构
  • 创建 VPC 和关联资源,例如子网,网络 ACL,安全组和实例。
  • 使用 DNS Services通过 DNS 名称解析来寻址微服务。
  • 通过 Transit Gateway连接 VPC。
  • 透明地为应用程序配置 Load Balancer。

抽象体系结构:

架构*" caption-side="bottom"}{: caption="*

在上面的图中,最终用户正在访问应用程序。 这些应用程序正在利用共享微服务。 该公司拥有单独的 DevOps 团队,这些团队拥有 application1,application2 和共享。 网络团队专注于连接和网络安全。 DevOps 团队管理用于实现其创建和支持的服务的虚拟服务实例 VSI。

具体架构

以下体系结构实现公司设置的隔离和连接需求。 请注意,application1,shared 和 application2 是 VPC。 随着时间的推移,每个 VPC 中的单专区和子网可扩展为更详细的多专区实现。

教程的体系结构
教程的体系结构

准备工作

本教程需要:

  • 具有以下插件的 IBM Cloud CLI:
    • Transit Gateway (tg)
    • IBM Cloud VPC (vpc-infrastructure)
    • DNS Services (dns)
  • git 以克隆源代码存储库。
  • 用于运行 Terraform 命令的 terraform CLI。

您将在 解决方案教程入门 指南中找到有关为您的操作环境下载和安装这些工具的指示信息。

此外:

  • 检查用户许可权。 请确保您的用户帐户具有足够的许可权来创建和管理 VPC 资源,创建 IBM Cloud® Transit Gateway 并创建 IBM Cloud® Transit Gateway 服务。 请参阅 VPC 的 必需许可权 列表。 您还需要能够创建资源组和 IAM 资源,例如访问组,策略,服务标识,...
  • 您需要 SSH 密钥来连接到虚拟服务器。 如果没有 SSH 密钥,请参阅为 VPC 创建密钥的 说明

规划 Identity and Access Management 环境

管理团队将使其他团队能够尽可能多地管理其资源。 管理团队将管理用户并控制访问权,但不会创建和破坏体系结构图中显示的资源。

“编辑者”,“操作员”,“查看者”和“管理者”是 IAM 访问角色。 每个服务定义角色和关联操作的确切含义。

团队:

  • 管理-定义帐户结构,例如资源组,访问组,用户和角色。
  • 网络-创建网络资源,例如 DNS Services,Transit Gateway 服务,VPC 和子网。
  • 共享-在共享 VPC 中创建 VSI 和块设备。 为共享服务创建 DNS 记录。
  • Application1-在 application1 VPC 中创建 VSI 和块设备
  • Application2-在 application2 VPC 中创建 VSI 和块设备。

IAM 概念

网络团队

实施了概念性团队所有权模型。 网络 团队管理所有网络资源,从而管理图中显示的大部分内容。

关注网络团队的体系结构
关注网络团队的体系结构

共享团队

共享 团队在其隔离的 VPC 中创建 VSI。 此外,团队需要将记录写入 DNS 服务中,因为 VSI 的 IP 地址是在创建时确定的。 需要对 VPC,子网和安全组的操作员访问权才能创建 VSI。

以共享团队为重点的体系结构
以共享团队为重点的体系结构

应用程序 团队需要与 共享 团队相同的访问权,但对 DNS Services的管理者访问权除外。

应用程序 团队访问权:

专注于应用程序团队的体系结构
专注于应用程序团队的体系结构

IAM 体系结构

如果您对资源组和 IAM 访问组有很好的了解,那么可以快速浏览此部分并开始执行创建资源的步骤。

访问组

将为每个团队创建一个访问组。 访问策略将添加到访问组,然后将用户 (团队成员) 添加到访问组以授予访问权。

Transit Gateway 服务实例由 网络 团队专门管理。 需要编辑者访问权才能创建。 对已创建实例的管理者访问权允许 VPC 连接到 Transit Gateway。

在此示例中,将创建单个 DNS 区域 widgets.example.com,并允许所有 VPC 访问 DNS 区域。 DNS 服务实例由 网络 团队 (编辑者角色) 创建,并且允许区域需要“管理者”角色。 在 VPC 上的实例中运行时的 DNS 解析不需要 IAM 访问权。 共享 团队需要列出 DNS 实例 (查看者角色) 并添加 A 或 CNAME 记录 (管理者角色)。

VPC 基础架构服务 (IS) 由大约 15 种不同的服务类型组成。 有些仅是 网络 团队关注的问题,例如网络 ACL (访问控制表)。 其他只是微服务团队关注的问题,比如 VSI 实例。 但有些由 网络 团队编辑,由微服务团队 (如子网) 操作。 网络 团队将创建子网,微服务团队将在子网中创建实例。 对于本教程,将针对下表中的每个访问组汇总 VPC IS 服务类型 Transit Gateway 和 DNS。 表的内容是必需的角色。

根据其职责分配给团队的必需角色
服务 网络 共享 应用程序
Transit Gateway 编辑者,经理
DNS 编辑者,经理 查看者,经理
IS: Network ACL 编辑者
IS: 实例,卷,浮动 IP,SSH 密钥,映像,负载均衡器 编辑者 编辑者
IS: VPC,子网,安全组 编辑者 运算符 运算符

资源组

现在,共享 团队和 网络 团队已完全分离。 但是,如何将 Application1 与 Shared 和 Application2隔离开来? 他们是相同类型服务的编辑者。

这是资源组可以提供帮助的地方。 每个服务实例 (例如,资源) 都具有在创建时初始化的资源组属性,并且无法更改该属性。 换言之,每个资源都在一个资源组中。

资源组图:

资源组图
资源组图

将允许每个微服务团队在相应的资源组中进行访问。 网络 团队将有权访问所有这些资源组。

网络资源组包含 Transit Gateway 和 DNS 服务。 网络团队可以访问这些资源。 共享团队将具有对 DNS 服务的“管理者”访问权。 共享团队需要编写共享服务的 DNS 条目。

在本教程的稍后部分中,在创建所有资源之后,可以在 IBM Cloud 控制台中打开 资源列表。 可以对资源组进行过滤。

创建本地工作环境

所有操作都将在 bash shell 中执行,并使用 terraformibmcloud 命令。 您将在 解决方案教程入门 指南中找到有关为您的操作环境下载和安装这些工具的指示信息。

  1. Git 克隆以下 存储库:

    git clone https://github.com/IBM-Cloud/vpc-tg-dns-iam
    cd vpc-tg-dns-iam
    

    验证每个团队都有一个目录 (现在跳过 application2 ):

    • 管理/
    • 网络/
    • 共享/
    • application1/
  2. 创建 terraform.tfvars 文件:

    cp terraform.tfvars.template terraform.tfvars
    

    接下来,编辑 terraform.tfvars 以设置这些变量:

    • ssh_key_name- 必需ibm_region 中指定现有 SSH 密钥,如上面的 开始之前 部分中所指定。
    • ibm_region-如果需要,请替换缺省值 us-south。 CLI 命令 ibmcloud regions 将显示所有可能的区域。
    • basename-将缺省值 widget0 替换为 7 字符或更少的名称 (如果需要)。 创建的大多数资源都将使用此资源作为名称前缀。
    • 此时请勿取消注释 transit_gatewayshared_lb
  3. 仅限 Windows 用户: 如果 git 未在 Windows 计算机上创建符号链接,那么需要将文件内容复制到团队文件夹中:

    cp variables.tf terraform.tfvars admin
    cp variables.tf terraform.tfvars network
    cp variables.tf terraform.tfvars shared
    cp variables.tf terraform.tfvars application1
    

关于成为团队成员的注意事项

可以使用用户填充每个团队的访问组。 但是,本教程将在每个团队的访问组中创建服务标识,而不是创建用户。 您是管理员,将通过对团队的服务标识使用 API 密钥来 成为 不同访问组的成员。 服务标识名称为 ${basename}-x,其中 x 是网络,共享,application1 和 application2。 稍后,您将使用类似于以下内容的内容填充每个团队目录中的 local.env 文件:

export TF_VAR_ibmcloud_api_key=0thisIsNotARealKeyALX0vkLNSUFC7rMLEWYpVtyZaS9

在每个步骤中,当您 cd 进入团队目录时,将提醒您执行以下操作: source local.env

Terraform 将用于创建资源。 打开 admin/main.tf 并注意 provider ibm 子句以及对从环境变量初始化的 ibmcloud_api_key 的引用:

provider ibm {
 ibmcloud_api_key = var.ibmcloud_api_key # initialized with the TF_VAR_ibmcloud_api_key
}

如果需要使用 IBM Cloud CLI 作为团队成员:

ibmcloud login --apikey $TF_VAR_ibmcloud_api_key

创建启用 IAM 的资源 (管理团队)

管理团队将需要对本教程中使用的帐户中启用 IAM 的资源具有“管理员”访问权。 请参阅 如何分配用户作为帐户管理员的全部权限? 管理团队将负责创建 IAM 资源。 以下指示信息使用 ibmcloud iam api-key-create 命令为管理员创建 API 密钥。 Terraform 将使用 API 密钥来代表您执行任务。

PI 密钥与帐户的密码相同。 确保 API 密钥安全。

  1. 初始化并验证基本名称 shell 变量。 验证它是否与 terraform.tfvars 文件中的基本名称匹配:

    eval $(grep basename terraform.tfvars | sed -e 's/  *//g' -e 's/#.*//')
    echo basename=$basename
    
  2. 在 local.env中更改目录,生成个人 API 密钥并对其进行源。 当调用 Terraform 时,它将成为您。 Terraform 将是管理员:

    cd admin
    echo export TF_VAR_ibmcloud_api_key=$(ibmcloud iam api-key-create $basename-admin --output json | jq .apikey) > local.env
    cat local.env
    source local.env
    
  3. 应用 main.tf Terraform 配置文件将创建以下资源:

    • 每个团队的资源组
    • 每个团队的访问组以及每个访问组中的服务标识
    • 资源组的访问组策略
    • 资源的访问组策略
    terraform init
    terraform apply
    
  4. 验证是否已创建资源:

    ibmcloud resource groups | grep $basename
    
    ibmcloud iam access-groups | grep $basename
    
    ibmcloud iam service-ids | grep $basename
    
    ibmcloud iam access-group-policies $basename-network
    

    输出将类似于以下内容:

    $ ibmcloud resource groups | grep $basename
    widget0-application2   36b06a303f224f28ad42aebbb491cc44   false           ACTIVE
    widget0-shared         91518c45e47a427fa4f63edb58e4f227   false           ACTIVE
    widget0-network        bf6e75cd71854576a31056abced2abf0   false           ACTIVE
    widget0-application1   db2f3dc8aacf4a6aa2d2fa07e795cb57   false           ACTIVE
    $ ibmcloud iam access-groups | grep $basename
    widget0-application1   AccessGroupId-26b7ef37-78db-4a2c-a2af-7f6591e73c15   application1 administrators
    widget0-application2   AccessGroupId-8afdec20-f760-4a15-8f3e-296d81818028   application2 administrators
    widget0-network        AccessGroupId-d50b129d-9adc-4fc4-b297-487b3f938ec5   network administrators
    widget0-shared         AccessGroupId-30d73f44-5602-47a7-846e-e6480c9dceff   shared administrators
    $ ibmcloud iam service-ids | grep $basename
    ServiceId-5e919b97-380c-4343-a337-3901cafbd956   widget0-application2                                                                                                       2020-07-15T21:25+0000   2020-07-15T22:03+0000   application 2 service id                                                                                                                                              false
    ServiceId-307df062-f4b7-45f8-8ec8-94ad1ed61730   widget0-network                                                                                                            2020-07-15T21:49+0000   2020-07-15T22:03+0000   network service id                                                                                                                                                    false
    $ ibmcloud iam access-group-policies $basename-network
    Retrieving all policies of access group widget0-network under account 8675309 as jenny@example.com
    OK
    
    Policy ID:   00ceb354-7360-4ad5-9fda-5c03e462c5c0
    Roles:       Editor
    Resources:
                 Resource Group ID     91518c45e47a427fa4f63edb58e4f227
                 Resource Group Name   widget0-shared
                 Service Name          is
                 flowLogCollectorId    *
                 Memo                  Policy applies to the resource(s) within the resource group
    
    Policy ID:   115ebe9f-eea0-4308-9e7f-bb887d64426b
    Roles:       Editor
    Resources:
                 Resource Group ID     db2f3dc8aacf4a6aa2d2fa07e795cb57
                 Resource Group Name   widget0-application1
                 Service Name          is
                 vpnGatewayId          *
                 Memo                  Policy applies to the resource(s) within the resource group
    ...
    
  5. (可选) 浏览到帐户 资源组 并查找资源组。

  6. (可选) 浏览到 访问组 以查看访问组,单击访问组,然后单击顶部的 服务标识 面板以查看创建的服务标识。

创建 VPC 和 DNS (网络团队)

网络 团队将创建网络资源以匹配体系结构,确保满足连接目标并在其 VPC 中隔离团队。 他们不希望控制 VPC 实例的详细信息。 应用程序的数量,计算机的大小,微服务的 DNS 记录等很可能是不断变化的,而不是 网络 团队所关心的问题。

管理团队仅为他们提供了创建 VPC 的适当许可权 资源,DNS Services 和 Transit Gateway 服务。

  1. 更改目录,在 local.env 中生成 API 密钥并成为网络访问组的成员:

    team=network
    cd ../$team
    echo export TF_VAR_ibmcloud_api_key=$(ibmcloud iam service-api-key-create $team $basename-$team --output json | jq .apikey) > local.env
    cat local.env
    source local.env
    
  2. (可选) 打开 variables_network.tf 文件并注意 CIDR 块规范和区域布局。 在以下片段中,请注意 shared 和 application1 是在没有重叠 IP 地址的情况下指定的:

    variable network_architecture {
      default = {
        shared = {
          cidr        = "10.0.0.0/16"
          cidr_remote = "10.0.0.0/8"
          zones = {
            z1 = {
              zone_id = "1",
              cidr    = "10.0.0.0/24",
            }
            z2 = {
              zone_id = "2",
              cidr    = "10.0.1.0/24",
        ...
        application1 = {
          cidr        = "10.1.0.0/16"
          cidr_remote = "0.0.0.0"
          zones = {
            z1 = {
              zone_id = "1",
              cidr    = "10.1.0.0/24",
            }
            z2 = {
              zone_id = "2",
              cidr    = "10.1.1.0/24",
         ...
    

    Transit Gateway 将具有与每个 VPC 的连接,并根据 CIDR 范围来路由流量。 因此,避免重叠将确保成功。

  3. 创建资源:

    terraform init
    terraform apply
    
  4. 列出 VPC 资源

    创建的 VPC 资源由子网命令的输出进行摘要,如下所示,为简洁起见进行了编辑。 请注意三个 VPC,不重叠的 CIDR 块和资源组成员资格:

    ibmcloud target -r $(grep ibm_region terraform.tfvars | sed -e 's/  *//g' -e 's/#.*//' -e 's/.*=//' -e 's/"//g')
    ibmcloud is subnets --all-resource-groups | grep $basename
    

    输出将类似于以下内容:

    $ ibmcloud is subnets --all-resource-groups | grep $basename
    widget0-shared-z1           available   10.0.0.0/24    widget0-shared           us-south-1   widget0-shared
    widget0-shared-z2           available   10.0.1.0/24    widget0-shared           us-south-2   widget0-shared
    widget0-shared-z3           available   10.0.2.0/24    widget0-shared           us-south-3   widget0-shared
    widget0-application1-z1     available   10.1.0.0/24    widget0-application1     us-south-1   widget0-application1
    widget0-application1-z2     available   10.1.1.0/24    widget0-application1     us-south-2   widget0-application1
    widget0-application1-z3     available   10.1.2.0/24    widget0-application1     us-south-3   widget0-application1
    widget0-application2-z1     available   10.2.0.0/24    widget0-application2     us-south-1   widget0-application2
    widget0-application2-z2     available   10.2.1.0/24    widget0-application2     us-south-2   widget0-application2
    widget0-application2-z3     available   10.2.2.0/24    widget0-application2     us-south-3   widget0-application2
    
  5. (可选) 浏览到 虚拟专用云,并查找上面创建的 VPC,子网和所有其他资源。

  6. (可选) 调查 main.tf 中的 Terraform 配置以了解 DNS Services 初始化。 DNS Services 实例和区域是使用 Terraform 片段创建的:

    resource "ibm_resource_instance" "dns" {
      name              = "${var.basename}-dns"
      resource_group_id = data.ibm_resource_group.shared.id
      location          = "global"
      service           = "dns-svcs"
      plan              = "standard-dns"
    }
    
    resource "ibm_dns_zone" "widgets_example_com" {
      name        = "widgets.example.com"
      instance_id = ibm_resource_instance.dns.guid
      description = "this is a description"
      label       = "this-is-a-label"
    }
    

    然后,将区域作为允许的网络添加到 VPC:

    resource "ibm_dns_permitted_network" "shared" {
      instance_id = ibm_resource_instance.dns.guid
      zone_id     = ibm_dns_zone.widgets_example_com.zone_id
      vpc_crn     = module.vpc_shared.vpc.crn
      type        = "vpc"
    }
    
    
  7. 列出 DNS 配置。 已创建 DNS Services 实例。 已创建 widgets.example.com 区域。 最后,将该区域添加到所有 VPC。

    ibmcloud dns instances
    
    ibmcloud dns zones -i $basename-dns
    
    zone_id=$(ibmcloud dns zones -i $basename-dns --output json | jq -r '.[] | .id')
    ibmcloud dns permitted-networks $zone_id -i $basename-dns
    

    输出将类似于以下内容:

    $ ibmcloud dns instances
    Retrieving service instances for service 'dns-svcs' ...
    OK
    Name          ID                                     Location   State    Service Name   
    widget0-dns   3b0d5546-5999-4c7e-a757-f5fd21dd44ed   global     active   dns-svcs   
    $ ibmcloud dns zones -i $basename-dns
    Listing zones for service instance 'widget0-dns' ...
    OK
    ID                                               Name                  Status   
    5a1a2295-1c38-49dd-9809-aaaf5a127e79c1b          widgets.example.com   ACTIVE   
    $ zone_id=$(ibmcloud dns zones -i $basename-dns --output json | jq -r '.[] | .id')
    $ ibmcloud dns permitted-networks $zone_id -i $basename-dns
    Listing permitted networks for zone '5a1a2295-1c38-49dd-9809-f5a127e79c1b' ...
    OK
    Name                   ID                                          Type   VPC_CRN                                                                                                               State   
    widget0-shared         r006-353208ab-4e95-46fb-934b-b5566cde8975   vpc    crn:v1:bluemix:public:is:us-south:a/713c783d9a507a53135fe6793c37cc74::vpc:r006-353208ab-4e95-46fb-934b-b5566cde8975   ACTIVE   
    widget0-application1   r006-287258c6-2eb3-4908-b326-6f03c3e47aa6   vpc    crn:v1:bluemix:public:is:us-south:a/713c783d9a507a53135fe6793c37cc74::vpc:r006-287258c6-2eb3-4908-b326-6f03c3e47aa6   ACTIVE   
    widget0-application2   r006-fa51e99e-bd93-4451-a4eb-76eed9939d3c   vpc    crn:v1:bluemix:public:is:us-south:a/713c783d9a507a53135fe6793c37cc74::vpc:r006-fa51e99e-bd93-4451-a4eb-76eed9939d3c   ACTIVE   
    
  8. (可选) 浏览至 资源列表 并找到 DNS Services,单击它并进行调查。

创建共享微服务和关联的 DNS 记录 (共享团队)

  1. 更改目录,在 local.env 中生成 API 密钥并成为共享访问组的成员:

    team=shared
    cd ../$team
    echo export TF_VAR_ibmcloud_api_key=$(ibmcloud iam service-api-key-create $team $basename-$team --output json | jq .apikey) > local.env
    cat local.env
    source local.env
    
  2. (可选) 在此点深入挖掘 Terraform 源代码。 共享 团队将提供微服务。 虽然 网络 团队已创建共享 VPC 和某些网络资源,但 共享 团队将创建实例并选择实例概要文件。 Linux 配置脚本和简单演示应用程序在 user_data 属性中提供,并在下面的 应用程序团队 部分中进行讨论。

    main.tf 中,请注意以下两个资源:

    locals {
      network_context = data.terraform_remote_state.network.outputs.shared
    }
    
    resource ibm_is_instance "vsishared" {
      name           = "${var.basename}-shared-vsi"
      vpc            = local.network_context.vpc.id
      resource_group = data.ibm_resource_group.shared.id
      zone           = local.network_context.subnets["z1"].zone
      keys           = [data.ibm_is_ssh_key.ssh_key.id]
      image          = data.ibm_is_image.image.id
      profile        = var.profile[var.generation]
    
      primary_network_interface {
        subnet = local.network_context.subnets["z1"].id
        security_groups = [
          local.network_context.security_group_outbound_all.id, # nodejs is not available on an IBM mirror
          local.network_context.security_group_ibm_dns.id,
          local.network_context.security_group_data_inbound.id,
        ]
      }
      user_data = module.user_data_app.user_data_centos
    }
    
    resource ibm_dns_resource_record "shared" {
      count = var.shared_lb ? 0 : 1 # shared load balancer?
      instance_id = local.network_context.dns.guid
      zone_id     = local.network_context.dns.zone_id
      type        = "A"
      name        = "shared"
      rdata       = ibm_is_instance.vsishared.primary_network_interface[0].primary_ip.address
      ttl         = 3600
    }
    

    以上 local.network_context网络 团队专门为 共享 团队生成的输出。

  3. 创建共享资源:

    terraform init
    terraform apply
    
  4. (可选) 浏览到 VPC 的虚拟服务器实例 并查找共享实例。 单击它并验证以下内容:

    • 实例没有来自公用因特网的入局连接 (请检查安全组)
    • 找到专用 IP 地址
  5. (可选) 浏览到 资源列表 并找到 DNS Services,单击它并找到名称为 shared 的 DNS 记录。 请注意,“值”是实例的专用 IP 地址。

为应用程序创建面向公众的微服务 (Application1 团队)

  1. 更改目录,在 local.env 中生成 API 密钥,并成为 application1 访问组的成员:

    team=application1
    cd ../$team
    echo export TF_VAR_ibmcloud_api_key=$(ibmcloud iam service-api-key-create $team $basename-$team --output json | jq .apikey) > local.env
    cat local.env
    source local.env
    

    application1 团队资源与 shared 团队的资源非常相似。 事实上,它们更简单一些,因为不需要将记录放入 DNS Services中。 应用程序使用地址 http://shared.widgets.example.com 来访问共享微服务。

  2. (可选) 调查初始化 CentOS 实例的源代码。 它已在此探索阶段由所有团队共享的 Terraform 模块中捕获。

    ../common/user_data_app/main.tf:

    locals {
      shared_app_user_data_centos = <<EOS
    #!/bin/sh
    curl -sL https://rpm.nodesource.com/setup_20.x | sudo bash -
    yum install nodejs -y
    cat > /app.js << 'EOF'
    ${file("${path.module}/app.js")}
    EOF
    cat > /lib/systemd/system/a-app.service << 'EOF'
    ${file("${path.module}/a-app.service")}
    EOF
    systemctl daemon-reload
    systemctl start a-app
    EOS
    }
    
    output user_data_centos {
      value = replace(local.shared_app_user_data_centos, "REMOTE_IP", var.remote_ip)
    }
    

    详细说明:

    • Nodejs 随 curlyum 命令一起安装
    • nodejs 应用程序放入 /app.js中。
    • 将为 app.js 创建 systemctl 服务
    • 服务已启动
  3. (可选) 调查 app.js 内容。 它有两个特别有趣的部分。 首先,有一个 /info 链接,用于返回运行应用程序的实例的描述。 ../common/user_data_app/app.js:

    const server = http.createServer((req, res) => {
      switch(req.url) {
      case '/info':
        res.statusCode = 200;
        res.setHeader('Content-Type', 'application/json');
        res.end(JSON.stringify({
          req_url:  req.url,
          os_hostname:  os.hostname(),
          ipArrays: ips()
        }, null, 3));
        break
      case '/remote':
        getRemote(req, res)
        break
    

    其次,/remote 链接调用远程服务器 IP,并返回该远程服务器的描述以及用于访问远程服务器的 remote_url 和 remote_ip 地址。

    const IP='REMOTE_IP'
    
    function getRemote(req, res) {
      path = '/info'
      remote_url = 'http://' + IP + ':3000' + path
      http.get(remote_url, (resp) => {
        let rawData = '';
        resp.on('data', (chunk) => { rawData += chunk; });
        resp.on('end', () => {
          try {
            console.log(rawData)
            rawObj = JSON.parse(rawData)
            res.statusCode = 200;
            res.end(JSON.stringify({remote_url: remote_url, remote_ip: resp.connection.remoteAddress, remote_info: rawObj}, null, 3))
    

    在本例中,REMOTE_IP 将为 shared.widgets.example.com,因为 common/user_data_app/main.tf: 中存在以下内容:

    output user_data_centos {
      value = replace(local.shared_app_user_data_centos, "REMOTE_IP", var.remote_ip)
    }
    

    返回到 application1/main.tf:

    module user_data_app {
      source    = "../common/user_data_app"
      remote_ip = "shared.widgets.example.com"
    }
    
  4. 创建资源:

    terraform init
    terraform apply
    

    结果如下所示:

    $ terraform apply
    ...
    Apply complete! Resources: 2 added, 0 changed, 0 destroyed.
    
    Outputs:
    
    ibm1_private_ip = "10.1.0.4"
    ibm1_public_ip = "52.116.140.202"
    test_info = "curl 52.116.140.202:3000/info"
    test_remote = "curl 52.116.140.202:3000/remote"
    

    尝试上面建议的两个 curl 命令 (test_infotest_remote)。 从输出复制语句。

    curl 52.116.140.202:3000/info
    

    第一个结果类似于下面捕获的内容:

    {
       "req_url": "/info",
       "os_hostname": "widget0-application1-vsi",
       "ipArrays": [
          [
             "10.1.0.4"
          ]
       ]
    }
    

    然后尝试第二个命令 (从输出中):

    curl 52.116.140.202:3000/remote
    

    等等,第二个 curl 命令不起作用! 请在下一步中进行修正。 请记住这些 curl 命令,稍后将再次使用这些命令。

创建 Transit Gateway

IBM Cloud Transit Gateway 是用于互连 IBM Cloud VPC 资源的网络服务,可提供动态可伸缩性,高可用性和安心数据未通过公共因特网。 先前选择了每个 VPC 的 CIDR 块而没有重叠,以允许 Transit Gateway 按 IP 地址路由包。

  1. 更改目录并成为网络组的成员 (使用现有 API 密钥):

    cd ../network
    source local.env
    
  2. (可选) 调查 Terraform 文件。 打开 main.tf 文件,您将注意到 Transit Gateway 资源 (ibm_tg)。 每个都有一个 count = var.transit_gateway ? 1 : 0。 这是一个 Terraform 构造,它根据 transit_gateway 的值创建长度为 1 或 0 的资源数组。 长度为 0 的数组将导致没有资源。 例如:

    resource "ibm_tg_gateway" "tgw"{
      count = var.transit_gateway ? 1 : 0
      name              = "${var.basename}-tgw"
      location          = var.ibm_region
      global            = false
      resource_group    = data.ibm_resource_group.network.id
    }
    
  3. 编辑 terraform.tfvars 文件并取消注释行 transit_gateway = true 以启用 Transit Gateway的供应。

  4. 应用更改

    terraform apply
    
  5. 使用以下命令打印 Transit Gateway。

    ibmcloud tg gateways
    GATEWAY_ID=$(ibmcloud tg gateways --output json | sed -e '/^OK$/d' | jq -r '.[]|select(.name=="'$basename-tgw'")|.id')
    ibmcloud tg connections $GATEWAY_ID
    

    请注意输出中的三个 VPC 连接。 它将类似于以下内容:

    $ ibmcloud tg gateways
    Listing gateways under account
    OK
    
    GatewayID           e2801c16-1a6d-4d47-9c58-1a3b3c1d9b1b
    CRN                 crn:v1:bluemix:public:transit:us-south:a/86785309::gateway:e2801c16-1a6d-4d47-9c58-1a3b3c1d9b1b
    Name                widget0-tgw
    Routing             local
    Location            us-south
    Created             2020-07-16T09:09:38.048-07:00
    Resource group ID   bf6e75cd71854576a31056abced2abf0
    Status              available
    
    $ GATEWAY_ID=$(ibmcloud tg gateways --output json | sed -e '/^OK$/d' | jq -r '.[]|select(.name=="'$basename-tgw'")|.id')
    $ ibmcloud tg connections $GATEWAY_ID
    Listing connections for gateway e2801c16-1a6d-4d47-9c58-1a3b3c1d9b1b under account
    OK
    
    Name                    widget0-shared
    Network Type            vpc
    Connection ID           dff6ecfd-388d-471a-908a-98880426fbee
    Status                  attached
    Default Prefix Filter   permit
    NetworkID               crn:v1:bluemix:public:is:us-south:a/86785309::vpc:r006-b08a7c2c-c0ea-4908-b0ab-b96cd8ba221a
    
    Name                    widget0-application1
    Network Type            vpc
    Connection ID           bbce29f9-9ce4-47d4-911d-5341601cea07
    Status                  attached
    Default Prefix Filter   permit
    NetworkID               crn:v1:bluemix:public:is:us-south:a/86785309::vpc:r006-8fdc0e7e-3a98-4f6b-93e0-505c61e3faac
    
    Name                    widget0-application2
    Network Type            vpc
    Connection ID           208c00cc-aee2-498e-8b1c-37ddc276f200
    Status                  attached
    Default Prefix Filter   permit
    NetworkID               crn:v1:bluemix:public:is:us-south:a/86785309::vpc:r006-fa80afa7-b16b-4db7-95dd-69a558db4285
    
  6. (可选) 浏览 Transit Gateway 并查找上面创建的网关。

  7. 从上面执行先前失败的 curl 命令,以验证是否存在从 application1 VPC 到共享 VPC 的路径。 它看起来是这样的

    $ curl 169.48.152.220:3000/remote
    
    {
       "remote_url": "http://shared.widgets.example.com:3000/info",
       "remote_ip": "10.0.0.4",
       "remote_info": {
          "req_url": "/info",
          "os_hostname": "widget0-shared-vsi",
          "ipArrays": [
             [
                "10.0.0.4"
             ]
          ]
       }
    }
    

插入 Load Balancer 并替换 DNS 记录

将负载均衡器添加到体系结构
将负载均衡器添加到体系结构

  1. 更改目录并成为共享访问组的成员 (使用现有 API 密钥):

    cd ../shared
    source local.env
    
  2. (可选) 调查 Terraform 配置文件。 VPC 服务的Load Balancer可在 VPC 同一区域内的多个服务器实例之间分配流量。 共享 团队可以在多个实例之间平衡负载。 现在,负载均衡器池将仅具有先前创建的单个实例。 请参阅 lb.tf 以了解实现。 在 ibm_is_lb 资源中,使用 dns 子句来标识专用 DNS 区域以放置负载均衡器 DNS 地址:

    resource "ibm_is_lb" "shared_lb" {
      ...
      dns {
        instance_crn = local.network_context.dns.crn
        zone_id      = local.network_context.dns.zone_id
      }
    }
    
  3. 提供 DNS CNAME 记录 shared.widgets.example.com 以标识负载均衡器,因此应用程序在没有源代码更改的情况下继续工作:

    # shared.widgets.example.com
    resource ibm_dns_resource_record "shared_lb" {
      count = var.shared_lb ? 1 : 0 # shared load balancer?
      instance_id = local.network_context.dns.guid
      zone_id     = local.network_context.dns.zone_id
      type        = "CNAME"
      name        = "shared"
      rdata       = ibm_is_lb.shared_lb[0].hostname
      ttl         = 3600
    }
    

    使用相同的 count = var.shared_lb ? 1 : 0 。 负载均衡器主机名将类似于 b7911a41-us-south.widgets.example.com。 CNAME 记录将由应用程序使用。

  4. 编辑 terraform.tfvars 文件并取消注释 shared_lb = true。 然后应用更改:

    terraform apply
    
  5. 从先前的 application1 部分执行 curl .../remote 命令 (忽略刚刚为共享微服务生成的输出)。 请注意,remote_ip 是 10.0.1.4(负载均衡器),remote_info 是 10.0.0.4(实例)。 再 Curl 几次,并注意到负载均衡器的 remote_ip 可能会更改。

    $ curl 169.48.152.220:3000/remote
    
    {
       "remote_url": "http://shared.widgets.example.com:3000/info",
       "remote_ip": "10.0.1.4",
       "remote_info": {
          "req_url": "/info",
          "os_hostname": "widget0-shared-vsi",
          "ipArrays": [
             [
                "10.0.0.4"
             ]
          ]
       }
    }
    

为应用程序创建面向公众的微服务 (Application2 团队)

第二个 应用程序 团队环境与第一个应用程序环境相同。 (可选),通过修改 application1来创建 application2

  1. 输入 ./application1 目录并创建 application2 目录

    cd ../application1
    mkdir ../application2
    sed -e 's/application1/application2/g' main.tf > ../application2/main.tf
    cp terraform.tfvars variables.tf versions.tf ../application2
    
  2. 更改目录,在 local.env 中生成 API 密钥,并成为 application2 访问组的成员:

    team=application2
    cd ../$team
    echo export TF_VAR_ibmcloud_api_key=$(ibmcloud iam service-api-key-create $team $basename-$team --output json | jq .apikey) > local.env
    cat local.env
    source local.env
    
  3. 创建资源:

    terraform init
    terraform apply
    
  4. 测试 curl 命令

除去资源

  1. 破坏资源。 您可以按顺序将 (cd) 更改为团队目录,并执行 source local.env; terraform destroy。 顺序为 application2,application1,shared,network 和 admin。 还有一个脚本将为您执行此操作:

    cd ..
    ./bin/destroy.sh
    

扩展教程

其他考量因素

  • 应用程序 团队正在通过浮动 IP 地址提供对应用程序的访问权。 请考虑将其连接到 IBM Cloud Internet Services。 它可以管理公共 DNS 并提供安全性。 在多个位置和区域中部署隔离的工作负载 有一个示例。
  • 应用程序 团队可以使用负载均衡器 (如 共享 团队) 进行水平扩展。
  • 共享 团队可以通过将实例添加到 shared/main.tf 来将其他实例添加到负载均衡器。
  • 共享 团队可以将其实现平台切换到 Kubernetes。

Continuous Delivery

  • 当前在创建 VPC 实例时安装软件。 没有考虑将新版软件交付生产。
  • 对于共享微服务,可以使用新版本创建新的 VSI,并且在可以调整验证 DNS 之后,或者可以使用共享负载均衡器来切换到新版本。

自动化,登台和开发

  • 对于生产,团队可以各有自己的 Schematics 工作空间。 通过 Schematics,可以在可以共享状态和输出的云中直接执行 Terraform 配置。
  • 可以调整 Terraform 脚本以允许登台和开发环境。 将这些环境放入新帐户中。
  • 可以构造持续部署环境,以通过开发,登台和生产来移动代码和环境。 需要回滚吗? 如何实现这一目标?

总结

系统的体系结构受云资源的包含和所有权的影响。 对于来自系统各个方面的架构师来说,将他们的关注点贡献给架构是很重要的。 每个团队都需要能够控制其生成和释放的资源。 隔离将降低发生问题的可能性,并在发生问题时控制爆炸半径。