+12

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

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.

    # -*- mode: ruby -*-
    # vi:set ft=ruby sw=2 ts=2 sts=2:

    # Xác định số lượng máy control plane (MASTER_NODE) và máy node (WORKER_NODE)
    NUM_MASTER_NODE = 1
    NUM_WORKER_NODE = 2

    IP_NW = "192.168.56."
    MASTER_IP_START = 1
    NODE_IP_START = 2

    # Tất cả thiết lập Vagrant được khai báo dưới đây. Số "2" trong Vagrant.configure
    # là thiết lập phiên bản sử dụng
    # Đừng thay đổi trừ khi bạn biết mình đang làm gì

    Vagrant.configure("2") do |config|

    # Để tham khảo thêm, xem tài liệu tại
    # https://docs.vagrantup.com.

    # Tất cả môi trường mà Vagrant xây dựng đều cần một box. Bạn có thể tìm các
    # box tại https://vagrantcloud.com/search.
    # Đây là một số thông tin chi tiết về vagrant box "ubuntu/bionic64":
        # Hệ điều hành: Ubuntu 18.04 LTS (Bionic Beaver)
            # Ubuntu 18.04 LTS sẽ được cập nhật bảo mật và sửa lỗi 
            # từ Canonical, công ty đứng sau Ubuntu, cho đến tháng 4 năm 2023 
            # đối với bản desktop và server, và đến tháng 4 năm 2028 đối 
            # với bản server có Extended Security Maintenance (ESM).
        # Kiến trúc: x86_64 (64-bit)
        # Dung lượng bộ nhớ: 10 GB
        # RAM: 2 GB
        # CPUs: 2
        # Giao diện đồ họa: None (headless)
        # Người tạo: VirtualBox

    config.vm.box = "ubuntu/bionic64"

    # Tắt tính năng tự động cập nhật của box. Nếu tắt,
    # boxes sẽ chỉ kiểm tra cập nhật khi người dùng chạy
    # `vagrant box outdated`. Không khuyến khích.

    config.vm.box_check_update = false

    # Xem thêm tài liệu của Virtual box tại
    # https://developer.hashicorp.com/vagrant/docs/providers/virtualbox/configuration

    # Khởi tạo Control Plane
    (1..NUM_MASTER_NODE).each do |i|
        config.vm.define "kubemaster" do |node|
            node.vm.provider "virtualbox" do |vb|
                vb.name = "kubemaster"
                vb.memory = 2048
                vb.cpus = 2
            end
            node.vm.hostname = "kubemaster"
            node.vm.network :private_network, ip: IP_NW + "#{MASTER_IP_START + i}"
        end
    end



    # Khởi tạo Nodes
    (1..NUM_WORKER_NODE).each do |i|
        config.vm.define "kubenode0#{i}" do |node|
            node.vm.provider "virtualbox" do |vb|
                vb.name = "kubenode0#{i}"
                vb.memory = 2048
                vb.cpus = 2
            end
            node.vm.hostname = "kubenode0#{i}"
            node.vm.network :private_network, ip: IP_NW + "#{NODE_IP_START + i}"
        end
    end
    end

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:

    vagrant up

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

    Bringing machine 'kubemaster' up with 'virtualbox' provider...
    Bringing machine 'kubenode01' up with 'virtualbox' provider...
    Bringing machine 'kubenode02' up with 'virtualbox' provider...
    ==> kubemaster: Importing base box 'ubuntu/bionic64'...
    ==> kubemaster: Matching MAC address for NAT networking...
    ==> kubemaster: Setting the name of the VM: kubemaster
    ==> kubemaster: Clearing any previously set network interfaces...
    ==> kubemaster: Preparing network interfaces based on configuration...
        kubemaster: Adapter 1: nat
        kubemaster: Adapter 2: hostonly
    ==> kubemaster: Forwarding ports...
        kubemaster: 22 (guest) => 2222 (host) (adapter 1)
    ==> kubemaster: Running 'pre-boot' VM customizations...
    ==> kubemaster: Booting VM...
    ==> kubemaster: Waiting for machine to boot. This may take a few minutes...
        kubemaster: SSH address: 127.0.0.1:2222
        kubemaster: SSH username: vagrant
        kubemaster: SSH auth method: private key
        kubemaster: Warning: Connection reset. Retrying...
        kubemaster: Warning: Connection aborted. Retrying...
        kubemaster: 
        kubemaster: Vagrant insecure key detected. Vagrant will automatically replace
        kubemaster: this with a newly generated keypair for better security.
        kubemaster: 
        kubemaster: Inserting generated public key within guest...
        kubemaster: Removing insecure key from the guest if it's present...
        kubemaster: Key inserted! Disconnecting and reconnecting using new SSH key...
    ==> kubemaster: Machine booted and ready!
    ==> kubemaster: Checking for guest additions in VM...
        kubemaster: The guest additions on this VM do not match the installed version of
        kubemaster: VirtualBox! In most cases this is fine, but in rare cases it can
        kubemaster: prevent things such as shared folders from working properly. If you see
        kubemaster: shared folder errors, please make sure the guest additions within the
        kubemaster: virtual machine match the version of VirtualBox you have installed on
        kubemaster: your host and reload your VM.
        kubemaster:
        kubemaster: Guest Additions Version: 5.2.42
        kubemaster: VirtualBox Version: 7.0
    ==> kubemaster: Setting hostname...
    ==> kubemaster: Configuring and enabling network interfaces...
    ==> kubemaster: Mounting shared folders...
        kubemaster: /vagrant => C:/Users/MSI BRAVO/kubernetes-install-cluster-with-kubeadm
    ==> kubenode01: Importing base box 'ubuntu/bionic64'...
    ==> kubenode01: Matching MAC address for NAT networking...
    ==> kubenode01: Setting the name of the VM: kubenode01
    ==> kubenode01: Fixed port collision for 22 => 2222. Now on port 2200.
    ==> kubenode01: Clearing any previously set network interfaces...
    ==> kubenode01: Preparing network interfaces based on configuration...
        kubenode01: Adapter 1: nat
        kubenode01: Adapter 2: hostonly
    ==> kubenode01: Forwarding ports...
        kubenode01: 22 (guest) => 2200 (host) (adapter 1)
    ==> kubenode01: Running 'pre-boot' VM customizations...
    ==> kubenode01: Booting VM...
    ==> kubenode01: Waiting for machine to boot. This may take a few minutes...
        kubenode01: SSH address: 127.0.0.1:2200
        kubenode01: SSH username: vagrant
        kubenode01: SSH auth method: private key
        kubenode01: Warning: Connection reset. Retrying...
        kubenode01: Warning: Connection aborted. Retrying...
        kubenode01: 
        kubenode01: Vagrant insecure key detected. Vagrant will automatically replace
        kubenode01: this with a newly generated keypair for better security.
        kubenode01: 
        kubenode01: Inserting generated public key within guest...
        kubenode01: Removing insecure key from the guest if it's present...
        kubenode01: Key inserted! Disconnecting and reconnecting using new SSH key...
    ==> kubenode01: Machine booted and ready!
    ==> kubenode01: Checking for guest additions in VM...
        kubenode01: The guest additions on this VM do not match the installed version of
        kubenode01: VirtualBox! In most cases this is fine, but in rare cases it can
        kubenode01: prevent things such as shared folders from working properly. If you see
        kubenode01: shared folder errors, please make sure the guest additions within the
        kubenode01: virtual machine match the version of VirtualBox you have installed on
        kubenode01: your host and reload your VM.
        kubenode01:
        kubenode01: Guest Additions Version: 5.2.42
        kubenode01: VirtualBox Version: 7.0
    ==> kubenode01: Setting hostname...
    ==> kubenode01: Configuring and enabling network interfaces...
    ==> kubenode01: Mounting shared folders...
        kubenode01: /vagrant => C:/Users/MSI BRAVO/kubernetes-install-cluster-with-kubeadm
    ==> kubenode02: Importing base box 'ubuntu/bionic64'...
    ==> kubenode02: Matching MAC address for NAT networking...
    ==> kubenode02: Setting the name of the VM: kubenode02
    ==> kubenode02: Fixed port collision for 22 => 2222. Now on port 2201.
    ==> kubenode02: Clearing any previously set network interfaces...
    ==> kubenode02: Preparing network interfaces based on configuration...
        kubenode02: Adapter 1: nat
        kubenode02: Adapter 2: hostonly
    ==> kubenode02: Forwarding ports...
        kubenode02: 22 (guest) => 2201 (host) (adapter 1)
    ==> kubenode02: Running 'pre-boot' VM customizations...
    ==> kubenode02: Booting VM...
    ==> kubenode02: Waiting for machine to boot. This may take a few minutes...
        kubenode02: SSH address: 127.0.0.1:2201
        kubenode02: SSH username: vagrant
        kubenode02: SSH auth method: private key
        kubenode02: Warning: Connection reset. Retrying...
        kubenode02: Warning: Connection aborted. Retrying...
        kubenode02: 
        kubenode02: Vagrant insecure key detected. Vagrant will automatically replace
        kubenode02: this with a newly generated keypair for better security.
        kubenode02: 
        kubenode02: Inserting generated public key within guest...
        kubenode02: Removing insecure key from the guest if it's present...
        kubenode02: Key inserted! Disconnecting and reconnecting using new SSH key...
    ==> kubenode02: Machine booted and ready!
    ==> kubenode02: Checking for guest additions in VM...
        kubenode02: The guest additions on this VM do not match the installed version of
        kubenode02: VirtualBox! In most cases this is fine, but in rare cases it can
        kubenode02: prevent things such as shared folders from working properly. If you see
        kubenode02: shared folder errors, please make sure the guest additions within the
        kubenode02: virtual machine match the version of VirtualBox you have installed on
        kubenode02: your host and reload your VM.
        kubenode02:
        kubenode02: Guest Additions Version: 5.2.42
        kubenode02: VirtualBox Version: 7.0
    ==> kubenode02: Setting hostname...
    ==> kubenode02: Configuring and enabling network interfaces...
    ==> kubenode02: Mounting shared folders...
        kubenode02: /vagrant => C:/Users/MSI BRAVO/kubernetes-install-cluster-with-kubeadm

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

    vagrant status

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

    Current machine states:

    kubemaster                running (virtualbox)
    kubenode01                running (virtualbox)
    kubenode02                running (virtualbox)

    This environment represents multiple VMs. The VMs are all listed
    above with their current state. For more information about a specific
    VM, run `vagrant status NAME`.

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:

    bcdedit /set hypervisorlaunchtype off

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 <hostname>

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

    cat <<EOF | sudo tee /etc/modules-load.d/k8s.conf
    overlay
    br_netfilter
    EOF

    sudo modprobe overlay
    sudo modprobe br_netfilter
  • 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:

    lsmod | grep overlay
    lsmod | grep br_netfilter

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

    #  thiết lập các tham số sysctl, luôn tồn tại dù khởi động lại
    cat <<EOF | sudo tee /etc/sysctl.d/k8s.conf
    net.bridge.bridge-nf-call-iptables  = 1
    net.bridge.bridge-nf-call-ip6tables = 1
    net.ipv4.ip_forward                 = 1
    EOF

    # Áp dụng các tham số sysctl mà không cần khởi động lại
    sudo sysctl --system
  • 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:

    sysctl net.bridge.bridge-nf-call-iptables net.bridge.bridge-nf-call-ip6tables net.ipv4.ip_forward

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:

    sudo apt-get update

    sudo apt-get install \
    ca-certificates \
    curl \
    gnupg \
    lsb-release

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

    sudo mkdir -m 0755 -p /etc/apt/keyrings
    curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg

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

    echo \
    "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu \
    $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null

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

    sudo apt-get update

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

    sudo apt-get install 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:

    sudo vi /etc/containerd/config.toml

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

    [plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc]
        [plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc.options]
            SystemdCgroup = true

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

    sudo systemctl restart containerd

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:

    # Đầu tiên là tắt swap
    sudo swapoff -a

    # Sau đó tắt swap mỗi khi khởi động trong /etc/fstab
    sudo sed -i '/ swap / s/^\(.*\)$/#\1/g' /etc/fstab

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:
    sudo apt-get update
    sudo apt-get install -y apt-transport-https ca-certificates curl
Tải Google Cloud public signing key:
    sudo mkdir -m 0755 -p /etc/apt/keyrings
    sudo curl -fsSLo /etc/apt/keyrings/kubernetes-archive-keyring.gpg https://packages.cloud.google.com/apt/doc/apt-key.gpg
Thêm Kubernetes apt repository:
    echo "deb [signed-by=/etc/apt/keyrings/kubernetes-archive-keyring.gpg] https://apt.kubernetes.io/ kubernetes-xenial main" | sudo tee /etc/apt/sources.list.d/kubernetes.list
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:
    sudo apt-get update
    sudo apt-get install -y kubelet kubeadm kubectl
    sudo apt-mark hold kubelet kubeadm kubectl

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:

    sudo kubeadm init --apiserver-advertise-address=192.168.56.2 --pod-network-cidr=10.244.0.0/16
  • --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:

    Your Kubernetes control-plane has initialized successfully!

    To start using your cluster, you need to run the following as a regular user:

    mkdir -p $HOME/.kube
    sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
    sudo chown $(id -u):$(id -g) $HOME/.kube/config

    You should now deploy a Pod network to the cluster.
    Run "kubectl apply -f [podnetwork].yaml" with one of the options listed at:
    /docs/concepts/cluster-administration/addons/

    You can now join any number of machines by running the following on each node
    as root:

    kubeadm join <control-plane-host>:<control-plane-port> --token <token> --discovery-token-ca-cert-hash sha256:<hash>

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:

    mkdir -p $HOME/.kube
    sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
    sudo chown $(id -u):$(id -g) $HOME/.kube/config

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

    export KUBECONFIG=/etc/kubernetes/admin.conf

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:

    sudo kubeadm join --token <token> <control-plane-host>:<control-plane-port> --discovery-token-ca-cert-hash sha256:<hash>

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

    kubeadm token list

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

    TOKEN                    TTL  EXPIRES              USAGES           DESCRIPTION            EXTRA GROUPS
    8ewj1p.9r9hcjoqgajrj4gi  23h  2018-06-12T02:51:28Z authentication,  The default bootstrap  system:
                                                       signing          token generated by     bootstrappers:
                                                                        'kubeadm init'.        kubeadm:
                                                                                               default-node-token

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:

    kubeadm token create

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

    5didvk.d09sbcov8ph2amjw

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

    openssl x509 -pubkey -in /etc/kubernetes/pki/ca.crt | openssl rsa -pubin -outform der 2>/dev/null | \
    openssl dgst -sha256 -hex | sed 's/^.* //'

Output sẽ tương tự:

    8cb2de97839780a412b93877f8507ad6c94f73add17d5d7058e91741c9d5ec78

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

    cat /$HOME/.kube/config | grep server

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

    server: https://192.168.56.2:6443

<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:

    [preflight] Running pre-flight checks

    ... (log output of join workflow) ...

    Node join complete:
    * Certificate signing request sent to control-plane and response
    received.
    * Kubelet informed of new secure connection details.

    Run 'kubectl get nodes' on control-plane to see this machine join.

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:

    sudo netstat -lntp

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

kubemaster

    Active Internet connections (only servers)
    Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name
    tcp        0      0 127.0.0.1:10248         0.0.0.0:*               LISTEN      8013/kubelet
    tcp        0      0 127.0.0.1:10249         0.0.0.0:*               LISTEN      8182/kube-proxy
    tcp        0      0 192.168.56.2:2379       0.0.0.0:*               LISTEN      7811/etcd
    tcp        0      0 127.0.0.1:2379          0.0.0.0:*               LISTEN      7811/etcd
    tcp        0      0 192.168.56.2:2380       0.0.0.0:*               LISTEN      7811/etcd
    tcp        0      0 127.0.0.1:2381          0.0.0.0:*               LISTEN      7811/etcd
    tcp        0      0 127.0.0.1:10257         0.0.0.0:*               LISTEN      7791/kube-controlle
    tcp        0      0 127.0.0.1:10259         0.0.0.0:*               LISTEN      7907/kube-scheduler
    tcp        0      0 127.0.0.1:34677         0.0.0.0:*               LISTEN      2826/containerd
    tcp        0      0 127.0.0.53:53           0.0.0.0:*               LISTEN      817/systemd-resolve
    tcp        0      0 0.0.0.0:22              0.0.0.0:*               LISTEN      1380/sshd
    tcp6       0      0 :::10250                :::*                    LISTEN      8013/kubelet
    tcp6       0      0 :::6443                 :::*                    LISTEN      7884/kube-apiserver
    tcp6       0      0 :::10256                :::*                    LISTEN      8182/kube-proxy
    tcp6       0      0 :::22                   :::*                    LISTEN      1380/sshd

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*

    Active Internet connections (only servers)
    Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name    
    tcp        0      0 127.0.0.1:10248         0.0.0.0:*               LISTEN      8987/kubelet        
    tcp        0      0 127.0.0.1:10249         0.0.0.0:*               LISTEN      9208/kube-proxy     
    tcp        0      0 127.0.0.1:39989         0.0.0.0:*               LISTEN      2785/containerd     
    tcp        0      0 127.0.0.53:53           0.0.0.0:*               LISTEN      782/systemd-resolve 
    tcp        0      0 0.0.0.0:22              0.0.0.0:*               LISTEN      1431/sshd
    tcp6       0      0 :::10250                :::*                    LISTEN      8987/kubelet        
    tcp6       0      0 :::10256                :::*                    LISTEN      9208/kube-proxy     
    tcp6       0      0 :::22                   :::*                    LISTEN      1431/sshd

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

    NAME           STATUS     ROLES           AGE    VERSION
    kubemaster     NotReady   control-plane   3h1m   v1.26.2
    kubenode01     NotReady   <none>          3h     v1.26.2
    kubenode02     NotReady   <none>          179m   v1.26.2

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

    NAMESPACE     NAME                                   READY   STATUS    RESTARTS   AGE
    kube-system   coredns-787d4945fb-5cwlq               0/1     Pending   0          3h8m
    kube-system   coredns-787d4945fb-q2s4p               0/1     Pending   0          3h8m
    kube-system   etcd-controlplane                      1/1     Running   0          3h8m
    kube-system   kube-apiserver-controlplane            1/1     Running   0          3h8m
    kube-system   kube-controller-manager-controlplane   1/1     Running   0          3h8m
    kube-system   kube-proxy-7twwr                       1/1     Running   0          3h7m
    kube-system   kube-proxy-8mxt7                       1/1     Running   0          3h8m
    kube-system   kube-proxy-v9rc6                       1/1     Running   0          3h8m
    kube-system   kube-scheduler-controlplane            1/1     Running   0          3h9m

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:

    kubectl apply -f https://github.com/weaveworks/weave/releases/download/v2.8.1/weave-daemonset-k8s.yaml

Output sẽ như sau

    serviceaccount/weave-net created
    clusterrole.rbac.authorization.k8s.io/weave-net created
    clusterrolebinding.rbac.authorization.k8s.io/weave-net created
    role.rbac.authorization.k8s.io/weave-net created
    rolebinding.rbac.authorization.k8s.io/weave-net created
    daemonset.apps/weave-net created

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:

    kubectl edit ds weave-net -n kube-system

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)

    spec:
    ...
        template:
        ...
            spec:
            ...
                containers:
                ...
                    env:
                    - name: IPALLOC_RANGE
                      value: 10.244.0.0/16
                      ...
                    name: weave

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)

    NAMESPACE     NAME                                 READY   STATUS    RESTARTS   AGE
    kube-system   coredns-787d4945fb-48tbh             1/1     Running   0          6m57s
    kube-system   coredns-787d4945fb-nrsp7             1/1     Running   0          6m57s
    kube-system   etcd-kubemaster                      1/1     Running   0          7m10s
    kube-system   kube-apiserver-kubemaster            1/1     Running   0          7m12s
    kube-system   kube-controller-manager-kubemaster   1/1     Running   0          7m10s
    kube-system   kube-proxy-8sxss                     1/1     Running   0          4m19s
    kube-system   kube-proxy-j7z6x                     1/1     Running   0          6m58s
    kube-system   kube-proxy-nj8j2                     1/1     Running   0          4m14s
    kube-system   kube-scheduler-kubemaster            1/1     Running   0          7m10s
    kube-system   weave-net-7mldz                      2/2     Running   0          2m
    kube-system   weave-net-dk5dl                      2/2     Running   0          70s
    kube-system   weave-net-znhnm                      2/2     Running   0          2m

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)

    NAME         STATUS   ROLES           AGE     VERSION
    kubemaster   Ready    control-plane   9m54s   v1.26.2
    kubenode01   Ready    <none>          6m59s   v1.26.2
    kubenode02   Ready    <none>          6m54s   v1.26.2

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:

    kubectl drain <node name> --delete-emptydir-data --force --ignore-daemonsets

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

    kubeadm reset

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:

    iptables -F && iptables -t nat -F && iptables -t mangle -F && iptables -X

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

    ipvsadm -C

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

    kubectl delete node <node name>

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:

    sudo kubeadm reset --kubeconfig="$HOME/.kube/config"

--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):

    vagrant destroy

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.


All rights reserved

Viblo
Hãy đăng ký một tài khoản Viblo để nhận được nhiều bài viết thú vị hơn.
Đăng kí