Xây dựng Kubernetes cluster bằng công cụ kubeadm trên Virtual Box

Tram Ho

GitHub repo: https://github.com/holdennguyen/kubernetes-install-cluster-with-kubeadm

Vagrant
Kubernetes
Kubernetes
containerd

Giải thích chi tiết từng bước cho người mới bắt đầu.
Tham khảo tài liệu của K8s – mục Bootstrapping clusters with kubeadm.
Hướng dẫn này sẽ dựng Kubernetes cluster trên máy tính cá nhân bằng cách sử dụng máy ảo Virtual Box. Chúng ta sẽ sử dụng phần mềm Vagrant để tự động hóa quá trình tạo máy ảo Virtual Box.

Trước khi bắt đầu

  • 🚧 Mô hình cluster: 1 máy Control Plan và 2 máy Node.
  • 🖥️ Hệ điều hành: Ubuntu 18.04 LTS (Bionic Beaver)
  • ⚙️ Tài nguyên hệ thống: 2 GB of RAM and 2 CPUs per machine.
  • 📮 Mỗi máy sẽ có hostname, MAC address, và product_uuid riêng biệt.
  • 🧱 Không thiết lập firewall. (Mặc định cho phép traffic ra vào các port)
  • 🌐 Các máy trong cluster được kết nối mạng với nhau (private network, sử dụng network interface enp0s8 của các máy ảo).

Các bước cần làm

  • ▶️ Tạo máy ảo Virtual Box bằng Vagrant
  • ▶️ Cài đặt container runtime (containerd) trên tất cả các máy ảo
  • ▶️ Cài đặt kubeadm, kubelet và kubectl trên tất cả các máy ảo
  • ▶️ Khởi động control plane và nodes
  • ▶️ Dọn dẹp môi trường

Tạo máy ảo Virtual Box bằng Vagrant

Vagrant là một công cụ để tạo và quản lý môi trường máy ảo. Nó thường được coi là một dạng Infrastructure as Code (IaC), cho phép chúng ta khởi tạo và quản lý cơ sở hạ tầng của mình bằng code thay vì chọn bằng tay trên console. Vagrant chủ yếu đóng vai trò là công cụ sử dụng cho môi trường máy ảo và thường sẽ không dùng để quản lý cơ sở hạ tầng Production.

Bắt đầu

Chúng ta sẽ tạo các máy ảo với Virtual Box bởi vì nó miễn phí và hoạt động ổn trên tất cả các hệ điều hành.

Đầu tiên, tải và cài đặt VirtualBox, Vagrant trên máy tính của bạn.

Chúng ta sẽ xây dựng các máy ảo theo khai báo trong Vagrantfile. Tạo Vagrantfile với nội dung như sau vào thư mục của bạn.

Trong Vagrantfile này, chúng ta đơn giản chỉ khai báo:

  • Số lượng máy ảo: NUM_MASTER_NODE, NUM_WORKER_NODE
  • Địa chỉ IP: IP_NW, MASTER_IP_START, NODE_IP_START
  • Kết nối mạng nội bộ: node.vm.network
  • hostname riêng biệt cho mỗi máy ảo: node.vm.hostname
  • Hệ điều hành: config.vm.box
  • Tài nguyên hệ thống: vb.memory, vb.cpus

Cú pháp trong VagrantfileRuby, nhưng để viết hay chỉnh sửa bạn không cần phải hiểu về ngôn ngữ lập trình Ruby. Xem thêm đây để biết thêm thông tin về cú pháp trong Vagrantfile.

Bắt đầu khởi tạo

Chạy câu lệnh:

Output sẽ tương tự như sau:

Bạn có thể kiểm tra trạng thái các máy ảo đã dựng bằng lệnh sau:

Thông tin về các máy ảo được tạo và quản lý bởi vagrant được trả về

Lỗi nhức nách: vagrant up times out tại bước ‘default: SSH auth method: private key’

Lỗi này xảy ra khi bật máy ảo không thành công. Mặc định, Virtual Box sử dụng TSC mode gọi là “RealTscOffset,” để điều chỉnh giá trị TSC (Time Stamp Counter) trên máy ảo để đồng bộ clock freqency của CPU giữa máy host và máy ảo.

Nếu bạn đang sử dụng Windows đã bật phần mềm máy ảo Hyper-V, phải tắt Hyper-V để tránh gây ra xung đột với Virtual Box dẫn đến lỗi vagrant up time out ở trên.

Để tắt hoàn toàn Hyper-V, chạy lệnh sau trong cmd:

sau đó tắt và bật lại máy tính.

Chú ý rằng bcdedit là viết tắt của boot configuration data edit, nói cách khác nó sẽ ảnh hưởng đến những phần mềm có thiết lập khi boot lại hệ điều hành, vì vậy bạn cần phải shutdown máy hoàn toàn (không suspend hay restart) để áp dụng thay đổi. Để PC tắt trong khoảng 10 giây trước khi bật lại. Nếu PC không cho shutdown trong Start menu, bạn có thể chạy lệnh shutdown /p trong cmd dưới quyền admin. Trên laptop, bạn có thể cần phải tháo pin.

Cài lại VagrantVirtual Box. Nếu lỗi vẫn còn, có thể bạn sẽ phải cài lại hệ điều hành Windows, nhớ đừng bật Hyper-V!

Truy cập vào máy ảo bằng Vagrant

Để ssh vào máy ảo, chỉ cần chạy lệnh:

Vagrant SSH with VSCode

Có thể thấy trong output khi chạy vagrant up, Vagrant có chuyển tiếp port 22 và tạo ssh keypairs cho mỗi máy ảo dù chúng ta không thiết lập trong Vagrantfile. Để xem thêm thông tin, bạn có thể đọc Vagrant Share: SSH SharingVagrantfile: config.ssh.

OK, sang bước kế tiếp nào!

Cài đặt container runtime (containerd) trên tất cả các máy ảo

Thực hiện công việc ở bước này trên tất cả các máy ảo

Ghi chú: Dockershim đã bị bỏ khỏi dự án Kubernetes ở bản 1.24. Đọc Dockershim Removal FAQ để biết thêm thông tin.

Dockershim là một thành phẩn của Kubernetes được sử dụng để giao tiếp với Docker runtime. Nó được giới thiệu như một giải pháp tạm thời cho phép Kubernetes sử dụng Docker như một container runtime trước khi Kubernetescontainer runtime interface (CRI) của riêng họ.

Bạn cần phải cài đặt một container runtime trên mỗi node trong cụm K8s (Kubernetes) để các Pods có thể chạy ở đó. Và phiên bản K8s 1.26 yêu cầu phải sử dụng một container runtime tương thích với Container Runtime Interface (CRI) của K8s. Đây là một số container runtime phổ biến với Kubernetes:

Bạn có thể xem hướng dẫn cài đặt cho các loại trên tại đây. Trong hướng dẫn này, chúng ta sẽ sử dụng Containerd.

Cài đặt và thiết lập các yêu cầu cần chuẩn bị trước

Tải các module của nhân Linux

  • modules-load.d trong Linux là thư mục hệ thống sử dụng để thiết lập các module của kernel được tải lên tiến trình. Nó bao gồm các tệp đuôi .conf chỉ định các module được tải khi hệ thống khởi động.
  • Module overlay được sử dụng để cung cấp overlay filesystem, là một kiểu filesystem cho phép nhiều filesystem xếp chồng lên nhau. Nó cực kỳ hữu dụng trong công nghệ containerization, nơi các container cần những filesystem cô lập của riêng nó.
  • Module br_netfilter được sử dụng để bật tính năng lọc và thao tác gói tin ở kernel-level, hữu dụng đối với việc kiểm soát lưu lượng mạng và bảo mật. Nó thường được dùng cùng với các mạng của namespace và các thiết bị mạng ảo để cung cấp việc cô lập cũng như định tuyến cho ứng dụng containerized.

Để kiểm tra module overlaybr_netfilter đã được load, chạy lệnh dưới đây:

Chuyển tiếp IPv4 và cho phép iptables nhận diện brigded traffic

  • sysctl.d là thư mục hệ thống trong Linux, sử dụng để thiết lập các tham số cho kernel trong runtime. Nó chứa các tệp có đuôi .conf quy định các giá trị của biến sysctl, đó là các tham số của kernel có thể được sử dụng để tinh chỉnh hành vi của Linux kernel.
  • Trong môi trường containerized, thông thường cần phải bật (đặt giá trị 1) net.bridge.bridge-nf-call-iptables để traffic giữa các container có thể lọc bởi iptables firewall của máy chủ. Điều này rất quan trọng vì lý do bảo mật, nó cho phép máy chủ cung cấp các lớp bảo mật mạng cho ứng dụng containerized.

Để kiểm tra net.bridge.bridge-nf-call-iptables, net.bridge.bridge-nf-call-ip6tables, net.ipv4.ip_forward đã được bật trong thiết lập sysctl hay chưa, chạy lệnh:

Cài đặt containerd

Gói containerd.io ở định dạng DEB và RPM được phân phối bởi Docker (không phải bởi dự án containerd). So sánh với các tệp nhị phân gốc của containerd, gói containerd.io cũng bao gồm runc, nhưng lại không có CNI plugins.

Container Network Interface (CNI) là giao diện tiêu chuẩn để cấu hình mạng cho các container trên Linux. Nó cho phép một loạt các tùy chọn kết nối mạng bao gồm overlay network, load balancing và các chính sách bảo mật sử dụng với ứng dụng containerized. Trong hướng dẫn này, chúng ta sẽ sử dụng CNI plugin với Pod network add-on sẽ được cài đặt ở bước sau trong mục Khởi tạo control plane và nodes.

Cập nhật apt package index và cài đặt packages cho phép apt sử dụng repository qua HTTPS:

Thêm GPG key chính thức của Docker:

Sử dụng lệnh sau để cài đặt repository:

Cập nhật lại apt package index sau khi cài đặt repo:

Cài đặt phiên bản mới nhất của gói containerd.io

Cgroup drivers

Trong Linux, các control group được sử dụng để giới hạn tài nguyên phân bổ cho các tiến trình.

Các kubeletcontainer runtime chạy dưới nó đều cần control groups để thực hiện việc quản lý tài nguyên cho các podcontainer như yêu cầu hay giới hạn về cpu/memory. Để giao tiếp với các control group, kubeletcontainer runtime cần sử dụng cgroup driver. Một điều cực kỳ quan trọng đó là kubeletcontainer runtime cần phải sử dụng cùng một loại cgroup driver với thiết lập giống nhau.

Có hai loại cgroup drivers hỗ trợ đó là:

  • cgroupfs
  • systemd

Bởi vì các máy ảo đã dựng của chúng ta sử dụng systemd, vậy nên ta sẽ thiết lập kubeletcontainerd dùng systemd làm cgroup driver.

Tùy thuộc vào bản phân phối và phiên bản của Linux, bạn sẽ thấy loại cgroup driver khác nhau. Để xem loại cgroup driver hiện tại trên Linux, bạn có thể kiểm tra giá trị của cgroup mount point bằng cách nhập lệnh: cat /proc/mounts | grep cgroup

Thiết lập cgroup driver cho containerd

Để thiết lập cho containerd dùng cgroup driversystemd, chạy:

thay thế toàn bộ nội dung trong tệp config.toml với nội dung cài đặt sau:

nhớ khởi động lại containerd để áp dụng thay đổi

Thiết lập cgroup driver cho kubelet

Trong phiên bản 1.22, nếu người dùng không cài đặt trường cgroupDriver trong KubeletConfiguration, kubeadm sẽ mặc định nó là systemd.
Chúng ta không cần làm gì để thiết lập cgroup driver cho kubelet trong hướng dẫn này vì sẽ dùng kubeadm để khởi tạo cụm K8s trong các bước tiếp theo.
Bạn có thể xem tại đây để biết thêm thông tin về cách thiết lập.

Cài đặt kubeadm, kubelet và kubectl trên tất cả các máy ảo

Thực hiện công việc ở bước này trên tất cả các máy ảo

Kubeadm là một command-line tool dùng để khởi tạo một Kubernetes cluster. Nó là một bản phân phối chính thức của Kubernetes và được thiết kế để đơn giản hóa quá trình thiết lập Kubernetes cluster. Kubeadm tự động hóa nhiều tác vụ liên quan đến thiết lập cluster chẳng hạn như cấu hình control plane components, tạo TLS certificates, và thiết lập Kubernetes networking.

Một trong những nội dung chính được đề cập trong kỳ thi Certified Kubernetes Administrator (CKA) là thiết lập cluster, bao gồm việc sử dụng các công cụ như kubeadm để khởi tạo một Kubernetes cluster mới.

Tắt swap space:

Bạn phải tắt tính năng swap để kubelet hoạt động bình thường. Xem thêm thảo luận về điều này trong issue: https://github.com/kubernetes/kubernetes/issues/53533

Kubelet, là node agent chính chạy trên worker node, giả sử mỗi node có một lượng bộ nhớ khả dụng cố định. Nếu node bắt đầu tiến hành swap, kubelet có thể bị delay hoặc các vấn đề khác ảnh hưởng đến tính stabilityreliability của Kubernetes cluster. Chính vì vậy, Kubernetes khuyên swap nên được disabled trên mỗi node trong cluster.

Để tắt swap trên máy Linux, sử dụng:

Cài đặt kubeadm, kubelet và kubectl :

  • kubelet: component chạy trên tất cả các máy trong cluster và thực hiện những việc như khởi động các podcontainer.
  • kubectl: command line tool dùng để nói chuyện với cluster.
  • kubeadm: công cụ cài đặt các component còn lại của kubernetes cluster.

kubeadm sẽ không cài đặt kubelet hay kubectl cho bạn, vì vậy hãy đảm bảo chúng sử dụng các phiên bản phù hợp với các component khác trong Kubernetes control planekubeadm cài cho bạn.

Cảnh báo: Hướng dẫn này sẽ loại bỏ các Kubernetes packages ra khỏi mọi tiến trình system upgrade. Do kubeadmKubernetes cần được đặc biệt chú ý mỗi khi upgrade.

Để biết thêm thông tin về việc các phiên bản lệch nhau được hỗ trợ hãy xem:

Cập nhật apt package index và cài các package cần thiết để sử dụng trong Kubernetes apt repository:

Tải Google Cloud public signing key:

Thêm Kubernetes apt repository:

Cập nhật lại apt package index, cài đặt phiên bản mới nhất của kubelet, kubeadmkubectl, ghim phiên bản hiện tại tránh việc tự động cập nhật:

kubelet sẽ tự động khởi động lại mỗi giây vì ở trạng thái crashloop, đợi kubeadm đưa ra yêu cầu cần thực hiện.

Ghi chú: 🔐 Client certificates được tạo bởi kubeadm sẽ bị hết hạn sau 1 year. Đọc thêm ở đây để biết thêm về cách tùy chỉnh và làm mới certificates.

Khởi động control plane và nodes

Khởi tạo control plane

control plane là nơi chạy các component bao gồm etcd (cơ sở dữ liệu của cluster) và API Server (nơi các câu lệnh kubectl giao tiếp).

Để tiến hành khởi tạo, chạy câu lệnh sau ở máy ảo mà chúng ta đặt tên là kubemaster:

  • --apiserver-advertise-address=192.168.56.2: Địa chỉ IP mà máy chủ API sẽ lắng nghe các câu lệnh. Trong hướng dẫn này sẽ là địa chỉa IP của máy ảo kubemaster.
  • --pod-network-cidr=10.244.0.0/16: control plane sẽ tự động phân bổ địa chỉ IP trong CIDR chỉ định cho các pod trên mọi node trong cụm cluster. Bạn sẽ cần phải chọn CIDR sao cho không trùng với bất kỳ dải mạng hiện có để tránh xung đột địa chỉ IP.

kubeadm init đầu tiên sẽ chạy một loại các bước kiểm tra để đảm bảo máy đã sẵn sàng chạy Kubernetes. Những bước kiểm tra này sẽ đưa ra các cảnh báo và thoát lệnh khi có lỗi. Kế tiếp kubeadm init tải xuống và cài đặt các thành phần của control plane. Việc này có thể sẽ mất vài phút, sau khi kết thúc bạn sẽ thấy thông báo:

Lưu lại câu lệnh kubeadm join... khi init thành công để thêm các node vào cluster.

Để kubectl có thể dùng với non-root user, chạy những lệnh sau, chúng cũng được nhắc trong output khi kubeadm init thành công:

Mặt khác, nếu bạn là root user, có thể dùng lệnh sau:

Cảnh báo: Kubeadm cấp certificate trong admin.conf để có Subject: O = system:masters, CN = kubernetes-admin.
system:masters là một nhóm người dùng siêu cấp, bỏ qua lớp ủy quyền (như RBAC). Tuyệt đối không chia sẻ tệp admin.conf với bất kỳ ai, thay vào đó hãy cấp cho người dùng các quyền tùy chỉnh bằng cách tạo cho họ một tệp kubeconfig với lệnh kubeadm kubeconfig. Để biết thêm chi tiết hãy đọc Generating kubeconfig files for additional users.

Thêm các node vào cluster

Chạy câu lệnh trong phần output của kubeadm init trên tất cả các worker node – máy ảo:kubenode01, kubenode02 với sudo permission:

Nếu bạn không lưu lại lệnh kubeadm join, quay lại máy control-plane: kubemaster.

Lấy <token> bằng lệnh

Output sẽ tương tự như sau:

Mặc định, <tokens> sẽ hết hạn sau 24 giờ. Nếu bạn thêm worker node khi <token> đã hết hạn, bạn có thể tạo <token> mới bằng cách chạy lệnh sau trên control-plane node:

Output sẽ cho <token> mới tương tự như sau:

Lấy <hash> bằng lệnh

Output sẽ tương tự:

Lấy <control-plane-host>:<control-plane-port> bằng lệnh

Sẽ được output tương tự:

<control-plane-host>:<control-plane-port> sẽ là 192.168.56.2:6443

Thêm worker node vào Kubernetes cluster thành công

Bạn sẽ nhận được thông báo thành công như sau trên các máy worker node:

Sau vài giây, bạn sẽ thấy thông tin node này trong phần output của lệnh kubectl get nodes khi chạy trên control plane node.

Kiểm tra các component của Kubernetes cluster

Ở control-plane kubemaster và worker nodes kubenode01, kubenode02 chạy lệnh:

Tất cả các components với LISTEN ports tương ứng sẽ được hiển thị như dưới đây:

kubemaster

kube-apiserver hiển thị chỉ LISTEN tới IPv6 :::6443 nhưng thực chất API server đang lắng nghe qua địa chỉ IPv6 cho phép truy cập qua địa chỉ IPv4, còn gọi là IPv4-mapped IPv6 address. Đây là lý do tại sao có thể chạy lệnh kubeadm join trên worker nodes thành công với --apiserver-advertise-address tới địa chỉ IPv4.
Ví dụ, địa chỉ IPv4 192.168.5.2 có thể biểu diễn bằng địa chỉ IPv6 ::ffff:192.168.5.2.

kubenode*

Cài đặt Pod network add-on

Chạy lệnh kubectl get nodes trên control plane để kiểm tra các node đã thêm vào cluster

Có thể thấy, các máy ảo kubemaster, kubenode01, kubenode02 đã được thêm vào Kubernetes cluster nhưng đang có STATUSNotReady.

Chạy lệnh kubectl get pods -A trên control plane để xem tất cả pod trong kube-system namespace

Bạn phải triển khai Container Network Interface (CNI) hỗ trợ Pod network add-on để các Pod có thể giao tiếp với nhau. Cluster DNS (CoreDNS) sẽ không được khởi động cho đến khi hoàn thất thiết lập pod network.

Pod network add-onsKubernetes-specific CNI plugins cung cấp kết nối mạng giữa các pod trong một Kubernetes cluster. Nó tạo một mạng overlay ảo phủ toàn bộ cluster và gắn cho mỗi pod một địa chỉ IP riêng.

Trong khi CNI plugins có thể được sử dụng với mọi container runtime, pod network add-ons dành riêng cho Kubernetes và cung cấp chức năng mạng cần thiết cho mô hình mạng Kubernetes. Một số ví dụ về pod network add-ons có kể đến Calico, Flannel, and Weave Net. (Xem thêm các pod network add-ons khác tại đây)

Trong hướng dẫn này, chúng ta sẽ sử dụng Weave Net add-ons. Nó dễ dàng cài đặt, sử dụng và phù hợp với việc triển khai ở quy mô nhỏ.

Để cài đặt nó cho Kubernetes cluster, chạy lệnh dưới đây trên control plane kubemaster:

Output sẽ như sau

Cần đảm bảo rằng dải mạng của Pod không bị trùng lặp với mạng trên các máy trong cluster. Nếu bạn khai báo --pod-network-cidr khi chạy kubeadm init, phải thêm tham số IPALLOC_RANGE vào tệp YAML của Weave network plugin. Chạy lệnh sau trên control plane kubemaster:

Lệnh này sẽ cho phép bạn chỉnh sửa tệp YAML của weave-net daemon set. Tìm đến phần spec của container có tham số name: weave để thêm biến môi trường IPALLOC_RANGE và truyền tham số --pod-network-cidr khi chạy kubeadm init. (Tệp được mở trong trình chỉnh sửa vi)

Lưu tệp và đợi một vài phút để weave-net daemon set khởi động lại các pod.

Thiết lập thành công

Chạy lại lệnh kubectl get pods -A trên control plane để kiểm tra, bạn sẽ thấy 3 pods của weave-net daemon setcoredns pods hiển thị đang chạy. (STATUS: Running)

Chạy kubectl get nodes để kiểm tra trạng thái các node trong cluster, chúng sẽ đều ở trạng thái sẵn sàng. (STATUS: Ready)

Nếu bạn thắc mắc tại sao ROLES của các worker node hiển thị <none>, điều đó có nghĩa là các node này đang không chạy các control plane component hay Kubernetes services chỉ định role. Thông thường worker nodes sẽ không chạy các control plane component, vì thế điều này hoàn toàn bình thường trong một Kubernetes cluster.

Networking là một phần trung tâm của Kubernetes, xem thêm Kubernetes networking model để biết thêm thông tin.

Nếu muốn tùy chỉnh cluster với kubeadm, bạn có thể đọc Create cluster kubeadm.

Clean up

Sẽ có lúc bạn gặp những lỗi không biết cách giải quyết hoặc đơn giản chỉ muốn bắt đầu lại từ đầu, phần này sẽ dành cho bạn!

Giữ lại các máy ảo, chỉ dọn dẹp Kubernetes cluster

Loại bỏ node

Chạy lệnh này để bỏ tất cả các pod đang chạy trên node theo đúng quy trình:

Reset các trạng thái được cài đặt bởi kubeadm

Quá trình reset này sẽ không bao gồm việc reset hay dọn dẹp iptables rules hay IPVS tables. Nếu bạn muốn reset iptables, phải thực hiện thủ công như sau:

Nếu muốn reset IPVS tables, bạn phải chạy lệnh dưới đây:

Bây giờ tiến hành loại bỏ node khỏi cluster:

Nếu muốn thiết lập lại, run kubeadm init (thiết lập thành control-plane) hoặc kubeadm join (thiết lập thành worker node) với các đối số phù hợp.

Dọn dẹp control plane

Tiến hành quá trình đảo ngược lại tất cả các thay đổi kubeadm init đã thực hiện trên máy với lệnh:

--kubeconfig=string: Xóa kubeconfig file được dùng để giao tiếp với cluster. Nếu không khai báo, một số thư mục sẽ được tìm để xóa kubeconfig file. (Nếu bạn thiết lập cho non-root user sau khi chạy kubeadm init, đừng quên xóa tệp thiết lập $HOME/.kube/config)

Tương tự như đã đề cập ở phần loại bỏ node, quá trình reset này sẽ không reset hay dọn dẹp iptables rules hay IPVS tables. Nếu muốn reset, bạn phải làm thủ công như khi loại bỏ node.

Xóa bỏ tất cả các máy ảo

Bởi vì sử dụng Vagrant để tự động hóa quá trình tạo các máy ảo, bạn có thể xóa bỏ tất cả chỉ với một câu lệnh. Chạy lệnh này ở thư mục đang sử dụng trên máy tính (Nơi cài đặt VagrantVirtual Box):

Nếu bạn chỉ muốn tắt các máy ảo, thay vào đó hãy chạy lệnh vagrant halt. Khi đó, lúc vagrant up lại, tất cả công việc đã thực hiện trên máy ảo sẽ vẫn còn đó thay vì mất hết. Tìm hiểu thêm về lệnh này tại đây.

Chia sẻ bài viết ngay

Nguồn bài viết : Viblo