commit 7f72d9883a4377de37222a59621c6f0adf9b079b Author: Vassiliy Yegorov Date: Tue Jun 7 10:41:53 2022 +0700 init 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" + } + } +}