IaC示例:Terraform & Ansible自動化建立K3S叢集

上一篇文章介紹了一個輕量級的 Kubernetes 發行版本 - k3s 。

這篇文章,我們將透過使用以下幾個 IaC(Infrastructure as Code)工具,在本地環境(例如你的 Linux 工作臺)自動化部署一個可用的 K3S 叢集

Packer - HashiCorp 開源的一個系統映象構建工具。

Terraform - HashiCorp 開源的基礎設施及程式碼自動化管理工具。

Ansible - RedHat贊助的一個開源社群專案,IT自動化配置工具。

環境需求

本演示將的所有操作將在一臺支援虛擬化(kvm + qemu + libvirt) Linux 主機上執行。

在 Ubuntu 上啟用虛擬化環境,請參考 KVM hypervisor: a beginner‘s guide 。

在 Fedora 上啟用虛擬化環境,請參考 Getting startyed with virtualization (libvirt) 。

在 openSUSE 上啟用虛擬化環境,請參考 Virtualization Guide 。

其他 Linux 發行版,請參考相關文件。

我是在我的膝上型電腦上執行的操作,系統是 openSUSE Leap 15。4 。

除了上述的虛擬化需求外,還需要在系統上安裝上面提到的幾個工具。如果你的環境中有 LinuxBrew,則可透過 Brew 直接安裝

❯ brew install packer terraform ansible

否則,請下載各自官方釋出的二進位制包,解壓後放到

PATH

路徑中。

❯ packer versionPacker v1。8。3❯ terraform versionTerraform v1。3。2on linux_amd64❯ ansible ——versionansible [core 2。13。4]

因為本示例中,使用了 Terraform 的 ansbile provisioner,因此還需要安裝這個外掛

❯ mkdir -p ~/。terraform。d/plugins❯ curl -sL \ https://raw。githubusercontent。com/radekg/terraform-provisioner-ansible/master/bin/deploy-release。sh \ ——output /tmp/deploy-release。sh❯ chmod +x /tmp/deploy-release。sh❯ /tmp/deploy-release。sh -v 2。5。0❯ rm -rf /tmp/deploy-release。sh

完成以上需求之後,我們將開始執行如下步驟

使用 Packer 建立一個基於 Debian 11。5。0 的虛擬機器系統模板映象,該映象中,將會配置好 SSH 免密登陸金鑰。

使用 Terraform 在本地虛擬環境中,創建出需要的虛擬機器,並生成後續 ansible 配置虛擬機器需要的 inventory 檔案。

使用 Ansible 配置虛擬機器節點安裝 k3s 叢集,以及演示應用。

以上所有步驟的程式碼在 (https://github。com/mengzyou/i。。。)

將程式碼克隆到本地

❯ git clone https://github。com/mengzyou/iac-examples。git❯ cd iac-example/k3scluster/

建立虛擬機器映象

首先我們需要透過 Packer 建立一個虛擬機器系統映象,後續需要使用該映象來建立虛擬機器例項,需要的程式碼在

k3scluster/packer/

目錄下

❯ cd packer/❯ tree 。|—— Makefile|—— base。pkr。hcl`—— preseed |—— debian11。txt

這裡透過 Makefile 來呼叫 packer 進行映象的構建,和上傳到虛擬化環境,注意以下變數配置

LIBVIRT_HYPERVISOR_URI := “qemu:///system”LIBVIRT_TEMPLATES_IMAGES_POOL := “templates”LIBVIRT_TEMPLATES_IMAGES_POOL_DIR := “/var/lib/libvirt/images/templates”LIBVIRT_IMAGE_NAME := “debian11-5。qcow2”ROOT_PASSWORD := “rootPassword”$(eval SSH_IDENTITY=$(shell find ~/。ssh/ -name ’id_*‘ -not -name ’*。pub‘ | head -n 1))

預設使用

${HOME}/。ssh/id_rsa

的金鑰對作為 SSH 免密訪問的金鑰,如果沒有,請先建立一個。

執行

make image

進行映象的構建,以及在本地虛擬化環境建立名為

templates

的儲存池,並將映象上傳到該儲存池中,命名為

debian11-5.qcow2

的卷,具體的程式碼,請檢視

Makefile

❯ make image。。。

完成之後,我們可以透過

virsh

命令檢視映象卷

❯ sudo virsh vol-list ——pool templates 名稱 路徑———————————————————————————————————— debian11-5。qcow2 /var/lib/libvirt/images/templates/debian11-5。qcow2

補充

: 在檔案

base。pkr。hcl

中,對 iso 檔案源的配置

iso_url = “https://mirrors。ustc。edu。cn/debian-cd/current/amd64/iso-cd/debian-11。5。0-amd64-netinst。iso”

配置網路地址時,在 packer 進行構建時,可能會下載 iso 檔案超時而導致構建失敗。可透過預先下載對應的 iso 檔案到本地檔案系統,然後將

iso_url

配置為本地路徑,例如

iso_url = “/data/debian-11。5。0-amd64-netinst。iso”

這樣可以避免由於網路問題導致構建失敗。

建立虛擬機器例項

接下來,我們將使用 Terraform 建立並初始化叢集所需要的虛擬機器例項,進入

k3scluster/terraform/

目錄

❯ cd 。。/terraform/

該目錄下包含了建立叢集所需虛擬機器資源的定義,首先看

provider。tf

檔案

terraform { required_providers { libvirt = { source = “dmacvicar/libvirt” version = “0。7。0” } } required_version = “>= 0。13”}provider “libvirt” { uri = var。libvirt_uri}

因為我們需要透過 libvirt 建立虛擬機器,因此這裡需要 dmacvicar/libvirt 的 Provider,該 Provider 的 uri 配置為變數

var。libvirt_uri

,預設為

qemu:///system

,也就是本地虛擬環境。

其他需要的變數定義都放在

variables。tf

檔案中。資原始檔

vms。tf

定義了需要建立的資源,其中包括

resource “libvirt_network” “network” { name = var。net_name mode = “nat” domain = var。net_domain addresses = [var。subnet] dhcp { enabled = true } dns { enabled = true local_only = true }}

建立一個 NAT 模式的虛擬網路,預設的網路地址為

192。168。123。0/24

,可透過變數

net_domain

修改。

resource “libvirt_volume” “disk” { count = length(var。vms) name = “${var。vms[count。index]。name}。qcow2” pool = “default” base_volume_name = var。template_img base_volume_pool = var。templates_pool}

根據變數

vms

定義的虛擬機器例項,建立虛擬機器的系統磁碟,基於變數

templates_pool

template_image

指定的模板映象,預設也就是上面我們透過 Packer 建立的系統映象。

resource “libvirt_domain” “vm” { count = length(var。vms) name = var。vms[count。index]。name autostart = true qemu_agent = true vcpu = lookup(var。vms[count。index], “cpu”, 1) memory = lookup(var。vms[count。index], “memory”, 512)。。。 }}

libvirt_domain

資源定義了需要建立的虛擬機器例項,並透過

ansible provisioner

進行是初始化配置(配置靜態IP地址和主機名)。

resource “local_file” “ansible_hosts” { content = templatefile(“。/tpl/ansible_hosts。tpl”, { vms = var。vms subnet = var。subnet gateway = cidrhost(var。subnet, 1) mask = cidrnetmask(var。subnet) nameserver = cidrhost(var。subnet, 1) user = var。user }) filename = “。。/ansible/k3s_hosts” file_permission = 0644 directory_permission = 0755}

該資源定義透過模板檔案建立虛擬機器例項的 Ansible Inventory 檔案,便於下一步透過 Ansible 進行 K3S 叢集的建立。

在應用之前,我們需要配置

vms

變數,來指定我們需要的虛擬機器例項資訊

❯ cp 。k3svms。tfvars k3dcluster。auto。tfvars

vms = [ { name = “control” cpu = 1 memory = 1024 ip = 10 groups = [“k3s”] vars = { role = “server” } }, { name = “worker1” cpu = 1 memory = 1024 ip = 21 groups = [“k3s”] vars = { role = “agent” } }, { name = “worker2” cpu = 1 memory = 1024 ip = 22 groups = [“k3s”] vars = { role = “agent” } }]

上面定義了3臺例項,1臺作為k3s叢集的 server 節點,2臺作為k3s叢集的 role 節點,預設IP地址將會被配置為

control : 192。168。123。10

worker1 : 192。168。123。21

worker2 : 192。168。123。22

接下來我們將執行 Terrform 操作

❯ terraform init❯ terraform plan ❯ terrafrom apply ——auto-approve。。。Apply complete! Resources: 8 added, 0 changed, 0 destroyed。Outputs:vms_ip_addresses = { “control” = “192。168。123。10” “worker1” = “192。168。123。21” “worker2” = “192。168。123。22”}

完成之後,3臺虛擬機器將會建立並執行,同時在

k3scluster/ansible/

目錄中將建立名為

k3s_hosts

的 Inventory 檔案。

部署K3S叢集

完成虛擬機器的建立之後,我們進入

k3scluster/ansible/

目錄,進行下一步操作

❯ cd 。。/ansible/❯ ls apps。yml  init。yml  k3s。yaml  k3s_hosts  main。yml  roles

其中檔案

k3s_hosts

是在上一步生成的 Inventory 檔案,

init。yml

檔案是初始化節點的 playbook,在上一步的 Terraform 應用中以及執行了。

main。yml

檔案是安裝配置 K3S 叢集的 playbook,

roles/

目錄包含了所有的任務。

在執行具體任務之前,我們可以透過 ansbile 測試下虛擬機器節點的可用性

❯ ansible -i k3s_hosts all -m pingworker1 | SUCCESS => { “changed”: false, “ping”: “pong”}worker2 | SUCCESS => { “changed”: false, “ping”: “pong”}control | SUCCESS => { “changed”: false, “ping”: “pong”}

接下來執行

main。yml

playbook

❯ ansible-playbook -i k3s_hosts main。yml。。。PLAY RECAP ********************************************control : ok=16 changed=7 unreachable=0 failed=0 skipped=4 rescued=0 ignored=0 worker1 : ok=8 changed=4 unreachable=0 failed=0 skipped=6 rescued=0 ignored=0 worker2 : ok=8 changed=4 unreachable=0 failed=0 skipped=6 rescued=0 ignored=0

這將會呼叫

roles/k3s/

裡定義的任務,安裝和配置 K3S 叢集,具體的執行任務,請檢視 roles 裡的程式碼。

成功之後,會發現在當前目錄生成了一個

k3s。yaml

的檔案,這是從 control 節點獲取的 kubeconfig 檔案,我們需要替換一下 api-server 的 IP

❯ sed -i ’s/127。0。0。1/192。168。123。10/g‘ k3s。yaml

之後,我們就可以透過該 kubeconfig 檔案來訪問該叢集了,例如

❯ kubectl ——kubeconfig k3s。yaml cluster-infoKubernetes control plane is running at https://192。168。123。10:6443CoreDNS is running at https://192。168。123。10:6443/api/v1/namespaces/kube-system/services/kube-dns:dns/proxyMetrics-server is running at https://192。168。123。10:6443/api/v1/namespaces/kube-system/services/https:metrics-server:https/proxy❯ kubectl ——kubeconfig k3s。yaml get noNAME STATUS ROLES AGE VERSIONworker2。k3s。local Ready 4m19s v1。25。2+k3s1worker1。k3s。local Ready 4m18s v1。25。2+k3s1control。k3s。local Ready control-plane,master 4m39s v1。25。2+k3s1

至此,我們就完成了一個 K3S 叢集的部署,並可以在部署其他應用。最後,我們也可以繼續使用 ansible 來部署演示應用。

檔案

apps。yml

是部署演示應用的 playbook,其透過

roles/k3s-app/

任務,與 k3s server 節點互動來進行應用部署,其會部署 Traefik Ingress 和一個 whoami web 應用,直接執行

❯ ansible-playbook -i k3s_hosts apps。yml。。。PLAY RECAP *****************************************************control : ok=4 changed=3 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0

完成之後,透過 kubectl 命令檢視部署的 pod

❯ kubectl ——kubeconfig k3s。yaml get po -n whoamiNAME READY STATUS RESTARTS AGEwhoami-5b844ffb57-mffgf 1/1 Running 0 79s❯ kubectl ——kubeconfig k3s。yaml get ingressroute -n whoamiNAME AGEwhoami 2m12s

嘗試訪問 whoami 應用

❯ http http://192。168。123。10/HTTP/1。1 200 OKContent-Length: 413Content-Type: text/plain; charset=utf-8Date: Thu, 13 Oct 2022 08:58:06 GMTHostname: whoami-5b844ffb57-mffgfIP: 127。0。0。1IP: ::1IP: 10。42。2。3IP: fe80::b83a:19ff:febe:7a7fRemoteAddr: 10。42。0。5:60580GET / HTTP/1。1Host: 192。168。123。10User-Agent: HTTPie/3。2。1Accept: */*Accept-Encoding: gzip, deflateX-Forwarded-For: 192。168。123。1X-Forwarded-Host: 192。168。123。10X-Forwarded-Port: 80X-Forwarded-Proto: httpX-Forwarded-Server: traefik-rjbr9X-Real-Ip: 192。168。123。1

銷燬叢集

透過以上方式建立的 K3S 叢集,我們可以很方便的透過 Terraform 銷燬並重新建立。當完成了相關的應用測試之後,我們可以透過以下命令銷燬叢集

❯ rm -f k3s。yaml❯ cd 。。/terraform/❯ terraform destroy ——auto-approve。。。Destroy complete! Resources: 8 destroyed。

我就將會刪除所建立的所有相關資源,恢復乾淨的本地環境。

當需要叢集的時候,只需要執行上面的步驟就可以建立一個新的 K3S 叢集。

總結

這裡演示了一個 IaC 場景,透過程式碼化基礎設施資源,我們可以很容易地透過 Terraform,Ansible 等工具管理並維護相應的基礎設施資源。

這裡我們演示在本地虛擬化環境建立虛擬機器並部署k3S叢集,那透過 Terraform 的其他 Providers (例如 AWS, GCP等共有云),我們可以程式碼化管理我們的公有云基礎設施環境,並可以將相應的流程加入 CI/CD 中,可快速建立需要的環境做測試。

IaC 是現代化基礎設施運維的方向,結合相關工具,我們可以輕鬆實現基礎設施自動化運維。

同時釋出在 Mengz’s Blog