diff --git a/.gitignore b/.gitignore index 30e28e8ce..1516d20c0 100644 --- a/.gitignore +++ b/.gitignore @@ -1,9 +1,17 @@ *.pyc *.swp *~ + prepare-vms/tags prepare-vms/infra prepare-vms/www + +prepare-scw/.terraform* +prepare-scw/terraform.* +prepare-scw/stage2/*.tf +prepare-scw/stage2/kubeconfig.* +prepare-scw/stage2/wildcard_dns.* + slides/*.yml.html slides/autopilot/state.yaml slides/index.html diff --git a/prepare-scw/README.md b/prepare-scw/README.md new file mode 100644 index 000000000..4c839a2e5 --- /dev/null +++ b/prepare-scw/README.md @@ -0,0 +1,13 @@ +This directory contains a Terraform configuration to deploy +a bunch of Kubernetes clusters on Scaleway, using their managed +Kubernetes (Kapsule). + +To use it: + +```bash +scw init +terraform init +terraform apply +cd stage2 +terraform apply +``` diff --git a/prepare-scw/kapsule_cluster/main.tf b/prepare-scw/kapsule_cluster/main.tf new file mode 100644 index 000000000..500c5fb7e --- /dev/null +++ b/prepare-scw/kapsule_cluster/main.tf @@ -0,0 +1,18 @@ +resource "scaleway_k8s_cluster" "my_cluster" { + name = var.cluster_name + tags = var.common_tags + version = var.k8s_version + cni = var.cni +} + +resource "scaleway_k8s_pool" "my_pool" { + cluster_id = scaleway_k8s_cluster.my_cluster.id + name = "pool-0" + tags = var.common_tags + node_type = var.node_type + size = var.pool_size + min_size = var.pool_min_size + max_size = var.pool_max_size + autoscaling = true + autohealing = true +} diff --git a/prepare-scw/kapsule_cluster/outputs.tf b/prepare-scw/kapsule_cluster/outputs.tf new file mode 100644 index 000000000..dd76422cd --- /dev/null +++ b/prepare-scw/kapsule_cluster/outputs.tf @@ -0,0 +1,11 @@ +output "kubeconfig" { + value = scaleway_k8s_cluster.my_cluster.kubeconfig +} + +output "cluster_id" { + value = scaleway_k8s_cluster.my_cluster.id +} + +output "wildcard_dns" { + value = scaleway_k8s_cluster.my_cluster.wildcard_dns +} diff --git a/prepare-scw/kapsule_cluster/providers.tf b/prepare-scw/kapsule_cluster/providers.tf new file mode 100644 index 000000000..bf7840b90 --- /dev/null +++ b/prepare-scw/kapsule_cluster/providers.tf @@ -0,0 +1,17 @@ +terraform { + required_providers { + scaleway = { + source = "scaleway/scaleway" + version = "2.0.0" + } + kubernetes = { + source = "hashicorp/kubernetes" + version = "2.0.3" + } + local = { + source = "hashicorp/local" + version = "2.1.0" + } + } + required_version = ">= 0.14" +} diff --git a/prepare-scw/kapsule_cluster/variables.tf b/prepare-scw/kapsule_cluster/variables.tf new file mode 100644 index 000000000..bacea9722 --- /dev/null +++ b/prepare-scw/kapsule_cluster/variables.tf @@ -0,0 +1,39 @@ +variable "cluster_name" { + type = string + default = "deployed-with-terraform" +} + +variable "cni" { + type = string + default = "cilium" +} + +variable "common_tags" { + type = list(string) + default = [] +} + +variable "k8s_version" { + type = string + default = "1.22.2" +} + +variable "node_type" { + type = string + default = "DEV1-M" +} + +variable "pool_size" { + type = number + default = 2 +} + +variable "pool_min_size" { + type = number + default = 1 +} + +variable "pool_max_size" { + type = number + default = 5 +} diff --git a/prepare-scw/locals.tf b/prepare-scw/locals.tf new file mode 100644 index 000000000..5b43c3ea7 --- /dev/null +++ b/prepare-scw/locals.tf @@ -0,0 +1,6 @@ +locals { + # Common tags to be assigned to all resources + common_tags = [ + "created-by=terraform" + ] +} diff --git a/prepare-scw/main.tf b/prepare-scw/main.tf new file mode 100644 index 000000000..f497c23df --- /dev/null +++ b/prepare-scw/main.tf @@ -0,0 +1,29 @@ +module "kapsule_cluster" { + count = var.how_many_clusters + source = "./kapsule_cluster" + cluster_name = format("tf-%03d", count.index + 101) +} + +output "kubectl_config" { + value = format("scw k8s kubeconfig install %s", split("/", module.kapsule_cluster.0.cluster_id)[1]) +} + +resource "local_file" "stage2" { + filename = "${path.module}/stage2/main.tf" + content = templatefile( + "${path.module}/stage2.tmpl", + { count = var.how_many_clusters } + ) +} + +resource "local_file" "kubeconfig" { + count = var.how_many_clusters + filename = format("%s/stage2/kubeconfig.%03d", path.module, count.index + 101) + content = module.kapsule_cluster[count.index].kubeconfig.0.config_file +} + +resource "local_file" "wildcard_dns" { + count = var.how_many_clusters + filename = format("%s/stage2/wildcard_dns.%03d", path.module, count.index + 101) + content = trimprefix(module.kapsule_cluster[count.index].wildcard_dns, "*.") +} diff --git a/prepare-scw/providers.tf b/prepare-scw/providers.tf new file mode 100644 index 000000000..45783207c --- /dev/null +++ b/prepare-scw/providers.tf @@ -0,0 +1,16 @@ +terraform { + required_providers { + scaleway = { + source = "scaleway/scaleway" + version = "2.0.0" + } + } + required_version = ">= 0.14" +} + +provider "scaleway" { + #zone = "nl-ams-1" + #region = "nl-ams" + #project_id = "7ee16446-7711-4171-a7c2-4bb6f0d4c4c8" +} + diff --git a/prepare-scw/stage2.tmpl b/prepare-scw/stage2.tmpl new file mode 100644 index 000000000..7c7f853ea --- /dev/null +++ b/prepare-scw/stage2.tmpl @@ -0,0 +1,136 @@ +terraform { + required_providers { + kubernetes = { + source = "hashicorp/kubernetes" + version = "2.0.3" + } + } + required_version = ">= 0.14" +} + + +%{ for index in range(101, 101+count) ~} + +provider "kubernetes" { + alias = "kapsule_cluster_${index}" + config_path = "$${path.module}/kubeconfig.${index}" +} + +resource "kubernetes_namespace" "sshpod_${index}" { + provider = kubernetes.kapsule_cluster_${index} + metadata { + name = "sshpod" + } +} + +resource "kubernetes_deployment" "sshpod_${index}" { + provider = kubernetes.kapsule_cluster_${index} + metadata { + name = "sshpod" + namespace = kubernetes_namespace.sshpod_${index}.metadata.0.name + } + spec { + selector { + match_labels = { + app = "sshpod" + } + } + template { + metadata { + labels = { + app = "sshpod" + } + } + spec { + service_account_name = "sshpod" + container { + image = "jpetazzo/sshpod" + name = "sshpod" + env { + name = "PASSWORD" + value = random_string.sshpod_${index}.result + } + lifecycle { + post_start { + exec { + command = [ "sh", "-c", "curl http://myip.enix.org/REMOTE_ADDR > /etc/HOSTIP || true" ] + } + } + } + resources { + limits = { + cpu = "2" + memory = "100M" + } + requests = { + cpu = "100m" + memory = "100M" + } + } + } + } + } + } +} + +resource "kubernetes_service" "sshpod_${index}" { + provider = kubernetes.kapsule_cluster_${index} + metadata { + name = "sshpod" + namespace = kubernetes_namespace.sshpod_${index}.metadata.0.name + } + spec { + selector = { + app = "sshpod" + } + port { + port = 22 + target_port = 22 + node_port = 32222 + } + type = "NodePort" + } +} + +resource "kubernetes_service_account" "sshpod_${index}" { + provider = kubernetes.kapsule_cluster_${index} + metadata { + name = "sshpod" + namespace = kubernetes_namespace.sshpod_${index}.metadata.0.name + } +} + +resource "kubernetes_cluster_role_binding" "sshpod_${index}" { + provider = kubernetes.kapsule_cluster_${index} + metadata { + name = "sshpod" + } + role_ref { + api_group = "rbac.authorization.k8s.io" + kind = "ClusterRole" + name = "cluster-admin" + } + subject { + kind = "ServiceAccount" + name = "sshpod" + namespace = "sshpod" + } +} + +resource "random_string" "sshpod_${index}" { + length = 6 + special = false + upper = false +} + +output "ssh_${index}" { + value = format( + "ssh -l %s -p %s ssh.%s # password=%s", + "k8s", + "32222", + file(format("%s/wildcard_dns.%03d", path.module, ${index})), + random_string.sshpod_${index}.result + ) +} + +%{ endfor ~} diff --git a/prepare-scw/stage2/README.md b/prepare-scw/stage2/README.md new file mode 100644 index 000000000..99bd0e5e3 --- /dev/null +++ b/prepare-scw/stage2/README.md @@ -0,0 +1 @@ +This directory will only contain generated files. \ No newline at end of file diff --git a/prepare-scw/variables.tf b/prepare-scw/variables.tf new file mode 100644 index 000000000..07412ae41 --- /dev/null +++ b/prepare-scw/variables.tf @@ -0,0 +1,4 @@ +variable "how_many_clusters" { + type = number + default = 2 +}