Skip to content

Commit d91f6a4

Browse files
committed
k8s: Terraform deployment for Azure clusters
This provides a Terraform configuration for deploying our Kubernetes clusters to Azure. We deploy an identical cluster to each of a list of regions, with one small node for admin purposes due to a requirement to not use spot instances for the main node group for the and two autoscaling groups one with small 8 core nodes for most jobs and one with bigger nodes for the more resource intensive ones. This is different to our current scheme where each cluster has a single node group and we direct jobs in Jenkins. With this scheme we allow the Kubernetes scheduler to place jobs, or we can still direct them to specific node sizes using nodeSelector in the jobs and the labels that are assigned to the nodegroups. This is a more Kubernetes way of doing things and decouples further from Jenkins. This needs updates for authentication, and for the storage space for the Terraform state. Signed-off-by: Mark Brown <[email protected]>
1 parent f043f71 commit d91f6a4

File tree

5 files changed

+172
-0
lines changed

5 files changed

+172
-0
lines changed

k8s/azure/README

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
This needs to be run on a machine with Terraform install and the
2+
Azure CLI. Personal login for the Azure CLI can be done with:
3+
4+
az login
5+
6+
The actual account used is a service principal account though:
7+
8+
az ad sp create-for-rbac -n kernelci-k8s
9+
10+
which outputs an appId and password, this should be distributed via the
11+
credential store and set in terraform variables, see variables.tf.
12+
13+
When the clusters are created a logged in user can set up the client
14+
credentials like this:
15+
16+
for c in $(az aks list --query '[].name' -o tsv) ; do
17+
az aks get-credentials --resource-group kernelci-workers --name ${c}
18+
done
19+
20+
(TBD: also put this in outputs.tf, need to figure out syntax for arrays)

k8s/azure/aks-cluster.tf

Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
# FIXME: For real deployment we should store the terraform state
2+
# in cloud storage rather than just the current directory, terraform
3+
# supports Azure blob storage directly. This means configuration
4+
# doesn't need to be on a single machine somewhere.
5+
#
6+
# See https://www.terraform.io/language/settings/backends/azurerm
7+
#
8+
#terraform {
9+
# backend "azurerm" {
10+
# resource_group_name = "kernelci-tf-storage"
11+
# storage_account_name = "kernelci-tf"
12+
# container_name = "tfstate"
13+
# key = "workers.terraform.tfstate"
14+
# }
15+
#}
16+
17+
provider "azurerm" {
18+
features {}
19+
}
20+
21+
# We assign all clusters to the same resource group, this is purely for
22+
# accounting purposes so it doesn't matter where the resource group is
23+
resource "azurerm_resource_group" "workers" {
24+
name = "kernelci-workers"
25+
location = "East US"
26+
27+
tags = {
28+
environment = "kernelci-workers"
29+
}
30+
}
31+
32+
locals {
33+
zones = toset([
34+
"uksouth",
35+
"eastus",
36+
])
37+
}
38+
39+
resource "azurerm_kubernetes_cluster" "workers" {
40+
for_each = local.zones
41+
42+
name = "${each.key}-workers-aks"
43+
location = each.key
44+
resource_group_name = azurerm_resource_group.workers.name
45+
dns_prefix = "${each.key}-workers-k8s"
46+
47+
# Automatically roll out upgrades from AKS
48+
automatic_channel_upgrade = "stable"
49+
50+
# Single always present node as AKS requires a default node pool -
51+
# Terraform and/or AKS don't let us tag this as a spot instance and
52+
# ideally we can scale the builders down to 0 so this is a small
53+
# instance not tagged for work.
54+
default_node_pool {
55+
name = "default"
56+
node_count = 1
57+
vm_size = "Standard_DS2_v2"
58+
os_disk_size_gb = 30
59+
60+
node_labels = {
61+
"kernelci/management" = "management"
62+
}
63+
}
64+
65+
service_principal {
66+
client_id = var.appId
67+
client_secret = var.password
68+
}
69+
70+
role_based_access_control {
71+
enabled = true
72+
}
73+
74+
tags = {
75+
environment = "kernelci"
76+
}
77+
}
78+
79+
# Smaller nodes for most jobs
80+
resource "azurerm_kubernetes_cluster_node_pool" "small_workers" {
81+
for_each = azurerm_kubernetes_cluster.workers
82+
83+
name = "smallworkers"
84+
kubernetes_cluster_id = each.value.id
85+
86+
# 3rd gen Xeon 8 cores, 32G RAM - general purpose
87+
vm_size = "Standard_D8s_v5"
88+
89+
# Currently things struggle with scale to 0 so require a node
90+
enable_auto_scaling = true
91+
min_count = 1
92+
node_count = 1
93+
max_count = 10
94+
95+
priority = "Spot"
96+
# We could set this lower to control costs, -1 means up to on demand
97+
# price
98+
spot_max_price = -1
99+
100+
node_labels = {
101+
"kernelci/worker" = "worker"
102+
"kernelci/worker-size" = "small"
103+
}
104+
}
105+
106+
# Big nodes for more intensive jobs (and large numbers of small jobs)
107+
resource "azurerm_kubernetes_cluster_node_pool" "big_workers" {
108+
for_each = azurerm_kubernetes_cluster.workers
109+
110+
name = "bigworkers"
111+
kubernetes_cluster_id = each.value.id
112+
113+
# 3rd gen Xeon, 32 core, 64G RAM - compute optimised
114+
vm_size = "Standard_F32s_v2"
115+
116+
# Currently things struggle with scale to 0 so require a node
117+
enable_auto_scaling = true
118+
min_count = 1
119+
node_count = 1
120+
max_count = 10
121+
122+
priority = "Spot"
123+
# We could set this lower to control costs, -1 means up to on demand
124+
# price
125+
spot_max_price = -1
126+
127+
node_labels = {
128+
"kernelci/worker" = "worker"
129+
"kernelci/worker-size" = "big"
130+
}
131+
}

k8s/azure/outputs.tf

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
output "resource_group_name" {
2+
value = azurerm_resource_group.workers.name
3+
}

k8s/azure/variables.tf

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
variable "appId" {
2+
description = "Azure Kubernetes Service Cluster service principal"
3+
}
4+
5+
variable "password" {
6+
description = "Azure Kubernetes Service Cluster password"
7+
}

k8s/azure/versions.tf

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
terraform {
2+
required_providers {
3+
azurerm = {
4+
source = "hashicorp/azurerm"
5+
version = "2.66.0"
6+
}
7+
}
8+
9+
required_version = ">= 0.14"
10+
}
11+

0 commit comments

Comments
 (0)