Skip to content

Commit eb7d8b1

Browse files
committed
figured out how to replace an AKS cluster
1 parent c5e743e commit eb7d8b1

File tree

7 files changed

+68
-78
lines changed

7 files changed

+68
-78
lines changed

_examples/aks/README.md

Lines changed: 20 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# AKS (Azure Kubernetes Service)
22

3-
This example shows how to use the Terraform Kubernetes Provider and Terraform Helm Provider to configure an AKS cluster. The example builds the AKS cluster and applies the Kubernetes configurations in a single operation.
3+
This example shows how to use the Terraform Kubernetes Provider and Terraform Helm Provider to configure an AKS cluster. The example config in this directory builds the AKS cluster and applies the Kubernetes configurations in a single operation. This guide will also show you how to make changes to the underlying AKS cluster in such a way that Kuberntes/Helm resources are recreated after the underlying cluster is replaced.
44

55
You will need the following environment variables to be set:
66

@@ -11,7 +11,7 @@ You will need the following environment variables to be set:
1111

1212
See [AWS Provider docs](https://www.terraform.io/docs/providers/aws/index.html#configuration-reference) for more details about these variables and alternatives, like `AWS_PROFILE`.
1313

14-
To install the EKS cluster using default values, run terraform init and apply from the directory containing this README.
14+
To install the AKS cluster using default values, run terraform init and apply from the directory containing this README.
1515

1616
```
1717
terraform init
@@ -20,21 +20,32 @@ terraform apply
2020

2121
## Kubeconfig for manual CLI access
2222

23-
This example generates a kubeconfig file in the current working directory. However, the token in this config expires in 15 minutes. The token can be refreshed by running `terraform apply` again. Export the KUBECONFIG to manually access the cluster:
23+
This example generates a kubeconfig file in the current working directory, which can be used for manual CLI access to the cluster.
2424

2525
```
26-
terraform apply
2726
export KUBECONFIG=$(terraform output kubeconfig_path|jq -r)
2827
kubectl get pods -n test
2928
```
3029

31-
## Optional variables
32-
33-
The Kubernetes version can be specified at apply time:
30+
However, in a real-world scenario, this config file would have to be replaced periodically as the AKS client certificates eventually expire (see the [Azure documentation](https://docs.microsoft.com/en-us/azure/aks/certificate-rotation) for the exact expiry dates). If the certificates are replaced, the AKS module will have to be targeted to pull in the new credentials before they can be passed into the Kubernetes or Helm providers.
3431

3532
```
36-
terraform apply -var=kubernetes_version=1.18
33+
terraform state rm module.kubernetes-config
34+
terraform plan
35+
terraform apply
36+
export KUBECONFIG=$(terraform output kubeconfig_path|jq -r)
37+
kubectl get pods -n test
3738
```
3839

39-
See https://docs.aws.amazon.com/eks/latest/userguide/platform-versions.html for currently available versions.
40+
This approach prevents the Kubernetes and Helm provider from using cached, invalid credentials, which would cause provider configuration errors durring the plan and apply phases. (The resources that were previously deployed will not be affected by the `state rm`).
41+
42+
## Replacing the AKS cluster, or its authentication credentials
4043

44+
When the cluster is initially created, the Kubernetes and Helm providers will not be initialized until authentication details are created for the cluster. However, for future operations that may involve replacing the underlying cluster (for example, changing VM sizes), the AKS cluster will have to be targeted without the Kubernetes/Helm providers, as shown below. This is done by removing the `module.kubernetes-config` from Terraform State prior to replacing cluster credentials, to avoid passing outdated credentials into the providers.
45+
46+
This will create the new cluster and the Kubernetes resources in a single apply. If this is being applied to an existing cluster (such as in the case of credential rotation), the existing Kubernetes/Helm resources will continue running and simply undergo a credential refresh.
47+
48+
```
49+
terraform state rm module.kubernetes-config
50+
terraform apply
51+
```

_examples/aks/aks-cluster/main.tf

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,3 @@
1-
provider "azurerm" {
2-
features {}
3-
}
4-
51
resource "azurerm_resource_group" "test" {
62
name = var.cluster_name
73
location = var.location
@@ -16,7 +12,8 @@ resource "azurerm_kubernetes_cluster" "test" {
1612
default_node_pool {
1713
name = "default"
1814
node_count = 1
19-
vm_size = "Standard_DS2_v2"
15+
#vm_size = "Standard_DS2_v2"
16+
vm_size = "Standard_A2_v2"
2017
}
2118

2219
identity {
Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,19 @@
1-
output "cluster_id" {
2-
value = azurerm_kubernetes_cluster.test.id
1+
output "client_cert" {
2+
value = azurerm_kubernetes_cluster.test.kube_config.0.client_certificate
3+
}
4+
5+
output "client_key" {
6+
value = azurerm_kubernetes_cluster.test.kube_config.0.client_key
7+
}
8+
9+
output "ca_cert" {
10+
value = azurerm_kubernetes_cluster.test.kube_config.0.cluster_ca_certificate
311
}
412

513
output "data_disk_uri" {
614
value = azurerm_managed_disk.test.id
715
}
16+
17+
output "endpoint" {
18+
value = azurerm_kubernetes_cluster.test.kube_config.0.host
19+
}

_examples/aks/kubernetes-config/main.tf

Lines changed: 1 addition & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -1,54 +1,10 @@
1-
provider "azurerm" {
2-
features {}
3-
}
4-
5-
# The client certificate used for authenticating into the AKS cluster will eventually expire,
6-
# (especially true if your clusters are created and destroyed periodically).
7-
# This data source fetches new authentication certificates.
8-
# Alternatively, use `terraform refresh` to fetch them manually.
9-
data "azurerm_kubernetes_cluster" "main" {
10-
depends_on = [var.cluster_id]
11-
name = var.cluster_name
12-
resource_group_name = var.cluster_name
13-
}
14-
15-
provider "kubernetes" {
16-
host = data.azurerm_kubernetes_cluster.main.kube_config.0.host
17-
client_key = base64decode(data.azurerm_kubernetes_cluster.main.kube_config.0.client_key)
18-
client_certificate = base64decode(data.azurerm_kubernetes_cluster.main.kube_config.0.client_certificate)
19-
cluster_ca_certificate = base64decode(data.azurerm_kubernetes_cluster.main.kube_config.0.cluster_ca_certificate)
20-
}
21-
221
resource "kubernetes_namespace" "test" {
23-
depends_on = [var.cluster_id]
242
metadata {
253
name = "test"
264
}
275
}
286

29-
resource "kubernetes_persistent_volume" "test" {
30-
depends_on = [var.cluster_id]
31-
metadata {
32-
name = "test"
33-
}
34-
spec {
35-
capacity = {
36-
storage = "1Gi"
37-
}
38-
access_modes = ["ReadWriteOnce"]
39-
persistent_volume_source {
40-
azure_disk {
41-
caching_mode = "None"
42-
data_disk_uri = var.data_disk_uri
43-
disk_name = "managed"
44-
kind = "Managed"
45-
}
46-
}
47-
}
48-
}
49-
507
resource "kubernetes_deployment" "test" {
51-
depends_on = [var.cluster_id]
528
metadata {
539
name = "test"
5410
namespace= kubernetes_namespace.test.metadata.0.name
@@ -67,6 +23,7 @@ depends_on = [var.cluster_id]
6723
}
6824
}
6925
spec {
26+
automount_service_account_token = false
7027
container {
7128
image = "nginx:1.19.4"
7229
name = "tf-acc-test"
@@ -87,17 +44,7 @@ depends_on = [var.cluster_id]
8744
}
8845
}
8946

90-
provider "helm" {
91-
kubernetes {
92-
host = data.azurerm_kubernetes_cluster.main.kube_config.0.host
93-
client_key = base64decode(data.azurerm_kubernetes_cluster.main.kube_config.0.client_key)
94-
client_certificate = base64decode(data.azurerm_kubernetes_cluster.main.kube_config.0.client_certificate)
95-
cluster_ca_certificate = base64decode(data.azurerm_kubernetes_cluster.main.kube_config.0.cluster_ca_certificate)
96-
}
97-
}
98-
9947
resource helm_release nginx_ingress {
100-
depends_on = [var.cluster_id]
10148
name = "nginx-ingress-controller"
10249

10350
repository = "https://charts.bitnami.com/bitnami"

_examples/aks/kubernetes-config/variables.tf

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1-
variable "cluster_id" {
2-
type = string
3-
}
4-
1+
#variable "client_cert" {
2+
# type = string
3+
#}
4+
#
55
variable "cluster_name" {
66
type = string
77
}

_examples/aks/main.tf

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,19 +15,37 @@ terraform {
1515
}
1616
}
1717

18-
resource "random_id" "cluster_name" {
19-
byte_length = 5
18+
provider "kubernetes" {
19+
host = module.aks-cluster.endpoint
20+
client_key = base64decode(module.aks-cluster.client_key)
21+
client_certificate = base64decode(module.aks-cluster.client_cert)
22+
cluster_ca_certificate = base64decode(module.aks-cluster.ca_cert)
23+
}
24+
25+
provider "helm" {
26+
kubernetes {
27+
host = module.aks-cluster.endpoint
28+
client_key = base64decode(module.aks-cluster.client_key)
29+
client_certificate = base64decode(module.aks-cluster.client_cert)
30+
cluster_ca_certificate = base64decode(module.aks-cluster.ca_cert)
31+
}
32+
}
33+
34+
provider "azurerm" {
35+
features {}
2036
}
2137

2238
module "aks-cluster" {
39+
providers = { azurerm = azurerm }
2340
source = "./aks-cluster"
2441
cluster_name = local.cluster_name
2542
location = var.location
2643
}
2744

2845
module "kubernetes-config" {
46+
providers = { kubernetes = kubernetes, helm = helm }
47+
depends_on = [module.aks-cluster]
2948
source = "./kubernetes-config"
30-
cluster_id = module.aks-cluster.cluster_id # creates dependency on cluster creation
3149
cluster_name = local.cluster_name
3250
data_disk_uri = module.aks-cluster.data_disk_uri
3351
}

_examples/aks/variables.tf

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,11 @@ variable "location" {
33
default = "westus2"
44
}
55

6+
resource "random_id" "cluster_name" {
7+
byte_length = 5
8+
}
9+
610
locals {
7-
cluster_name = "tf-k8s-${random_id.cluster_name.hex}"
11+
cluster_name = "tf-k8s-${random_id.cluster_name.hex}"
12+
cluster_credentials_updated = timestamp()
813
}

0 commit comments

Comments
 (0)