Packer là một công cụ để tự động hóa việc tạo ra nhiều image của Hashicorp. Nó hỗ trợ nhiều cloud như AWS EC2, DigitalOcean, LXD, VMWare, QEMU, v.v. Trong bài viết này, mình sẽ chia sẻ cách đóng gói một image có chứa bộ kubernetes cho QEMU/KVM dựa trên Cloud Image rút gọn của Ubuntu 18.04.
Yêu cầu:
- Packer
- Cloud-localds (from cloud-image-utils in ubuntu)
- QEMU/KVM được cài đặt sẵn trong máy chủ
1. Đảm bảo bạn đã cài đặt QEMU/KVM cũng như Packer trong máy chủ. Nếu bạn sử dụng Linux, bạn có thể sử dụng các lệnh sau:
sudo apt install packer -y
sudo apt-get install cloud-image-utils qemu-system-x86 -y
2. Tạo file cấu hình chứa các thông tin để build image có tên kubernetes.json. Đầu tiên hãy tạo 1 thư mục chứa các file config.
sudo mkdir -p /root/packer
Sau đó chạy đoạn code dưới để tạo file kubernetes.json.
cat > /root/packer/kubernetes.json << 'OEF'
{
"builders":[
{
"type": "qemu",
"iso_url": "{{ user `image_url` }}",
"iso_checksum": "{{ user `image_checksum` }}",
"iso_checksum_type": "{{ user `image_checksum_type` }}",
"format": "qcow2",
"disk_image": true,
"disk_size": "{{ user `disk_size` }}",
"output_directory": "build",
"disk_compression": true,
"headless": true,
"boot_command": [
"<enter>"
],
"accelerator": "kvm",
"ssh_username": "{{ user `ssh_username` }}",
"ssh_password": "{{ user `ssh_password` }}",
"ssh_port": 22,
"ssh_wait_timeout": "300s",
"vm_name": "{{ user `vm_name` }}",
"use_default_display": false,
"qemuargs": [
["-m", "{{ user `memory` }}"],
["-smp", "cpus={{ user `cpus` }}"],
["-cdrom", "{{ user `cloud_init_image` }}"],
["-serial", "mon:stdio"]
]
}
],
"provisioners": [
{
"execute_command": "echo '{{ user `ssh_password` }}' | {{.Vars}} sudo -E -S bash -x '{{.Path}}'",
"scripts": [
"setup.sh"
],
"type": "shell"
},
{
"type": "shell",
"inline": ["sudo sync"]
}
],
"variables": {
"cpus": "2",
"image_checksum": "2f8c35d32e9c0e09efe75759e1c1b9c3dbd8f41392051e6c4220d2b689dc85b4",
"image_checksum_type": "sha256",
"image_url" : "https://cloud-images.ubuntu.com/minimal/releases/bionic/release/ubuntu-18.04-minimal-cloudimg-amd64.img",
"cloud_init_image": "/root/packer/cloud-init.img",
"disk_size": "8192",
"memory": "2048M",
"ssh_username": "ubuntu",
"ssh_password": "Hoanghd164",
"vm_name": "kubernetes-{{timestamp}}.qcow2"
}
}
OEF
Ghi chú:
- image_checksum có thể được tìm thấy từ SHA256SUMS hoặc sử dụng sha256sum <image_file>
- image_url, có thể là đường dẫn file local hoặc đường dẫn http(s), trong trường hợp này, chúng ta sử dụng đường dẫn https từ cloud image của Ubuntu.
- cloud_init_image là cloud image ubuntu rút gọn có hỗ trợ cấu hình cloudinit.
- ssh_username, theo mặc định, sử dụng image rút gọn thường sử dụng ubuntu làm username mặc định.
- ssh_password là giá trị cần được xác định trong cấu hình cloudinit lúc khởi tạo máy ảo.
3. Tạo file userdata.cfg
cat > /root/packer/userdata.cfg << 'OEF'
#cloud-config
password: Hoanghd164
ssh_pwauth: true
chpasswd:
expire: false
locale: en_US.UTF-8
locale_configfile: /etc/default/locale'''
OEF
Sau đó tạo 1 image mới gắn file userdata.cfg để cài đặt cấu hình cloudinit:
cloud-localds /root/packer/cloud-init.img /root/packer/userdata.cfg
4. Tạo file script cài đặt Keepalived, Haproxy, Containerd và Kubernetes.
cat > /root/packer/setup.sh << 'OEF'
#!/bin/bash -x
apt update && apt-get install ca-certificates curl gnupg lsb-release -y
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg
echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" | tee /etc/apt/sources.list.d/docker.list
curl -s https://packages.cloud.google.com/apt/dists/kubernetes-xenial/main/binary-amd64/Packages | grep Version | tail -5
curl -s https://packages.cloud.google.com/apt/doc/apt-key.gpg | apt-key add - && \
echo 'deb http://apt.kubernetes.io/ kubernetes-xenial main' | tee /etc/apt/sources.list.d/kubernetes.list && \
apt update && apt-get upgrade -y
apt-get install containerd.io -y
apt-get install -y kubelet=1.23.8-00 kubectl=1.23.8-00 kubeadm=1.23.8-00
apt-get install keepalived -y
apt-get install haproxy -y
tee /etc/sysctl.d/kubernetes.conf<<EOF
net.bridge.bridge-nf-call-ip6tables = 1
net.bridge.bridge-nf-call-iptables = 1
net.ipv4.ip_forward = 1
EOF
echo "net.netfilter.nf_conntrack_max=1000000" >> /etc/sysctl.conf
sysctl --system
tee /etc/modules-load.d/containerd.conf <<EOF
overlay
br_netfilter
EOF
modprobe overlay
modprobe br_netfilter
sysctl --system
sed -i "/ swap / s/^\(.*\)$/#\1/g" /etc/fstab || sed -i '/swap/d' /etc/fstab
swapoff -a
mkdir -p /etc/containerd
containerd config default > /etc/containerd/config.toml
systemctl enable containerd
systemctl restart containerd
kubeadm config images pull
OEF
Ghi chú:
- kubeadm config images pull, lệnh này sẽ kéo các image docker cần thiết để chạy Kubernetes. Điều này sẽ tiết kiệm thời gian của bạn khi bạn khởi động một Cluster, vì image docker được đưa vào image của VM.
- sudo apt-mark hold kubelet kubeadm kubectl lệnh này sẽ đảm bảo các gói được đề cập không được nâng cấp để tránh bị hỏng khi tự động nâng cấp được kích hoạt.
5. Tất cả mọi thứ được thiết lập! Bước tiếp theo là xác thực cấu hình và sau đó build image.
Sau khi chuẩn bị xong các file, bạn sẽ có cây thư mục như dưới.
packer/
├── cloud-init.img
├── kubernetes.json
├── setup.sh
└── userdata.cfg
0 directories, 4 files
Xác thực cấu hình bằng lệnh dưới.
$ cd /root/packer/ && packer validate kubernetes.json
Template validated successfully.
Nếu xác thực không có lỗi, tiến hành build image.
packer build kubernetes.json
Đây là đoạn logs quá trình build image, mình đã lược bỏ 1 số phần để cho gọn.
$ packer build kubernetes.json
qemu output will be in this color.
==> qemu: Retrieving ISO
1 items: 199.94 MiB / 199.94 MiB [=====================================================================================================================================================================================================================================] 23s
qemu: Transferred: https://cloud-images.ubuntu.com/minimal/releases/bionic/release/ubuntu-18.04-minimal-cloudimg-amd64.img
==> qemu: Copying hard drive...
==> qemu: Resizing hard drive...
==> qemu: Found port for communicator (SSH, WinRM, etc): 2423.
==> qemu: Looking for available port between 5900 and 6000 on 127.0.0.1
==> qemu: Starting VM, booting disk image
qemu: The VM will be run headless, without a GUI. If you want to
qemu: view the screen of the VM, connect via VNC without a password to
qemu: vnc://127.0.0.1:5965
==> qemu: Overriding defaults Qemu arguments with QemuArgs...
==> qemu: Waiting 10s for boot...
==> qemu: Connecting to VM via VNC (127.0.0.1:5965)
==> qemu: Typing the boot command over VNC...
==> qemu: Using ssh communicator to connect: 127.0.0.1
==> qemu: Waiting for SSH to become available...
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
qemu: I1207 17:29:19.761412 2583 version.go:255] remote version is much newer: v1.25.4; falling back to: stable-1.23
qemu: [config/images] Pulled k8s.gcr.io/kube-apiserver:v1.23.14
qemu: [config/images] Pulled k8s.gcr.io/kube-controller-manager:v1.23.14
qemu: [config/images] Pulled k8s.gcr.io/kube-scheduler:v1.23.14
qemu: [config/images] Pulled k8s.gcr.io/kube-proxy:v1.23.14
qemu: [config/images] Pulled k8s.gcr.io/pause:3.6
qemu: [config/images] Pulled k8s.gcr.io/etcd:3.5.1-0
qemu: [config/images] Pulled k8s.gcr.io/coredns/coredns:v1.8.6
==> qemu: Provisioning with shell script: /tmp/packer-shell368451394
==> qemu: Halting the virtual machine...
==> qemu: Converting hard drive...
==> qemu: Error getting file lock for conversion; retrying...
Build 'qemu' finished.
==> Builds finished. The artifacts of successful builds are:
--> qemu: VM files in directory: build
Bây giờ bạn đã thấy có 1 image mới có tên kubernetes-1670434068.qcow2 trong thư mục /root/packer/build
/root/packer/
├── build
│ └── kubernetes-1670434068.qcow2
├── cloud-init.img
├── kubernetes.json
├── packer_cache
│ └── 9bd9c054d3a88540f4806699924621fa27d683a6f38750b5011f58b944920d3a.iso
├── setup.sh
└── userdata.cfg
2 directories, 6 files
6. Image đã sẵn sàng để sử dụng, nếu kích thước đĩa os được tạo ra qua nhỏ, bạn có thể thay đổi kích thước image bằng lệnh sau qemu-img resize <IMAGE_FILE> +DESIRED_SIZE. Giả sử mình muốn kubernetes-1584350145.qcow2 cái hiện có kích thước 8GB, được thay đổi kích thước thành 100GB, thì lệnh sẽ là:
qemu-img resize kubernetes-1670434068.qcow2 +92G
Và khi bạn tạo máy ảo mới bằng file image kubernetes-1670434068.qcow2, tất cả các ứng dụng bạn đã chạy đã có sẵn trong máy ảo.
ubuntu@ubuntu:~$ sudo -s
root@ubuntu:~# which kubeadm │root@kvm-node03:~#
/usr/bin/kubeadm
│root@kvm-node03:~#
root@ubuntu:~# which kubectl │root@kvm-node03:~#
/usr/bin/kubectl
│root@kvm-node03:~#
root@ubuntu:~# which haproxy │root@kvm-node03:~#
/usr/sbin/haproxy
│root@kvm-node03:~#
root@ubuntu:~# which keepalived │root@kvm-node03:~#
/usr/sbin/keepalived
Chúc các bạn thành công.