乐趣区

关于devops: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 version
Packer v1.8.3

❯ terraform version
Terraform v1.3.2
on linux_amd64

❯ ansible --version
ansible [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_pooltemplate_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 ping
worker1 | 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-info
Kubernetes control plane is running at https://192.168.123.10:6443
CoreDNS is running at https://192.168.123.10:6443/api/v1/namespaces/kube-system/services/kube-dns:dns/proxy
Metrics-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 no
NAME                STATUS   ROLES                  AGE     VERSION
worker2.k3s.local   Ready    <none>                 4m19s   v1.25.2+k3s1
worker1.k3s.local   Ready    <none>                 4m18s   v1.25.2+k3s1
control.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 whoami
NAME                      READY   STATUS    RESTARTS   AGE
whoami-5b844ffb57-mffgf   1/1     Running   0          79s

❯ kubectl --kubeconfig k3s.yaml get ingressroute -n whoami
NAME     AGE
whoami   2m12s

尝试拜访 whoami 利用

❯ http http://192.168.123.10/
HTTP/1.1 200 OK
Content-Length: 413
Content-Type: text/plain; charset=utf-8
Date: Thu, 13 Oct 2022 08:58:06 GMT

Hostname: whoami-5b844ffb57-mffgf
IP: 127.0.0.1
IP: ::1
IP: 10.42.2.3
IP: fe80::b83a:19ff:febe:7a7f
RemoteAddr: 10.42.0.5:60580
GET / HTTP/1.1
Host: 192.168.123.10
User-Agent: HTTPie/3.2.1
Accept: */*
Accept-Encoding: gzip, deflate
X-Forwarded-For: 192.168.123.1
X-Forwarded-Host: 192.168.123.10
X-Forwarded-Port: 80
X-Forwarded-Proto: http
X-Forwarded-Server: traefik-rjbr9
X-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

退出移动版