使用 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。

抽象架構:

架構
教學的架構圖

在上方的圖表中,一般使用者正在存取應用程式。 應用程式正在運用共用微服務。 公司有個別的 DevOps 團隊,他們擁有 application1、application2 及共用。 網路團隊著重於連線功能和網路安全。 DevOps 團隊管理虛擬服務實例 (VSI),用來實作他們所建立及支援的服務。

具體架構

下列架構實作公司所設定的隔離及連線功能需求。 請注意,application1、共用及 application2 是 VPC。 在一段時間內,每一個 VPC 中的單一區域及子網路可以擴充至更詳細的多區域實作。

指導教學的架構
指導教學的架構

開始之前

本指導教學需要:

  • 具有下列外掛程式的 IBM Cloud CLI:
    • Transit Gateway (tg)
    • IBM Cloud VPC (vpc-infrastructure)
    • DNS Services (dns)
  • git,以複製原始碼儲存庫。
  • terraform CLI 以執行 Terraform 指令。

您將在 開始使用解決方案指導教學 手冊中找到下載並安裝適用於您作業環境的這些工具的指示。

此外:

  • 檢查使用者許可權。 確保您的使用者帳戶具有足夠許可權來建立及管理 VPC 資源,建立 IBM Cloud® Transit Gateway 並建立 IBM Cloud® Transit Gateway 服務。 請參閱 VPC 的 必要許可權 清單。 您也需要能夠建立資源群組及 IAM 資源,例如存取群組、原則、服務 ID...
  • 您需要 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 Infrastructure Service (IS) 包含大約 15 種不同的服務類型。 有些只是 網路 團隊的考量,例如網路 ACL (存取控制清單)。 其他只有微服務團隊才會關注,例如 VSI 實例。 但部分由 網路 團隊編輯,並由微服務團隊 (例如子網路) 操作。 網路 團隊將建立子網路,而微服務團隊將在子網路中建立實例。 基於本指導教學的目的,會針對下表中的每一個存取群組,彙總 VPC IS 服務類型 Transit Gateway 及 DNS。 表格的內容是必要的角色。

根據團隊的責任指派給團隊的必要角色
服務 網路 共用 應用程式 (application)
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 ):

    • admin/
    • network/
    • shared/
    • 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
    

關於成為團隊成員的附註

可以將使用者移入每一個團隊的存取群組。 但本指導教學不會建立使用者,而是會在每一個團隊的存取群組中建立服務 ID。 您是管理者,將使用團隊服務 ID 的 API 金鑰 成為 不同存取群組的成員。 服務 ID 名稱為 ${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 配置檔會建立下列資源:

    • 每一個團隊的資源群組
    • 每一個團隊的存取群組及每一個存取群組中的服務 ID
    • 資源群組的存取群組原則
    • 資源的存取群組原則
    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. 選擇性地導覽至 存取群組 以查看存取群組,按一下存取群組,然後按一下頂端的 服務 ID 畫面,以查看所建立的服務 ID。

建立 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 區塊規格及區域佈置。 在下列 Snippet 中,請注意指定 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 Snippet 建立:

    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 配置 Script 和簡式展示應用程式在 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 團隊資源與 共用 團隊資源非常類似。 事實上,它們比較簡單,因為-不需要將記錄放入 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、共用、網路、管理者。 還有一個 Script 將為您執行此動作:

    cd ..
    ./bin/destroy.sh
    

擴展指導教學

其他考量

  • 應用程式 團隊透過浮動 IP 位址提供對應用程式的存取權。 請考量將此連接至 IBM Cloud Internet Services。 它可以管理公用 DNS 並提供安全。 跨多個位置和區域部署隔離的工作負載 有一個範例。
  • 應用程式 團隊可以使用負載平衡器 (例如 共用 團隊) 來水平調整。
  • 共用 團隊可以透過將實例新增至 shared/main.tf,將其他實例新增至負載平衡器。
  • 共用 團隊可以將其實作平台切換至 Kubernetes。

Continuous Delivery

  • 目前已在建立 VPC 實例時完成軟體安裝。 尚未考慮將新版本軟體交付正式作業。
  • 對於共用微服務,可以使用新版本建立新的 VSI,並且在驗證之後可以調整 DNS,或者可以使用共用負載平衡器來切換至新版本。

自動化、暫置及開發

  • 對於正式作業,團隊可以各自擁有自己的 Schematics 工作區。 使用 Schematics,可以直接在可以共用狀態及輸出的雲端中執行 Terraform 配置。
  • 可以調整 Terraform Script 以容許暫置和開發環境。 將這些環境放入新帳戶。
  • 可以建構連續部署環境,以透過開發、暫置及正式作業來移動程式碼及環境。 需要回復嗎? 這將如何實現?

結論

系統的架構受雲端資源的包含及所有權影響。 對於來自系統所有層面的架構設計師來說,這很重要。 每一個團隊都需要能夠控制他們所產生及釋放的資源。 隔離將減少發生問題的可能性,並在發生問題時控制爆炸半徑。