Quickstart: Create a Kubernetes cluster with Azure Kubernetes Service using Terraform
Article tested with the following Terraform and Terraform provider versions:
Terraform enables the definition, preview, and deployment of cloud infrastructure. Using Terraform, you create configuration files using HCL syntax. The HCL syntax allows you to specify the cloud provider - such as Azure - and the elements that make up your cloud infrastructure. After you create your configuration files, you create an execution plan that allows you to preview your infrastructure changes before they're deployed. Once you verify the changes, you apply the execution plan to deploy the infrastructure.
Azure Kubernetes Service (AKS) manages your hosted Kubernetes environment. AKS allows you to deploy and manage containerized applications without container orchestration expertise. AKS also enables you to do many common maintenance operations without taking your app offline. These operations include provisioning, upgrading, and scaling resources on demand.
In this article, you learn how to:
- Use HCL (HashiCorp Language) to define a Kubernetes cluster
- Use Terraform and AKS to create a Kubernetes cluster
- Use the kubectl tool to test the availability of a Kubernetes cluster
Note
The example code in this article is located in the Microsoft Terraform GitHub repo.
Prerequisites
- Azure subscription: If you don't have an Azure subscription, create a free account before you begin.
Configure Terraform: If you haven't already done so, configure Terraform using one of the following options:
Azure service principal: If you don't have a service principal, create a service principal. Make note of the
appId
,display_name
,password
, andtenant
.SSH key pair: Use one of the following articles:
Kubernetes command-line tool (kubectl): Download kubectl.
Implement the Terraform code
Create a directory in which to test the sample Terraform code and make it the current directory.
Create a file named
providers.tf
and insert the following code:terraform { required_version = ">=1.0" required_providers { azurerm = { source = "hashicorp/azurerm" version = "~>3.0" } random = { source = "hashicorp/random" version = "~>3.0" } } } provider "azurerm" { features {} }
Create a file named
main.tf
and insert the following code:# Generate random resource group name resource "random_pet" "rg_name" { prefix = var.resource_group_name_prefix } resource "azurerm_resource_group" "rg" { location = var.resource_group_location name = random_pet.rg_name.id } resource "random_id" "log_analytics_workspace_name_suffix" { byte_length = 8 } resource "azurerm_log_analytics_workspace" "test" { location = var.log_analytics_workspace_location # The WorkSpace name has to be unique across the whole of azure; # not just the current subscription/tenant. name = "${var.log_analytics_workspace_name}-${random_id.log_analytics_workspace_name_suffix.dec}" resource_group_name = azurerm_resource_group.rg.name sku = var.log_analytics_workspace_sku } resource "azurerm_log_analytics_solution" "test" { location = azurerm_log_analytics_workspace.test.location resource_group_name = azurerm_resource_group.rg.name solution_name = "ContainerInsights" workspace_name = azurerm_log_analytics_workspace.test.name workspace_resource_id = azurerm_log_analytics_workspace.test.id plan { product = "OMSGallery/ContainerInsights" publisher = "Microsoft" } } resource "azurerm_kubernetes_cluster" "k8s" { location = azurerm_resource_group.rg.location name = var.cluster_name resource_group_name = azurerm_resource_group.rg.name dns_prefix = var.dns_prefix tags = { Environment = "Development" } default_node_pool { name = "agentpool" vm_size = "Standard_D2_v2" node_count = var.agent_count } linux_profile { admin_username = "ubuntu" ssh_key { key_data = file(var.ssh_public_key) } } network_profile { network_plugin = "kubenet" load_balancer_sku = "standard" } service_principal { client_id = var.aks_service_principal_app_id client_secret = var.aks_service_principal_client_secret } }
Create a file named
variables.tf
and insert the following code:variable "agent_count" { default = 3 } # The following two variable declarations are placeholder references. # Set the values for these variable in terraform.tfvars variable "aks_service_principal_app_id" { default = "" } variable "aks_service_principal_client_secret" { default = "" } variable "cluster_name" { default = "k8stest" } variable "dns_prefix" { default = "k8stest" } # Refer to https://azure.microsoft.com/global-infrastructure/services/?products=monitor for available Log Analytics regions. variable "log_analytics_workspace_location" { default = "eastus" } variable "log_analytics_workspace_name" { default = "testLogAnalyticsWorkspaceName" } # Refer to https://azure.microsoft.com/pricing/details/monitor/ for Log Analytics pricing variable "log_analytics_workspace_sku" { default = "PerGB2018" } variable "resource_group_location" { default = "eastus" description = "Location of the resource group." } variable "resource_group_name_prefix" { default = "rg" description = "Prefix of the resource group name that's combined with a random ID so name is unique in your Azure subscription." } variable "ssh_public_key" { default = "~/.ssh/id_rsa.pub" }
Create a file named
outputs.tf
and insert the following code:output "client_certificate" { value = azurerm_kubernetes_cluster.k8s.kube_config[0].client_certificate sensitive = true } output "client_key" { value = azurerm_kubernetes_cluster.k8s.kube_config[0].client_key sensitive = true } output "cluster_ca_certificate" { value = azurerm_kubernetes_cluster.k8s.kube_config[0].cluster_ca_certificate sensitive = true } output "cluster_password" { value = azurerm_kubernetes_cluster.k8s.kube_config[0].password sensitive = true } output "cluster_username" { value = azurerm_kubernetes_cluster.k8s.kube_config[0].username sensitive = true } output "host" { value = azurerm_kubernetes_cluster.k8s.kube_config[0].host sensitive = true } output "kube_config" { value = azurerm_kubernetes_cluster.k8s.kube_config_raw sensitive = true } output "resource_group_name" { value = azurerm_resource_group.rg.name }
Create a file named
terraform.tfvars
and insert the following code.aks_service_principal_app_id = "<service_principal_app_id>" aks_service_principal_client_secret = "<service_principal_password>"
Initialize Terraform
Run terraform init to initialize the Terraform deployment. This command downloads the Azure provider required to manage your Azure resources.
terraform init -upgrade
Key points:
- The
-upgrade
parameter upgrades the necessary provider plugins to the newest version that complies with the configuration's version constraints.
Create a Terraform execution plan
Run terraform plan to create an execution plan.
terraform plan -out main.tfplan
Key points:
- The
terraform plan
command creates an execution plan, but doesn't execute it. Instead, it determines what actions are necessary to create the configuration specified in your configuration files. This pattern allows you to verify whether the execution plan matches your expectations before making any changes to actual resources. - The optional
-out
parameter allows you to specify an output file for the plan. Using the-out
parameter ensures that the plan you reviewed is exactly what is applied. - To read more about persisting execution plans and security, see the security warning section.
Apply a Terraform execution plan
Run terraform apply to apply the execution plan to your cloud infrastructure.
terraform apply main.tfplan
Key points:
- The
terraform apply
command above assumes you previously ranterraform plan -out main.tfplan
. - If you specified a different filename for the
-out
parameter, use that same filename in the call toterraform apply
. - If you didn't use the
-out
parameter, callterraform apply
without any parameters.
Verify the results
Get the resource group name.
echo "$(terraform output resource_group_name)"
Browse to the Azure portal.
Under Azure services, select Resource groups and locate your new resource group to see the following resources created in this demo:
- Solution: By default, the demo names this solution ContainerInsights. The portal will show the solution's workspace name in parenthesis.
- Kubernetes service: By default, the demo names this service k8stest. (A Managed Kubernetes Cluster is also known as an AKS / Azure Kubernetes Service.)
- Log Analytics Workspace: By default, the demo names this workspace with a prefix of TestLogAnalyticsWorkspaceName- followed by a random number.
Get the Kubernetes configuration from the Terraform state and store it in a file that kubectl can read.
echo "$(terraform output kube_config)" > ./azurek8s
Verify the previous command didn't add an ASCII EOT character.
cat ./azurek8s
Key points:
- If you see
<< EOT
at the beginning andEOT
at the end, remove these characters from the file. Otherwise, you could receive the following error message:error: error loading config file "./azurek8s": yaml: line 2: mapping values are not allowed in this context
- If you see
Set an environment variable so that kubectl picks up the correct config.
export KUBECONFIG=./azurek8s
Verify the health of the cluster.
kubectl get nodes
Key points:
- When the AKS cluster was created, monitoring was enabled to capture health metrics for both the cluster nodes and pods. These health metrics are available in the Azure portal. For more information on container health monitoring, see Monitor Azure Kubernetes Service health.
- Several key values were output when you applied the Terraform execution plan. For example, the host address, AKS cluster user name, and AKS cluster password are output.
- To view all of the output values, run
terraform output
. - To view a specific output value, run
echo "$(terraform output <output_value_name>)"
.
Clean up resources
Delete AKS resources
When you no longer need the resources created via Terraform, do the following steps:
Run terraform plan and specify the
destroy
flag.terraform plan -destroy -out main.destroy.tfplan
Key points:
- The
terraform plan
command creates an execution plan, but doesn't execute it. Instead, it determines what actions are necessary to create the configuration specified in your configuration files. This pattern allows you to verify whether the execution plan matches your expectations before making any changes to actual resources. - The optional
-out
parameter allows you to specify an output file for the plan. Using the-out
parameter ensures that the plan you reviewed is exactly what is applied. - To read more about persisting execution plans and security, see the security warning section.
- The
Run terraform apply to apply the execution plan.
terraform apply main.destroy.tfplan
Delete service principal
Caution
Delete the service principal you used in this demo only if you're not using it for anything else.
Run az ad sp list to get the object ID of the service principal.
az ad sp list --display-name "<display_name>" --query "[].{\"Object ID\":id}" --output table
Run az ad sp delete to delete the service principal.
az ad sp delete --id <service_principal_object_id>
Troubleshoot Terraform on Azure
Troubleshoot common problems when using Terraform on Azure
Next steps
Feedback
Submit and view feedback for