本教程介紹了如何通過Terraform在VPC環境下部署一個阿里雲Container ServiceKubernetes叢集,並在該叢集之上,部署一個WordPress範例應用。
前提條件
在使用本教程之前,請確保完成以下準備工作:
請確保您已開通阿里雲Container Service,參見Container Service Kubernetes 版。
使用Terraform部署Container ServiceKubernetes叢集及WordPress應用,您需要一個阿里雲帳號和存取金鑰(AccessKey)。 請在阿里雲控制台中的AccessKey管理頁面上建立和查看您的AccessKey。
安裝Terraform,請參見在本地安裝和配置Terraform。
步驟一:下載Container ServiceKubernetes的Terraform模板
您可以從GitHub上下載建立Kubernetes叢集的Terraform模板(模板下載地址),模板中包含以下檔案:
main.tf
Terraform主檔案。定義了將要部署的資源。本模板加入了條件判斷,可實現對已有網路資源的引用和多個Kubernetes叢集的同時建立。該檔案定義了以下資源:
可用地區
定義了資源將要被建立在哪個地區。
provider "alicloud" { access_key = "${var.alicloud_access_key}" secret_key = "${var.alicloud_secret_key}" region = "${var.region}" } data "alicloud_zones" "default" { available_instance_type = data.alicloud_instance_types.default.instance_types[0].id }執行個體規格
data "alicloud_instance_types" "default" { cpu_core_count = var.cpu_core_count memory_size = var.memory_size }專用網路
指定vpc_id可使用已有VPC。
resource "alicloud_vpc" "vpc" { count = var.vpc_id == "" ? 1 : 0 cidr_block = var.vpc_cidr name = var.vpc_name == "" ? var.example_name : var.vpc_name }交換器
指定vswitch_ids可使用已有交換器。
resource "alicloud_vswitch" "vswitches" { count = length(var.vswitch_ids) > 0 ? 0 : length(var.vswitch_cidrs) vpc_id = var.vpc_id == "" ? join("", alicloud_vpc.vpc.*.id) : var.vpc_id cidr_block = element(var.vswitch_cidrs, count.index) availability_zone = data.alicloud_zones.default.zones[count.index % length(data.alicloud_zones.default.zones)]["id"] name = var.vswitch_name_prefix == "" ? format( "%s-%s", var.example_name, format(var.number_format, count.index + 1), ) : format( "%s-%s", var.vswitch_name_prefix, format(var.number_format, count.index + 1), ) }NAT Gateway
指定new_nat_gateway來決定是否要為模板中定義的 VPC 自動建立NAT Gateway,以保證Kubernetes叢集成功建立。
resource "alicloud_nat_gateway" "default" { count = var.new_nat_gateway == "true" ? 1 : 0 vpc_id = var.vpc_id == "" ? join("", alicloud_vpc.vpc.*.id) : var.vpc_id name = var.example_name }彈性網卡
resource "alicloud_eip" "default" { count = var.new_nat_gateway == "true" ? 1 : 0 bandwidth = 10 }綁定彈性網卡
resource "alicloud_eip_association" "default" { count = var.new_nat_gateway == "true" ? 1 : 0 allocation_id = alicloud_eip.default[0].id instance_id = alicloud_nat_gateway.default[0].id }添加SNAT條目
在模板中定義的NAT Gateway下自動添加SNAT條目來保證Kubernetes叢集成功建立。
resource "alicloud_snat_entry" "default" { count = var.new_nat_gateway == "false" ? 0 : length(var.vswitch_ids) > 0 ? length(var.vswitch_ids) : length(var.vswitch_cidrs) snat_table_id = alicloud_nat_gateway.default[0].snat_table_ids source_vswitch_id = length(var.vswitch_ids) > 0 ? split(",", join(",", var.vswitch_ids))[count.index % length(split(",", join(",", var.vswitch_ids)))] : length(var.vswitch_cidrs) < 1 ? "" : split(",", join(",", alicloud_vswitch.vswitches.*.id))[count.index % length(split(",", join(",", alicloud_vswitch.vswitches.*.id)))] snat_ip = alicloud_eip.default[0].ip_address }Container ServiceKubernetes叢集
改變k8s_number的值可同時建立多個Kubernetes叢集。
resource "alicloud_cs_kubernetes" "k8s" { count = var.k8s_number name = var.k8s_name_prefix == "" ? format( "%s-%s", var.example_name, format(var.number_format, count.index + 1), ) : format( "%s-%s", var.k8s_name_prefix, format(var.number_format, count.index + 1), ) vswitch_ids = [length(var.vswitch_ids) > 0 ? split(",", join(",", var.vswitch_ids))[count.index % length(split(",", join(",", var.vswitch_ids)))] : length(var.vswitch_cidrs) < 1 ? "" : split(",", join(",", alicloud_vswitch.vswitches.*.id))[count.index % length(split(",", join(",", alicloud_vswitch.vswitches.*.id)))]] new_nat_gateway = false master_instance_types = [var.master_instance_type == "" ? data.alicloud_instance_types.default.instance_types[0].id : var.master_instance_type] worker_instance_types = [var.worker_instance_type == "" ? data.alicloud_instance_types.default.instance_types[0].id : var.worker_instance_type] worker_numbers = [var.k8s_worker_number] master_disk_category = var.master_disk_category worker_disk_category = var.worker_disk_category master_disk_size = var.master_disk_size worker_disk_size = var.master_disk_size password = var.ecs_password pod_cidr = var.k8s_pod_cidr service_cidr = var.k8s_service_cidr enable_ssh = true install_cloud_monitor = true depends_on = [alicloud_snat_entry.default] }說明指定
kube_config = "~/.kube/config"可在Kubernetes叢集建立完成後將Kube Config內容自動下載並存放在檔案~/.kube/config中。
outputs.tf
該檔案定義了輸出參數。作為執行的一部分而建立的資源會產生這些輸出參數。和ROS模板指定的輸出參數類似。例如,該模板將部署一個Kubernetes叢集。以下輸出參數將提供叢集ID和其他資源參數。
// Output VPC output "vpc_id" { description = "The ID of the VPC." value = alicloud_cs_kubernetes.k8s[0].vpc_id } output "vswitch_ids" { description = "List ID of the VSwitches." value = [alicloud_cs_kubernetes.k8s.*.vswitch_ids] } output "nat_gateway_id" { value = alicloud_cs_kubernetes.k8s[0].nat_gateway_id } // Output kubernetes resource output "cluster_id" { description = "ID of the kunernetes cluster." value = [alicloud_cs_kubernetes.k8s.*.id] } output "security_group_id" { description = "ID of the Security Group used to deploy kubernetes cluster." value = alicloud_cs_kubernetes.k8s[0].security_group_id } output "worker_nodes" { description = "List worker nodes of cluster." value = [alicloud_cs_kubernetes.k8s.*.worker_nodes] } output "master_nodes" { description = "List master nodes of cluster." value = [alicloud_cs_kubernetes.k8s.*.master_nodes] }variables.tf
該檔案包含可傳遞到main.tf的變數,可協助您自訂環境。
# common variables variable "availability_zone" { description = "The available zone to launch ecs instance and other resources." default = "" } variable "number_format" { description = "The number format used to output." default = "%02d" } variable "example_name" { default = "tf-example-kubernetes" } # Instance types variables variable "cpu_core_count" { description = "CPU core count is used to fetch instance types." default = 2 } variable "memory_size" { description = "Memory size used to fetch instance types." default = 4 } # VPC variables variable "vpc_name" { description = "The vpc name used to create a new vpc when 'vpc_id' is not specified. Default to variable `example_name`" default = "" } variable "vpc_id" { description = "A existing vpc id used to create several vswitches and other resources." default = "" } variable "vpc_cidr" { description = "The cidr block used to launch a new vpc when 'vpc_id' is not specified." default = "10.1.0.0/21" } # VSwitch variables variable "vswitch_name_prefix" { description = "The vswitch name prefix used to create several new vswitches. Default to variable `example_name`" default = "" } variable "vswitch_ids" { description = "List of existing vswitch id." type = list(string) default = [] } variable "vswitch_cidrs" { description = "List of cidr blocks used to create several new vswitches when 'vswitch_ids' is not specified." type = list(string) default = ["10.1.2.0/24"] } variable "new_nat_gateway" { description = "Whether to create a new nat gateway. In this template, a new nat gateway will create a nat gateway, eip and server snat entries." default = "true" } # Cluster nodes variables variable "master_instance_type" { description = "The ecs instance type used to launch master nodes. Default from instance typs datasource." default = "" } variable "worker_instance_type" { description = "The ecs instance type used to launch worker nodes. Default from instance typs datasource." default = "" } variable "master_disk_category" { description = "The system disk category used to launch one or more master nodes." default = "cloud_efficiency" } variable "worker_disk_category" { description = "The system disk category used to launch one or more worker nodes." default = "cloud_efficiency" } variable "master_disk_size" { description = "The system disk size used to launch one or more master nodes." default = "40" } variable "worker_disk_size" { description = "The system disk size used to launch one or more worker nodes." default = "40" } variable "ecs_password" { description = "The password of instance." default = "Abc12345" } variable "k8s_number" { description = "The number of kubernetes cluster." default = 1 } variable "k8s_worker_number" { description = "The number of worker nodes in each kubernetes cluster." default = 3 } variable "k8s_name_prefix" { description = "The name prefix used to create several kubernetes clusters. Default to variable `example_name`" default = "" } variable "k8s_pod_cidr" { description = "The kubernetes pod cidr block. It cannot be equals to vpc's or vswitch's and cannot be in them." default = "172.20.0.0/16" } variable "k8s_service_cidr" { description = "The kubernetes service cidr block. It cannot be equals to vpc's or vswitch's or pod's and cannot be in them." default = "172.21.0.0/20" }
步驟二:執行Kubernetes Terraform指令碼
在存放以上檔案的路徑,運行terraform init命令,初始化工作空間。
$ terraform init Initializing the backend... Initializing provider plugins... - Checking for available provider plugins... - Downloading plugin for provider "alicloud" (hashicorp/alicloud) 1.62.0... The following providers do not have any version constraints in configuration, so the latest version was installed. To prevent automatic upgrades to new major versions that may contain breaking changes, it is recommended to add version = "..." constraints to the corresponding provider blocks in configuration, with the constraint strings suggested below. * provider.alicloud: version = "~> 1.62" Terraform has been successfully initialized!運行terraform apply 命令,開始建立Kubernetes叢集。
$ terraform apply data.alicloud_instance_types.default: Refreshing state... data.alicloud_zones.default: Refreshing state... An execution plan has been generated and is shown below. Resource actions are indicated with the following symbols: + create Terraform will perform the following actions: ... Plan: 7 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 alicloud_vpc.vpc: Creating... ... Apply complete! Resources: 7 added, 0 changed, 0 destroyed. Outputs: cluster_id = [ c0f2e04c77e234****** ] ...... vswitch_ids = [ vsw-bp1c3hfcd6l80izqc3tbx ]terraform apply命令執行完畢後,輸出叢集ID和其他參數。除此之外,將Kubernetes的Kube Config檔案存放在了目錄 ~/.kube 下。
您現在可以在Container Service控制台查看通過terraform建立的Kubernetes叢集,查看叢集、節點、日誌和容器等資訊。
步驟三:下載WordPress的Terraform模板
在建立好Kubernetes並完成了Kube Config的下載後,接下來就可以在Kubernetes上部署WordPress。 您可以從GitHub上下載建立WordPress的 Terraform模板(模板下載地址,模板中定義了建立WordPress的相關資源和配置,協助您完成在Kubernetes叢集的快速搭建WordPress。更多 Terraform Kubernetes的操作可參考Terraform官網的 Kubernetes 文檔介紹。
模板中包含以下檔案:
localvolumes.tf
定義儲存MySQL持久化資料的Persistent Volume。
resource "kubernetes_persistent_volume" "mysql" { metadata { name = "local-pv-mysql" labels { type = "local" } } spec { capacity { storage = "20Gi" } access_modes = ["ReadWriteOnce"] persistent_volume_source { host_path { path = "/tmp/data/pv-mysql" } } } }mysql.tf
建立MySQL密碼憑證Secret,並部署MySQL。
secret
resource "kubernetes_secret" "mysql" { metadata { name = "mysql-pass" } data { password = "${var.mysql_password}" } }Deployment
resource "kubernetes_service" "mysql" { metadata { name = "wordpress-mysql" labels { app = "wordpress" } } spec { port { port = 3306 } selector { app = "wordpress" tier = "${kubernetes_replication_controller.mysql.spec.0.selector.tier}" } cluster_ip = "None" } } resource "kubernetes_replication_controller" "mysql" { metadata { name = "wordpress-mysql" labels { app = "wordpress" } } spec { selector { app = "wordpress" tier = "mysql" } template { container { image = "mysql:${var.mysql_version}" name = "mysql" env { name = "MYSQL_ROOT_PASSWORD" value_from { secret_key_ref { name = "${kubernetes_secret.mysql.metadata.0.name}" key = "password" } } } port { container_port = 3306 name = "mysql" } volume_mount { name = "mysql-persistent-storage" mount_path = "/var/lib/mysql" } } volume { name = "mysql-persistent-storage" persistent_volume_claim { claim_name = "${kubernetes_persistent_volume_claim.mysql.metadata.0.name}" } } } } }
wordpress.tf
部署WordPress。
resource "kubernetes_service" "wordpress" { metadata { name = "wordpress" labels { app = "wordpress" } } spec { port { port = 80 } selector { app = "wordpress" tier = "${kubernetes_replication_controller.wordpress.spec.0.selector.tier}" } type = "LoadBalancer" } } resource "kubernetes_replication_controller" "wordpress" { metadata { name = "wordpress" labels { app = "wordpress" } } spec { selector { app = "wordpress" tier = "frontend" } template { container { image = "wordpress:${var.wordpress_version}-apache" name = "wordpress" env { name = "WORDPRESS_DB_HOST" value = "wordpress-mysql" } env { name = "WORDPRESS_DB_PASSWORD" value_from { secret_key_ref { name = "${kubernetes_secret.mysql.metadata.0.name}" key = "password" } } } port { container_port = 80 name = "wordpress" } volume_mount { name = "wordpress-persistent-storage" mount_path = "/var/www/html" } } volume { name = "wordpress-persistent-storage" persistent_volume_claim { claim_name = "${kubernetes_persistent_volume_claim.wordpress.metadata.0.name}" } } } } }outputs.tf
該檔案定義了輸出參數。輸出Loadbalancer Public IP,藉助該IP地址可直接存取部署好的WordPress應用。
output "slb_ip" { value = "${kubernetes_service.wordpress.load_balancer_ingress.0.ip}" }variables.tf
該檔案包含了部署MySQL和WordPress所依賴的參數。
variable "wordpress_version" { description = "The version of wordpress. Default to 4.7.3." default = "4.7.3" } variable "mysql_password" { description = "Please input mysql password." } variable "mysql_version" { description = "The version of mysql which wordpress used. Default to 5.6." default = "5.6" }
步驟四:執行WordPress Terraform指令碼
首先定位到您存放以上檔案的目錄,如 /root/terraform/kubernetes-wordpress。運行terraform apply命令,開始在建立好的Kubernetes叢集上部署MySQL和WordPress應用。值得注意的是,由於變數mysql_password在變數檔案中沒有定義預設值,因此在執行命令時需要指定該參數值。
$ terraform apply -var 'mysql_password=Abc1234'
An execution plan has been generated and is shown below.
Resource actions are indicated with the following symbols:
+ create
Terraform will perform the following actions:
...
Plan: 9 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
kubernetes_secret.mysql: Creating...
data.%: "" => "1"
data.password: "<sensitive>" => "<sensitive>"
metadata.#: "" => "1"
metadata.0.generation: "" => "<computed>"
metadata.0.name: "" => "mysql-pass"
......
Apply complete! Resources: 9 added, 0 changed, 0 destroyed.
Outputs:
slb_ip = 47.99.xx.xx步驟五:訪問WordPress
根據負載平衡Public IP,在瀏覽器中輸入IP地址即可實現對部署好的WordPress直接存取:
進入WordPress歡迎頁面,選擇語言,然後繼續配置。

輸入網站名稱以及管理員的使用者名稱和密碼。選擇安裝WordPress。

WordPress安裝完成後,單擊 登入,輸入管理員的使用者名稱和密碼,進入WordPress應用。
