diff --git a/k8s-cluster/.terraform.lock.hcl b/k8s-cluster/.terraform.lock.hcl new file mode 100644 index 0000000..4bcc41b --- /dev/null +++ b/k8s-cluster/.terraform.lock.hcl @@ -0,0 +1,77 @@ +# This file is maintained automatically by "terraform init". +# Manual edits may be lost in future updates. + +provider "registry.terraform.io/hashicorp/dns" { + version = "3.2.3" + hashes = [ + "h1:ODcR+vWOhCAJ2iCChZMVdRglNCx07VNr67OPLRPZyDY=", + "zh:03a304f4b76ac6c8bebffddcdf555bf77578a7f638948a681589def32e140cb8", + "zh:08c7d2498b747054e9c9df7838bfa4e4a6b5d63e2d29f0457247e384f792d56c", + "zh:20adf489819ba51ba9d9d15da2dbe1fecb92491b3d0dd80096873e5e84d8b4bd", + "zh:2959ff209d2578456ca490672b82864d483b9e9db9efc8e4ffada06e23017609", + "zh:3ecd0b22db79550fb1108ff7bd00c4066825e8c23bb64e3cc8d9b8102e8caa45", + "zh:6e53a9232245b4be52b56b078f15f270b89afe6abb9c9b8baab4a282fe0cf9f8", + "zh:78d5eefdd9e494defcb3c68d282b8f96630502cac21d1ea161f53cfe9bb483b3", + "zh:80437bdfa08eb90f70105b52cb06799a8f7967313654b43d28d7f654fcd4edc1", + "zh:816ddaca0ecc29e287376e5b0b8b0729ee13f23a9d74bfad5b14b7983e1a1775", + "zh:82d8ac7ad00c1a71d0a7c1aca03bb59a6b51128f895242df80b1f3d016c3c51a", + "zh:ec9243b8bd80693a6eeeea5d4f7f4e6f57bd44ae796d6d5b1a91790e359f8a61", + "zh:fd821adbfb03a2c9eac111ff27a32b3a5523b18f80333008de85482d3bbea645", + ] +} + +provider "registry.terraform.io/hashicorp/local" { + version = "2.2.3" + hashes = [ + "h1:aWp5iSUxBGgPv1UnV5yag9Pb0N+U1I0sZb38AXBFO8A=", + "zh:04f0978bb3e052707b8e82e46780c371ac1c66b689b4a23bbc2f58865ab7d5c0", + "zh:6484f1b3e9e3771eb7cc8e8bab8b35f939a55d550b3f4fb2ab141a24269ee6aa", + "zh:78a56d59a013cb0f7eb1c92815d6eb5cf07f8b5f0ae20b96d049e73db915b238", + "zh:78d5eefdd9e494defcb3c68d282b8f96630502cac21d1ea161f53cfe9bb483b3", + "zh:8aa9950f4c4db37239bcb62e19910c49e47043f6c8587e5b0396619923657797", + "zh:996beea85f9084a725ff0e6473a4594deb5266727c5f56e9c1c7c62ded6addbb", + "zh:9a7ef7a21f48fabfd145b2e2a4240ca57517ad155017e86a30860d7c0c109de3", + "zh:a63e70ac052aa25120113bcddd50c1f3cfe61f681a93a50cea5595a4b2cc3e1c", + "zh:a6e8d46f94108e049ad85dbed60354236dc0b9b5ec8eabe01c4580280a43d3b8", + "zh:bb112ce7efbfcfa0e65ed97fa245ef348e0fd5bfa5a7e4ab2091a9bd469f0a9e", + "zh:d7bec0da5c094c6955efed100f3fe22fca8866859f87c025be1760feb174d6d9", + "zh:fb9f271b72094d07cef8154cd3d50e9aa818a0ea39130bc193132ad7b23076fd", + ] +} + +provider "registry.terraform.io/hetznercloud/hcloud" { + version = "1.33.2" + constraints = "1.33.2" + hashes = [ + "h1:3Hx8p9LbcnHfBhy3nT7+unlc5rwkiSZjLt9SVQOSpB8=", + "zh:0a5d0f332d7dfe77fa27301094af98a185aabfb9f56d71b81936e03211e4d66f", + "zh:0e047859ee7296f335881933ccf8ce8c07aa47bef56d5449a81b85a2d9dac93a", + "zh:1d3d0896f518df9e245c3207ed231e528f5dcfe628508e7c3ceba4a2bfefaa7a", + "zh:1d7a31c8c490512896ce327ab220e950f1a2e30ee83cc2e58e69bbbfbbb87e72", + "zh:67cbb2492683cb22f6c54f26bee72aec140c8dd2d0881b2815d2ef80959fc751", + "zh:771062815e662979204ac2dc91c34c893f27670d67e02370e48124483d3c9838", + "zh:957ebb146898cd059c0cc8b4c32e574b61041d8b6a11cd854b3cc1d3baaeb3a9", + "zh:95dbd8634000b979213cb97b5d869cad78299ac994d0665d150c8dafc1390429", + "zh:a21b22b2e9d835e1b8b3b7e0b41a4d199171d62e9e9be78c444c700e96b31316", + "zh:aead1ba50640a51f20d574374f2c6065d9bfa4eea5ef044d1475873c33e58239", + "zh:cefabd0a78af40ea5cd08e1ca436c753df9b1c6496eb27281b755a2de1f167ab", + "zh:d98cffc5206b9a7550a23e13031a6f53566bd1ed3bf65314bc55ef12404d49ce", + "zh:dddaaf95b6aba701153659feff12c7bce6acc78362cb5ff8321a1a1cbf780cd9", + "zh:fd662b483250326a1bfbe5684c22c5083955a43e0773347eea35cd4c2cfe700e", + ] +} + +provider "registry.terraform.io/rancher/rke" { + version = "1.3.0" + constraints = "1.3.0" + hashes = [ + "h1:8Xz+agv4LCmYZsEMp0ByP3B9FilTH81pgpoVG4CdW1Q=", + "zh:192d29c7fdcf9ed18f0ad4cd4b3c4458483ec695bafdb9caf5c83d843625be3a", + "zh:50e9c6e5fccb1e43aa87117ee029cb5a9374babdf0c35d468543785013c51895", + "zh:76476e9bd450d0b9c34426c066241cecf2934f41d4088e633c4a511c56206abe", + "zh:90c09ce14887d7a20558d5d14072139c7c33d6440c80773dc53be18689534d8b", + "zh:b5781dbdcb05636e3ffd172de7691ce684fe8a336fec0a624504d13c345bbff3", + "zh:f3fce785a7d1f404f928a5ccdc4a1e2736c2f05fcc1f51f2c3d187f6a1344859", + "zh:f4ca9a812d9ea525e6f18b7b2701c61e6b1aa85974adea161f34c97ef76b1100", + ] +} diff --git a/k8s-cluster/README.md b/k8s-cluster/README.md new file mode 100644 index 0000000..d99eba6 --- /dev/null +++ b/k8s-cluster/README.md @@ -0,0 +1,9 @@ +# Sets up a k8s cluster + +## How-to + +* Make sure you have kubectl installed, choose a version fitting to your + desired k8s version, as defined in `variables.tf` +* Copy secret.auto.tfvars.example to secret.auto.tfvars +* Set up your API key in secret.auto.tfvars +* `terraform init` && `terraform plan` && `terraform apply` diff --git a/k8s-cluster/cluster.tf b/k8s-cluster/cluster.tf new file mode 100644 index 0000000..33d8c51 --- /dev/null +++ b/k8s-cluster/cluster.tf @@ -0,0 +1,36 @@ +resource "rke_cluster" "cluster" { + kubernetes_version = var.kubernetes_version + cluster_name = "hcloud_test" + dynamic nodes { + for_each = hcloud_server.k8s-control + iterator = node + content { + hostname_override = node.value.name + address = node.value.ipv4_address + internal_address = node.value.network.*.ip[0] + user = "ansible" + role = ["controlplane", "etcd"] + ssh_key = "${file("../ssh-terraform-hetzner")}" + } + } + dynamic nodes { + for_each = hcloud_server.k8s-worker + iterator = node + content { + hostname_override = node.value.name + address = node.value.ipv4_address + internal_address = node.value.network.*.ip[0] + user = "ansible" + role = ["worker"] + ssh_key = "${file("../ssh-terraform-hetzner")}" + } + } + addons_include = [ + "https://raw.githubusercontent.com/kubernetes/dashboard/v2.5.1/aio/deploy/recommended.yaml" + ] +} + +resource "local_sensitive_file" "kube_config" { + filename = "${path.root}/kube_config_single.yml" + content = "${rke_cluster.cluster.kube_config_yaml}" +} diff --git a/k8s-cluster/firewall.tf b/k8s-cluster/firewall.tf new file mode 100644 index 0000000..01868a2 --- /dev/null +++ b/k8s-cluster/firewall.tf @@ -0,0 +1,41 @@ +data "dns_a_record_set" "ctl" { + host = "zknt-hh3.trantuete.net" +} + +locals { + host_cidr = flatten([ + for ip in data.dns_a_record_set.ctl.addrs : + "${ip}/32" + ]) +} + +resource "hcloud_firewall" "k8s-node" { + name = "k8s-node" + rule { + direction = "in" + protocol = "icmp" + source_ips = [ + "0.0.0.0/0", + "::/0" + ] + } + + rule { + direction = "in" + protocol = "tcp" + port = "22" + source_ips = [ + "0.0.0.0/0", + "::/0" + ] + } + + rule { + direction = "in" + protocol = "tcp" + port = "6443" + source_ips = local.host_cidr + } + +} + diff --git a/k8s-cluster/network.tf b/k8s-cluster/network.tf new file mode 100644 index 0000000..37cd9c4 --- /dev/null +++ b/k8s-cluster/network.tf @@ -0,0 +1,23 @@ +resource "hcloud_network" "k8s-nodes" { + name = "k8s-nodes" + ip_range = var.ip_range +} + +resource "hcloud_network_subnet" "k8s-node-subnet" { + network_id = hcloud_network.k8s-nodes.id + type = "cloud" + network_zone = "eu-central" + ip_range = var.ip_range +} + +resource "hcloud_server_network" "k8s-control-network" { + count = length(hcloud_server.k8s-control) + server_id = hcloud_server.k8s-control[count.index].id + subnet_id = hcloud_network_subnet.k8s-node-subnet.id +} + +resource "hcloud_server_network" "k8s-worker-network" { + count = length(hcloud_server.k8s-worker) + server_id = hcloud_server.k8s-worker[count.index].id + subnet_id = hcloud_network_subnet.k8s-node-subnet.id +} diff --git a/k8s-cluster/provider.tf b/k8s-cluster/provider.tf new file mode 100644 index 0000000..d6551da --- /dev/null +++ b/k8s-cluster/provider.tf @@ -0,0 +1,3 @@ +provider "hcloud" { + token = var.hcloud_token +} diff --git a/k8s-cluster/secret.auto.tfvars.example b/k8s-cluster/secret.auto.tfvars.example new file mode 100644 index 0000000..476433a --- /dev/null +++ b/k8s-cluster/secret.auto.tfvars.example @@ -0,0 +1 @@ +hcloud_token = "tokitoki" diff --git a/k8s-cluster/server.tf b/k8s-cluster/server.tf new file mode 100644 index 0000000..3b8c7a8 --- /dev/null +++ b/k8s-cluster/server.tf @@ -0,0 +1,75 @@ +resource "hcloud_server" "k8s-control" { + count = var.node_count + name = "k8s-control-${count.index}" + image = var.os_type + server_type = var.server_type + location = var.location + labels = { + type = "control" + } + ssh_keys = [hcloud_ssh_key.default.id] + user_data = templatefile( + "user-data.yaml.tpl", + { + ssh_pubkey = file("../ssh-terraform-hetzner.pub") + containerd_version = var.containerd_version + docker_version = var.docker_version + } + ) + firewall_ids = [hcloud_firewall.k8s-node.id] + + network { + network_id = hcloud_network.k8s-nodes.id + } + + connection { + type = "ssh" + user = "root" + host = self.ipv6_address # or ipv4_address if your ISP sucks + private_key = file("../ssh-terraform-hetzner") + } + + provisioner "remote-exec" { + inline = [ + "cloud-init status --wait" + ] + } +} + +resource "hcloud_server" "k8s-worker" { + count = var.node_count + name = "k8s-worker-${count.index}" + image = var.os_type + server_type = var.server_type + location = var.location + labels = { + type = "worker" + } + ssh_keys = [hcloud_ssh_key.default.id] + user_data = templatefile( + "user-data.yaml.tpl", + { + ssh_pubkey = file("../ssh-terraform-hetzner.pub") + containerd_version = var.containerd_version + docker_version = var.docker_version + } + ) + firewall_ids = [hcloud_firewall.k8s-node.id] + + network { + network_id = hcloud_network.k8s-nodes.id + } + + connection { + type = "ssh" + user = "root" + host = self.ipv6_address # or ipv4_address if your ISP sucks + private_key = file("../ssh-terraform-hetzner") + } + + provisioner "remote-exec" { + inline = [ + "cloud-init status --wait" + ] + } +} diff --git a/k8s-cluster/ssh.tf b/k8s-cluster/ssh.tf new file mode 100644 index 0000000..adb5056 --- /dev/null +++ b/k8s-cluster/ssh.tf @@ -0,0 +1,4 @@ +resource "hcloud_ssh_key" "default" { + name = "terraform" + public_key = file("../ssh-terraform-hetzner.pub") +} diff --git a/k8s-cluster/terraform.tf b/k8s-cluster/terraform.tf new file mode 100644 index 0000000..7d18dcd --- /dev/null +++ b/k8s-cluster/terraform.tf @@ -0,0 +1,22 @@ +terraform { + required_providers { + hcloud = { + source = "hetznercloud/hcloud" + version = "1.33.2" + } + rke = { + source = "rancher/rke" + version = "1.3.0" + } + local = { + source = "hashicorp/local" + version = "2.2.3" + } + dns = { + source = "hashicorp/dns" + version = "3.2.3" + } + } + + required_version = ">= 1.1" +} diff --git a/k8s-cluster/user-data.yaml.tpl b/k8s-cluster/user-data.yaml.tpl new file mode 100644 index 0000000..6b98fd0 --- /dev/null +++ b/k8s-cluster/user-data.yaml.tpl @@ -0,0 +1,18 @@ +#cloud-config +users: + - name: "ansible" + groups: ["sudo"] + sudo: "ALL=(ALL) NOPASSWD:ALL" + shell: "/bin/bash" + ssh_authorized_keys: + - "${ssh_pubkey}" + +package_update: true +package_upgrade: true + +runcmd: + - curl -LO https://download.docker.com/linux/ubuntu/dists/focal/pool/stable/amd64/containerd.io_${containerd_version}-1_amd64.deb + - curl -LO https://download.docker.com/linux/ubuntu/dists/focal/pool/stable/amd64/docker-ce-cli_${docker_version}~3-0~ubuntu-focal_amd64.deb + - curl -LO https://download.docker.com/linux/ubuntu/dists/focal/pool/stable/amd64/docker-ce_${docker_version}~3-0~ubuntu-focal_amd64.deb + - dpkg -i *deb + - usermod -a -G docker ansible diff --git a/k8s-cluster/variables.tf b/k8s-cluster/variables.tf new file mode 100644 index 0000000..e09fd94 --- /dev/null +++ b/k8s-cluster/variables.tf @@ -0,0 +1,36 @@ +variable "hcloud_token" { + sensitive = true + # default = +} + +variable "location" { + default = "nbg1" +} + +variable "server_type" { + default = "cx21" +} + +variable "os_type" { + default = "ubuntu-20.04" +} + +variable "docker_version" { + default = "20.10.16" +} + +variable "containerd_version" { + default = "1.6.4" +} + +variable "kubernetes_version" { + default = "v1.22.4-rancher1-1" +} + +variable "node_count" { + default = 3 +} + +variable "ip_range" { + default = "10.0.82.0/24" +}