From 7f72d9883a4377de37222a59621c6f0adf9b079b Mon Sep 17 00:00:00 2001 From: Vassiliy Yegorov Date: Tue, 7 Jun 2022 10:41:53 +0700 Subject: [PATCH] init --- .gitignore | 43 +++++++++++ .terraform.lock.hcl | 24 ++++++ README.md | 26 +++++++ kubeone.yaml | 23 ++++++ main.tf | 161 +++++++++++++++++++++++++++++++++++++++ output.tf | 83 ++++++++++++++++++++ terraform.tfvars.example | 3 + variables.tf | 120 +++++++++++++++++++++++++++++ versions.tf | 9 +++ 9 files changed, 492 insertions(+) create mode 100644 .gitignore create mode 100644 .terraform.lock.hcl create mode 100644 README.md create mode 100644 kubeone.yaml create mode 100644 main.tf create mode 100644 output.tf create mode 100644 terraform.tfvars.example create mode 100644 variables.tf create mode 100644 versions.tf diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..a51211b --- /dev/null +++ b/.gitignore @@ -0,0 +1,43 @@ + +# Created by https://www.toptal.com/developers/gitignore/api/terraform +# Edit at https://www.toptal.com/developers/gitignore?templates=terraform + +### Terraform ### +# Local .terraform directories +**/.terraform/* + +# .tfstate files +*.tfstate +*.tfstate.* + +# Crash log files +crash.log +crash.*.log + +# Exclude all .tfvars files, which are likely to contain sensitive data, such as +# password, private keys, and other secrets. These should not be part of version +# control as they are data points which are potentially sensitive and subject +# to change depending on the environment. +*.tfvars +*.tfvars.json + +# Ignore override files as they are usually used to override resources locally and so +# are not checked in +override.tf +override.tf.json +*_override.tf +*_override.tf.json + +# Include override files you do wish to add to version control using negated pattern +# !example_override.tf + +# Include tfplan files to ignore the plan output of command: terraform plan -out=tfplan +# example: *tfplan* + +# Ignore CLI configuration files +.terraformrc +terraform.rc + +# End of https://www.toptal.com/developers/gitignore/api/terraform + +output.json diff --git a/.terraform.lock.hcl b/.terraform.lock.hcl new file mode 100644 index 0000000..bc86c83 --- /dev/null +++ b/.terraform.lock.hcl @@ -0,0 +1,24 @@ +# This file is maintained automatically by "terraform init". +# Manual edits may be lost in future updates. + +provider "registry.terraform.io/hetznercloud/hcloud" { + version = "1.31.1" + constraints = "~> 1.31.0" + hashes = [ + "h1:CWXFFa9rOMqAKVBDLS1qrf4PILhF20hCG6lrIt26LOs=", + "zh:1ac55d8db278a85ee24a9269b0d85ee138242d9f8d9b9ba8b95dc4a02d659137", + "zh:4720d6d96f0603c988bd95c963aa014b0e1b07fdc0b2c76fe3cb521a7ba54f1a", + "zh:4c69e86d325de13247b887007b53f712ce53528d98c73f06ff0d757d1c6b52ac", + "zh:560517e62d6f14feda622268adc9cfc3045440367b58b73fdd954804b72ae4a3", + "zh:792e1b647dd583e42a5b65c104ffde7e8b77f173e08e62bf5ca6b4e901c10ff1", + "zh:8046990a2d7b5cb304a4d959196a5dc642b81fd158b1da50d1dd72039ba2093d", + "zh:885bb88cd934f68cbc2016c812b99a49fc3a358c19c82d14b9f3adde6d2497af", + "zh:9f8728f650a30afc5bba6c97d40decdb3fd846db35e68659a7967262427ffa6b", + "zh:a78b7369b6a077c8a82266515f1bbdfd1eaa98fc82fa3e34c1aa1bbadf4e5514", + "zh:aaf306f40b7c3f48732437f15366f4ce042e3885b914f19f4652ac9b600899b1", + "zh:af533eee1f85ce3126931f0c3c1fe455918f3525079e92e9d85ee391e42ff4fc", + "zh:b0ce67d5ee900127a14e616c1f7463b211204627742b4051c1b33f464b97679e", + "zh:b743cd1355ba7b37b60a66f79b0e779d8d6c8adc7bdec151d2b14994dec7b809", + "zh:cdb210a89af1bf1563f0c933acd14b86a6a01e6289231e317cf5704abf54c9e6", + ] +} diff --git a/README.md b/README.md new file mode 100644 index 0000000..4122037 --- /dev/null +++ b/README.md @@ -0,0 +1,26 @@ +# Поднимаем кластер k8s в [любом] облаке + +## Утилиты +- [terraform](https://www.terraform.io/downloads) +- [kubeone](https://github.com/kubermatic/kubeone/releases/) + +## Видео к курсу +- [видео]() + +## Ставим + +- export HCLOUD_TOKEN="" +- terraform init +- terraform apply +- terraform output -json > output.json +- kubeone apply --manifest kubeone.yaml --tfjson + +## Сносим + +- kubeone reset --manifest kubeone.yaml -t output.json +- terraform destroy + +##### Автор +- **Vassiliy Yegorov** [vasyakrg](https://git.realmanual.ru) +- [школа](realmanual.ru) +- [youtube](youtube.com/realmanual) diff --git a/kubeone.yaml b/kubeone.yaml new file mode 100644 index 0000000..bf48fcc --- /dev/null +++ b/kubeone.yaml @@ -0,0 +1,23 @@ +apiVersion: kubeone.k8c.io/v1beta2 +kind: KubeOneCluster + +versions: + kubernetes: '1.21.12' + +cloudProvider: + hetzner: {} + external: true + +controlPlane: + hosts: + - sshPort: 22 # can be left out if using the default (22) + sshUsername: root + # You usually want to configure either a private key OR an + # agent socket, but never both. The socket value can be + # prefixed with "env:" to refer to an environment variable. + sshPrivateKeyFile: '~/.ssh/demo-cluster' + +apiEndpoint: + host: '' + port: 6443 + alternativeNames: [] diff --git a/main.tf b/main.tf new file mode 100644 index 0000000..81dc293 --- /dev/null +++ b/main.tf @@ -0,0 +1,161 @@ +/* +Copyright 2019 The KubeOne Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +resource "hcloud_ssh_key" "kubeone" { + name = "kubeone-${var.cluster_name}" + public_key = file(var.ssh_public_key_file) +} + +resource "hcloud_network" "net" { + name = var.cluster_name + ip_range = var.ip_range +} + +resource "hcloud_firewall" "cluster" { + name = "${var.cluster_name}-fw" + + labels = { + "kubeone_cluster_name" = var.cluster_name + } + + apply_to { + label_selector = "kubeone_cluster_name=${var.cluster_name}" + } + + rule { + description = "allow ICMP" + direction = "in" + protocol = "icmp" + source_ips = [ + "0.0.0.0/0", + ] + } + + rule { + description = "allow all TCP inside cluster" + direction = "in" + protocol = "tcp" + port = "any" + source_ips = [ + var.ip_range, + ] + } + + rule { + description = "allow all UDP inside cluster" + direction = "in" + protocol = "udp" + port = "any" + source_ips = [ + var.ip_range, + ] + } + + rule { + description = "allow SSH from any" + direction = "in" + protocol = "tcp" + port = "22" + source_ips = [ + "0.0.0.0/0", + ] + } + + rule { + description = "allow NodePorts from any" + direction = "in" + protocol = "tcp" + port = "30000-32767" + source_ips = [ + "0.0.0.0/0", + ] + } +} + +resource "hcloud_network_subnet" "kubeone" { + network_id = hcloud_network.net.id + type = "server" + network_zone = var.network_zone + ip_range = var.ip_range +} + +resource "hcloud_server_network" "control_plane" { + count = var.control_plane_replicas + server_id = element(hcloud_server.control_plane.*.id, count.index) + subnet_id = hcloud_network_subnet.kubeone.id +} + +resource "hcloud_placement_group" "control_plane" { + name = var.cluster_name + type = "spread" + + labels = { + "kubeone_cluster_name" = var.cluster_name + } +} + +resource "hcloud_server" "control_plane" { + count = var.control_plane_replicas + name = "${var.cluster_name}-control-plane-${count.index + 1}" + server_type = var.control_plane_type + image = var.image + location = var.datacenter + placement_group_id = hcloud_placement_group.control_plane.id + + ssh_keys = [ + hcloud_ssh_key.kubeone.id, + ] + + labels = { + "kubeone_cluster_name" = var.cluster_name + "role" = "api" + } +} + +resource "hcloud_load_balancer_network" "load_balancer" { + load_balancer_id = hcloud_load_balancer.load_balancer.id + subnet_id = hcloud_network_subnet.kubeone.id +} + +resource "hcloud_load_balancer" "load_balancer" { + name = "${var.cluster_name}-lb" + load_balancer_type = var.lb_type + location = var.datacenter + + labels = { + "kubeone_cluster_name" = var.cluster_name + "role" = "lb" + } +} + +resource "hcloud_load_balancer_target" "load_balancer_target" { + count = var.control_plane_replicas + type = "server" + load_balancer_id = hcloud_load_balancer.load_balancer.id + server_id = element(hcloud_server.control_plane.*.id, count.index) + use_private_ip = true + depends_on = [ + hcloud_server_network.control_plane, + hcloud_load_balancer_network.load_balancer + ] +} + +resource "hcloud_load_balancer_service" "load_balancer_service" { + load_balancer_id = hcloud_load_balancer.load_balancer.id + protocol = "tcp" + listen_port = 6443 + destination_port = 6443 +} diff --git a/output.tf b/output.tf new file mode 100644 index 0000000..68b7676 --- /dev/null +++ b/output.tf @@ -0,0 +1,83 @@ +/* +Copyright 2019 The KubeOne Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +output "kubeone_api" { + description = "kube-apiserver LB endpoint" + + value = { + endpoint = hcloud_load_balancer.load_balancer.ipv4 + apiserver_alternative_names = var.apiserver_alternative_names + } +} + +output "ssh_commands" { + value = formatlist("ssh ${var.ssh_username}@%s", hcloud_server.control_plane.*.ipv4_address) +} + +output "kubeone_hosts" { + description = "Control plane endpoints to SSH to" + + value = { + control_plane = { + hostnames = hcloud_server.control_plane.*.name + cluster_name = var.cluster_name + cloud_provider = "hetzner" + private_address = hcloud_server_network.control_plane.*.ip + public_address = hcloud_server.control_plane.*.ipv4_address + network_id = hcloud_network.net.id + ssh_agent_socket = var.ssh_agent_socket + ssh_port = var.ssh_port + ssh_private_key_file = var.ssh_private_key_file + ssh_user = var.ssh_username + } + } +} + +output "kubeone_workers" { + description = "Workers definitions, that will be transformed into MachineDeployment object" + + value = { + # following outputs will be parsed by kubeone and automatically merged into + # corresponding (by name) worker definition + "${var.cluster_name}-pool1" = { + replicas = var.workers_replicas + providerSpec = { + sshPublicKeys = [file(var.ssh_public_key_file)] + operatingSystem = var.worker_os + operatingSystemSpec = { + distUpgradeOnBoot = false + } + cloudProviderSpec = { + # provider specific fields: + # see example under `cloudProviderSpec` section at: + # https://github.com/kubermatic/machine-controller/blob/master/examples/hetzner-machinedeployment.yaml + serverType = var.worker_type + location = var.datacenter + image = var.image + networks = [ + hcloud_network.net.id + ] + # Datacenter (optional) + # datacenter = "" + labels = { + "kubeone_cluster_name" = var.cluster_name + "${var.cluster_name}-workers" = "pool1" + } + } + } + } + } +} diff --git a/terraform.tfvars.example b/terraform.tfvars.example new file mode 100644 index 0000000..8229aad --- /dev/null +++ b/terraform.tfvars.example @@ -0,0 +1,3 @@ +cluster_name = "kubeone-cluster" +ssh_public_key_file = "~/.ssh/demo-cluster.pub" +ssh_private_key_file = "~/.ssh/demo-cluster" diff --git a/variables.tf b/variables.tf new file mode 100644 index 0000000..1ae82a1 --- /dev/null +++ b/variables.tf @@ -0,0 +1,120 @@ +/* +Copyright 2019 The KubeOne Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +variable "cluster_name" { + description = "prefix for cloud resources" + type = string + + validation { + condition = can(regex("^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$", var.cluster_name)) + error_message = "Value of cluster_name should be lowercase and can only contain alphanumeric characters and hyphens(-)." + } +} + +variable "apiserver_alternative_names" { + description = "subject alternative names for the API Server signing cert." + default = [] + type = list(string) +} + +variable "worker_os" { + description = "OS to run on worker machines" + + # valid choices are: + # * ubuntu + # * centos + default = "ubuntu" + type = string +} + +variable "ssh_public_key_file" { + description = "SSH public key file" + default = "~/.ssh/demo-cluster.pub" + type = string +} + +variable "ssh_port" { + description = "SSH port to be used to provision instances" + default = 22 + type = number +} + +variable "ssh_username" { + description = "SSH user, used only in output" + default = "root" + type = string +} + +variable "ssh_private_key_file" { + description = "SSH private key file used to access instances" + default = "~/.ssh/demo-cluster" + type = string +} + +variable "ssh_agent_socket" { + description = "SSH Agent socket, default to grab from $SSH_AUTH_SOCK" + default = "env:SSH_AUTH_SOCK" + type = string +} + +# Provider specific settings + +variable "control_plane_type" { + default = "cx21" + type = string +} + +variable "control_plane_replicas" { + default = 1 + type = number +} + +variable "worker_type" { + default = "cx31" + type = string +} + +variable "workers_replicas" { + default = 3 + type = number +} + +variable "lb_type" { + default = "lb11" + type = string +} + +variable "datacenter" { + default = "nbg1" + type = string +} + +variable "image" { + default = "ubuntu-20.04" + type = string +} + +variable "ip_range" { + default = "192.168.0.0/16" + description = "ip range to use for private network" + type = string +} + +variable "network_zone" { + default = "eu-central" + description = "network zone to use for private network" + type = string +} diff --git a/versions.tf b/versions.tf new file mode 100644 index 0000000..63d4f1c --- /dev/null +++ b/versions.tf @@ -0,0 +1,9 @@ +terraform { + required_version = ">= 1.0.0" + required_providers { + hcloud = { + source = "hetznercloud/hcloud" + version = "~> 1.31.0" + } + } +}