Files
ubicloud/prog/kubernetes/provision_kubernetes_node.rb
Eren Başak e6711245c0 Introduce Kubernetes Cluster Provisioning Logic
In this commit, we introduce two progs to provision a k8s cluster.

KubernetesClusterNexus.assemble call creates a KubernetesCluster object
and manages the creation of control plane nodes using the
ProvisionKubernetesNode prog.

Nodes are created from plain images and k8s components are installed during
the provisioning, increasing the time to provision. Later, we will switch to
dedicated VM images.

Co-authored-by: Eren Başak <eren@ubicloud.com>
Co-authored-by: mohi-kalantari <mohi.kalantari1@gmail.com>
2025-01-28 09:59:38 +02:00

144 lines
5.1 KiB
Ruby

# frozen_string_literal: true
class Prog::Kubernetes::ProvisionKubernetesNode < Prog::Base
subject_is :kubernetes_cluster
def vm
@vm ||= Vm[frame["vm_id"]]
end
def write_hosts_file_if_needed(ip = nil)
return unless Config.development?
return if vm.sshable.cmd("cat /etc/hosts").include?(kubernetes_cluster.endpoint.to_s)
ip ||= kubernetes_cluster.cp_vms.first.ephemeral_net4
vm.sshable.cmd("sudo tee -a /etc/hosts", stdin: "#{ip} #{kubernetes_cluster.endpoint}\n")
end
label def start
name = "#{kubernetes_cluster.name.downcase}-control-plane-#{SecureRandom.alphanumeric(5).downcase}"
vm = Prog::Vm::Nexus.assemble_with_sshable(
"ubi",
kubernetes_cluster.project.id,
# we should reiterate how we name the vm. some how correlate it to the vm's info.
name: name,
location: kubernetes_cluster.location,
size: "standard-2",
boot_image: "ubuntu-jammy",
private_subnet_id: kubernetes_cluster.private_subnet_id,
enable_ip4: true
).subject
current_frame = strand.stack.first
current_frame["vm_id"] = vm.id
strand.modified!(:stack)
kubernetes_cluster.add_cp_vm(vm)
kubernetes_cluster.api_server_lb.add_vm(vm)
hop_install_software
end
label def install_software
nap 5 unless vm.strand.label == "wait"
vm.sshable.cmd <<BASH
set -ueo pipefail
echo "net.ipv6.conf.all.forwarding=1\nnet.ipv6.conf.all.proxy_ndp=1\nnet.ipv4.conf.all.forwarding=1\nnet.ipv4.ip_forward=1" | sudo tee /etc/sysctl.d/72-clover-forward-packets.conf
sudo sysctl --system
sudo apt update
sudo apt install -y ca-certificates curl apt-transport-https gpg
sudo install -m 0755 -d /etc/apt/keyrings
sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc
sudo chmod a+r /etc/apt/keyrings/docker.asc
echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/ubuntu \\$(. /etc/os-release && echo "\\$VERSION_CODENAME") stable" \\| sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
sudo apt update
sudo apt install -y containerd
sudo mkdir -p /etc/containerd
sudo touch /etc/containerd/config.toml
containerd config default | sudo tee /etc/containerd/config.toml
sudo sed -i 's/SystemdCgroup = false/SystemdCgroup = true/' /etc/containerd/config.toml
sudo systemctl restart containerd
curl -fsSL https://pkgs.k8s.io/core:/stable:/#{kubernetes_cluster.version}/deb/Release.key | sudo gpg --dearmor -o /etc/apt/keyrings/kubernetes-apt-keyring.gpg
echo 'deb [signed-by=/etc/apt/keyrings/kubernetes-apt-keyring.gpg] https://pkgs.k8s.io/core:/stable:/#{kubernetes_cluster.version}/deb/ /' | sudo tee /etc/apt/sources.list.d/kubernetes.list
sudo apt update
sudo apt install -y kubelet kubeadm kubectl
sudo apt-mark hold kubelet kubeadm kubectl
sudo systemctl enable --now kubelet
BASH
hop_bootstrap_rhizome
end
label def bootstrap_rhizome
bud Prog::BootstrapRhizome, {"target_folder" => "kubernetes", "subject_id" => vm.id, "user" => "ubi"}
hop_wait_bootstrap_rhizome
end
label def wait_bootstrap_rhizome
reap
hop_assign_role if leaf?
donate
end
label def assign_role
write_hosts_file_if_needed
hop_init_cluster if kubernetes_cluster.cp_vms.count == 1
hop_join_control_plane
end
label def init_cluster
case vm.sshable.cmd("common/bin/daemonizer --check init_kubernetes_cluster")
when "Succeeded"
pop vm_id: vm.id
when "NotStarted"
params = {
cluster_name: kubernetes_cluster.name,
lb_hostname: kubernetes_cluster.endpoint,
port: "443",
private_subnet_cidr4: kubernetes_cluster.private_subnet.net4,
private_subnet_cidr6: kubernetes_cluster.private_subnet.net6,
vm_cidr: vm.nics.first.private_ipv4
}
vm.sshable.cmd("common/bin/daemonizer /home/ubi/kubernetes/bin/init-cluster init_kubernetes_cluster", stdin: JSON.generate(params))
nap 30
when "InProgress"
nap 10
when "Failed"
Clog.emit("INIT CLUSTER FAILED")
nap 65536
# TODO: register deadline
end
nap 65536
end
label def join_control_plane
case vm.sshable.cmd("common/bin/daemonizer --check join_control_plane")
when "Succeeded"
pop vm_id: vm.id
when "NotStarted"
cp_sshable = kubernetes_cluster.cp_vms.first.sshable
params = {
cluster_endpoint: "#{kubernetes_cluster.endpoint}:443",
join_token: cp_sshable.cmd("sudo kubeadm token create --ttl 24h --usages signing,authentication").chomp,
certificate_key: cp_sshable.cmd("sudo kubeadm init phase upload-certs --upload-certs")[/certificate key:\n(.*)/, 1],
discovery_token_ca_cert_hash: cp_sshable.cmd("sudo kubeadm token create --print-join-command")[/discovery-token-ca-cert-hash (.*)/, 1]
}
vm.sshable.cmd("common/bin/daemonizer kubernetes/bin/join-control-plane-node join_control_plane", stdin: JSON.generate(params))
nap 15
when "InProgress"
nap 10
when "Failed"
# TODO: Create a page
Clog.emit("JOIN CLUSTER FAILED")
nap 65536
end
nap 65536
end
end