本教程介绍了如何通过Terraform在VPC环境下部署一个阿里云容器服务Kubernetes集群,并在该集群之上,部署一个WordPress样例应用。
前提条件
- 请确保您已开通阿里云容器服务,参见容器服务Kubernetes版。
- 使用Terraform部署容器服务Kubernetes集群及WordPress应用,您需要一个阿里云账号和访问密钥(AccessKey)。 请在阿里云控制台中的AccessKey管理页面上创建和查看您的AccessKey。
- 安装Terraform,请参见在本地安装和配置Terraform。
步骤一:下载容器服务Kubernetes的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网关
指定new_nat_gateway来决定是否要为模板中定义的 VPC 自动创建NAT网关,以保证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网关下自动添加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 }
- 容器服务Kubernetes集群
改变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 typs 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脚本
步骤三:下载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}" } } } } }
- secret
- 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/kuberneters-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应用。