This topic describes how to deploy an Alibaba Cloud Container Service for Kubernetes cluster in a VPC and deploy WordPress within the cluster by using Terraform.
Prerequisites
Before you begin, ensure that you have completed the following operations:
Activate Alibaba Cloud Container Service. For more information, see Alibaba Cloud Container Service for Kubernetes.
Prepare an Alibaba Cloud account and an AccessKey pair (AccessKey ID and AccessKey secret) to use Terraform. You can go to the Security Management page of the Alibaba Cloud console to create or view your AccessKey pair.
Install and configure Terraform. For more information, see Install and configure Terraform in the local PC.
Step 1: Download the Terraform template for Container Service for Kubernetes
You can download the Terraform template for creating Kubernetes clusters from GitHub. The template contains the following files:
main.tf
It is the main file of Terraform and defines the resources to be deployed. This template uses conditions to reference existing network resources and create multiple Kubernetes clusters at the same time. This file defines the following resources:
Region
Defines the region where resources will be created.
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 }
Instance type
data "alicloud_instance_types" "default" { cpu_core_count = var.cpu_core_count memory_size = var.memory_size }
VPC
You can use an existing VPC by specifying vpc_id.
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
You can use existing vSwitches by specifying 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
You can determine whether to create a NAT gateway for the VPC defined in the template by specifying new_nat_gateway.
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 }
ENI
resource "alicloud_eip" "default" { count = var.new_nat_gateway == "true" ? 1 : 0 bandwidth = 10 }
ENI attaching
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 entry
You can add an SNAT entry for the NAT gateway defined in the template.
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 cluster
You can create multiple Kubernetes clusters at the same time by specifying k8s_number.
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] }
NoteYou can download the kube config content and save it in the ~/.kube/config file by specifying
kube_config = "~/.kube/config"
.
outputs.tf
This file defines output parameters. These output parameters are generated from the resources created as part of the execution, similar to the output parameters specified in the ROS template. For example, a template for deploying a Kubernetes cluster must contain the following output parameters such as the cluster ID and other resource parameters:
// 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
This file contains variables that can be transferred to main.tf. These variables can help you customize the environment.
# 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" }
Step 2: Run the Kubernetes Terraform script
In the path where the preceding files are stored, run the terraform init command to initialize the workspace.
$ 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!
Run the terraform apply command to create a Kubernetes cluster.
$ 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 ]
After you run the terraform apply command, the cluster ID and other parameters are displayed and the kube config file is stored in the ~ /.kube directory.
Now you can log on to the Container Service console to view the Kubernetes cluster created from Terraform and its related cluster, node, log, and container information.
Step 3: Download the Terraform template for WordPress
After creating a Kubernetes cluster and downloading the kube config file, you can deploy WordPress in Kubernetes. You can download the Terraform template for creating WordPress from GitHub. The template defines the resources and configurations for creating WordPress in a Kubernetes cluster. For more information about Terraform Kubernetes, see Kubernetes documentation.
This template contains the following files:
localvolumes.tf
This file defines the persistent volume for storing MySQL persistent data.
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
This file defines how to create a secret for storing the administrator password of MySQL and how to deploy 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
This file defines how to deploy 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
This file defines output parameters. The public IP address of the Server Load Balancer (SLB) instance can be used to access the deployed WordPress application.
output "slb_ip" { value = "${kubernetes_service.wordpress.load_balancer_ingress.0.ip}" }
variables.tf
This file contains the parameters for deploying MySQL and 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" }
Step 4: Run the WordPress Terraform script
Find the directory where the preceding files are stored, such as /root/terraform/kuberneters-wordpress. Run the terraform apply command to deploy MySQL and WordPress in the created Kubernetes cluster. You must specify the mysql_password variable in the command because it has no default value defined in the variable file.
$ 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
Step 5: Access WordPress
Enter the public IP address of the SLB instance in the browser to access the deployed WordPress application.
Go to the welcome page of WordPress. Select a language and click Continue.
Enter a site name and the administrator username and password. Click Install WordPress.
After installing WordPress, click Log On. Enter the administrator username and password to access WordPress.