kubernetes-the-hard-way/virtual-machines/Vagrantfile

260 lines
8.5 KiB
Plaintext
Raw Normal View History

# -*- 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"
BOX_IMG = "ubuntu/jammy64"
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_NAME = "jumpbox"
JUMPER_NAT_START_IP = 10
CONTROLPLANE_NAME = "controlplane"
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_NAME).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(JUMPER_NAME).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 controlplanes 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 = BOX_IMG
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_NAME do |node|
# Name shown in the GUI
node.vm.provider "virtualbox" do |vb|
vb.name = CONTROLPLANE_NAME
vb.memory = 2048
vb.cpus = 2
end
node.vm.hostname = CONTROLPLANE_NAME
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 JUMPER_NAME do |node|
# Name shown in the GUI
node.vm.provider "virtualbox" do |vb|
vb.name = JUMPER_NAME
vb.memory = 512
vb.cpus = 1
end
node.vm.hostname = JUMPER_NAME
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_NAT_START_IP}"
#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_NAME]
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