Vagrant 學習筆記:搭建 K8s 叢集

2023-05-31 12:00:47

Vagrant學習筆記:搭建K8s叢集

通常情況下,我們在使用VMware、VirtualBox這一類虛擬機器器軟體建立虛擬開發環境時,往往需要經歷尋找並下載作業系統的安裝映象檔案,然後根據該映象檔案啟動的安裝嚮導一步一步地安裝與設定作業系統,最後還需要從零開始安裝開發與運維工具。整個過程會非常的費時費力,特別是在我們需要虛擬一個K8s叢集的情況下,工作量更是會隨著需要該叢集中需要的伺服器數量而成倍增加,這時候如果有一款像Vagrant這樣的自動化虛擬機器器管理工具就非常重要了。接下來,就讓我們來介紹一下Vagrant這個工具,以及如何使用它來虛擬一個由三臺伺服器構成的K8s叢集。

Vagrant的基本使用

正如之前所說,Vagrant是一款專用於實現虛擬機器器自動化管理的軟體工具,主要使用Ruby編寫而成,以命令列終端的工具的形式存在於計算機中。在這裡,需要特別強調的一件事是:Vagrant是一款「管理」虛擬機器器的軟體而非「建立」虛擬機器器的軟體。也就是說,Vagrant本身並不能用來建立虛擬機器器,它通常需要搭配VMware、VirtualBox這一類虛擬機器器軟體來使用,以便共同完成虛擬開發環境的快速搭建與設定。當然了,該工具允許人們通過編寫一個名為vagrantfile組態檔的方式來定義虛擬機器器的自動化構建與銷燬的過程,並設定虛擬機器器與其宿主機間的檔案共用、虛擬機器器網路環境等相關引數。除此之外,我們還可以通過編寫一些讓虛擬機器器在完成建立後,第一次被啟動時要執行的自定義指令碼,以便用於以批次處理的方式實現一些開發與運維工具的自動化安裝與設定,這也將大大地提高我們構建虛擬開發環境的效率。最後,由於Vagrant還支援批次複製已建立的虛擬機器器,這意味著我們只需要執行一次操作,就可以同時擁有多個相同設定、安裝了相同軟體的虛擬機器器。

和學習大多數工具的過程一樣,在正式介紹Vagrant的具體使用方式之前,我們也同樣有必要先了解一下這款命令列工具的整體設計架構。因為只有這樣,我們才能理解它的核心使用邏輯。

專案的組成架構

從整體設計上來說,一個交由Vagrant來管理的虛擬機器器專案通常由以下幾大模組組合而成。

  • Boxes:該模組指的是Vagrant用於建立虛擬開發環境時所需要使用的、擴充套件名為.box的映象檔案。需要注意的是,該映象檔案並不是我們之前使用傳統方式建立虛擬機器器時的、用於安裝作業系統的映象檔案,而是一個基於某個現有的虛擬機器器打包而成的快照檔案。該映象檔案中除了基礎資料的映象外,還包括一些後設資料檔案,這些後設資料將用於指導Vagrant將系統映象正確的載入到對應的虛擬機器器當中。需要注意的是,這些映象檔案是嚴格依賴於Providers所指定的虛擬機器器軟體的,也就是說,在VMware下使用的映象檔案是無法在VirtualBox上使用的,反之亦然;

  • Providers:該模組指的是Vagrant用於建立虛擬開發環境時所需要使用的虛擬機器器軟體,例如:VirtualBox、VMware、Hyper-V、KVM等。在Vagrant的架構中,Providers模組將以服務的形式存在,它的作用是幫助Vagrant利用Boxes模組指定的映象檔案來建立虛擬開發環境;

  • Provisioners:該模組指的是在Vagrant完成虛擬開發環境的建立後,讓虛擬機器器自動執行的自定義指令碼。在Vagrant的架構中,我們通常會利用這些自定義的指令碼來實現一些開發與運維工具的自動化安裝與設定,例如VIM編輯器及其外掛、Node.js執行平臺、Docker和K8s運維工具等。

  • Vagrant CLI:該模組指的是Vagrant用於管理虛擬機器器的一系列命令,包括建立、啟動、關閉、重啟、掛起等虛擬機器器操作,也包括打包,註冊等虛擬機器器映象檔案的操作。這些命令可以幫助我們更好地與Providers模組指定的虛擬機器器軟體進行互動。

當然,在使用Vagrant管理虛擬機器器的過程中,我們需要在vagrantfile組態檔中定義與Providers和Provisioners這兩個模組相關的引數,以及要使用的映象檔案。下面,我們就來重點介紹一下vagrantfile組態檔具體寫法。

編寫專案組態檔

如前所述,Vagrant虛擬機器器專案的組態檔名為vagrantfile,該檔案將負責定義虛擬機器器的建立引數、自動化執行的指令碼、虛擬機器器與宿主機之間的共用目錄及其通訊網路等關鍵資訊。由於Vagrant主要是用Ruby開發而成的,所以vagrantfile檔案中使用的設定語言自然也採用了這門程式語言的語法,但這也並不意味著我們必須先學會Ruby的全部語法才能使用Vagrant。因為Vagrant對自己的設定語言做了一定程度的重新定義,其語法規則事實上比我們真正在程式設計活動中使用的Ruby語言要簡單不少,對於任何一個有程式語言使用經驗的人來說,通常只需要學習幾個小時,就基本能應付日常使用中的大部分需求了。下面,就讓我們來實際體驗一下快速掌握這套語法規則的過程吧。

通常情況下,vagrantfile檔案都會被存放在Vagrant虛擬機器器專案的根目錄下,在實際使用中常常會藉由vagrant init命令來自動生成。例如,如果我們在計算機的任意位置上建立了一個名為vagrant_demo的目錄,那麼我們只需要在Powershell/Bash這樣的命令列終端環境,進入到vagrant_demo目錄中並執行vagrant init命令,然後就會在該目錄下看到一個自動生成的vagrantfile檔案,其主要內容如下。

# -*- mode: ruby -*-
# vi: set ft=ruby :

# 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://vagrantcloud.com/search.
  config.vm.box = "base"

  # 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

  # Create a forwarded port mapping which allows access to a specific port
  # within the machine from a port on the host machine. In the example below,
  # accessing "localhost:8080" will access port 80 on the guest machine.
  # NOTE: This will enable public access to the opened port
  # config.vm.network "forwarded_port", guest: 80, host: 8080

  # Create a forwarded port mapping which allows access to a specific port
  # within the machine from a port on the host machine and only allow access
  # via 127.0.0.1 to disable public access
  # config.vm.network "forwarded_port", guest: 80, host: 8080, host_ip: "127.0.0.1"

  # Create a private network, which allows host-only access to the machine
  # using a specific IP.
  # config.vm.network "private_network", ip: "192.168.33.10"

  # Create a public network, which generally matched to bridged network.
  # Bridged networks make the machine appear as another physical device on
  # your network.
  # config.vm.network "public_network"

  # Share an additional folder to the guest VM. The first argument is
  # the path on the host to the actual folder. The second argument is
  # the path on the guest to mount the folder. And the optional third
  # argument is a set of non-required options.
  # config.vm.synced_folder "../data", "/vagrant_data"

  # Provider-specific configuration so you can fine-tune various
  # backing providers for Vagrant. These expose provider-specific options.
  # Example for VirtualBox:
  #
  # config.vm.provider "virtualbox" do |vb|
  #   # Display the VirtualBox GUI when booting the machine
  #   vb.gui = true
  #
  #   # Customize the amount of memory on the VM:
  #   vb.memory = "1024"
  # end
  #
  # View the documentation for the provider you are using for more
  # information on available options.

  # Enable provisioning with a shell script. Additional provisioners such as
  # Ansible, Chef, Docker, Puppet and Salt are also available. Please see the
  # documentation for more information about their specific syntax and use.
  # config.vm.provision "shell", inline: <<-SHELL
  #   apt-get update
  #   apt-get install -y apache2
  # SHELL
end

如果讀者仔細觀察一下上述檔案的內容,就會發現它實際上就是vagrantflie組態檔的一個模板和一份以註釋形式編寫的簡易教學。下面我們就基於這個檔案來介紹一下如何具體設定一個Vagrant虛擬機器器專案。首先,如果我們去掉該檔案中的所有註釋,就會發現其當前真正發揮作用的設定只有以下三行程式碼。

Vagrant.configure("2") do |config|
  config.vm.box = "base"
end

不用懷疑,正是這三行程式碼構成了一個Vagrant專案的基本設定。其中,第一行定義了一個名為config的設定物件,該物件的各項屬性就是我們對虛擬機器器專案的全域性設定項,適用於該專案所管轄的所有虛擬機器器。根據該物件的宣告,我們還可以知道它採用的是版本為2的設定規則。然後,從第一行開始,直至遇到最後一行中的end這個結束符之前,我們編寫的所有程式碼都是在config物件的作用域內進行的細項設定。譬如在上面程式碼的第二行中,config.vm.box選項的作用是設定Vagrant建立虛擬機器器時所需要使用的映象檔案。需要特別注意的是,這裡的base是一個無效的映象名,我們需要根據自己的需要將其改為實際有效的映象檔名,例如,如果我們想安裝的是一個基於CentOS系統的虛擬機器器,就可以將這行程式碼改為config.vm.box = "centos-7"。除此之外,根據我們剛才移除的註釋內容,我們接下來還可以為虛擬機器器設定以下選項。

  • config.vm.hostname選項:該選項用於設定虛擬機器器的主機名,當我們需要模擬由多臺機器組成的開發環境時,主機名的設定通常是必不可少的,例如,如果我們建立了centos1centos2兩臺虛擬機器器,那麼在使用vagrant up命令啟動虛擬機器器就需要用主機名指定要啟動的是centos1還是centos2,否則所有的虛擬機器器將會一起被啟動,一瞬間佔用掉宿主機的大量資源。另外,該主機名也將會以環境變數的形式設定在虛擬機器器所安裝的作業系統中;

  • config.vm.network選項:該選項用於設定虛擬機器器的網路。在Vagrant管理的虛擬機器器之間,網路連線可以有以下三種模式。

    • NAT模式:這是Vagrant在預設情況下會使用的網路連線模式,不需要我們對其進行特別設定。在該模式下,虛擬機器器可以藉由其宿主機埠轉發的形式存取存取區域網,乃至整個網際網路。
    • host-only模式:該模式需要使用將config.vm.network選項設定為private_network,併為其手動指定IP地址,或者將網路型別設定為DHCP以便讓其自動分配IP地址。在該模式下,虛擬機器器只能被其宿主機存取,其他機器均無法存取它。
    • bridge模式:該模式需要使用將config.vm.network選項設定為public_network,併為其手動指定IP地址,或者為其指定要橋接的網路介面卡。在該模式下,虛擬機器器就相當於是其宿主機所在的區域網中的一臺獨立的機器,可以被其他機器存取。

    下面是一些該選項的具體設定範例。

    # 將網路設定為host-only模式,併為其手動設定IP地址
    config.vm.network :private_network, ip: "192.168.100.1"
    # 將網路設定為host-only模式,並將其設定為DHCP地址分配模式
    config.vm.network "private_network", type: "dhcp」
    # 將網路設定為bridge模式,併為其手動設定IP地址
    config.vm.network "public_network", ip: "192.168.31.7"
    # 將網路設定為bridge模式,併為其指定橋接介面卡
    config.vm.network "public_network", bridge: "en1: Wi-Fi (AirPort)"
    # 設定虛擬機器器與宿主之間的埠對映
    # 將宿主機上的8080埠對映到虛擬機器器的80埠
    config.vm.network :forwarded_port, guest: 80, host: 8080
    
  • config.vm.provider選項:該選項用於設定虛擬機器器的具體硬體引數。在Vagrant中,由於硬體引數的具體設定依賴於其具體使用的虛擬機器器軟體服務,所以在設定該選項是需要指定我們所使用的具體Providers型別,並定義出一個該型別的物件,然後再通過該物件來進行相關設定。例如,如果我們需要基於VirtualBox這款虛擬機器器軟體。使用Vagrant建立一臺雙核CPU,記憶體為4GB的虛擬機器器,就可以組態檔編寫如下。

    Vagrant.configure("2") do |config|
        # 其他全域性設定 ...
        config.vm.provider :virtualbox do |vb|
            # 設定虛擬機器器在VirtualBox管理控制檯中的名稱。
            vb.name = "vagrant_demo"
            # 設定虛擬機器器的記憶體大小,單位為MB
            vb.memory = "4096"
            #設定虛擬機器器的CPU核心數
            vb.cpus = 2
        end
    end
    
  • config.vm.synced_folder選項:該選項用於設定虛擬機器器與宿主機之間的共用目錄,預設情況下,該共用目錄就是vagrantfile檔案所在的目錄(即當前專案的根目錄),如果想特別指定其他目錄,就需要手動為該選項設定新的值,例如像下面這樣。

    # 在Windows系統中設定共用目錄
    # 將Windows系統的宿主機的"D:/code"目錄
    # 對映並掛載到Ubuntu系統的虛擬機器器中的"/home/www/"目錄中
    config.vm.synced_folder "D:/code", "/home/www/" 
    
  • config.ssh.username選項:該選項用於設定虛擬機器器中登入系統所用的使用者名稱。在Vagrant中,預設使用者名稱就是vagrant,如果我們使用的Box檔案是個官方映象,就務必要使用這個預設使用者名稱。但如果使用的是自己打包的映象檔案,那就可以根據實際情況通過該選項來設定我們所要使用的使用者名稱。

  • config.vm.provision選項:該選項用於設定可讓虛擬機器器自動執行的自定義指令碼,這些指令碼通常只能在第一次執行vagrant up命令時,額外特別執行vagrant provisionvagrant reload --provisionvagrant up --provision命令時自動執行,主要用於完成必備工具的安裝與設定操作。另外,由於Vagrant支援的自定義的指令碼型別包括Shell、Ansible、CFEngine、Chef、Docker等,所以我們在使用該選項設定自定義指令碼時,通常需要指定指令碼的型別和執行方式,下面是一些設定範例。

    Vagrant.configure("2") do |config|
        # 以內聯的方式執行 Shell 指令碼
        config.vm.provision "shell", inline: "echo 1"
        # 以外部檔案的方式執行 Shell 指令碼
        config.vm.provision "shell", path: "./scripts/script.sh"
    end
    

除了上述使用config物件進行的全域性設定之外,如果需要一次建立多臺虛擬機器器的話,我們還可以通過config.vm.define選項來定義一個區域性物件,以便針對某個具體的虛擬機器器來進行鍼對性的設定,該區域性物件可設定的選項與config全域性物件基本相同。下面是該選項的一個設定範例。

# 定義一個虛擬機器器列表
vm_list = [
    {
        :name => "centos1",
        :eth1 => "192.168.100.1",
        :mem => "2048",
        :cpu => "4",
        :sshport => 22231
    },
    {
        :name => "centos2",
        :eth1 => "192.168.100.2",
        :mem => "4096",
        :cpu => "2",
        :sshport => 22232
    }
]

Vagrant.configure(2) do |config|
    config.vm.box = "centos-7"
    # 遍歷虛擬機器器列表
    vm_list.each do |item|
        # 建立虛擬機器器級別的設定物件
        config.vm.define item[:name] do |vm_config|
            vm_config.vm.hostname = item[:name]
            vm_config.vm.network "private_network", ip: item[:eth1]
            # 禁用掉預設的SSH服務轉發埠
            vm_config.vm.network "forwarded_port", guest: 22, host: 2222, id: "ssh", disabled: "true"
            vm_config.vm.network "forwarded_port", guest: 22, host: item[:sshport]
            vm_config.vm.provider "virtualbox" do |vb|
                vb.name = item[:name];
                vb.memory = item[:mem];
                vb.cpus = item[:cpu];
            end
        end
    end
end

Vagrant CLI常用命令

在完成了組態檔的編寫之後,我們就可以使用Vagrant CLI來進行虛擬機器器的管理操作了。這裡需要提醒讀者注意的是:vagrantfile檔案中的設定程式碼通常只在第一次執行vagrant up命令時被執行。之後,如果我們不明確使用vagrant reload --provision命令進行重新載入,這些設定就不會再被執行了。下面,就讓我們來分類介紹一下Vagrant CLI的常用命令。

  1. 在需要使用SSH的方式進入指定虛擬機器器內執行某些操作是,我們可以使用vagrant ssh命令(如果當前專案下管轄有多臺虛擬機器器,就執行vagrant ssh <主機名>命令),如圖B-1所示。

    圖B-1:使用SSH方式進入虛擬機器器

  2. 在執行虛擬機器器的啟動、重啟與關閉等操作時,我們常會用到以下命令。

    # 啟動所有虛擬機器器
    vagrant up
    # 啟動指定的虛擬機器器
    vagrant up <主機名>
    # 重啟所有虛擬機器器
    vagrant reload
    # 重啟指定的虛擬機器器
    vagrant reload <主機名>
    # 關閉所有虛擬機器器
    vagrant halt
    # 關閉指定的虛擬機器器
    vagrant halt <主機名>
    # 掛起所有虛擬機器器
    vagrant suspend
    # 掛起指定的虛擬機器器
    vagrant suspend <主機名>
    
  3. 在需要銷燬專案中的虛擬機器器時,我們需要用到以下命令。

    # 銷燬所有虛擬機器器
    vagrant destroy -f
    # 銷燬指定的虛擬機器器
    vagrant destroy <主機名> -f
    

基於篇幅的考慮,我們在這裡只是介紹了Vagrant CLI的常用命令。如果我們需要使用到某個指定的命令,可以使用vagrant --helpvagrant <指定命令> --help這兩個命令來檢視Vagrant CLI提供的幫助資訊(在這裡,命令中的--help引數可以使用-h這樣的簡寫形式)。例如在圖B-2中,我們就根據這些幫助資訊執行對現有虛擬機器器的映象打包操作。

圖B-2:對現有虛擬機器器的映象打包操作

專案範例:搭建K8s叢集

在掌握了Vagrant的基本使用方法之後,我們接下來就可以通過實際專案來演示一下如何使用Vagrant+VirtualBox搭建一個部署了K8s系統的伺服器叢集。該叢集的主要設定如表B-1所示。

主機名 IP地址 記憶體 處理器數量 作業系統
k8s-master 192.168.100.21 4G 2 Ubuntu 20.04
k8s-worker1 192.168.100.22 2G 2 Ubuntu 20.04
k8s-worker2 192.168.100.23 2G 2 Ubuntu 20.04

準備工作

要想模擬出上面這個由三臺伺服器組成的K8s叢集,首先要做的是在宿主機中安裝VirtualBox。為此,我們需要利用搜尋引擎找到VirtualBox的官方網站,並進入到其下載頁面,然後根據宿主機所使用的作業系統來下載對應的安裝包。需要注意的是,除了主程式的安裝包之外,我們還需要下載並安裝相應的擴充套件包程式,以便在建立虛擬機器器時能對USB 3.0介面等高階特性進行模擬,如圖B-3所示。

圖B-3:下載VirtualBox安裝包及擴充套件程式

VirtualBox主程式的安裝包是以圖形化嚮導的方式來執行的,初學者只需要一路按照其預設選項完成安裝即可。在安裝完成VirtualBox之後,我們還需要對其進行一些全域性設定。為此,我們需要啟動VirtualBox,然後依次單擊其主選單中的「管理」 -> 「全域性設定」或按下快捷鍵Ctrl + g,並在彈出的如圖B-4所示的「常規」對話方塊中修改「預設虛擬電腦位置」,以免日後虛擬機器器佔用了過多Windows系統分割區的空間。最後,在如圖B-5所示的「擴充套件」索引標籤中匯入我們之前下載好的擴充套件程式。

圖B-4:VirtualBox全域性設定之「常規」對話方塊

圖B-5:VirtualBox全域性設定之「擴充套件」對話方塊

在完成了虛擬機器器軟體的安裝與設定操作之後,接下來的任務就是安裝Vagrant本身了。同樣的,我們需要利用搜尋引擎找到Vagrant的官方網站,並進入到其下載頁面,然後根據宿主機所使用的作業系統來下載對應的安裝包,如圖B-6所示。

圖B-6:下載Vagrant安裝包

具體在Windows系統中,該安裝包是也是以圖形化嚮導的方式來執行的,初學者只需要一路按照其預設選項完成安裝即可。在安裝過程中,Vagrant的安裝包會自動把安裝路徑加入到系統的PATH環境變數中,所以,我們可以通過在Powershell/Bash之類的命令列終端環境中執行vagrant version命令來驗證安裝是否成功。

$ vagrant version
Installed Version: 2.3.0
Latest Version: 2.3.0

在確認成功安裝了Vagrant之後,為了讓該工具能更好地管理使用VirtualBox建立的虛擬機器器,我們還需要繼續在命令列終端環境中執行vagrant plugin install vagrant-vbguest vagrant-share命令來安裝相關的外掛,以便該工具能自動安裝並設定虛擬機器器的驅動增強包,從而實現虛擬機器器與宿主機之間的目錄共用等功能。如果一切順利,我們可以通過vagrant plugin list命令來確認外掛的安裝。

$ vagrant plugin list
vagrant-share (2.0.0, global)
vagrant-vbguest (0.30.0, global)

搭建叢集

在完成上述準備工作之後,我們就可以正式開始建立用於模擬K8s叢集的Vagrant專案了,其主要步驟如下。

  1. 在計算機中的任意位置上建立一個名為k8s_cluster的目錄,並使用Powershell/Bash之類的命令列終端環境進入到該目錄中,並執行vagrant init命令,將其初始化為一個Vagrant專案的根目錄。

  2. k8s_cluster目錄下開啟上述命令自動生成的vagrantfile檔案,並將其內如修改如下。

    # 建立要建立的虛擬機器器清單
    vm_list = [
        {
            :name => "k8s-master",
            :eth1 => "192.168.100.21",
            :mem => "4096",
            :cpu => "2",
            :sshport => 22230
        },
        {
            :name => "k8s-worker1",
            :eth1 => "192.168.100.22",
            :mem => "2048",
            :cpu => "2",
            :sshport => 22231
        },
        {
            :name => "k8s-worker2",
            :eth1 => "192.168.100.23",
            :mem => "2048",
            :cpu => "2",
            :sshport => 22232
        }
    ]
    
    Vagrant.configure(2) do |config|
        # 全域性設定,指定要下載並使用的映象名稱,並設定要使用的字元編碼
        config.vm.box = "gusztavvargadr/ubuntu-server"
        config.vm.box_check_update = false
        Encoding.default_external = 'UTF-8'
        
        # 遍歷虛擬機器器清單,根據其中定義的引數建立虛擬機器器
        vm_list.each do |item|
            config.vm.define item[:name] do |vm_config|
                vm_config.vm.hostname = item[:name]
                vm_config.vm.network "public_network", ip: item[:eth1]
                # 禁用掉預設的SSH服務轉發埠
                vm_config.vm.network "forwarded_port", guest: 22, host: 2222, id: "ssh", disabled: "true"
                vm_config.vm.network "forwarded_port", guest: 22, host: item[:sshport]
                vm_config.vm.provider "virtualbox" do |vb|
                    vb.memory = item[:mem];
                    vb.cpus = item[:cpu];
                    vb.name = item[:name];
                end
                # 設定K8s叢集中所有機器都要執行的自定義指令碼
                vm_config.vm.provision "shell", path: "scripts/common.sh"
                if item[:name] == "k8s-master"
                    # 設定K8s叢集的主控節點要執行的自定義指令碼
                    vm_config.vm.provision "shell", path: "scripts/master.sh"
                else
                    # 設定K8s叢集的工作節點都要執行的自定義指令碼
                    vm_config.vm.provision "shell", path: "scripts/worker.sh"
                end
            end
        end
    end
    
  3. k8s_cluster目錄下建立一個名為scripts的目錄,並在該目錄下建立一個名為common.sh的、三機通用的設定指令碼檔案,並在其中輸入如下程式碼。

    #! /bin/bash
    
    # 指定要安裝哪一個版本的K8s
    KUBERNETES_VERSION="1.21.1-00"
    
    # 關閉swap分割區
    sudo swapoff -a
    sudo sed -ri 's/.*swap.*/#&/' /etc/fstab 
    
    echo "Swap diasbled..."
    
    # 關閉防火牆功能
    sudo ufw disable
    
    # 安裝一些 Docker+k8s 環境的依賴項
    sudo mv /etc/apt/sources.list /etc/apt/sources.list-backup
    sudo cp -i /vagrant/scripts/apt/sources.list /etc/apt/ 
    sudo apt update -y
    sudo apt install -y apt-transport-https ca-certificates curl wget software-properties-common build-essential
    
    echo "Dependencies installed..."
    
    # 安裝並設定 Docker CE
    curl -fsSL https://mirrors.aliyun.com/docker-ce/linux/ubuntu/gpg | sudo apt-key add -
    sudo add-apt-repository "deb [arch=amd64] https://mirrors.aliyun.com/docker-ce/linux/ubuntu $(lsb_release -cs) stable"
    sudo apt update -y
    sudo apt install -y docker-ce
    
    cat <<EOF | sudo tee /etc/docker/daemon.json
    {
    "registry-mirrors": ["https://registry.cn-hangzhou.aliyuncs.com"],
    "exec-opts":["native.cgroupdriver=systemd"]
    }
    EOF
    
    # 啟動 Docker
    sudo systemctl enable docker
    sudo systemctl daemon-reload
    sudo systemctl restart docker
    
    echo "Docker installed and configured..."
    
    # 安裝 k8s 元件:kubelet, kubectl, kubeadm
    curl https://mirrors.aliyun.com/kubernetes/apt/doc/apt-key.gpg | sudo apt-key add -
    cat <<EOF | sudo tee /etc/apt/sources.list.d/kubenetes.list
    deb https://mirrors.aliyun.com/kubernetes/apt/ kubernetes-xenial main
    EOF
    sudo apt update -y
    sudo apt install -y kubelet=$KUBERNETES_VERSION kubectl=$KUBERNETES_VERSION kubeadm=$KUBERNETES_VERSION
    
    # 如果想阻止自動更新,可以選擇鎖住相關軟體的版本
    sudo apt-mark hold kubeadm kubectl kubelet
    
    # 啟動 K8s 的服務元件:kubelet
    sudo systemctl start kubelet  
    sudo systemctl enable kubelet   
    
    echo "K8s installed and configured..."
    
  4. 繼續在scripts目錄下建立一個名為master.sh的、K8s叢集主控節點專用的指令碼檔案,並在其中輸入如下程式碼。

    #! /bin/bash
    
    # 指定主控節點的IP地址
    MASTER_IP="192.168.100.21"
    # 指定主控節點的主機名
    NODENAME=$(hostname -s)
    # 指定當前 K8s 叢集中 Service 所使用的 CIDR
    SERVICE_CIDR="10.96.0.0/12"
    # 指定當前 K8s 叢集中 Pod 所使用的 CIDR
    POD_CIDR="10.244.0.0/16"
    # 指定當前使用的 K8s 版本
    KUBE_VERSION=v1.21.1
    
    # 特別預先載入 coredns 外掛
    COREDNS_VERSION=1.8.0
    sudo docker pull registry.cn-hangzhou.aliyuncs.com/google_containers/coredns:$COREDNS_VERSION
    sudo docker tag registry.cn-hangzhou.aliyuncs.com/google_containers/coredns:$COREDNS_VERSION registry.cn-hangzhou.aliyuncs.com/google_containers/coredns/coredns:v$COREDNS_VERSION
    
    # 使用 kubeadm 工具初始化 K8s 叢集
    sudo kubeadm init \
    --kubernetes-version=$KUBE_VERSION \
    --apiserver-advertise-address=$MASTER_IP \
    --image-repository=registry.cn-hangzhou.aliyuncs.com/google_containers \
    --service-cidr=$SERVICE_CIDR \
    --pod-network-cidr=$POD_CIDR \
    --node-name=$NODENAME \
    --ignore-preflight-errors=Swap
    
    # 生成主控節點的組態檔
    mkdir -p $HOME/.kube
    sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
    sudo chown $(id -u):$(id -g) $HOME/.kube/config
    
    # 將主控節點的組態檔備份到別處
    config_path="/vagrant/configs"
    
    if [ -d $config_path ]; then
    sudo rm -f $config_path/*
    else
    sudo mkdir -p $config_path
    fi
    
    sudo cp -i /etc/kubernetes/admin.conf $config_path/config
    sudo touch $config_path/join.sh
    sudo chmod +x $config_path/join.sh       
    
    # 將往 K8s 叢集中新增工作節點的命令儲存為指令碼檔案
    kubeadm token create --print-join-command > $config_path/join.sh
    
    # 安裝名為 calico 的網路外掛
    # 1. 網路安裝
    sudo wget https://docs.projectcalico.org/v3.14/manifests/calico.yaml 
    sudo kubectl apply -f calico.yaml
    
    # 安裝名為 flannel 的網路外掛
    # 1. 網路安裝
    # sudo wget https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml
    # sudo kubectl apply -f kube-flannel.yml
    
  5. 繼續在scripts目錄下建立一個名為worker.sh的、K8s叢集中工作節點通用的指令碼檔案,並在其中輸入如下程式碼。

    #! /bin/bash
    
    # 執行之前儲存的,用於往K8s叢集中新增工作節點的指令碼
    /bin/bash /vagrant/configs/join.sh -v
    
    # 如果希望在工作節點中也能使用kubectl,可執行以下命令
    sudo -i -u vagrant bash << EOF
    mkdir -p /home/vagrant/.kube
    sudo cp -i /vagrant/configs/config /home/vagrant/.kube/
    sudo chown 1000:1000 /home/vagrant/.kube/config
    EOF
    
  6. scripts目錄下建立一個名為apt的目錄,並在該目錄下建立一個名為sources.list的、使用阿里雲國內映象的APT源組態檔,並在其中輸入如下程式碼。

    # 使用阿里雲的源
    deb http://mirrors.aliyun.com/ubuntu/ focal main restricted universe multiverse
    deb-src http://mirrors.aliyun.com/ubuntu/ focal main restricted universe multiverse
    deb http://mirrors.aliyun.com/ubuntu/ focal-security main restricted universe multiverse
    deb-src http://mirrors.aliyun.com/ubuntu/ focal-security main restricted universe multiverse
    deb http://mirrors.aliyun.com/ubuntu/ focal-updates main restricted universe multiverse
    deb-src http://mirrors.aliyun.com/ubuntu/ focal-updates main restricted universe multiverse
    deb http://mirrors.aliyun.com/ubuntu/ focal-proposed main restricted universe multiverse
    deb-src http://mirrors.aliyun.com/ubuntu/ focal-proposed main restricted universe multiverse
    deb http://mirrors.aliyun.com/ubuntu/ focal-backports main restricted universe multiverse
    deb-src http://mirrors.aliyun.com/ubuntu/ focal-backports main restricted universe multiverse
    
  7. 回到k8s_cluster目錄下並執行vagrant up命令,開始建立虛擬機器器。在vagrant up命令的執行過程中,讀者會看到Vagrant會在構建虛擬機器器之後,第一次啟動它們時自動執行scripts目錄中的指令碼,這些指令碼將會自動為虛擬機器器設定、安裝Docker與K8s環境,以下是其安裝軟體的版本資訊。

    Docker-CE:  20.10.17
    Kubernetes: 1.21.1
        kube-apiserver: v1.21.1
        kube-proxy: v1.21.1
        kube-controller-manager: v1.21.1
        kube-scheduler: v1.21.1
        pause: 3.4.1
        coredns: v1.8.0
        etcd: 3.4.13-0  
    

如果讀者想獲得上述範例的原始碼,也可以前往https://github.com/owlman/vagrant-ubuntu-k8s-cluster處獲得。