Skip to content

Commit 3caddcb

Browse files
committed
feat: add GKE cluster modules
1 parent 8934bb6 commit 3caddcb

File tree

13 files changed

+782
-0
lines changed

13 files changed

+782
-0
lines changed

README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,10 @@ module "my_vpc" {
3939
rules.
4040
- [`gce_instance`](modules/gce_instance) - Create and manage a virtual machines
4141
instance.
42+
- [`gke_cluster`](modules/gke_cluster) - Create and manage a Kubernetes cluster
43+
where the node pool must be provisioned separately.
44+
- [`gke_node_pool`](modules/gke_node_pool) - Create and manage a Kubernetes
45+
node pool.
4246

4347
## Resources
4448

modules/gke_cluster/Makefile

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
SHELL := bash
2+
.ONESHELL:
3+
.SHELLFLAGS := -eu -o pipefail -c
4+
.DEFAULT_GOAL := validate
5+
.DELETE_ON_ERROR:
6+
MAKEFLAGS += --warn-undefined-variables
7+
MAKEFLAGS += --no-builtin-rules
8+
TERRAFORM := terraform
9+
10+
ifeq ($(origin .RECIPEPREFIX), undefined)
11+
$(error This Make does not support .RECIPEPREFIX. Please use GNU Make 4.0 or later)
12+
endif
13+
.RECIPEPREFIX =
14+
15+
.PHONY: help
16+
help:
17+
@echo "Usage: make <target>"
18+
@echo
19+
@echo "Targets:"
20+
@echo " init Initialize the Terraform working directory"
21+
@echo " validate Validate the configuration"
22+
@echo " clean Clean the Terraform working directory"
23+
24+
.PHONY: init
25+
init:
26+
$(TERRAFORM) init -backend=false
27+
28+
.PHONY: validate
29+
validate: init
30+
$(TERRAFORM) validate
31+
32+
.PHONY: clean
33+
clean:
34+
@rm -rf .terraform

modules/gke_cluster/README.md

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
# Google Kubernetes Engine Cluster
2+
3+
Terraform module to create and manage Kubernetes clusters.
4+
5+
## Usage
6+
7+
See the [examples](../../examples) directory for working examples for reference:
8+
9+
```hcl
10+
data "google_compute_network" "my_vpc" {
11+
name = "my-vpc"
12+
}
13+
14+
data "google_compute_subnetwork" "my_vpc_europe_west2" {
15+
name = "my-vpc"
16+
region = "europe-west2"
17+
}
18+
19+
module "kubernetes_cluster" {
20+
source = "git::https://github.com/kapetndev/terraform-google-compute.git//modules/gke_cluster?ref=v0.1.0"
21+
cluster_secondary_range_name = "gke-cluster-pods"
22+
kubernetes_version = "1.24.12-gke.500"
23+
location = "europe-west2"
24+
name = "my-cluster"
25+
network = data.google_compute_network.my_vpc.id
26+
services_secondary_range_name = "gke-cluster-services"
27+
subnetwork = data.google_compute_subnetwork_my_vpc_europe_west2.id
28+
}
29+
```
30+
31+
## Examples
32+
33+
- [kubernetes-cluster](../../examples/kubernetes-cluster) - Create a Kubernetes
34+
cluster and separately managed node pool.
35+
36+
## Requirements
37+
38+
| Name | Version |
39+
|------|---------|
40+
| [terraform](https://www.terraform.io/) | >= 1.0 |
41+
42+
## Providers
43+
44+
| Name | Version |
45+
|------|---------|
46+
| [google](https://registry.terraform.io/providers/hashicorp/google/latest) | >= 4.71.0 |
47+
| [random](https://registry.terraform.io/providers/hashicorp/random/latest) | >= 3.5.1 |
48+
49+
## Resources
50+
51+
| Name | Type |
52+
|------|------|
53+
| [`google_container_cluster.kubernetes_clusters`](https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/container_cluster) | resource |
54+
| [`google_container_engine_versions.supported`](https://registry.terraform.io/providers/hashicorp/google/latest/docs/data-sources/container_engine_versions) | data source |
55+
| [`random_id.cluster_name`](https://registry.terraform.io/providers/hashicorp/random/latest/docs/resources/id) | resource |
56+
57+
## Inputs
58+
59+
| Name | Description | Type | Default | Required |
60+
|------|-------------|------|---------|:--------:|
61+
| `kubernetes_version` | Kubernetes master version | `string` | | yes |
62+
| `location` | Compute zone or region the cluster master nodes will sit in | `string` | | yes |
63+
| `name` | Name of the cluster | `string` | | yes |
64+
| `network` | Name or `self_link` of the Google Compute Engine network to which the cluster is connected | `string` | | yes |
65+
| `subnetwork` | Name or `self_link` of the Google Compute Engine subnetwork in which the cluster's instances are launched | `string` | | yes |
66+
| `description` | A brief description of this resource | string | `null` | no |
67+
| `descriptive_name` | The authoritative name of the cluster. Used instead of `name` variable | `string` | `null` | no |
68+
| `enable_intranode_visability` | Enable Intra-node visibility for the cluster | `bool` | `false` | no |
69+
| `enable_vertical_pod_autoscaling` | Enable vertical pod autoscaling | `bool` | `true` | no |
70+
| `ip_allocation_policy` | Configuration for cluster IP allocations | `object{...}` | `null` | no |
71+
| `ip_allocation_policy.cluster_ipv4_cidr_block` | The IP address range for the cluster pod IPs. Set to blank to have a range chosen with the default size. Set to /netmask (e.g. /14) to have a range chosen with a specific netmask. Set to a CIDR notation (e.g. 10.96.0.0/14) from the RFC-1918 private networks (e.g. 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16) to pick a specific range to use | `string` | `null` | no |
72+
| `ip_allocation_policy.cluster_secondary_range_name` | The name of the existing secondary range in the cluster's subnetwork to use for pod IP addresses. Alternatively, `cluster_ipv4_cidr_block` can be used to automatically create a GKE-managed one | `string` | `null` | no |
73+
| `ip_allocation_policy.services_ipv4_cidr_block` | The IP address range of the services IPs in this cluster. Set to blank to have a range chosen with the default size. Set to /netmask (e.g. /14) to have a range chosen with a specific netmask. Set to a CIDR notation (e.g. 10.96.0.0/14) from the RFC-1918 private networks (e.g. 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16) to pick a specific range to use | `string` | `null` | no |
74+
| `ip_allocation_policy.services_secondary_range_name` | The name of the existing secondary range in the cluster's subnetwork to use for service `ClusterIP`s. Alternatively, `services_ipv4_cidr_block` can be used to automatically create a GKE-managed one | `string` | `null` | no |
75+
| `ip_allocation_policy.stack_type` | The IP Stack Type of the cluster. Default value is `IPV4`. Possible values are `IPV4` and `IPV4_IPV6` | `string` | `IPV4` | no |
76+
| `issue_client_certificate` | Issue a client certificate to authenticate to the cluster endpoint | `bool` | `false` | no |
77+
| `kubernetes_version_release_channel` | Kubernetes master version release channel | `string` | `null` | no |
78+
| `labels` | User defined labels to assign to the cluster | `map(string)` | `{}` | no |
79+
| `maintenance_policy` | The maintenance policy to use for the cluster | `object{...}` | `null` | no |
80+
| `maintenance_policy.recurring_window` | The window for recurring maintenance operations | `object{...}` | | yes |
81+
| `maintenance_policy.recurring_window.end_time` | Time for the (initial) recurring maintenance to end in RFC3339 format. This value is also used to calculte duration of the maintenance window | `string` | | yes |
82+
| `maintenance_policy.recurring_window.start_time` | Time for the (initial) recurring maintenance to start in RFC3339 format | `string` | | yes |
83+
| `maintenance_policy.recurring_window.recurrence` | RRULE recurrence rule for the recurring maintenance window specified in RFC5545 format. This value is used to compute the start time of subsequent windows | `string` | `FREQ=WEEKLY;BYDAY=MO,TU,WE,TH` | no |
84+
| `maintenance_policy.exclusions` | Exceptions to maintenance window. Non-emergency maintenance should not occur in these windows. A cluster can have up to three maintenance exclusions at a time | `list(object{...})` | `null` | no |
85+
| `maintenance_policy.exclusions[*].end_time` | Time for the maintenance exclusion to end in RFC3339 format | `string` | | yes |
86+
| `maintenance_policy.exclusions[*].name` | Human-readable description of the maintenance exclusion. This field is for display purposes only | `string` | | yes |
87+
| `maintenance_policy.exclusions[*].start_time` | Time for the maintenance exclusion to start in RFC3339 format | `string` | | yes |
88+
| `maintenance_policy.exclusions[*].scope` | The scope of the maintenance exclusion. Possible values are `NO_UPGRADES`, `NO_MINOR_UPGRADES`, and `NO_MINOR_OR_NODE_UPGRADES` | `string` | `null` | no |
89+
| `prefix` | An optional prefix used to generate the cluster name | `string` | `null` | no |
90+
| `project_id` | The ID of the project in which the resource belongs. If it is not provided, the provider project is used | `string` | `null` | no |
91+
| `security_group` | The name of the RBAC security group for use with Google security groups in Kubernetes RBAC. Group name must be in format `gke-security-groups@yourdomain.com` | `string` | `null` | no |
92+
93+
## Outputs
94+
95+
| Name | Description |
96+
|------|-------------|
97+
| `name` | Kubernetes cluster name |
98+
| `cluster_ca_certificate` | Base64 encoded public certificate that is the root of trust for the cluster |

modules/gke_cluster/main.tf

Lines changed: 143 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,143 @@
1+
locals {
2+
min_master_version = (
3+
var.kubernetes_version_release_channel != null
4+
? data.google_container_engine_versions.supported[0].release_channel_default_version[var.kubernetes_version_release_channel]
5+
: var.kubernetes_version
6+
)
7+
name = "${local.prefix}${var.name}"
8+
prefix = var.prefix != null ? "${var.prefix}-" : ""
9+
}
10+
11+
data "google_container_engine_versions" "supported" {
12+
count = var.kubernetes_version_release_channel != null ? 1 : 0
13+
location = var.location
14+
project = var.project_id
15+
version_prefix = var.kubernetes_version
16+
}
17+
18+
resource "random_id" "cluster_name" {
19+
count = var.descriptive_name == null ? 1 : 0
20+
byte_length = 4
21+
prefix = "${local.name}-"
22+
}
23+
24+
resource "google_container_cluster" "kubernetes_cluster" {
25+
description = var.description
26+
location = var.location
27+
name = coalesce(var.descriptive_name, random_id.cluster_name[0].hex)
28+
network = var.network
29+
project = var.project_id
30+
resource_labels = var.labels
31+
subnetwork = var.subnetwork
32+
33+
# Enable intranode visibility to expose pod-to-pod traffic to the VPC for flow
34+
# logging.
35+
enable_intranode_visibility = var.enable_intranode_visibility
36+
37+
# It is not possible to create a cluster with no node pool defined, but it is
38+
# desirable to use a node pool that is managed separately. Therefore it is
39+
# necessary to create the smallest possible default node pool and immediately
40+
# delete it.
41+
#
42+
# This is deliberately not configurable as it is not recommended to use the
43+
# default node pool.
44+
initial_node_count = 1
45+
remove_default_node_pool = true
46+
47+
# Send all logging and monitoring data to Google Cloud Monitoring.
48+
logging_service = "logging.googleapis.com/kubernetes"
49+
monitoring_service = "monitoring.googleapis.com/kubernetes"
50+
51+
# Ensure the minimum version of the master. GKE will auto-update the master to
52+
# new versions, so this does not guarantee the current master version.
53+
min_master_version = local.min_master_version
54+
55+
# Configure the cluster addons. The addons listed are all enabled by default
56+
# when the cluster is created.
57+
addons_config {
58+
horizontal_pod_autoscaling {
59+
disabled = false
60+
}
61+
62+
http_load_balancing {
63+
disabled = false
64+
}
65+
}
66+
67+
# Allows for Google Groups to work with Kubernetes role-based access control
68+
# (RBAC).
69+
dynamic "authenticator_groups_config" {
70+
for_each = var.security_group != null ? [""] : []
71+
72+
content {
73+
security_group = var.security_group
74+
}
75+
}
76+
77+
# https://cloud.google.com/kubernetes-engine/docs/how-to/alias-ips
78+
dynamic "ip_allocation_policy" {
79+
for_each = var.ip_allocation_policy != null ? [""] : []
80+
81+
content {
82+
cluster_ipv4_cidr_block = var.ip_allocation_policy.cluster_ipv4_cidr_block
83+
cluster_secondary_range_name = var.ip_allocation_policy.cluster_secondary_range_name
84+
services_ipv4_cidr_block = var.ip_allocation_policy.services_ipv4_cidr_block
85+
services_secondary_range_name = var.ip_allocation_policy.services_secondary_range_name
86+
stack_type = var.ip_allocation_policy.stack_type
87+
}
88+
}
89+
90+
dynamic "maintenance_policy" {
91+
for_each = var.maintenance_policy != null ? [""] : []
92+
93+
content {
94+
recurring_window {
95+
end_time = var.maintenance_policy.recurring_window.end_time
96+
recurrence = var.maintenance_policy.recurring_window.recurrence
97+
start_time = var.maintenance_policy.recurring_window.start_time
98+
}
99+
100+
dynamic "maintenance_exclusion" {
101+
for_each = coalesce(var.maintenance_policy.exclusions, [])
102+
103+
content {
104+
end_time = maintenance_exclusion.value.end_time
105+
exclusion_name = maintenance_exclusion.value.name
106+
start_time = maintenance_exclusion.value.start_time
107+
108+
dynamic "exclusion_options" {
109+
for_each = maintenance_exclusion.value.scope != null ? [""] : []
110+
111+
content {
112+
scope = maintenance_exclusion.value.scope
113+
}
114+
}
115+
}
116+
}
117+
}
118+
}
119+
120+
# By default we do not want to issue a client certificate to authenticate to
121+
# the cluster endpoint. This is because the certificate is not automatically
122+
# rotated and therefore is a security risk.
123+
master_auth {
124+
client_certificate_config {
125+
issue_client_certificate = var.issue_client_certificate
126+
}
127+
}
128+
129+
# Provide more control over automatic upgrades by specifying a release
130+
# channel. See
131+
# https://cloud.google.com/kubernetes-engine/docs/concepts/release-channels
132+
dynamic "release_channel" {
133+
for_each = var.kubernetes_version_release_channel != null ? [""] : []
134+
135+
content {
136+
channel = var.kubernetes_version_release_channel
137+
}
138+
}
139+
140+
vertical_pod_autoscaling {
141+
enabled = var.enable_vertical_pod_autoscaling
142+
}
143+
}

modules/gke_cluster/outputs.tf

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
output "name" {
2+
description = "Kubernetes cluster name."
3+
value = google_container_cluster.kubernetes_cluster.name
4+
}
5+
6+
output "cluster_ca_certificate" {
7+
description = "Base64 encoded public certificate that is the root of trust for the cluster."
8+
value = google_container_cluster.kubernetes_cluster.master_auth[0].cluster_ca_certificate
9+
sensitive = true
10+
}

0 commit comments

Comments
 (0)