diff --git a/.gitignore b/.gitignore index 9882402..5dd4f22 100644 --- a/.gitignore +++ b/.gitignore @@ -11,6 +11,8 @@ crash.log # terraform.tvars terraform.tfvars +*.tfvars + # known files created by terraform modules id_rsa* kube_config* diff --git a/linode/infra.tf b/linode/infra.tf new file mode 100644 index 0000000..22cbc42 --- /dev/null +++ b/linode/infra.tf @@ -0,0 +1,95 @@ +provider "linode" { + token = var.linode_token +} + +data "linode_domain" "linode_domain_for_rancher" { + domain = var.linode_domain_for_rancher +} + +resource "linode_nodebalancer" "rke-lb" { + label = "${var.prefix}-rke" + region = var.region +} + +resource "linode_nodebalancer_config" "rke-lb-config" { + nodebalancer_id = linode_nodebalancer.rke-lb.id + port = 443 + protocol = "tcp" + check = "connection" + check_attempts = 2 + check_timeout = 3 + check_interval = 5 + stickiness = "table" + algorithm = "roundrobin" +} + +resource "linode_nodebalancer_node" "rke-lb-node" { + count = var.rke_node_count + nodebalancer_id = linode_nodebalancer.rke-lb.id + config_id = linode_nodebalancer_config.rke-lb-config.id + label = "${var.prefix}-rke-h${count.index + 1}" + address = "${element(linode_instance.rke.*.private_ip_address, count.index)}:443" + mode = "accept" +} + +resource "linode_domain_record" "rancher_dns_record" { + domain_id = data.linode_domain.linode_domain_for_rancher.id + name = var.rancher_server_name + record_type = "A" + target = linode_nodebalancer.rke-lb.ipv4 + ttl_sec = "300" +} + +resource "linode_instance" "rke" { + count = var.rke_node_count + image = var.instance_image + label = "${var.prefix}-rke-h${count.index + 1}" + region = var.region + type = var.instance_type + authorized_keys = var.authorized_keys + root_pass = var.root_password + private_ip = true + + connection { + host = self.ip_address + type = "ssh" + user = var.node_username + private_key = file(pathexpand(var.ssh_private_key_path)) + } + + provisioner "remote-exec" { + inline = [ + "export DEBIAN_FRONTEND=noninteractive;curl -sSL https://raw.githubusercontent.com/rancher/install-docker/master/${var.docker_version}.sh | sh -" + ] + } +} + +module "rancher_common" { + source = "../rancher-common" + + node_public_ip = null + rancher_nodes = [ + for index, x in linode_instance.rke[*] : { + public_ip = linode_instance.rke[index].ip_address + private_ip = "" + roles = ["etcd", "controlplane", "worker"] + } + ] + node_username = var.node_username + ssh_private_key_pem = var.ssh_private_key_path + rke_kubernetes_version = var.rke_kubernetes_version + + ingress_tls_source = "secret" + cert_manager_version = "" + server_certificate = var.server_certificate + server_certificate_key = var.server_certificate_key + rancher_version = var.rancher_version + + rancher_server_dns = join(".", [var.rancher_server_name, var.linode_domain_for_rancher]) + + admin_password = var.rancher_server_admin_password + + create_workload_cluster = var.create_workload_cluster + workload_kubernetes_version = var.workload_kubernetes_version + workload_cluster_name = var.workload_cluster_name +} diff --git a/linode/output.tf b/linode/output.tf new file mode 100644 index 0000000..886f219 --- /dev/null +++ b/linode/output.tf @@ -0,0 +1,7 @@ +output "rancher_server_url" { + value = module.rancher_common.rancher_url +} + +output "rancher_node_ips" { + value = linode_instance.rke[*].ip_address +} \ No newline at end of file diff --git a/linode/variables.tf b/linode/variables.tf new file mode 100644 index 0000000..16cdfc8 --- /dev/null +++ b/linode/variables.tf @@ -0,0 +1,122 @@ +variable "linode_token" { + description = "Your Linode APIv4 Access Token" +} + +variable "linode_domain_for_rancher" { + description = "Domain created in Linode, under which rancher DNS entry is created" +} + +variable "prefix" { + description = "Prefix to use for various resources" +} + +variable "authorized_keys" { +} + +variable "node_username" { + default = "root" +} + +variable "root_password" { +} + +variable "region" { +} + +variable "instance_type" { + default = "g6-standard-4" +} + +variable "instance_image" { + default = "linode/ubuntu18.04" +} + +variable "ssh_private_key_path" { + default = "~/.ssh/id_rsa" +} + +variable "rke_node_count" { + default = "3" +} + +variable "docker_version" { + default = "19.03.2" +} + +variable "rke_kubernetes_version" { + type = string + description = "Kubernetes version to use for Rancher server RKE cluster" + default = "v1.18.8-rancher1-1" +} + +variable "rancher_server_name" { + default = "rancher" +} +variable "rancher_version" { + default = "stable" +} + +variable "rancher_replicas" { + default = "3" +} + +variable ingress_tls_source { + type = string + description = "Specify the source of TLS certificates. Valid options: rancher, letsEncrypt, secret" + default = "rancher" +} + +# This option is relevant only if ingress_tls_source is set to "letsEncrypt" +variable lets_encrypt_email { + type = string + description = "Email address used for communication about your certificate (for example, expiry notices)" + default = null +} + +# This option is relevant only if ingress_tls_source is set to "secret" +variable server_certificate { + type = string + description = "Specify the location of the server certificate file (public). Ex: /home/ubuntu/tls.crt" + default = null +} + +# This option is relevant only if ingress_tls_source is set to "secret" +variable server_certificate_key { + type = string + description = "Specify the location of the server certificate private key file. Ex: /home/ubuntu/tls.key" + default = null +} + +# This option is relevant only if ingress_tls_source is set to "secret" and if private CA is used +variable use_private_ca { + type = bool + description = "Specify if private CA signed certificates are used" + default = false +} + +variable server_private_ca_certificate { + type = string + description = "Specify the location of the private CA certificate file. Ex: /home/ubuntu/ca.crt" + default = null +} +# Required +variable "rancher_server_admin_password" { + type = string + description = "Admin password to use for Rancher server bootstrap" +} + +variable "create_workload_cluster" { + type = bool + description = "Specify if workload cluster needs to be created after completion of Rancher Server installation" + default = true +} + +variable "workload_kubernetes_version" { + type = string + description = "Kubernetes version to use for managed workload cluster" + default = "v1.17.11-rancher1-1" +} + +variable "workload_cluster_name" { + default = "quickstart-linode-custom" +} \ No newline at end of file diff --git a/linode/versions.tf b/linode/versions.tf new file mode 100644 index 0000000..703429b --- /dev/null +++ b/linode/versions.tf @@ -0,0 +1,9 @@ +terraform { + required_providers { + linode = { + source = "linode/linode" + version = "~> 1.13.2" + } + } + required_version = ">= 0.13" +} diff --git a/rancher-common/kubernetes.tf b/rancher-common/kubernetes.tf index 70e6f00..389cfc9 100644 --- a/rancher-common/kubernetes.tf +++ b/rancher-common/kubernetes.tf @@ -1,7 +1,7 @@ # Kubernetes resources locals { - cert_manager_crds_content = file(join("/", [path.module, "files/cert-manager/crds-${var.cert_manager_version}.yaml"])) + cert_manager_crds_content = var.ingress_tls_source == "secret" ? "" : file(join("/", [path.module, "files/cert-manager/crds-${var.cert_manager_version}.yaml"])) cert_manager_crds_sections = split("---", local.cert_manager_crds_content) } diff --git a/rancher-common/rke.tf b/rancher-common/rke.tf index b8b93c5..dbccd87 100644 --- a/rancher-common/rke.tf +++ b/rancher-common/rke.tf @@ -11,7 +11,7 @@ resource "rke_cluster" "rancher_cluster" { internal_address = var.node_internal_ip user = var.node_username role = ["controlplane", "etcd", "worker"] - ssh_key = file(var.ssh_private_key_pem) + ssh_key = file(pathexpand(var.ssh_private_key_pem)) } } diff --git a/vsphere/cloud-init.template b/vsphere/cloud-init.template new file mode 100644 index 0000000..1c54407 --- /dev/null +++ b/vsphere/cloud-init.template @@ -0,0 +1,7 @@ +#cloud-config +resize_rootfs: true +hostname: ${node_name} +ssh_authorized_keys: +%{ for key in authorized_keys ~} + - ${key} +%{ endfor ~} \ No newline at end of file diff --git a/vsphere/infra.tf b/vsphere/infra.tf new file mode 100644 index 0000000..ddeecf2 --- /dev/null +++ b/vsphere/infra.tf @@ -0,0 +1,109 @@ +provider "vsphere" { + user = var.vsphere_user + password = var.vsphere_password + vsphere_server = var.vsphere_server + allow_unverified_ssl = var.vsphere_server_allow_unverified_ssl +} + +data "vsphere_datacenter" "dc" { + name = var.vsphere_datacenter +} + +data "vsphere_datastore" "datastore" { + name = var.vsphere_datastore + datacenter_id = data.vsphere_datacenter.dc.id +} + +data "vsphere_resource_pool" "pool" { + name = var.vsphere_resource_pool + datacenter_id = data.vsphere_datacenter.dc.id +} + +data "vsphere_network" "network" { + name = var.vsphere_network + datacenter_id = data.vsphere_datacenter.dc.id +} + +data "vsphere_virtual_machine" "template" { + name = var.vsphere_virtual_machine + datacenter_id = data.vsphere_datacenter.dc.id +} + +resource "vsphere_virtual_machine" "rke" { + name = "${var.prefix}-rke-h${count.index + 1}" + resource_pool_id = data.vsphere_resource_pool.pool.id + datastore_id = data.vsphere_datastore.datastore.id + count = var.rke_node_count + num_cpus = var.vm_cpus + memory = var.vm_memory + guest_id = data.vsphere_virtual_machine.template.guest_id + scsi_type = data.vsphere_virtual_machine.template.scsi_type + network_interface { + network_id = data.vsphere_network.network.id + adapter_type = data.vsphere_virtual_machine.template.network_interface_types[0] + } + cdrom { + client_device = true + } + clone { + template_uuid = data.vsphere_virtual_machine.template.id + } + vapp { + properties = { + user-data = base64encode(templatefile("${path.module}/cloud-init.template", { + node_name = "${var.prefix}-rke-h${count.index + 1}", + authorized_keys = var.authorized_keys + } + )) + hostname = "${var.prefix}-rke-h${count.index + 1}" + } + } + disk { + label = "disk0" + size = 80 + unit_number = 0 + eagerly_scrub = data.vsphere_virtual_machine.template.disks[0].eagerly_scrub + thin_provisioned = data.vsphere_virtual_machine.template.disks[0].thin_provisioned + } + + connection { + host = self.default_ip_address + type = "ssh" + user = var.vm_username + private_key = file(pathexpand(var.ssh_private_key_path)) + } + + provisioner "remote-exec" { + inline = [ + "export DEBIAN_FRONTEND=noninteractive;curl -sSL https://raw.githubusercontent.com/rancher/install-docker/master/${var.docker_version}.sh | sh -", + "sudo usermod -aG docker ubuntu" + ] + } +} +module "rancher_common" { + source = "../rancher-common" + + node_public_ip = null + rancher_nodes = [ + for index, x in vsphere_virtual_machine.rke[*] : { + public_ip = vsphere_virtual_machine.rke[index].default_ip_address + private_ip = "" + roles = ["etcd", "controlplane", "worker"] + } + ] + node_username = var.vm_username + ssh_private_key_pem = var.ssh_private_key_path + rke_kubernetes_version = var.rke_kubernetes_version + + ingress_tls_source = var.ingress_tls_source + cert_manager_version = var.cert_manager_version + rancher_version = var.rancher_version + + rancher_server_dns = join(".", [vsphere_virtual_machine.rke[0].default_ip_address, var.domain_for_rancher]) + + admin_password = var.rancher_server_admin_password + + create_workload_cluster = var.create_workload_cluster + workload_kubernetes_version = var.workload_kubernetes_version + workload_cluster_name = var.workload_cluster_name +} diff --git a/vsphere/output.tf b/vsphere/output.tf new file mode 100644 index 0000000..3adeb44 --- /dev/null +++ b/vsphere/output.tf @@ -0,0 +1,7 @@ +output "rancher_server_url" { + value = module.rancher_common.rancher_url +} + +output "rancher_node_ips" { + value = vsphere_virtual_machine.rke[*].default_ip_address +} \ No newline at end of file diff --git a/vsphere/variables.tf b/vsphere/variables.tf new file mode 100644 index 0000000..40a737c --- /dev/null +++ b/vsphere/variables.tf @@ -0,0 +1,119 @@ +variable "vsphere_server" { +} + +variable "vsphere_server_allow_unverified_ssl" { + description = "Allow use of unverified SSL certificates (Ex: Self signed)" + default = false +} +variable "vsphere_user" { +} + +variable "vsphere_password" { +} + +variable "vsphere_datacenter" { +} + +variable "vsphere_datastore" { +} + +variable "vsphere_resource_pool" { +} + +variable "vsphere_network" { +} + +variable "vsphere_virtual_machine" { + description = "Virtual Machine template name" +} + +variable "prefix" { + description = "Prefix to use for various resources" +} + +variable "authorized_keys" { +} + +variable "ssh_private_key_path" { + default = "~/.ssh/id_rsa" +} + +variable "rke_node_count" { + default = "3" +} + +variable "docker_version" { + default = "19.03.2" +} + +variable "rke_kubernetes_version" { + type = string + description = "Kubernetes version to use for Rancher server RKE cluster" + default = "v1.18.8-rancher1-1" +} + +variable "rancher_server_name" { + default = "rancher" +} + +variable "domain_for_rancher" { + default = "xip.io" +} + +variable "rancher_version" { + default = "stable" +} + +variable "rancher_replicas" { + default = "3" +} + +variable ingress_tls_source { + type = string + description = "Specify the source of TLS certificates. Valid options: rancher, letsEncrypt, secret" + default = "rancher" +} + +# This variable is used only if ingress_tls_source is set to either "rancher" or "letsEncrypt +variable "cert_manager_version" { + type = string + description = "Version of cert-manager to install alongside Rancher (format: 0.0.0)" + default = "0.15.1" +} + +variable "rancher_server_admin_password" { + type = string + description = "Admin password to use for Rancher server bootstrap" +} + +variable "create_workload_cluster" { + type = bool + description = "Specify if workload cluster needs to be created after completion of Rancher Server installation" + default = true +} + +variable "workload_kubernetes_version" { + type = string + description = "Kubernetes version to use for managed workload cluster" + default = "v1.17.11-rancher1-1" +} + +variable "workload_cluster_name" { + default = "quickstart" +} + +variable "vm_username" { + default = "root" +} + +variable "vm_cpus" { + default = 2 +} + +variable "vm_memory" { + default = 4096 +} + +variable "vm_disk" { + default = 80 +} diff --git a/vsphere/versions.tf b/vsphere/versions.tf new file mode 100644 index 0000000..fd66655 --- /dev/null +++ b/vsphere/versions.tf @@ -0,0 +1,8 @@ +terraform { + required_providers { + vsphere = { + source = "hashicorp/vsphere" + } + } + required_version = ">= 0.13" +}