Skip to content

Commit c9ba413

Browse files
committed
feat: implement terraform module for STACKIT Kubernetes and server management with comprehensive README and variable definitions
1 parent 1fcbe8e commit c9ba413

13 files changed

Lines changed: 670 additions & 2 deletions

File tree

.github/workflows/tflint.yml

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,5 +36,6 @@ jobs:
3636
continue-on-error: true
3737
run: tflint --recursive --format compact --only=terraform_unused_declarations
3838

39-
- name: Validate STACKIT flavors (live)
40-
run: python3 scripts/validate_stackit_flavors.py
39+
# runs 6h
40+
# - name: Validate STACKIT flavors (live)
41+
# run: python3 scripts/validate_stackit_flavors.py
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
PLACEHOLDER
Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
# terraform-stackit-kubernetes
2+
3+
Terraform module for managing STACKIT Kubernetes Engine (SKE) clusters.
4+
5+
## Usage
6+
7+
```hcl
8+
module "kubernetes" {
9+
source = "./stackit-verified-modules/terraform-stackit-kubernetes"
10+
11+
project_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
12+
13+
clusters = {
14+
production = {
15+
node_pools = [
16+
{
17+
name = "system"
18+
machine_type = "c1.3"
19+
minimum = 2
20+
maximum = 3
21+
availability_zones = ["eu01-1","eu01-2"]
22+
allow_system_components = true
23+
},
24+
{
25+
name = "application"
26+
machine_type = "c1.3"
27+
minimum = 2
28+
maximum = 5
29+
availability_zones = ["eu01-1","eu01-2"]
30+
}
31+
]
32+
}
33+
34+
staging = {
35+
node_pools = [
36+
{
37+
name = "system"
38+
machine_type = "c1.2"
39+
minimum = 1
40+
maximum = 2
41+
availability_zones = ["eu01-1","eu01-2"]
42+
allow_system_components = true
43+
},
44+
{
45+
name = "application"
46+
machine_type = "c1.2"
47+
minimum = 1
48+
maximum = 3
49+
availability_zones = ["eu01-1","eu01-2"]
50+
}
51+
]
52+
maintenance = {
53+
start = "02:00:00Z"
54+
end = "03:00:00Z"
55+
}
56+
hibernations = [
57+
{
58+
start = "0 20 * * *"
59+
end = "0 6 * * 1-5"
60+
timezone = "Europe/Berlin"
61+
}
62+
]
63+
}
64+
}
65+
}
66+
```
67+
68+
## Defaults
69+
70+
| Attribute | Default |
71+
|---|---|
72+
| `maintenance.enable_kubernetes_version_updates` | `true` |
73+
| `maintenance.enable_machine_image_version_updates` | `true` |
74+
| `maintenance.start` | `"01:00:00Z"` |
75+
| `maintenance.end` | `"02:00:00Z"` |
76+
| `network.control_plane.access_scope` | `"PUBLIC"` |
77+
78+
All node pool optional attributes (`cri`, `os_name`, `volume_size`, `volume_type`) default to the provider's built-in defaults when not specified.
79+
80+
## Inputs
81+
82+
| Name | Description | Type | Required |
83+
|---|---|---|---|
84+
| `project_id` | STACKIT project ID to which the clusters are associated. | `string` | yes |
85+
| `clusters` | Map of SKE cluster configurations. The map key is used as the cluster name. | `map(object({...}))` | yes |
86+
87+
## Outputs
88+
89+
| Name | Description |
90+
|---|---|
91+
| `clusters` | Map of created SKE clusters with their key attributes (id, name, kubernetes_version_used, egress_address_ranges, pod_address_ranges). |
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
resource "stackit_ske_cluster" "this" {
2+
for_each = var.clusters
3+
4+
project_id = var.project_id
5+
name = each.key
6+
kubernetes_version_min = each.value.kubernetes_version_min
7+
region = each.value.region
8+
node_pools = each.value.node_pools
9+
maintenance = each.value.maintenance
10+
11+
network = {
12+
id = each.value.network_id
13+
control_plane = {
14+
access_scope = each.value.public_access_enabled ? "PUBLIC" : "SNA"
15+
}
16+
}
17+
18+
extensions = each.value.extensions
19+
hibernations = each.value.hibernations
20+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
output "clusters" {
2+
description = "Map of created SKE clusters with their key attributes."
3+
value = {
4+
for name, cluster in stackit_ske_cluster.this : name => {
5+
id = cluster.id
6+
name = cluster.name
7+
kubernetes_version_used = cluster.kubernetes_version_used
8+
egress_address_ranges = cluster.egress_address_ranges
9+
pod_address_ranges = cluster.pod_address_ranges
10+
}
11+
}
12+
}

stackit-verified-modules/terraform-stackit-kubernetes/providers.tf

Whitespace-only changes.
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
terraform {
2+
required_version = ">= 1.5"
3+
4+
required_providers {
5+
stackit = {
6+
source = "stackitcloud/stackit"
7+
version = ">= 0.88.0"
8+
}
9+
}
10+
}
Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
variable "clusters" {
2+
type = map(object({
3+
kubernetes_version_min = optional(string)
4+
region = optional(string)
5+
6+
node_pools = list(object({
7+
name = string
8+
machine_type = optional(string, "c1.2")
9+
minimum = optional(number, 1)
10+
maximum = optional(number, 2)
11+
availability_zones = optional(list(string), ["eu01-m"]) # max two eu01-1, eu01-2, eu01-3, eu01-m
12+
allow_system_components = optional(bool, false)
13+
cri = optional(string, "containerd")
14+
labels = optional(map(string))
15+
max_surge = optional(number, 2)
16+
max_unavailable = optional(number)
17+
os_name = optional(string, "flatcar") # or "ubuntu"
18+
os_version_min = optional(string)
19+
volume_size = optional(number, 20)
20+
volume_type = optional(string, "storage_premium_perf1")
21+
taints = optional(list(object({
22+
effect = string
23+
key = string
24+
value = optional(string)
25+
})))
26+
}))
27+
28+
maintenance = optional(object({
29+
enable_kubernetes_version_updates = optional(bool, true)
30+
enable_machine_image_version_updates = optional(bool, true)
31+
start = string
32+
end = string
33+
}), {
34+
enable_kubernetes_version_updates = true
35+
enable_machine_image_version_updates = true
36+
start = "01:00:00Z"
37+
end = "02:00:00Z"
38+
})
39+
40+
network_id = optional(string)
41+
public_access_enabled = optional(bool, true)
42+
43+
extensions = optional(object({
44+
acl = optional(object({
45+
enabled = bool
46+
allowed_cidrs = list(string)
47+
}))
48+
dns = optional(object({
49+
enabled = bool
50+
zones = optional(list(string))
51+
}))
52+
observability = optional(object({
53+
enabled = bool
54+
instance_id = optional(string)
55+
}))
56+
}))
57+
58+
hibernations = optional(list(object({
59+
start = string
60+
end = string
61+
timezone = optional(string)
62+
})))
63+
}))
64+
description = "Map of SKE cluster configurations. The map key is used as the cluster name."
65+
66+
validation {
67+
condition = alltrue([
68+
for name, _ in var.clusters :
69+
can(regex("^[a-z][a-z0-9-]*$", name))
70+
])
71+
error_message = "Cluster names must start with a lowercase letter and contain only lowercase letters, numbers, and hyphens."
72+
}
73+
74+
validation {
75+
condition = alltrue(flatten([
76+
for cluster in var.clusters : [
77+
for np in cluster.node_pools :
78+
np.minimum >= 1
79+
]
80+
]))
81+
error_message = "Node pool minimum must be at least 1."
82+
}
83+
84+
validation {
85+
condition = alltrue(flatten([
86+
for cluster in var.clusters : [
87+
for np in cluster.node_pools :
88+
np.minimum <= np.maximum
89+
]
90+
]))
91+
error_message = "Node pool minimum must be less than or equal to maximum."
92+
}
93+
}
94+
95+
variable "project_id" {
96+
type = string
97+
description = "STACKIT project ID to which the clusters are associated."
98+
99+
validation {
100+
condition = can(regex("^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$", var.project_id))
101+
error_message = "The project_id must be a valid UUID."
102+
}
103+
}

0 commit comments

Comments
 (0)