最新資訊
使用Terraform在GCP和AWS之間建立VPN

【技術文章】

科技趨勢

【技術文章】使用Terraform在GCP和AWS之間建立VPN

使用Terraform在GCP和AWS之間建立VPN

大綱

 

 

GCP提供的標準步驟如下:
https://cloud.google.com/solutions/automated-network-deployment-multicloud?hl=zh-cn
本文件目的簡化步驟、補足標準步驟上說明不足的地方與提供測試結果數據。
另外也展示了只靠修改程式碼即可將相同的架構部署到不同區域。
完成所需時間:約30分鐘

架構展示

架構圖


圖片來源:GCP Documentation

先決條件

  • 決定在GCP與AWS部署的區域
  • 在AWS區域中預先建立金鑰對或是匯入金鑰對
  • 指定GCP的Project名稱
  • 為GCP OS Login上傳ssh連線用的公鑰(需安裝Cloud SDK)
gcloud compute os-login ssh-keys add --key-file ~/.ssh/id_rsa.pub

輸出範例如下:

loginProfile:
  name: '012345678901234567890'
  posixAccounts:
  - gid: '0123456789'
    homeDirectory: /home/[username]
    operatingSystemType: LINUX
    primary: true
    uid: '0123456789'
    username: [username]
  • [username]即為登入GCP機器時的使用者帳號。

GCP OS Login參考文件
https://cloud.google.com/compute/docs/oslogin

透過官方提供的設定檔部署時,相關資源的資訊如下:

  GCP AWS
機器規格 n1-highmem-8 r4.2xlarge
部署地區 us-west1(Oregon) us-west-2(Oregon)

準備GCP部署環境

  1. 建立新的Project或是選擇現有的Project,把Project ID複製下來。

  2. 為Project啟用Compute Engine and Deployment Manager API:
    點此啟用API

  3. 下載Service Account的憑證:
    點此跳到憑證的頁面
    Service Account選單中選擇Compute Engine default service account。
    類型選擇JSON之後點選建立,憑證會下載到本機,格式為:[PROJECT_ID]-[UNIQUE_ID].json。

準備AWS部署環境

  1. 在AWS管理控制台,點選自己的用戶名稱,點選我的安全登入資料。或是點此直接跳到憑證頁面
  2. 在頁面中點選建立存取金鑰。
  3. 點選下載.csv檔案,金鑰會下載到本機,格式為:[IAM用戶別名]_accessKeys.csv。

準備Terraform部署環境

  1. 從GitHub clone repository:
git clone https://github.com/GoogleCloudPlatform/autonetdeploy-multicloudvpn.git
  1. 切換到clone過來的目錄:
cd autonetdeploy-multicloudvpn
  1. 執行下列指令,下載Terraform:
./get_terraform.sh

get_terraform.sh原始碼

  • 如果有預先安裝Terraform的話這個步驟可以跳過。

修改程式碼讓VM可以從本機SSH連入

  1. 修改./terraform/aws_compute.tf的下面字串:
key_name = "vm-ssh-key"

"vm-ssh-key"改為先決條件中金鑰對的名稱(要以""把名稱包住)。

  1. 修改./terraform/gcp_compute.tf

找到這行代碼:

 metadata_startup_script = replace(

貼上代碼到上面代碼的前面:

  metadata = {
    enable-oslogin = "TRUE"
  }

設置憑證與Project ID

  1. 設置GCP憑證

執行下列script匯入GCP憑證位置:

./gcp_set_credentials.sh /path/to/credential/[PROJECT_ID]-[UNIQUE_ID].json

gcp_set_credentials.sh原始碼

  1. 設置GCP Project ID

執行下列兩行指令以指定Project ID:


 

gcloud config set project [PROJECT-ID] ./gcp_set_project.sh

gcp_set_project.sh原始碼

  1. 設置AWS憑證

執行下列script匯入AWS憑證位置:

./aws_set_credentials.sh /path/to/credential/[IAM用戶別名]_accessKeys.csv

aws_set_credentials.sh原始碼

開始在Oregon部署Terraform

  1. 切換到Terraform設定檔所在的資料夾:
cd terraform
  1. 下載Terraform的GCP與AWS的提供商模組:
terraform init
  1. 檢查Terraform的語法是否有錯誤:
terraform validate
  1. 試部署Terraform:
terraform plan

plan的作用是在部署前Call所有相關的API做一次Dry run,不會把對資源的變更推送到雲端。
此外還會列出一串資源的清單,並且在資源前面以+標示要建立的資源、-標示要刪除的資源以及以~標示部署後會變更的資源。

執行terraform plan的輸出不應該有任何錯誤,但是aws_set_credentials.sh的原始碼有BUG,因此只參考官方教學操作會出現下面的錯誤訊息。

Error: error using credentials to get account ID: error calling sts:GetCallerIdentity: InvalidClientTokenId: The security token included in the request is invalid.

錯誤的成因是AWS的憑證無法匯出到預設的位置,在官方修正之前的解決方法是:

[IAM用戶別名]_accessKeys.csv裡面的Access key IDSecret access key的值。

Access key ID,Secret access key
ABCDEFGHIJKLMNOPQRST,1234567890abcdefghijklmnopqrstuvwxyzABCD

複製到~/.aws/credentials_autonetdeploy等號後的空值上,以下為修改後的範例。

[default]
aws_access_key_id=ABCDEFGHIJKLMNOPQRST
aws_secret_access_key=1234567890abcdefghijklmnopqrstuvwxyzABCD

如果出現下列錯誤,代表aws_compute.tf沒有修改到。

Error: Error launching source instance: InvalidKeyPair.NotFound: The key pair 'vm-ssh-key' does not exist
  1. 以Terraform部署所有資源:
terraform apply

Terraform會再做一次plan,推估要變更的資源後,詢問是否要推送變更到雲端。
範例如下:

Plan: 34 to add, 0 to change, 0 to destroy.

Do you want to perform these actions?
  Terraform will perform the actions described above.
  Only 'yes' will be accepted to approve.

  Enter a value: 

在這裏只有輸入yes才會實際提交部署,部署大約需要四分鐘的時間。

如果出現下列資訊,代表資源部署成功了。

Outputs:

aws_instance_external_ip = [AWS_EXTERNAL_IP]
aws_instance_internal_ip = 172.16.0.100
gcp_instance_external_ip = [GCP_EXTERNAL_IP]
gcp_instance_internal_ip = 10.240.0.100

此時可以以[AWS_EXTERNAL_IP]或是[GCP_EXTERNAL_IP]連上建立的VM

需要復現部署資訊的時候,可以執行terraform output

在執行所有terraform開頭的指令時,工作資料夾必須在main.tf所在的資料夾,在本例中是~/autonetdeploy-multicloudvpn/terraform/

驗證部署

  • 執行terraform show,從輸出中確認資源部署的屬性。(可選)
  • 從本機ping [AWS_EXTERNAL_IP]ping [GCP_EXTERNAL_IP]確認機器存在。
  • 從本機執行ssh -i ~/.ssh/id_rsa ubuntu@[AWS_EXTERNAL_IP]以連上AWS VM。
  • 從本機執行ssh -i ~/.ssh/id_rsa [username]@[GCP_EXTERNAL_IP]以連上GCP VM。
  • 從AWS與GCP VM執行curl ifconfig.co/ip以確認Public IP。
  • 從AWS VMping 10.240.0.100與從GCP VMping 172.16.0.100,確認VPN Tunnel有成功的串接兩朵雲。

測試數據

ping

  • AWS ping to GCP public IP

$ ping [GCP_EXTERNAL_IP] -c 10 PING [GCP_EXTERNAL_IP] ([GCP_EXTERNAL_IP]) 56(84) bytes of data. . . . — [GCP_EXTERNAL_IP] ping statistics — 10 packets transmitted, 10 received, 0% packet loss, time 9015ms rtt min/avg/max/mdev = 16.685/16.867/17.086/0.134 ms

  • AWS ping to GCP internal IP

$ ping 10.240.0.100 -c 10 PING 10.240.0.100 (10.240.0.100) 56(84) bytes of data. . . . — 10.240.0.100 ping statistics — 10 packets transmitted, 10 received, 0% packet loss, time 9011ms rtt min/avg/max/mdev = 16.039/16.264/17.302/0.352 ms

  • GCP ping to AWS public IP

$ ping [AWS_EXTERNAL_IP] -c 10 PING [AWS_EXTERNAL_IP] ([AWS_EXTERNAL_IP]) 56(84) bytes of data. . . . — [AWS_EXTERNAL_IP] ping statistics — 10 packets transmitted, 10 received, 0% packet loss, time 9012ms rtt min/avg/max/mdev = 15.620/15.751/15.854/0.108 ms

  • GCP ping to AWS internal IP

$ ping 172.16.0.100 -c 10 PING 172.16.0.100 (172.16.0.100) 56(84) bytes of data. . . . — 172.16.0.100 ping statistics — 10 packets transmitted, 10 received, 0% packet loss, time 9014ms rtt min/avg/max/mdev = 16.341/16.548/17.750/0.426 ms

iperf

可以透過執行shell script測試iperf對external或是internal IP的結果

/tmp/run_iperf_to_ext.sh
/tmp/run_iperf_to_int.sh

這兩個script是Terraform在分別建立AWS與GCP VM時自動生成,放在/tmp/底下,並且安裝與啟動iperf3以方便測試。
script執行的指令是:iperf3 -c <EXT_IP or INT_IP> -p 80 -i 1 -t 30 -P 8 -V

  • AWS using iperf to test GCP external IP result

Test Complete. Summary Results: [ ID] Interval Transfer Bandwidth Retr . . . [SUM] 0.00-30.00 sec 16.7 GBytes 4.80 Gbits/sec 117 sender [SUM] 0.00-30.00 sec 16.7 GBytes 4.79 Gbits/sec receiver CPU Utilization: local/sender 12.2% (0.6%u/11.6%s), remote/receiver 2.1% (0.2%u/1.9%s)

  • AWS using iperf to test GCP internal IP result

Test Complete. Summary Results: [ ID] Interval Transfer Bandwidth Retr . . . [SUM] 0.00-30.00 sec 3.14 GBytes 899 Mbits/sec 3131 sender [SUM] 0.00-30.00 sec 3.13 GBytes 896 Mbits/sec receiver CPU Utilization: local/sender 3.5% (0.3%u/3.2%s), remote/receiver 0.9% (0.1%u/0.8%s)

  • GCP using iperf to test AWS external IP result

Test Complete. Summary Results: [ ID] Interval Transfer Bandwidth Retr . . . [SUM] 0.00-30.00 sec 22.9 GBytes 6.55 Gbits/sec 0 sender [SUM] 0.00-30.00 sec 22.9 GBytes 6.55 Gbits/sec receiver CPU Utilization: local/sender 18.8% (0.5%u/18.3%s), remote/receiver 0.9% (0.1%u/0.8%s)

  • GCP using iperf to test AWS internal IP result

Test Complete. Summary Results: [ ID] Interval Transfer Bandwidth Retr . . . [SUM] 0.00-30.00 sec 1.53 GBytes 439 Mbits/sec 2686 sender [SUM] 0.00-30.00 sec 1.53 GBytes 437 Mbits/sec receiver CPU Utilization: local/sender 1.8% (0.2%u/1.7%s), remote/receiver 1.4% (0.2%u/1.2%s)

從結果可以發現,透過VPN Tunnel傳輸時,因為封包會被加密解密,因此速度會大幅降低。
但是對ping的回應時間幾乎沒有影響。

移除在Oregon的部署

  1. 先以plan確認會被destroy移除的部署資源範圍:

terraform plan -destroy

plan -destroy的作用是刪除前Call所有相關的API做一次Dry run,一樣不會把對資源的變更推送到雲端。

  1. 執行destroy,移除所有資源:

terraform destroy

這時候跟apply一樣會再執行一次plan -destroy,推估要刪除的資源後,詢問是否要推送變更到雲端。

輸出範例:

Do you really want to destroy all resources?
  Terraform will destroy all your managed infrastructure, as shown above.
  There is no undo. Only 'yes' will be accepted to confirm.
  Enter a value:

由於所有資源將被移除,因此必須輸入yes才能確認繼續移除資源。

在執行terraform destroy時,務必再三確認將被移除的資源範圍。

如果出現下面資訊,代表資源移除成功了。
Destroy complete! Resources: 34 destroyed.

修改程式碼部署到香港

  1. 把AWS部署區域改為香港

修改aws_variables.tf裡面的程式碼區塊:

variable "aws_region" {
  description = "Default to Oregon region."
  default     = "us-west-2"
}

variable "aws_instance_type" {
  description = "Machine Type. Includes 'Enhanced Networking' via ENA."
  default     = "r4.2xlarge"
}

"us-west-2"改為"ap-east-1",讓部署區域改為香港。
另外要把"r4.2xlarge"改為"r5.2xlarge",因為香港沒有r4大小的機器。

不要忘記在ap-east-1部署金鑰對,金鑰對名稱可以與之前的區域一樣,以簡化部署。

  1. 把GCP部署區域改為香港

修改gcp_variables.tf裡面的程式碼區塊

variable "gcp_region" {
  description = "Default to Oregon region."
  default     = "us-west1"
}

"us-west1"改為"asia-east2",讓部署區域同樣改為香港。

  1. 按照之前的步驟把資源部署到香港

快速複習:
terraform validate驗證語法是否符合格式。
terraform plan確認要部署的資源。
terraform apply推送指令部署資源。

不需要執行terraform init的原因是,之前在部署到Oregon的時候已經下載過兩朵雲的提供商模組了。

如果出現下列資訊,代表資源部署成功了。

Outputs:

aws_instance_external_ip = [AWS_EXTERNAL_IP_HK]
aws_instance_internal_ip = 172.16.0.100
gcp_instance_external_ip = [GCP_EXTERNAL_IP_HK]
gcp_instance_internal_ip = 10.240.0.100

測試數據

ping

  • AWS ping to GCP public IP at HK

$ ping [AWS_EXTERNAL_IP_HK] -c 10 PING [AWS_EXTERNAL_IP_HK] ([AWS_EXTERNAL_IP_HK]) 56(84) bytes of data. . . . — [GCP_EXTERNAL_IP_HK] ping statistics — 10 packets transmitted, 10 received, 0% packet loss, time 9015ms rtt min/avg/max/mdev = 2.438/2.688/2.955/0.157 ms

  • AWS ping to GCP internal IP at HK

$ ping 10.240.0.100 -c 10 PING 10.240.0.100 (10.240.0.100) 56(84) bytes of data. . . . — 10.240.0.100 ping statistics — 10 packets transmitted, 10 received, 0% packet loss, time 9010ms rtt min/avg/max/mdev = 2.050/2.281/3.607/0.450 ms

  • GCP ping to AWS public IP at HK

$ ping [AWS_EXTERNAL_IP_HK] -c 10 PING [AWS_EXTERNAL_IP_HK] ([AWS_EXTERNAL_IP_HK]) 56(84) bytes of data. . . . — [AWS_EXTERNAL_IP_HK] ping statistics — 10 packets transmitted, 10 received, 0% packet loss, time 9015ms rtt min/avg/max/mdev = 2.150/2.723/4.891/0.764 ms

  • GCP ping to AWS internal IP at HK

$ ping 172.16.0.100 -c 10 PING 172.16.0.100 (172.16.0.100) 56(84) bytes of data. . . . — 172.16.0.100 ping statistics — 10 packets transmitted, 10 received, 0% packet loss, time 9011ms rtt min/avg/max/mdev = 1.979/2.198/3.720/0.511 ms

iperf

  • AWS using iperf to test GCP external IP result at HK

Test Complete. Summary Results: [ ID] Interval Transfer Bandwidth Retr . . . [SUM] 0.00-30.00 sec 16.7 GBytes 4.79 Gbits/sec 1063 sender [SUM] 0.00-30.00 sec 16.7 GBytes 4.78 Gbits/sec receiver CPU Utilization: local/sender 8.2% (0.3%u/8.0%s), remote/receiver 1.3% (0.1%u/1.2%s)

  • AWS using iperf to test GCP internal IP result at HK

Test Complete. Summary Results: [ ID] Interval Transfer Bandwidth Retr . . . [SUM] 0.00-30.00 sec 4.48 GBytes 1.28 Gbits/sec 6343 sender [SUM] 0.00-30.00 sec 4.47 GBytes 1.28 Gbits/sec receiver CPU Utilization: local/sender 4.0% (0.2%u/3.8%s), remote/receiver 3.4% (0.4%u/3.0%s)

  • GCP using iperf to test AWS external IP result at HK

Test Complete. Summary Results: [ ID] Interval Transfer Bandwidth Retr . . . [SUM] 0.00-30.00 sec 20.9 GBytes 5.98 Gbits/sec 11727 sender [SUM] 0.00-30.00 sec 20.9 GBytes 5.97 Gbits/sec receiver CPU Utilization: local/sender 19.3% (0.6%u/18.7%s), remote/receiver 2.8% (0.2%u/2.6%s)

  • GCP using iperf to test AWS internal IP result at HK

Test Complete. Summary Results: [ ID] Interval Transfer Bandwidth Retr . . . [SUM] 0.00-30.00 sec 3.35 GBytes 959 Mbits/sec 2907 sender [SUM] 0.00-30.00 sec 3.34 GBytes 957 Mbits/sec receiver CPU Utilization: local/sender 4.3% (0.3%u/4.0%s), remote/receiver 5.3% (0.6%u/4.8%s)

從結果可以推測,由於香港AWS與GCP的機房距離比較近,因此ping的回應時間比Oregon快。
另外,也可以合理推測,由於提高了AWS的機器規格,因此在AWS到GCP走internet大量傳輸時,CPU usage相對比較低。

移除在香港的部署

參照之前的步驟移除在香港建立的資源。

最後可以再下一次terraform show,以確認所有資源真的被清空了。
不過AWS金鑰對、GCP上傳的ssh key、GCP被啟用的API等手動變更的項目不會復原。

附註

Terraform於2020/8/10推出了0.13.0版本,本文件引用的Google官方做法(0.12.0)日後隨時可能會為了跟上Terraform的版本而更動語法。
相信撇除更動代碼的操作之外不會有太大的改變。
每次Terraform的改版都是來的這麼迅速與美妙!