使用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部署環境
-
建立新的Project或是選擇現有的Project,把Project ID複製下來。
-
為Project啟用Compute Engine and Deployment Manager API:
點此啟用API -
下載Service Account的憑證:
點此跳到憑證的頁面
Service Account選單中選擇Compute Engine default service account。
類型選擇JSON之後點選建立,憑證會下載到本機,格式為:[PROJECT_ID]-[UNIQUE_ID].json。
準備AWS部署環境
- 在AWS管理控制台,點選自己的用戶名稱,點選我的安全登入資料。或是點此直接跳到憑證頁面。
- 在頁面中點選建立存取金鑰。
- 點選下載.csv檔案,金鑰會下載到本機,格式為:[IAM用戶別名]_accessKeys.csv。
準備Terraform部署環境
- 從GitHub clone repository:
git clone https://github.com/GoogleCloudPlatform/autonetdeploy-multicloudvpn.git
- 切換到clone過來的目錄:
cd autonetdeploy-multicloudvpn
- 執行下列指令,下載Terraform:
./get_terraform.sh
- 如果有預先安裝Terraform的話這個步驟可以跳過。
修改程式碼讓VM可以從本機SSH連入
- 修改
./terraform/aws_compute.tf
的下面字串:
key_name = "vm-ssh-key"
把"vm-ssh-key"
改為先決條件中金鑰對的名稱(要以""
把名稱包住)。
- 修改
./terraform/gcp_compute.tf
找到這行代碼:
metadata_startup_script = replace(
貼上代碼到上面代碼的前面:
metadata = {
enable-oslogin = "TRUE"
}
設置憑證與Project ID
- 設置GCP憑證
執行下列script匯入GCP憑證位置:
./gcp_set_credentials.sh /path/to/credential/[PROJECT_ID]-[UNIQUE_ID].json
- 設置GCP Project ID
執行下列兩行指令以指定Project ID:
gcloud config set project [PROJECT-ID] ./gcp_set_project.sh
- 設置AWS憑證
執行下列script匯入AWS憑證位置:
./aws_set_credentials.sh /path/to/credential/[IAM用戶別名]_accessKeys.csv
開始在Oregon部署Terraform
- 切換到Terraform設定檔所在的資料夾:
cd terraform
- 下載Terraform的GCP與AWS的提供商模組:
terraform init
- 檢查Terraform的語法是否有錯誤:
terraform validate
- 試部署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 ID
與Secret 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
- 以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 VM
ping 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的部署
- 先以
plan
確認會被destroy
移除的部署資源範圍:
terraform plan -destroy
plan -destroy
的作用是刪除前Call所有相關的API做一次Dry run,一樣不會把對資源的變更推送到雲端。
- 執行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.
修改程式碼部署到香港
- 把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部署金鑰對,金鑰對名稱可以與之前的區域一樣,以簡化部署。
- 把GCP部署區域改為香港
修改gcp_variables.tf
裡面的程式碼區塊
variable "gcp_region" {
description = "Default to Oregon region."
default = "us-west1"
}
將"us-west1"
改為"asia-east2"
,讓部署區域同樣改為香港。
- 按照之前的步驟把資源部署到香港
快速複習:
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的改版都是來的這麼迅速與美妙!