255 lines
8.4 KiB
Ruby
255 lines
8.4 KiB
Ruby
# -*- mode: ruby -*-
|
|
# vi:set ft=ruby sw=2 ts=2 sts=2:
|
|
|
|
# Set the Kubernetes install mode
|
|
# "MANUAL" - This mode adds a jumpbox and leave some networking undone. Its
|
|
# meant to be used with a guide like "Kubernetes The Hard Way."
|
|
# "KUBEADM" This mode is similar to the exam,
|
|
# 1. Setup /etc/hosts file on each node transitively.
|
|
# where where you'll be given
|
|
# machines that have there hostnames and SSH configured, so you won't
|
|
# need to know so much networking setup. Also no jumpbox is included.
|
|
INSTALL_MODE = "MANUAL"
|
|
|
|
BOOT_TIMEOUT_SEC = 120
|
|
|
|
# Set the build mode
|
|
# "BRIDGE" - Places VMs on your local network so cluster can be accessed from browser.
|
|
# You must have enough spare IPs on your network for the cluster nodes.
|
|
# "NAT" - Places VMs in a private virtual network. Cluster cannot be accessed
|
|
# without setting up a port forwarding rule for every NodePort exposed.
|
|
# Use this mode if for some reason BRIDGE doesn't work for you.
|
|
BUILD_MODE = "NAT"
|
|
|
|
# Define the number of worker nodes
|
|
# If this number is changed, remember to update setup-hosts.sh script with the new hosts IP details in /etc/hosts of each VM.
|
|
NUM_WORKER_NODES = 2
|
|
|
|
# Network parameters for NAT mode
|
|
NAT_IP_PREFIX = "192.168.56"
|
|
JUMPER_IP_START = 10
|
|
CONTROLPLANE_NAT_IP = 11
|
|
NODE_IP_START = 20
|
|
|
|
# Host operating system detection
|
|
module OS
|
|
def OS.windows?
|
|
(/cygwin|mswin|mingw|bccwin|wince|emx/ =~ RUBY_PLATFORM) != nil
|
|
end
|
|
|
|
def OS.mac?
|
|
(/darwin/ =~ RUBY_PLATFORM) != nil
|
|
end
|
|
|
|
def OS.unix?
|
|
!OS.windows?
|
|
end
|
|
|
|
def OS.linux?
|
|
OS.unix? and not OS.mac?
|
|
end
|
|
|
|
def OS.jruby?
|
|
RUBY_ENGINE == "jruby"
|
|
end
|
|
end
|
|
|
|
# Determine host adapter for bridging in BRIDGE mode
|
|
def get_bridge_adapter()
|
|
if OS.windows?
|
|
return %x{powershell -Command "Get-NetRoute -DestinationPrefix 0.0.0.0/0 | Get-NetAdapter | Select-Object -ExpandProperty InterfaceDescription"}.chomp
|
|
elsif OS.linux?
|
|
return %x{ip route | grep default | awk '{ print $5 }'}.chomp
|
|
elsif OS.mac?
|
|
return %x{mac/mac-bridge.sh}.chomp
|
|
end
|
|
end
|
|
|
|
# Helper method to get the machine ID of a node.
|
|
# This will only be present if the node has been
|
|
# created in VirtualBox.
|
|
def get_machine_id(vm_name)
|
|
machine_id_filepath = ".vagrant/machines/#{vm_name}/virtualbox/id"
|
|
if not File.exist? machine_id_filepath
|
|
return nil
|
|
else
|
|
return File.read(machine_id_filepath)
|
|
end
|
|
end
|
|
|
|
# Helper method to determine whether all nodes are up
|
|
def all_nodes_up()
|
|
if get_machine_id("controlplane").nil?
|
|
return false
|
|
end
|
|
|
|
(1..NUM_WORKER_NODES).each do |i|
|
|
if get_machine_id("node0#{i}").nil?
|
|
return false
|
|
end
|
|
end
|
|
|
|
if get_machine_id("jumpbox").nil?
|
|
return false
|
|
end
|
|
|
|
return true
|
|
end
|
|
|
|
# Sets up hosts file and DNS
|
|
def setup_dns(node)
|
|
if INSTALL_MODE == "KUBEADM"
|
|
# Set up /etc/hosts
|
|
node.vm.provision "setup-hosts", :type => "shell", :path => "ubuntu/vagrant/setup-hosts.sh" do |s|
|
|
s.args = [NAT_IP_PREFIX, BUILD_MODE, NUM_WORKER_NODES, CONTROLPLANE_NAT_IP, NODE_IP_START]
|
|
end
|
|
end
|
|
# Set up DNS resolution
|
|
node.vm.provision "setup-dns", type: "shell", :path => "ubuntu/update-dns.sh"
|
|
end
|
|
|
|
# Runs provisioning steps that are required by masters and workers
|
|
def provision_kubernetes_node(node)
|
|
# Set up DNS
|
|
setup_dns node
|
|
# Set up ssh
|
|
node.vm.provision "setup-ssh", :type => "shell", :path => "ubuntu/ssh.sh"
|
|
end
|
|
|
|
# All Vagrant configuration is done below. The "2" in Vagrant.configure
|
|
# configures the configuration version (we support older styles for
|
|
# backwards compatibility). Please don't change it unless you know what
|
|
# you're doing.
|
|
Vagrant.configure("2") do |config|
|
|
# The most common configuration options are documented and commented below.
|
|
# For a complete reference, please see the online documentation at
|
|
# https://docs.vagrantup.com.
|
|
|
|
# Every Vagrant development environment requires a box. You can search for
|
|
# boxes at https://portal.cloud.hashicorp.com/vagrant/discover
|
|
# config.vm.box = "base"
|
|
|
|
config.vm.box = "ubuntu/jammy64"
|
|
config.vm.boot_timeout = BOOT_TIMEOUT_SEC
|
|
|
|
# Set SSH login user and password
|
|
config.ssh.username = "root"
|
|
config.ssh.password = "vagrant"
|
|
|
|
# Disable automatic box update checking. If you disable this, then
|
|
# boxes will only be checked for updates when the user runs
|
|
# `vagrant box outdated`. This is not recommended.
|
|
config.vm.box_check_update = false
|
|
|
|
# Provision controlplane Nodes
|
|
config.vm.define "controlplane" do |node|
|
|
# Name shown in the GUI
|
|
node.vm.provider "virtualbox" do |vb|
|
|
vb.name = "controlplane"
|
|
vb.memory = 2048
|
|
vb.cpus = 2
|
|
end
|
|
node.vm.hostname = "controlplane"
|
|
if BUILD_MODE == "BRIDGE"
|
|
adapter = ""
|
|
node.vm.network :public_network, bridge: get_bridge_adapter()
|
|
else
|
|
node.vm.network :private_network, ip: NAT_IP_PREFIX + ".#{CONTROLPLANE_NAT_IP}"
|
|
node.vm.network "forwarded_port", guest: 22, host: "#{2710}"
|
|
end
|
|
provision_kubernetes_node node
|
|
# Install (opinionated) configs for vim and tmux on master-1. These used by the author for CKA exam.
|
|
node.vm.provision "file", source: "./ubuntu/tmux.conf", destination: "$HOME/.tmux.conf"
|
|
node.vm.provision "file", source: "./ubuntu/vimrc", destination: "$HOME/.vimrc"
|
|
end
|
|
|
|
# Provision Worker Nodes
|
|
(1..NUM_WORKER_NODES).each do |i|
|
|
config.vm.define "node0#{i}" do |node|
|
|
node.vm.provider "virtualbox" do |vb|
|
|
vb.name = "node0#{i}"
|
|
vb.memory = 1024
|
|
vb.cpus = 1
|
|
end
|
|
node.vm.hostname = "node0#{i}"
|
|
if BUILD_MODE == "BRIDGE"
|
|
node.vm.network :public_network, bridge: get_bridge_adapter()
|
|
else
|
|
node.vm.network :private_network, ip: NAT_IP_PREFIX + ".#{NODE_IP_START + i}"
|
|
node.vm.network "forwarded_port", guest: 22, host: "#{2720 + i}"
|
|
end
|
|
provision_kubernetes_node node
|
|
end
|
|
end
|
|
|
|
if INSTALL_MODE == "MANUAL"
|
|
# Provision a JumpBox
|
|
config.vm.define "jumpbox" do |node|
|
|
# Name shown in the GUI
|
|
node.vm.provider "virtualbox" do |vb|
|
|
vb.name = "jumpbox"
|
|
vb.memory = 512
|
|
vb.cpus = 1
|
|
end
|
|
node.vm.hostname = "jumpbox"
|
|
if BUILD_MODE == "BRIDGE"
|
|
adapter = ""
|
|
node.vm.network :public_network, bridge: get_bridge_adapter()
|
|
else
|
|
node.vm.network :private_network, ip: NAT_IP_PREFIX + ".#{JUMPER_IP_START}"
|
|
node.vm.network "forwarded_port", guest: 22, host: "#{2730}"
|
|
end
|
|
provision_kubernetes_node node
|
|
end
|
|
end
|
|
|
|
if BUILD_MODE == "BRIDGE"
|
|
# Trigger that fires after each VM starts.
|
|
# Does nothing until all the VMs have started, at which point it
|
|
# gathers the IP addresses assigned to the bridge interfaces by DHCP
|
|
# and pushes a hosts file to each node with these IPs.
|
|
config.trigger.after :up do |trigger|
|
|
trigger.name = "Post provisioner"
|
|
trigger.ignore = [:destroy, :halt]
|
|
trigger.ruby do |env, machine|
|
|
if all_nodes_up()
|
|
puts " Gathering IP addresses of nodes..."
|
|
nodes = ["controlplane"]
|
|
ips = []
|
|
(1..NUM_WORKER_NODES).each do |i|
|
|
nodes.push("node0#{i}")
|
|
end
|
|
nodes.each do |n|
|
|
ips.push(%x{vagrant ssh #{n} -c 'public-ip'}.chomp)
|
|
end
|
|
hosts = ""
|
|
ips.each_with_index do |ip, i|
|
|
hosts << ip << " " << nodes[i] << "\n"
|
|
end
|
|
puts " Setting /etc/hosts on nodes..."
|
|
File.open("hosts.tmp", "w") { |file| file.write(hosts) }
|
|
nodes.each do |node|
|
|
system("vagrant upload hosts.tmp /tmp/hosts.tmp #{node}")
|
|
system("vagrant ssh #{node} -c 'cat /tmp/hosts.tmp | sudo tee -a /etc/hosts'")
|
|
end
|
|
File.delete("hosts.tmp")
|
|
puts <<~EOF
|
|
|
|
VM build complete!
|
|
|
|
Use either of the following to access any NodePort services you create from your browser
|
|
replacing "port_number" with the number of your NodePort.
|
|
|
|
EOF
|
|
(1..NUM_WORKER_NODES).each do |i|
|
|
puts " http://#{ips[i]}:port_number"
|
|
end
|
|
puts ""
|
|
else
|
|
puts " Nothing to do here"
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|