企業運維實踐-還不會部署高可用的kubernetes叢集?使用kubeadm方式安裝高可用k8s叢集v1.23.7

2022-07-25 18:02:28

關注「WeiyiGeek」公眾號

設為「特別關注」每天帶你玩轉網路安全運維、應用開發、物聯網IOT學習!

希望各位看友【關注、點贊、評論、收藏、投幣】,助力每一個夢想。

文章目錄:

0x00 前言簡述

0x01 環境準備

  • 主機規劃
  • 軟體版本
  • 網路規劃

0x02 安裝部署

  • 1.準備基礎主機環境設定
  • 2.負載均衡管理ipvsadm工具安裝與核心載入
  • 3.高可用HAProxy與Keepalived軟體安裝設定
  • 4.容器執行時containerd.io安裝設定
  • 5.安裝源設定與初始化叢集設定準備
  • 6.使用kubeadm安裝部署K8S叢集
  • 7.部署設定 Calico 網路外掛

0x03 叢集輔助外掛部署

  • 1.叢集中基於nfs的provisioner的動態持卷環境部署
  • 2.叢集中安裝metrics-server獲取使用者端資源監控指標
  • 3.叢集管理原生UI工具kubernetes-dashboard安裝部署
  • 4.叢集管理K9S使用者端工具安裝使用
  • 5.叢集服務Service七層負載均衡ingress環境搭建部署

溫馨提示:若文章中有圖片顯示不全,可存取我的部落格【 https://blog.weiyigeek.top 】繼續瀏覽該篇文章。


0x00 前言簡述

描述: 在我部落格以及前面的文章之中講解Kubernetes相關叢集環境的搭建說明, 隨著K8S及其相關元件的迭代, 與讀者當前接觸的版本有所不同,在上一章中我們一起實踐了【使用二進位制方式進行安裝部署高可用的K8S叢集V1.23.6】(https://blog.weiyigeek.top/2022/5-7-654.html) , 所以本章將實踐使用kubeadm方式部署搭建高可用的kubernetes叢集V1.23.7,此處仍然按照ubuntu 20.04系統以及haproxy、keepalive、containerd、etcd、kubeadm、kubectl 等相關工具外掛【最新或者穩定的版本】進行實踐,這裡不再對k8s等相關基礎知識做介紹,如有新入門的童鞋,請存取如下【部落格文章】(https://blog.weiyigeek.top/tags/k8s/) 或者【B站專欄】(https://www.bilibili.com/read/readlist/rl520875?spm_id_from=333.999.0.0) 按照順序學習。

Kubernetes 簡述
Kubernetes (後續簡稱k8s)是 Google(2014年6月) 開源的一個容器編排引擎,使用Go語言開發,它支援自動化部署、大規模可伸縮、以及雲平臺中多個主機上的容器化應用進行管理。其目標是讓部署容器化的應用更加簡單並且高效,提供了資源排程、部署管理、服務發現、擴容縮容、狀態 監控、維護等一整套功能, 努力成為跨主機叢集的自動化部署、自動化擴充套件以及執行應用程式容器的平臺,它支援一些列CNCF畢業專案,包括 Containerd、calico 等 。

擴充套件文章:

1.使用二進位制方式部署v1.23.6的K8S叢集實踐(上)【 https://mp.weixin.qq.com/s/sYpHENyehAnGOQQakYzhUA

2.使用二進位制方式部署v1.23.6的K8S叢集實踐(下)【 https://mp.weixin.qq.com/s/-ksiNJG6v4q47ez7_H3uYQ

本章完整原文地址:


0x01 環境準備

主機規劃

溫馨提示: 同樣此處使用的是 Ubuntu 20.04 作業系統, 該系統已做安全加固和核心優化符合等保2.0要求【SecOpsDev/Ubuntu-InitializeSecurity.sh at master · WeiyiGeek/SecOpsDev (github.com)】, 如你的Linux未進行相應設定環境可能與讀者有些許差異, 如需要進行(windows server、Ubuntu、CentOS)安全加固請參照如下加固指令碼進行加固, 請大家瘋狂的 star 。

加固指令碼地址:【 https://github.com/WeiyiGeek/SecOpsDev/blob/master/OS-作業系統/Linux/Ubuntu/Ubuntu-InitializeSecurity.sh

主機地址 主機名稱 主機設定 主機角色 軟體元件
10.20.176.212 devtest-master-212 8C/16G 控制節點
10.20.176.213 devtest-master-213 8C/16G 控制節點
10.20.176.214 devtest-master-214 8C/32G 控制節點
10.20.176.215 devtest-work-215 8C/16G 工作節點
10.20.176.211 slbvip.k8s.devtest - 虛擬VIP 虛擬網路卡地址

軟體版本

作業系統

  • Ubuntu 20.04 LTS - 5.4.0-92-generic

高可用軟體

  • ipvsadm - 1:1.31-1
  • haproxy - 2.0.13-2
  • keepalived - 1:2.0.19-2

ETCD資料庫

  • etcd - v3.5.4

容器執行時

  • containerd.io - 1.6.6

Kubernetes

  • kubeadm - v1.23.7
  • kube-apiserver - v1.23.7
  • kube-controller-manager - v1.23.7
  • kubectl - v1.23.7
  • kubelet - v1.23.7
  • kube-proxy - v1.23.7
  • kube-scheduler - v1.23.7

網路外掛&輔助軟體

  • calico - v3.22
  • coredns - v1.9.1
  • kubernetes-dashboard - v2.5.1
  • k9s - v0.25.18

網路規劃

子網 Subnet 網段 備註
nodeSubnet 10.20.176.0/24 宿主機節點子網
ServiceSubnet 10.96.0.0/16 SVC 子網
PodSubnet 10.66.0.0/16 POD 子網

0x02 安裝部署

1.準備基礎主機環境設定

步驟 01.【所有主機】主機名設定按照上述主機規劃進行設定。

# 例如, 在10.20.176.212主機中執行。
hostnamectl set-hostname devtest-master-212
# 例如, 在10.20.176.213主機中執行。
hostnamectl set-hostname devtest-master-213
# 例如, 在10.20.176.214主機中執行。
hostnamectl set-hostname devtest-master-214

# 例如, 在10.10.107.215主機中執行。
hostnamectl set-hostname devtest-work-215

步驟 02.【所有主機】將規劃中的主機名稱與IP地址進行硬解析。

sudo tee -a /etc/hosts <<'EOF'
10.20.176.211 slbvip.k8s.devtest
10.20.176.212 devtest-master-212
10.20.176.213 devtest-master-213
10.20.176.214 devtest-master-214
10.20.176.215 devtest-work-215
EOF

步驟 03.驗證每個節點上IP、MAC 地址和 product_uuid 的唯一性,保證其能相互正常通訊

# 使用命令 ip link 或 ifconfig -a 來獲取網路介面的 MAC 地址
ifconfig -a
# 使用命令 檢視 product_uuid 校驗
sudo cat /sys/class/dmi/id/product_uuid

步驟 04.【所有主機】系統時間同步與時區設定

date -R
sudo ntpdate ntp.aliyun.com
sudo timedatectl set-timezone Asia/Shanghai
# 或者
# sudo dpkg-reconfigure tzdata
sudo timedatectl set-local-rtc 0
timedatectl

步驟 05.【所有主機】禁用系統交換分割區

swapoff -a && sed -i 's|^/swap.img|#/swap.ing|g' /etc/fstab
# 驗證交換分割區是否被禁用
free | grep "Swap:"

步驟 06.【所有主機】系統核心引數調整

# 禁用 swap 分割區
egrep -q "^(#)?vm.swappiness.*" /etc/sysctl.conf && sed -ri "s|^(#)?vm.swappiness.*|vm.swappiness = 0|g"  /etc/sysctl.conf || echo "vm.swappiness = 0" >> /etc/sysctl.conf
# 允許轉發
egrep -q "^(#)?net.ipv4.ip_forward.*" /etc/sysctl.conf && sed -ri "s|^(#)?net.ipv4.ip_forward.*|net.ipv4.ip_forward = 1|g"  /etc/sysctl.conf || echo "net.ipv4.ip_forward = 1" >> /etc/sysctl.conf

# - 允許 iptables 檢查橋接流量
egrep -q "^(#)?net.bridge.bridge-nf-call-iptables.*" /etc/sysctl.conf && sed -ri "s|^(#)?net.bridge.bridge-nf-call-iptables.*|net.bridge.bridge-nf-call-iptables = 1|g" /etc/sysctl.conf || echo "net.bridge.bridge-nf-call-iptables = 1" >> /etc/sysctl.conf
egrep -q "^(#)?net.bridge.bridge-nf-call-ip6tables.*" /etc/sysctl.conf && sed -ri "s|^(#)?net.bridge.bridge-nf-call-ip6tables.*|net.bridge.bridge-nf-call-ip6tables = 1|g" /etc/sysctl.conf || echo "net.bridge.bridge-nf-call-ip6tables = 1" >> /etc/sysctl.conf 

步驟 07.【所有主機】禁用系統防火牆

ufw disable && systemctl disable ufw && systemctl stop ufw

2.負載均衡管理ipvsadm工具安裝與核心載入

步驟 01.安裝ipvs模組以及負載均衡相關依賴。

# 檢視可用版本
sudo apt-cache madison ipvsadm
  # ipvsadm |   1:1.31-1 | http://mirrors.aliyun.com/ubuntu focal/main amd64 Packages

# 安裝
sudo apt -y install ipvsadm ipset sysstat conntrack

# 鎖定版本 
apt-mark hold ipvsadm
  # ipvsadm set on hold.

步驟 02.將模組載入到核心中(開機自動設定-需要重啟機器生效)

tee /etc/modules-load.d/k8s-.conf <<'EOF'
# netfilter
br_netfilter

# containerd
overlay

# nf_conntrack
nf_conntrack

# ipvs
ip_vs
ip_vs_lc
ip_vs_lblc
ip_vs_lblcr
ip_vs_rr
ip_vs_wrr
ip_vs_sh
ip_vs_dh
ip_vs_fo
ip_vs_nq
ip_vs_sed
ip_vs_ftp
ip_tables
ip_set
ipt_set
ipt_rpfilter
ipt_REJECT
ipip
xt_set
EOF

步驟 03.手動載入模組到Linux核心中。

mkdir -vp /etc/modules.d/
tee /etc/modules.d/k8s-ipvs.modules <<'EOF'
#!/bin/bash
# netfilter 模組 允許 iptables 檢查橋接流量
modprobe -- br_netfilter
# containerd
modprobe -- overlay
# nf_conntrack
modprobe -- nf_conntrack
# ipvs
modprobe -- ip_vs
modprobe -- ip_vs_lc
modprobe -- ip_vs_lblc
modprobe -- ip_vs_lblcr
modprobe -- ip_vs_rr
modprobe -- ip_vs_wrr
modprobe -- ip_vs_sh
modprobe -- ip_vs_dh
modprobe -- ip_vs_fo
modprobe -- ip_vs_nq
modprobe -- ip_vs_sed
modprobe -- ip_vs_ftp
modprobe -- ip_tables
modprobe -- ip_set
modprobe -- ipt_set
modprobe -- ipt_rpfilter
modprobe -- ipt_REJECT
modprobe -- ipip
modprobe -- xt_set
EOF

# 許可權設定、並載入到系統之中
chmod 755 /etc/modules.d/k8s-ipvs.modules && bash /etc/modules.d/k8s-ipvs.modules && lsmod | grep -e ip_vs -e nf_conntrack
  # ip_vs_sh               16384  0
  # ip_vs_wrr              16384  0
  # ip_vs_rr               16384  0
  # ip_vs                 155648  6 ip_vs_rr,ip_vs_sh,ip_vs_wrr
  # nf_conntrack          139264  1 ip_vs
  # nf_defrag_ipv6         24576  2 nf_conntrack,ip_vs
  # nf_defrag_ipv4         16384  1 nf_conntrack
  # libcrc32c              16384  5 nf_conntrack,btrfs,xfs,raid456,ip_vs

sysctl --system

溫馨提示: 在 kernel 4.19 版本及以上將使用 nf_conntrack 模組, 則在 4.18 版本以下則需使用nf_conntrack_ipv4 模組。


3.高可用HAProxy與Keepalived軟體安裝設定

描述: 由於是測試學習環境, 此處我未專門準備兩臺HA伺服器, 而是直接採用master節點機器,如果是正式環境建議獨立出來。

步驟 01.【Master節點機器】安裝下載 haproxy (HA代理健康檢測) 與 keepalived (虛擬路由協定-主從)。

# 檢視可用版本
sudo apt-cache madison haproxy keepalived
  #  haproxy | 2.0.13-2ubuntu0.5 | http://mirrors.aliyun.com/ubuntu focal-security/main amd64 Packages
  # keepalived | 1:2.0.19-2ubuntu0.2 | http://mirrors.aliyun.com/ubuntu focal-updates/main amd64 Packages

# 安裝
sudo apt -y install haproxy keepalived

# 鎖定版本 
apt-mark hold haproxy keepalived

步驟 02.【Master節點機器】進行 HAProxy 設定,其設定目錄為 /etc/haproxy/,所有節點設定是一致的。

sudo cp /etc/haproxy/haproxy.cfg{,.bak}
tee /etc/haproxy/haproxy.cfg<<'EOF'
global
  user haproxy
  group haproxy
  maxconn 2000
  daemon
  log /dev/log local0
  log /dev/log local1 err
  chroot /var/lib/haproxy
  stats socket /run/haproxy/admin.sock mode 660 level admin expose-fd listeners
  stats timeout 30s
  # Default SSL material locations
  ca-base /etc/ssl/certs
  crt-base /etc/ssl/private
  # See: https://ssl-config.mozilla.org/#server=haproxy&server-version=2.0.3&config=intermediate
  ssl-default-bind-ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384
  ssl-default-bind-ciphersuites TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256
  ssl-default-bind-options ssl-min-ver TLSv1.2 no-tls-tickets

defaults
  log     global
  mode    http
  option  httplog
  option  dontlognull
  timeout connect 5000
  timeout client  50000
  timeout server  50000
  timeout http-request 15s
  timeout http-keep-alive 15s
  # errorfile 400 /etc/haproxy/errors/400.http
  # errorfile 403 /etc/haproxy/errors/403.http
  # errorfile 408 /etc/haproxy/errors/408.http
  # errorfile 500 /etc/haproxy/errors/500.http
  # errorfile 502 /etc/haproxy/errors/502.http
  # errorfile 503 /etc/haproxy/errors/503.http
  # errorfile 504 /etc/haproxy/errors/504.http

# 注意: 管理HAproxy (可選)
# frontend monitor-in
#   bind *:33305
#   mode http
#   option httplog
#   monitor-uri /monitor

# 注意: 基於四層代理, 1644 3為VIP的 ApiServer 控制平面埠, 由於是與master節點在一起所以不能使用6443埠.
frontend k8s-master
  bind 0.0.0.0:16443
  bind 127.0.0.1:16443
  mode tcp
  option tcplog
  tcp-request inspect-delay 5s
  default_backend k8s-master

# 注意: Master 節點的預設 Apiserver 是6443埠
backend k8s-master
  mode tcp
  option tcplog
  option tcp-check
  balance roundrobin
  default-server inter 10s downinter 5s rise 2 fall 2 slowstart 60s maxconn 250 maxqueue 256 weight 100
  server devtest-master-212 10.20.176.212:6443 check
  server devtest-master-213 10.20.176.213:6443 check
  server devtest-master-214 10.20.176.214:6443 check
EOF

步驟 03.【Master節點機器】進行 KeepAlived 相關設定 ,其設定目錄為 /etc/haproxy/

# 建立設定目錄,分別在各個master節點執行。
mkdir -vp /etc/keepalived
# __ROLE__ 角色: MASTER 或者 BACKUP
# __NETINTERFACE__ 宿主機物理網路卡名稱 例如我的ens32
# __IP__ 宿主機物理IP地址
# __VIP__ 虛擬VIP地址
sudo tee /etc/keepalived/keepalived.conf <<'EOF'
! Configuration File for keepalived
global_defs {
  router_id LVS_DEVEL
script_user root
  enable_script_security
}
vrrp_script chk_apiserver {
  script "/etc/keepalived/check_apiserver.sh"
  interval 5
  weight -5
  fall 2  
  rise 1
}
vrrp_instance VI_1 {
  state __ROLE__
  interface __NETINTERFACE__
  mcast_src_ip __IP__
  virtual_router_id 51
  priority 101
  advert_int 2
  authentication {
    auth_type PASS
    auth_pass K8SHA_KA_AUTH
  }
  virtual_ipaddress {
    __VIP__
  }
  # HA 健康檢查
  # track_script {
  #   chk_apiserver
  # }
}
EOF

# 此處將 devtest-master-212 設定為 Master (devtest-master-212 主機上執行)
# devtest-master-212 10.20.176.212 => MASTER
sed -i -e 's#__ROLE__#MASTER#g' \
  -e 's#__NETINTERFACE__#ens32#g' \
  -e 's#__IP__#10.20.176.212#g' \
  -e 's#__VIP__#10.20.176.211#g' /etc/keepalived/keepalived.conf 

# devtest-master-213 10.20.176.213 => BACKUP  (devtest-master-213 主機上執行)
sed -i -e 's#__ROLE__#BACKUP#g' \
  -e 's#__NETINTERFACE__#ens32#g' \
  -e 's#__IP__#10.20.176.213#g' \
  -e 's#__VIP__#10.20.176.211#g' /etc/keepalived/keepalived.conf 

# devtest-master-214 10.20.176.214 => BACKUP  (devtest-master-214 主機上執行)
sed -i -e 's#__ROLE__#BACKUP#g' \
  -e 's#__NETINTERFACE__#ens32#g' \
  -e 's#__IP__#10.20.176.214#g' \
  -e 's#__VIP__#10.20.176.211#g' /etc/keepalived/keepalived.conf 

溫馨提示: 注意上述的健康檢查是關閉註釋了的,你需要將K8S叢集建立完成後再開啟。

track_script {
  chk_apiserver
}

步驟 04.【Master節點機器】進行設定 KeepAlived 健康檢查檔案。

sudo tee /etc/keepalived/check_apiserver.sh <<'EOF'
#!/bin/bash
err=0
for k in $(seq 1 3)
do
  check_code=$(pgrep haproxy)
  if [[ $check_code == "" ]]; then
    err=$(expr $err + 1)
    sleep 1
    continue
  else
    err=0
    break
  fi
done

if [[ $err != "0" ]]; then
  echo "systemctl stop keepalived"
  /usr/bin/systemctl stop keepalived
  exit 1
else
  exit 0
fi
EOF
sudo chmod +x /etc/keepalived/check_apiserver.sh

步驟 05.【Master節點機器】啟動 haproxy 、keepalived 相關服務及測試VIP漂移。

# 過載 Systemd 設定 haproxy 、keepalived 開機自啟以及立即啟動
sudo systemctl daemon-reload
sudo systemctl enable --now haproxy && sudo systemctl enable --now keepalived
  # Synchronizing state of haproxy.service with SysV service script with /lib/systemd/systemd-sysv-install.
  # Executing: /lib/systemd/systemd-sysv-install enable haproxy
  # Synchronizing state of keepalived.service with SysV service script with /lib/systemd/systemd-sysv-install.
  # Executing: /lib/systemd/systemd-sysv-install enable keepalived

# 在 devtest-master-212 主機中發現vip地址在其主機上。
root@devtest-master-212:~$ ip addr
  # 2: ens32: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
  #   link/ether 00:50:56:8a:57:69 brd ff:ff:ff:ff:ff:ff
  #   inet 10.20.176.212/24 brd 10.20.176.255 scope global ens32
  #       valid_lft forever preferred_lft forever
  #   inet 10.20.176.211/24 scope global ens32
  #       valid_lft forever preferred_lft forever
  #   inet6 fe80::250:56ff:fe8a:5769/64 scope link
  #       valid_lft forever preferred_lft forever

# 其它兩臺Master主機上通訊驗證。
root@devtest-master-213:~$ ping 10.20.176.211
  # PING 10.20.176.211 (10.20.176.211) 56(84) bytes of data.
  # 64 bytes from 10.20.176.211: icmp_seq=1 ttl=64 time=0.161 ms
root@devtest-master-214:~$ ping 10.20.176.211

然後我們可以手動驗證VIP漂移,我們將該伺服器上keepalived停止掉。

root@devtest-master-212:~$ pgrep haproxy
  # 6120
  # 6121
root@devtest-master-212:~$ /usr/bin/systemctl stop keepalived

# 此時,發現VIP已經飄到devtest-master-212主機中
root@devtest-master-215:~$ ip addr show ens32
  # 2: ens32: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
  #     link/ether 00:0c:29:93:28:61 brd ff:ff:ff:ff:ff:ff
  #     inet10.20.176.215/24 brd 10.10.107.255 scope global ens32
  #       valid_lft forever preferred_lft forever
  #     inet 10.20.176.211/32 scope global ens32
  #       valid_lft forever preferred_lft forever

至此,HAProxy 與 Keepalived 設定就告一段落了。


4.容器執行時containerd.io安裝設定

步驟 01.分別在master與work節點上安裝containerd。

# 1.解除安裝舊版本 
sudo apt-get remove docker docker-engine docker.io containerd runc

# 2.更新apt包索引並安裝包以允許apt在HTTPS上使用儲存庫
sudo apt-get install -y \
  apt-transport-https \
  ca-certificates \
  curl \
  gnupg-agent \
  software-properties-common

# 3.新增Docker官方GPG金鑰 # -fsSL
curl https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -

# 4.通過搜尋指紋的最後8個字元進行金鑰驗證
sudo apt-key fingerprint 0EBFCD88

# 5.設定穩定儲存庫
sudo add-apt-repository \
  "deb [arch=amd64] https://download.docker.com/linux/ubuntu \
  $(lsb_release -cs) \
  stable"

# 6.安裝特定版本在repo中列出可用的版本
sudo apt-cache madison containerd.io
  # containerd.io |    1.6.6-1 | https://download.docker.com/linux/ubuntu focal/stable amd64 Packages
  # containerd.io |    1.6.4-1 | https://download.docker.com/linux/ubuntu focal/stable amd64 Packages
  # containerd.io |   1.5.11-1 | https://download.docker.com/linux/ubuntu focal/stable amd64 Packages

# 7.使用第二列中的版本字串安裝特定的版本,例如: 1.6.6-1
sudo apt-get install containerd.io=1.6.6-1
# 離線安裝: apt install -y ./containerd.io_1.6.6-1_amd64.deb

步驟 02.下載安裝後在【所有節點】進行containerd 設定,此處將建立並修改 config.toml 檔案.

# 為 containerd 生成預設設定
mkdir -vp /etc/containerd
containerd config default >/etc/containerd/config.toml
ls /etc/containerd/config.toml
  # /etc/containerd/config.toml

# pause 映象源
sed -i "s#k8s.gcr.io/pause#registry.cn-hangzhou.aliyuncs.com/google_containers/pause#g"  /etc/containerd/config.toml

# 使用 SystemdCgroup
sed -i 's#SystemdCgroup = false#SystemdCgroup = true#g' /etc/containerd/config.toml

# docker.io mirror
sed -i '/registry.mirrors]/a\ \ \ \ \ \ \ \ [plugins."io.containerd.grpc.v1.cri".registry.mirrors."docker.io"]' /etc/containerd/config.toml
sed -i '/registry.mirrors."docker.io"]/a\ \ \ \ \ \ \ \ \ \ endpoint = ["https://05f073ad3c0010ea0f4bc00b7105ec20.mirror.swr.myhuaweicloud.com","https://xlx9erfu.mirror.aliyuncs.com","https://docker.mirrors.ustc.edu.cn"]' /etc/containerd/config.toml

# gcr.io mirror
sed -i '/registry.mirrors]/a\ \ \ \ \ \ \ \ [plugins."io.containerd.grpc.v1.cri".registry.mirrors."gcr.io"]' /etc/containerd/config.toml
sed -i '/registry.mirrors."gcr.io"]/a\ \ \ \ \ \ \ \ \ \ endpoint = ["https://gcr.mirrors.ustc.edu.cn"]' /etc/containerd/config.toml

# k8s.gcr.io mirror
sed -i '/registry.mirrors]/a\ \ \ \ \ \ \ \ [plugins."io.containerd.grpc.v1.cri".registry.mirrors."k8s.gcr.io"]' /etc/containerd/config.toml
sed -i '/registry.mirrors."k8s.gcr.io"]/a\ \ \ \ \ \ \ \ \ \ endpoint = ["https://gcr.mirrors.ustc.edu.cn/google-containers/","https://registry.cn-hangzhou.aliyuncs.com/google_containers/"]' /etc/containerd/config.toml

# quay.io mirror
sed -i '/registry.mirrors]/a\ \ \ \ \ \ \ \ [plugins."io.containerd.grpc.v1.cri".registry.mirrors."quay.io"]' /etc/containerd/config.toml
sed -i '/registry.mirrors."quay.io"]/a\ \ \ \ \ \ \ \ \ \ endpoint = ["https://quay.mirrors.ustc.edu.cn"]' /etc/containerd/config.toml

步驟 03.修改設定後【所有節點】過載containerd服務並檢視相關服務及其版本。

# 設定過載與服務重啟
systemctl daemon-reload && systemctl restart containerd.service
systemctl status -l containerd.service
  # ● containerd.service - containerd container runtime
  #    Loaded: loaded (/lib/systemd/system/containerd.service; enabled; vendor preset: enabled)
  #    Active: active (running) since Thu 2022-06-16 05:22:50 UTC; 5 days ago
  #      Docs: https://containerd.io
  #  Main PID: 790 (containerd)
  #     Tasks: 51
  #    Memory: 76.3M
  #    CGroup: /system.slice/containerd.service
  #            ├─ 790 /usr/bin/containerd

# 使用者端版本檢視
root@devtest-master-212:/var/cache/apt/archives# ctr version
# Client:
#   Version:  1.6.6
#   Revision: 10c12954828e7c7c9b6e0ea9b0c02b01407d3ae1
#   Go version: go1.17.11
# Server:
#   Version:  1.6.6
#   Revision: 10c12954828e7c7c9b6e0ea9b0c02b01407d3ae1
#   UUID: 71a28bbb-6ed6-408d-a873-e394d48b35d8

root@devtest-master-212:/var/cache/apt/archives# runc -v
  # runc version 1.1.2
  # commit: v1.1.2-0-ga916309
  # spec: 1.0.2-dev
  # go: go1.17.11
  # libseccomp: 2.5.1

5.安裝源設定與初始化叢集設定準備

步驟 01.【所有節點】Kubernetes 安裝源設定及其kubelet、kubeadm、kubectl工具下載安裝

# (1) gpg 簽名下載匯入
curl https://mirrors.aliyun.com/kubernetes/apt/doc/apt-key.gpg | sudo apt-key add -

# (2) Kubernetes 安裝源
cat <<EOF | sudo tee /etc/apt/sources.list.d/kubernetes.list 
deb https://mirrors.aliyun.com/kubernetes/apt/ kubernetes-xenial main
EOF
apt update
# 其它方式:
# (2) 設定穩定儲存庫
# sudo add-apt-repository "deb https://mirrors.aliyun.com/kubernetes/apt/ kubernetes-xenial main"

# (3) K8S可用版本,此處可以看見最新的是 1.24.1 , 由於博主實踐的K8S是為開發測試環境所搭建,則此處選擇 1.23.7 版本。
apt-cache madison kubelet | more
  kubelet |  1.24.1-00 | https://mirrors.aliyun.com/kubernetes/apt kubernetes-xenial/main amd64 Packages
  kubelet |  1.24.0-00 | https://mirrors.aliyun.com/kubernetes/apt kubernetes-xenial/main amd64 Packages
  kubelet |  1.23.7-00 | https://mirrors.aliyun.com/kubernetes/apt kubernetes-xenial/main amd64 Packages

# (4) 下載安裝指定版本的kubelet、kubeadm、kubectl
K8S_VERSION="1.23.7-00"
sudo apt install kubelet=${K8S_VERSION} kubeadm=${K8S_VERSION} kubectl=${K8S_VERSION}

步驟 02.【所有節點】過載systemd守護行程並將 kubelet 設定成開機啟動

systemctl daemon-reload
systemctl restart containerd.service
systemctl enable kubelet && systemctl start kubelet

步驟 03.【devtest-master-212】為了節約拉取實踐我們可以在某一臺master節點上先拉取所K8S叢集所需要的映象。

# 列出所需映象
kubeadm config images list --kubernetes-version=1.23.7
  # k8s.gcr.io/kube-apiserver:v1.23.7
  # k8s.gcr.io/kube-controller-manager:v1.23.7
  # k8s.gcr.io/kube-scheduler:v1.23.7
  # k8s.gcr.io/kube-proxy:v1.23.7
  # k8s.gcr.io/pause:3.6
  # k8s.gcr.io/etcd:3.5.1-0
  # k8s.gcr.io/coredns/coredns:v1.8.6

# 使用阿里提供的映象源進行拉取v1.23.7版本依賴的相關映象
for i in $(kubeadm config images list --kubernetes-version=1.23.7 --image-repository registry.cn-hangzhou.aliyuncs.com/google_containers -v 5);do
  ctr -n k8s.io images pull ${i}
done
  # registry.cn-hangzhou.aliyuncs.com/google_containers/kube-apiserver:v1.23.7
  # registry.cn-hangzhou.aliyuncs.com/google_containers/kube-controller-manager:v1.23.7
  # registry.cn-hangzhou.aliyuncs.com/google_containers/kube-scheduler:v1.23.7
  # registry.cn-hangzhou.aliyuncs.com/google_containers/kube-proxy:v1.23.7
  # registry.cn-hangzhou.aliyuncs.com/google_containers/pause:3.6
  # registry.cn-hangzhou.aliyuncs.com/google_containers/etcd:3.5.1-0
  # registry.cn-hangzhou.aliyuncs.com/google_containers/coredns:v1.8.6

# 從 container.io 中的映象匯出本地
for images in $(ctr -n k8s.io i ls name~=registry.cn-hangzhou.aliyuncs.com/google_containers -q);do
  temp_name=${images##*/} 
  tar_name=$(echo $temp_name |  tr ':' '_')
  echo "export ${images} >> $tar_name.tar"
  ctr -n k8s.io images export ${tar_name}.tar ${images}
done

# 從本地匯入映象到 container.io 中
for tarfile in $(ls);do
    $ ctr images import --base-name foo/bar foobar.tar
  ctr -n k8s.io images export ${tar_name}.tar ${images}
done

步驟 04.匯入到各個節點後我們可以通過如下命令檢視匯入的映象列表資訊。

# 方式1
ctr -n k8s.io i ls name~=registry.cn-hangzhou.aliyuncs.com/google_container

# 方式2
crictl images | grep "registry.cn-hangzhou.aliyuncs.com/google"
registry.cn-hangzhou.aliyuncs.com/google-containers/pause-amd64               3.0                 99e59f495ffaa       314kB
registry.cn-hangzhou.aliyuncs.com/google_containers/coredns                   v1.8.6              a4ca41631cc7a       13.6MB
registry.cn-hangzhou.aliyuncs.com/google_containers/etcd                      3.5.1-0             25f8c7f3da61c       98.9MB
registry.cn-hangzhou.aliyuncs.com/google_containers/kube-apiserver            v1.23.7             03c169f383d97       32.6MB
registry.cn-hangzhou.aliyuncs.com/google_containers/kube-controller-manager   v1.23.7             e34d4a6252edd       30.2MB
registry.cn-hangzhou.aliyuncs.com/google_containers/kube-proxy                v1.23.7             b1aa05aa5100e       39.3MB
registry.cn-hangzhou.aliyuncs.com/google_containers/kube-scheduler            v1.23.7             ed0ccfa052ab4       15.1MB
registry.cn-hangzhou.aliyuncs.com/google_containers/pause                     3.6                 6270bb605e12e       302kB

6.使用kubeadm安裝部署K8S叢集

步驟 01.【devtest-master-212 節點】生成K8S初始化yaml組態檔,並根據實際情況進行編輯。

$ kubeadm config print init-defaults > kubeadm-init-default.yaml
$ vim kubeadm-init-default.yaml

# 此處為v1.23.x 適用的叢集初始化設定清單
tee kubeadm-init-cluster.yaml <<'EOF'
apiVersion: kubeadm.k8s.io/v1beta3
bootstrapTokens:
- groups:
  - system:bootstrappers:kubeadm:default-node-token
  token: devtes.httpweiyigeektop
  ttl: 24h0m0s
  usages:
  - signing
  - authentication
kind: InitConfiguration
localAPIEndpoint:
  advertiseAddress: 10.20.176.212   # 關鍵點: 當前節點地址
  bindPort: 6443                    # 關鍵點: API埠預設即可
nodeRegistration:
  criSocket: /run/containerd/containerd.sock  # 關鍵點: 指定containerd為執行時
  imagePullPolicy: IfNotPresent
  name: devtest-master-212          # 關鍵點: 當前節點名稱
  taints:
  - effect: NoSchedule
    key: node-role.kubernetes.io/master
---
apiServer:
  certSANs:                         # 關鍵點: 證書中心包含的SANs列表一般包含VIP與各節點的主機名稱
  - slbvip.k8s.devtest
  - localhost
  - devtest-master-212
  - devtest-master-213
  - devtest-master-214
  - 10.20.176.211
  - 10.20.176.212
  - 10.20.176.213
  - 10.20.176.214
  - 10.66.66.2
  timeoutForControlPlane: 4m0s
apiVersion: kubeadm.k8s.io/v1beta3
certificatesDir: /etc/kubernetes/pki
clusterName: kubernetes
controllerManager: {}
dns:
  type: CoreDNS
etcd:
  local:
    dataDir: /var/lib/etcd
imageRepository: registry.cn-hangzhou.aliyuncs.com/google_containers  # 關鍵點: 叢集所需映象倉庫源加快拉取
kind: ClusterConfiguration
kubernetesVersion: v1.23.7                      # 關鍵點: K8S叢集版本此處與我們提前下載的映象版本必須一致否則將會重新拉取指定K8S叢集所需映象。
controlPlaneEndpoint: slbvip.k8s.devtest:16443  # 關鍵點: 高可用VIP地址的域名與haproxy代理埠。
networking:
  dnsDomain: cluster.test                       # 關鍵點: 叢集dns根域預設cluster.local
  serviceSubnet: 10.96.0.0/12                   # 關鍵點: services 服務子網段
  podSubnet: 10.66.0.0/16                       # 關鍵點: pod 服務子網段
scheduler: {}
---
apiVersion: kubeproxy.config.k8s.io/v1alpha1
kind: KubeProxyConfiguration
mode: ipvs                                      # 關鍵點: 啟用IPVS支援
ipvs:
  excludeCIDRs:
  - 10.66.66.2/32                               # 關鍵點: 排出指定IP
EOF

步驟 02.【devtest-master-212 節點】準備好初始化yaml清單後, 通過 kubeadm init 命令進行叢集的初始化,並將紀錄檔輸入到kubeadm-init.log。

kubeadm init --config=kubeadm-init-cluster.yaml --v=5 | tee kubeadm-init.log
# --config 指定yaml組態檔
# --v 指定紀錄檔等級 debug

# 當執行後出現如下提示表明節點初始化安裝成功,可以按照指定提示進行執行。
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

# Alternatively, if you are the root user, you can run:
  export KUBECONFIG=/etc/kubernetes/admin.conf

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

# 【控制節點加入命令】
# You can now join any number of control-plane nodes by copying certificate authorities and service account keys on each node and then running the following as root:
  kubeadm join slbvip.k8s.devtest:16443 --token devtes.httpweiyigeektop \
        --discovery-token-ca-cert-hash sha256:4e5b3acb1d821bbd3976355f7b12b1daaa44e1fc38cbdfb2f86f4078d9507f22 \
        --control-plane

# 【工作節點加入命令】
# Then you can join any number of worker nodes by running the following on each as root:
kubeadm join slbvip.k8s.devtest:16443 --token devtes.httpweiyigeektop \
        --discovery-token-ca-cert-hash sha256:4e5b3acb1d821bbd3976355f7b12b1daaa44e1fc38cbdfb2f86f4078d9507f22

步驟 03.將【devtest-master-212】節點中/etc/kubernetes/目錄中的如下檔案進行復制打包,並通過http協定將其分享給其它機器進行下載

# 將ca證書拷貝到指定目錄
mkdir -vp /tmp/pki/etcd && cp /etc/kubernetes/pki/ca.* /etc/kubernetes/pki/sa.* /etc/kubernetes/pki/front-proxy-ca.* /tmp/pki
cp /etc/kubernetes/pki/etcd/ca.* /tmp/pki/etcd/

# 壓縮依賴依賴的ca證書目錄
tar -zcvf pki.tar.gz pki/

# 使用 python 搭建一個臨時 http 服務
python3 -m http.server 8080

# 在其它【節點】進入到/tmp/執行如下命令進行下載
cd /tmp/ && wget 10.20.176.212:8080/pki.tar.gz
tar -zxvf /tmp/pki.tar.gz -C /etc/kubernetes/

# 檢視解壓後的複製到/etc/kubernetes/目錄中的檔案相關結構。
tree /etc/kubernetes/
/etc/kubernetes/
└── pki
    ├── ca.crt
    ├── ca.key
    ├── etcd
    │   ├── ca.crt
    │   └── ca.key
    ├── front-proxy-ca.crt
    ├── front-proxy-ca.key
    ├── sa.key
    └── sa.pub
2 directories, 8 files

步驟 04.在其餘【master】節點中執行如下 kubeadm join 命令新增新的 Master 節點到K8S叢集控制面板中, 加入成功後如下圖所示:

kubeadm join slbvip.k8s.devtest:16443 \
--control-plane \
--token devtes.httpweiyigeektop \
--discovery-token-ca-cert-hash sha256:4e5b3acb1d821bbd3976355f7b12b1daaa44e1fc38cbdfb2f86f4078d9507f22 \
--cri-socket /run/containerd/containerd.sock

溫馨提示: 在v1.23.x如果要使用containerd執行時必須--cri-socket指定其執行時socket。


步驟 05.在其餘【work】節點中執行如下 kubeadm join 命令新增新的 Work 節點到K8S叢集中, 加入成功後如下圖所示:

kubeadm join slbvip.k8s.devtest:16443 \
  --token devtes.httpweiyigeektop \
  --discovery-token-ca-cert-hash sha256:4e5b3acb1d821bbd3976355f7b12b1daaa44e1fc38cbdfb2f86f4078d9507f22 \
  --cri-socket /run/containerd/containerd.sock


步驟 06.全部加入到叢集後我們可以通過如下命令進行檢視新增的節點以及其節點角色設定,最終執行結果如下圖所示。

# 叢集節點檢視
root@devtest-master-212:~$ kubectl get node
  # NAME                 STATUS   ROLES                  AGE     VERSION
  # devtest-master-212   Ready    control-plane,master   15m     v1.23.7
  # devtest-master-213   Ready    control-plane,master   5m19s   v1.23.7
  # devtest-master-214   Ready    control-plane,master   2m7s    v1.23.7
  # devtest-work-215     Ready    <none>                 14m     v1.23.7

# 叢集節點角色設定,此處將devtest-work-215節點的ROLES設定為 work。
root@devtest-master-212:~$ kubectl label node devtest-work-215 node-role.kubernetes.io/work=
  # node/devtest-work-215 labeled


步驟 07.檢視叢集資訊、叢集元件、以及叢集中所有Pod進行檢視, 執行結果如下

root@devtest-master-212:~# kubectl cluster-info
  Kubernetes control plane is running at https://slbvip.k8s.devtest:16443
  CoreDNS is running at https://slbvip.k8s.devtest:16443/api/v1/namespaces/kube-system/services/kube-dns:dns/proxy
  To further debug and diagnose cluster problems, use 'kubectl cluster-info dump'.

root@devtest-master-212:~# kubectl get cs
  Warning: v1 ComponentStatus is deprecated in v1.19+
  NAME                 STATUS    MESSAGE                         ERROR
  scheduler            Healthy   ok
  controller-manager   Healthy   ok
  etcd-0               Healthy   {"health":"true","reason":""}

root@devtest-master-212:~# kubectl get pod -A


步驟 08.開啟所有【master】中keepalived的健康檢查,並重啟keepalived.service服務

vim /etc/keepalived/keepalived.conf
...
# 開啟 HA 健康檢查,例如
  track_script {
    chk_apiserver
  }
  
systemctl restart keepalived.service

步驟 09.然後我們為kubectl新增命令自動補齊不全功能,執行如下程式碼即可。

apt install -y bash-completion
source /usr/share/bash-completion/bash_completion
source <(kubectl completion bash)
echo "source <(kubectl completion bash)" >> ~/.bashrc

步驟 10.最後我們可以部署一個nginx的Pod驗證叢集環境, 並通過curl進行存取,但是此時你會發現只有在【devtest-work-215】主機上才能存取該nginx,而其它節點存取時會報Connection timed out, 其原因可看下面的溫馨提示。

kubectl run nginx --image nginx:latest --port=80
  pod/nginx created

kubectl get pod -o wide
  NAME    READY   STATUS    RESTARTS   AGE   IP          NODE               NOMINATED NODE   READINESS GATES
  nginx   1/1     Running   0          68s   10.22.0.5   devtest-work-215   <none>           <none>

curl -I http://10.22.0.5
  curl: (28) Failed to connect to 10.22.0.5 port 80: Connection timed out

溫馨提示: 這是由於我們沒有為叢集設定網路外掛,而常用的網路外掛是flannel、calico(下面將會以此為例)以及當下cilium。


步驟 11.特別注意此處為了能在後續演示中將Pod應用排程到Master節點上,此時我們需要分別去除控制節點的汙點。

kubectl taint node devtest-master-212 node-role.kubernetes.io/master=:NoSchedule-
  # node/devtest-master-212 untainted

kubectl taint node devtest-master-213 node-role.kubernetes.io/master=:NoSchedule-
  # node/devtest-master-213 untainted

kubectl taint node devtest-master-214 node-role.kubernetes.io/master=:NoSchedule-
  # node/devtest-master-214 untainted


7.部署設定 Calico 網路外掛

描述: 在節點加入到叢集時有時你會發現其節點狀態為 NotReady, 以及前面部署Pod無法被其它節點機器進行代理轉發存取,所以部署calico外掛可以讓Pod與叢集正常通訊。

步驟 01.在【devtest-master-212】節點上拉取最新版本的 calico 當前最新版本為 v3.22, 官方專案地址 (https://github.com/projectcalico/calico)

# 拉取 calico 部署清單
wget https://docs.projectcalico.org/v3.22/manifests/calico.yaml

步驟 02.修改 calico.yaml 檔案的中如下 K/V, 即 Pod 獲取IP地址的地址池, 從網路規劃中我們設定為 10.66.0.0/16, 注意預設情況下如下欄位是註釋的且預設地址池為192.168.0.0/16

$ vim calico.yaml
# The default IPv4 pool to create on startup if none exists. Pod IPs will be
# chosen from this range. Changing this value after installation will have
# no effect. This should fall within `--cluster-cidr`.
- name: CALICO_IPV4POOL_CIDR
  value: "10.66.0.0/16"


步驟 03.執行 kubectl apply 命令部署 calico 到叢集之中。

kubectl apply -f calico.yaml
  # configmap/calico-config created
  # ....
  # poddisruptionbudget.policy/calico-kube-controllers created

步驟 04.檢視calico網路外掛在各節點上部署結果,狀態為Running表示部署成功。

kubectl get pod -n kube-system -o wide| head -n 6
  # NAME                                         READY   STATUS    RESTARTS        AGE     IP              NODE                 NOMINATED NODE   READINESS GATES
  # calico-kube-controllers-6b77fff45-w29rq      1/1     Running   0               8m5s    10.66.35.65     devtest-master-214   <none>           <none>
  # calico-node-7gxdc                            1/1     Running   0               8m5s    10.20.176.213   devtest-master-213   <none>           <none>
  # calico-node-tsk6w                            1/1     Running   0               8m5s    10.20.176.212   devtest-master-212   <none>           <none>
  # calico-node-vnkhg                            1/1     Running   0               8m5s    10.20.176.215   devtest-work-215     <none>           <none>
  # calico-node-xh2dw                            1/1     Running   0               8m5s    10.20.176.214   devtest-master-214   <none>           <none>


步驟 05.此時刪除 nginx 的 Pod 再重新建立一個Pod應用,並在非【devtest-work-215 】節點上進行存取測試

root@devtest-master-212:/opt/init/k8s# kubectl run nginx --image=nginx:latest --port=80
  # pod/nginx created

root@devtest-master-212:/opt/init/k8s# kubectl get pod nginx
  # NAME    READY   STATUS    RESTARTS   AGE
  # nginx   1/1     Running   0          10s

root@devtest-master-212:/opt/init/k8s# kubectl get pod nginx -o wide
  # NAME    READY   STATUS    RESTARTS   AGE   IP   NODE   NOMINATED NODE       READINESS GATES
  # nginx   1/1     Running   0          13s   10.66.53.66   devtest-work-215   <none>   <none>

root@devtest-master-212:/opt/init/k8s# curl -I 10.66.53.66
  # HTTP/1.1 200 OK
  # Server: nginx/1.21.5
  # Date: Wed, 15 Jun 2022 11:39:48 GMT
  # Content-Type: text/html
  # Content-Length: 615
  # Last-Modified: Tue, 28 Dec 2021 15:28:38 GMT
  # Connection: keep-alive
  # ETag: "61cb2d26-267"
  # Accept-Ranges: bytes

至此,高可用的K8S叢集部署完畢,在下節中將實踐演示在叢集中安裝 Metrics Server 、kubernetes-dashboard、nfs-provisioner、ingress 等安裝實踐。


0x03 叢集輔助外掛部署

1.叢集中基於nfs的provisioner的動態持卷環境部署

描述: 在K8S叢集中我們常常會使用動態持久卷對應用資料進行持久化儲存,例如應用設定、依賴外掛、應用資料以及應用存取紀錄檔等,所以動態持久卷的重要性不言而喻,此小節將講解如何搭建以及nfs儲存服務以及使用kubernetes-sigs提供的[nfs-subdir-external-provisioner] (https://github.com/kubernetes-sigs/nfs-subdir-external-provisioner)專案針對已存在的 nfs 伺服器進行 provisioner 部署。


Q: 什麼是nfs-subdir-external-provisioner?

NFS subdir external provisioner 是一個自動設定器,它使用您現有的和已設定的 NFS 伺服器來支援通過 Persistent Volume Claims 動態設定 Kubernetes Persistent Volumes。
持久卷設定為 ${namespace}-${pvcName}-${pvName}。

溫馨提示:在進行此環境搭建時,請注意您必須已經有設定好的 NFS 伺服器,為了保持與早期部署檔案的向後相容性,NFS Client Provisioner 的命名在部署 YAML 中保留為 nfs-storage-provisioner。

專案地址: https://github.com/kubernetes-sigs/nfs-subdir-external-provisioner


步驟 01.我在一臺Ubuntu 20.04主機上設定 NFS 儲存伺服器(IP地址為10.20.176.102),如果你已有儲存伺服器提供的NFS伺服器則可以略過此步驟,其它作業系統安裝部署請看出我的這篇部落格文章[NFS網路檔案系統基礎設定與使用] (https://blog.weiyigeek.top/2019/5-16-104.html)

# Step1.Install Required Packages(Server)
$ apt-get update
$ apt-get install nfs-kernel-server rpcbind

# Step2.Configure NFS Server
# [根據需求設定] 設定允許連線的ip, Example Allow 192.168.1.0/24 to be Accessed on Network
$ nano /etc/hosts.allow
portmap: 192.168.1.0/24   

# [根據需求設定] idmapd 設定, 此處設定埠為40000
$ nano /etc/default/nfs-common
NEED_IDMAPD=YES  
STATDOPTS="--port 40000"

# [根據需求設定] 核心服務設定,此處mountd伺服器埠為40001
$ nano /etc/default/nfs-kernel-server
RPCMOUNTDOPTS="--manage-gids --port 40001"

# NFS 伺服器共用路徑設定
$ nano /etc/exports
# Example for NFSv2 and NFSv3:
# /srv/homes       hostname1(rw,sync,no_subtree_check) hostname2(ro,sync,no_subtree_check)
# Example for NFSv4:
# /srv/nfs4        gss/krb5i(rw,sync,fsid=0,crossmnt,no_subtree_check)
# /srv/nfs4/homes  gss/krb5i(rw,sync,no_subtree_check)
/app/storage/nfs *(rw,sync,no_root_squash,no_subtree_check)

# Step3.建立NFS設定需要共用的目錄
mkdir -vp /app/storage/nfs

# Step4.自啟動RPC服務於nfs共用服務
systemctl enable rpcbind nfs-server.service
systemctl start rpcbind nfs-server.service

# Step5.更新nfs組態檔 (nano /etc/exports)
  exportfs -a

# Step6.Ubuntu防火牆規則設定 (PS: 通過rpcinfo命令可以檢視 NFS 相關的埠)
ufw allow 111,2049,40000,40001/tcp
ufw reload

步驟 02.【所有節點】在使用者端嘗試掛載搭建的NFS伺服器,並分別在節點機器掛載到/storage/nfs目錄中

# 檢視 NFS 掛載目錄
showmount -e 127.0.0.1
  # Export list for 127.0.0.1:
  # /app/storage/nfs *

# 掛載 NFS 伺服器到指定節點目錄的/storage/nfs目錄
mkdir -vp /storage/nfs
# 臨時掛載
mount -t nfs 10.20.176.102:/app/storage/nfs /storage/nfs
# 永久掛載將掛載設定寫入到/etc/fstab中
tee -a /etc/fstab <<"EOF"
10.20.176.102:/app/storage/nfs /storage/nfs nfs defaults 0 0
EOF
mount -a 

# 檢視掛載資訊
$ mount -l
$ df -Th | grep "/storage/nfs"
10.20.176.102:/app/storage/nfs nfs4   97G   11G   82G  12% /storage/nfs

# 如果不使用了則可執行如下命令進行解除安裝掛載點
umount /storage/nfs 


步驟 03.helm3 部署工具快速安裝

# helm3 安裝
$ wget https://get.helm.sh/helm-v3.9.0-linux-amd64.tar.gz && tar -zxf helm-v3.9.0-linux-amd64.tar.gz
$ tar -zxf helm-v3.9.0-linux-amd64.tar.gz
$ cp linux-amd64/helm /usr/local/bin/helm3



步驟 04.在Github中下載nfs-subdir-external-provisioner的release壓縮包或者使用helm3指定倉庫進行安裝。

  • 方式1.release 壓縮包
$ wget https://github.com/kubernetes-sigs/nfs-subdir-external-provisioner/releases/download/nfs-subdir-external-provisioner-4.0.16/nfs-subdir-external-provisioner-4.0.16.tgz
$ tar -zxvf nfs-subdir-external-provisioner-4.0.16.tgz
# 按照指定需求編輯如下values值
$ egrep -v '^$|#' values.yaml
replicaCount: 1
strategyType: Recreate
image:
  repository: registry.cn-hangzhou.aliyuncs.com/weiyigeek/nfs-subdir-external-provisioner
  tag: v4.0.2
  pullPolicy: IfNotPresent
imagePullSecrets: []
nfs:
  server: 10.20.176.102
  path: /app/storage/nfs
  mountOptions:
  volumeName: nfs-subdir-external-provisioner-root
  reclaimPolicy: Retain
storageClass:
  create: true
  provisionerName: cluster.local/nfs-storage-subdir-provisioner
  defaultClass: false
  name: nfs-storage
  allowVolumeExpansion: true
  reclaimPolicy: Delete
  archiveOnDelete: true
  onDelete:
  pathPattern:
  accessModes: ReadWriteOnce
  annotations: {}
leaderElection:
  enabled: true
rbac:
  create: true
podSecurityPolicy:
  enabled: false
podAnnotations: {}
podSecurityContext: {}
securityContext: {}
serviceAccount:
  create: true
  annotations: {}
  name:
resources: {}
nodeSelector: {}
tolerations: []
affinity: {}
labels: {}

# 指定下載解壓目錄進行chat圖表安裝
$ helm3 install nfs-storage nfs-subdir-external-provisioner/
  NAME: nfs-storage
  LAST DEPLOYED: Mon Jun 20 15:41:50 2022
  NAMESPACE: default
  STATUS: deployed
  REVISION: 1
  TEST SUITE: None
  • 方式2.helm3指定倉庫
$ helm repo add nfs-subdir-external-provisioner https://kubernetes-sigs.github.io/nfs-subdir-external-provisioner/
$ helm nfs-storage nfs-subdir-external-provisioner/nfs-subdir-external-provisioner \
  --set nfs.server=10.20.176.102 \
  --set nfs.path=/app/storage/nfs

# 更新
$ helm3 upgrade nfs-storage nfs-subdir-external-provisioner/

溫馨提示: 由於nfs-subdir-external-provisioner映象是k8s.gcr.io域名下國內可能無法拉取,此處我已經拉取到阿里雲映象倉庫中registry.cn-hangzhou.aliyuncs.com/weiyigeek/nfs-subdir-external-provisioner:v4.0.2,如果你需要自行拉取請參考此篇使用Aliyun容器映象服務對海外映象倉庫中映象進行拉取構建 ()


步驟 05.檢視部署的nfs-storage動態持久卷以及其pod狀態

$ helm3 list
  NAME            NAMESPACE       REVISION        UPDATED                                 STATUS          CHART                                    APP VERSION
  nfs-storage     default         1               2022-06-20 15:41:50.960642233 +0800 CST deployed        nfs-subdir-external-provisioner-4.0.16   4.0.2

$ kubectl get storageclasses.storage.k8s.io
  NAME          PROVISIONER                                    RECLAIMPOLICY   VOLUMEBINDINGMODE   ALLOWVOLUMEEXPANSION   AGE
  nfs-storage   cluster.local/nfs-storage-subdir-provisioner   Delete          Immediate           true                   17s

$ kubectl get pod
  NAME                                                           READY   STATUS    RESTARTS   AGE
  nfs-storage-nfs-subdir-external-provisioner-77f4d85f74-kljck   1/1     Running   0          33s

步驟 06.如想解除安裝helm3安裝的nfs-storage動態卷執行如下命令即可。

$ helm3 uninstall nfs-storage
release "nfs-storage" uninstalled

至此,基於NFS的provisioner 動態持久卷的安裝部署到此結束。

溫馨提示: 如果需要部署多個nfs持久卷, 則我們需要更改values.yaml中如下欄位,並使用不同的名稱。

# values.yaml
nfs:
  server: 10.20.176.102
  path: /app/storage/nfs/pvc/local
  volumeName: nfs-subdir-external-provisioner-local
  ....
storageClass:
  ....
  provisionerName: cluster.local/nfs-local-subdir-provision  # 關鍵點(提供者不能一樣)
  name: nfs-local

# 例如,此處建立兩個nfs動態卷即nfs-local與nfs-dev。
helm3 install nfs-local nfs-subdir-external-provisioner/
helm3 install nfs-dev nfs-subdir-external-provisioner-dev/

# helm 部署結果檢視
helm3 list
  # NAME            NAMESPACE       REVISION        UPDATED                                 STATUS          CHART                                   APP VERSION
  # nfs-dev         default         1               2022-07-14 11:27:33.997601363 +0800 CST deployed        nfs-subdir-external-provisioner-4.0.16  4.0.2
  # nfs-local       default         1               2022-07-14 11:28:02.49579496 +0800 CST  deployed        nfs-subdir-external-provisioner-4.0.16  4.0.2

# storageclasses 檢視
kubectl get storageclasses.storage.k8s.io
  # NAME                PROVISIONER                                  RECLAIMPOLICY   VOLUMEBINDINGMODE   ALLOWVOLUMEEXPANSION   AGE
  # nfs-dev (default)   cluster.local/nfs-dev-subdir-provisioner     Delete          Immediate           true                   4m36s
  # nfs-local           cluster.local/nfs-local-subdir-provisioner   Delete          Immediate           true                   4m8s

# nfs-subdir-external-provisioner pod 檢視
kubectl get pod
  # NAME                                                         READY   STATUS    RESTARTS   AGE
  # nfs-dev-nfs-subdir-external-provisioner-cf7684f8b-fzl9h      1/1     Running   0          5m4s
  # nfs-local-nfs-subdir-external-provisioner-6f97d44bb8-424tk   1/1     Running   0          4m36s

正常情況下顯示出的紀錄檔資訊:

$ kubectl logs -f nfs-dev-nfs-subdir-external-provisioner-cf7684f8b-fzl9h
  # I0714 03:27:35.390909       1 leaderelection.go:242] attempting to acquire leader lease  default/cluster.local-nfs-dev-subdir-provisioner...
  # I0714 03:27:35.400777       1 leaderelection.go:252] successfully acquired lease default/cluster.local-nfs-dev-subdir-provisioner
  # I0714 03:27:35.400856       1 event.go:278] Event(v1.ObjectReference{Kind:"Endpoints", Namespace:"default", Name:"cluster.local-nfs-dev-subdir-provisioner", UID:"34019115-d09e-433d-85d6-c254c5492ce5", APIVersion:"v1", ResourceVersion:"5510886", FieldPath:""}): type: 'Normal' reason: 'LeaderElection' nfs-dev-nfs-subdir-external-provisioner-cf7684f8b-fzl9h_b0aaa93a-f7fc-4931-b0cf-e04f42cefd9a became leader
  # I0714 03:27:35.400943       1 controller.go:820] Starting provisioner controller cluster.local/nfs-dev-subdir-provisioner_nfs-dev-nfs-subdir-external-provisioner-cf7684f8b-fzl9h_b0aaa93a-f7fc-4931-b0cf-e04f42cefd9a!
  # I0714 03:27:35.501130       1 controller.go:869] Started provisioner controller cluster.local/nfs-dev-subdir-provisioner_nfs-dev-nfs-subdir-external-provisioner-cf7684f8b-fzl9h_b0aaa93a-f7fc-4931-b0cf-e04f42cefd9a!

2.叢集中安裝metrics-server獲取使用者端資源監控指標

描述: 通常在叢集安裝完成後,我們需要對其設定網路、持久卷儲存等外掛, 除此之外我們還需安裝metrics-server以便於獲取Node與Pod相關資源消耗等資訊,否則你在執行kubectl top命令時會提示error: Metrics API not available, 所以本小節將針對Metrics-server的安裝進行講解。

專案地址: https://github.com/kubernetes-sigs/metrics-server

Q: 什麼是metrics-server?

Metrics Server 是 Kubernetes 內建自動縮放管道的可延伸、高效的容器資源指標來源。
Metrics Server 從 Kubelets 收集資源指標,並通過 Metrics API 在 Kubernetes apiserver 中公開它們,供 Horizontal Pod Autoscaler 和 Vertical Pod Autoscaler 使用。

簡單的說: Metrics Server 是叢集解析監控資料的聚合器,安裝後用戶可以通過標準的API(/apis/metrics.k8s.io)來存取監控資料,此處值得注意的是Metrics-Server並非kube-apiserver的一部分,而是通過Aggregator這種外掛機制,在獨立部署的情況下同kube-apiserver一起統一對外服務的,當進行api請求時kube-aggregator統一介面會分析存取api具體的型別,幫我們負載到具體的api上。

溫馨提示: 我們可以通過 kubectl top 命令來存取 Metrics API 獲取資源監控相關資料。

溫馨提示: 注意 Metrics API 只可以查詢當前度量資料,並不儲存歷史資料。


安裝使用

步驟 01.Metrics Server 可以直接從 YAML 清單安裝,也可以通過官方 Helm 圖表安裝。

# (1) 下載 YAML 清單
wget https://github.com/kubernetes-sigs/metrics-server/releases/latest/download/components.yaml -O metrics-server.yaml
root@devtest-master-212:/opt/init/k8s# ls
  calico.yaml   kubeadm-init-cluster.yaml  kubeadm-init.log  metrics-server.yaml

# (2) 提前下載相應的映象加快部署
grep "image:" metrics-server.yaml
  # image: k8s.gcr.io/metrics-server/metrics-server:v0.6.1

# (3) 由於其映象國內無法存取此處我們採用阿里雲k8s.gcr.io映象源
sed -i 's#k8s.gcr.io/metrics-server#registry.cn-hangzhou.aliyuncs.com/google_containers#g' metrics-server.yaml

# (4) 部署資源清單
kubectl apply -f metrics-server.yaml
  # serviceaccount/metrics-server created
  ......
  # apiservice.apiregistration.k8s.io/v1beta1.metrics.k8s.io created

步驟 02.不論是在二進位制方式或kubeadm方式安裝k8s叢集, 都在部署 metrics-server 資源清單後 Pod 狀態為 0/1 並報出annot validate certificate for 10.10.107.223 because it doesn't contain any IP SANs錯誤問題解決。

  • 錯誤資訊:
$ kubectl describe pod -n kube-system metrics-server-6ffc8966f5-cf2qh
# Warning  Unhealthy  8s (x17 over 2m27s)  kubelet  Readiness probe failed: HTTP probe failed with statuscode: 500

$ kubectl logs -f --tail 50 -n kube-system metrics-server-6ffc8966f5-cf2qh
# E0520 11:13:17.379944       1 scraper.go:140] "Failed to scrape node" err="Get \"https://10.10.107.226:10250/metrics/resource\": x509: cannot validate certificate for 10.10.107.226 because it doesn't contain any IP SANs" node="node-1"
# E0520 11:13:17.382948       1 scraper.go:140] "Failed to scrape node" err="Get \"https://10.10.107.223:10250/metrics/resource\": x509: cannot validate certificate for 10.10.107.223 because it doesn't contain any IP SANs" node="master-223"
  • 問題原因: 由於 metrics-server 未獲得TLS Bootstrap 簽發證書的導致存取各節點資源時報錯。

  • 解決辦法: 啟用 TLS BootStrap 證書籤發

# 1.分別在 Master 與 Node 節點中啟用TLS BootStrap 證書籤發,在 kubelet 的 yaml 設定中追加入如下K/V.
# 方式1.Kubeadm 搭建的叢集
$ vim /var/lib/kubelet/config.yaml
...
serverTLSBootstrap: true

# 方式2.二進位制搭建的叢集(注意此路徑根據你的kubelet.service進行設定), 此處我們定義的路徑為 /etc/kubernetes/cfg/kubelet-config.yaml 
# /var/lib/kubelet/config.yaml
$ tee -a /etc/kubernetes/cfg/kubelet-config.yaml <<'EOF'
serverTLSBootstrap: true
EOF

# kubeadm 安裝方式可以使用如下
tee -a /var/lib/kubelet/config.yaml <<'EOF'
serverTLSBootstrap: true
EOF

# 2.最後分別重啟各個節點kubelet服務即可
systemctl daemon-reload && systemctl restart kubelet.service

# 3.檢視節點的證書籤發請求
kubectl get csr
  # NAME        AGE   SIGNERNAME                      REQUESTOR                        REQUESTEDDURATION   CONDITION
  # csr-6w6xp   7s    kubernetes.io/kubelet-serving   system:node:devtest-master-212   <none>              Pending
  # csr-bpqzl   5s    kubernetes.io/kubelet-serving   system:node:devtest-master-213   <none>              Pending
  # csr-gtksm   3s    kubernetes.io/kubelet-serving   system:node:devtest-work-215     <none>              Pending
  # csr-vzfs7   4s    kubernetes.io/kubelet-serving   system:node:devtest-master-214   <none>              Pending

# 4.同意簽發所有節點的CSR請求 
kubectl certificate approve $(kubectl get csr | grep -v NAME | grep "Pending"  | cut -d " " -f 1)
  # certificatesigningrequest.certificates.k8s.io/csr-6w6xp approved
  # certificatesigningrequest.certificates.k8s.io/csr-bpqzl approved
  # certificatesigningrequest.certificates.k8s.io/csr-gtksm approved
  # certificatesigningrequest.certificates.k8s.io/csr-vzfs7 approved


步驟 03.Metrics Server 預設是安裝在kube-system名稱空間下,我們可以檢視其deployment、Pod執行以及SVC情況。

# 1.部署清單狀態檢視
kubectl get deploy,pod,svc -n kube-system -l k8s-app=metrics-server
  # NAME                             READY   UP-TO-DATE   AVAILABLE   AGE
  # deployment.apps/metrics-server   1/1     1            1           5h37m

  # NAME                                  READY   STATUS    RESTARTS   AGE
  # pod/metrics-server-6ffc8966f5-c4jvn   1/1     Running   0          14m

  # NAME                     TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)   AGE
  # service/metrics-server   ClusterIP   10.111.197.94   <none>        443/TCP   5h37m

# 2.註冊到K8S叢集中的 metrics.k8s.io API 檢視
kubectl get apiservices.apiregistration.k8s.io  | grep "metrics"
  # v1beta1.metrics.k8s.io                 kube-system/metrics-server   True        14h

步驟 04.檢視各個節點以及Pod的資源指標(CPU/MEM)

$ kubectl top node
  # NAME                 CPU(cores)   CPU%   MEMORY(bytes)   MEMORY%
  # devtest-master-212   219m         2%     2793Mi          17%
  # devtest-master-213   211m         2%     2417Mi          15%
  # devtest-master-214   203m         1%     2467Mi          7%
  # devtest-work-215     90m          1%     1601Mi          10%

# 預設名稱空間中Pod的資源資訊
$ kubectl top pod
  # NAME    CPU(cores)   MEMORY(bytes)
	# nginx   0m           10Mi

3.叢集管理原生UI工具kubernetes-dashboard安裝部署

描述:Kubernetes Dashboard是Kubernetes叢集的通用、基於web的UI。它允許使用者管理叢集中執行的應用程式並對其進行故障排除,以及管理叢集本身。

專案地址: https://github.com/kubernetes/dashboard/

步驟 01.從Github中拉取dashboard部署資源清單,當前最新版本v2.6.0 【2022年6月22日 16:46:37】

# 下載資源清單並部署 dashboard 
$ wget -L https://raw.githubusercontent.com/kubernetes/dashboard/v2.6.0/aio/deploy/recommended.yaml -O dashboard.yaml
$ kubectl apply -f dashboard.yaml
$ grep "image:" dashboard.yaml
  # image: kubernetesui/dashboard:v2.6.0
  # image: kubernetesui/metrics-scraper:v1.0.8

# 或者一條命令搞定部署
kubectl apply -f https://raw.githubusercontent.com/kubernetes/dashboard/v2.6.0/aio/deploy/recommended.yaml
  # serviceaccount/kubernetes-dashboard created
  ......
  # deployment.apps/dashboard-metrics-scraper created

步驟 02.使用kubectl get命令檢視部署的dashboard相關資源是否正常。

$ kubectl get pod,svc -n kubernetes-dashboard
NAME                                         READY   STATUS    RESTARTS   AGE
dashboard-metrics-scraper-6f669b9c9b-vfmzp   1/1     Running   0          73m
kubernetes-dashboard-67b9478795-2gwmm        1/1     Running   0          73m

NAME                                TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)    AGE
service/dashboard-metrics-scraper   ClusterIP   10.106.168.38    <none>        8000/TCP   73m
service/kubernetes-dashboard        ClusterIP   10.106.191.197   <none>        443/TCP    73m

# 編輯 service/kubernetes-dashboard 服務將埠通過nodePort方式進行暴露為30443。
$ kubectl edit svc -n kubernetes-dashboard kubernetes-dashboard
# service/kubernetes-dashboard edited
apiVersion: v1
kind: Service
.....
spec:
.....
  ports:
  - port: 443
    protocol: TCP
    targetPort: 8443
    nodePort: 31443  # 新增
  selector:
    k8s-app: kubernetes-dashboard
  sessionAffinity: None
  type: NodePort     # 修改

步驟 03.預設儀表板部署包含執行所需的最小RBAC許可權集,而要想使用dashboard操作叢集中的資源,通常我們還需要自定義建立kubernetes-dashboard管理員角色。
許可權控制參考地址: https://github.com/kubernetes/dashboard/blob/master/docs/user/access-control/README.md

# 建立後最小許可權的Token(只能操作kubernetes-dashboard名稱空間下的資源)
kubectl get sa -n kubernetes-dashboard kubernetes-dashboard
kubectl describe secrets -n kubernetes-dashboard kubernetes-dashboard-token-jhdpb | grep '^token:'|awk '{print $2}'

Kubernetes Dashboard 支援幾種不同的使用者身份驗證方式:

  • Authorization header
  • Bearer Token (預設)
  • Username/password
  • Kubeconfig file (預設)

溫馨提示: 此處使用Bearer Token方式, 為了方便演示我們向 Dashboard 的服務帳戶授予管理員許可權 (Admin privileges), 而在生產環境中通常不建議如此操作, 而是指定一個或者多個名稱空間下的資源進行操作。

tee rbac-dashboard-admin.yaml <<'EOF'
apiVersion: v1
kind: ServiceAccount
metadata:
  name: dashboard-admin
  namespace: kubernetes-dashboard
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: dashboard-admin
  namespace: kubernetes-dashboard
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: cluster-admin
subjects:
  - kind: ServiceAccount
    name: dashboard-admin
    namespace: kubernetes-dashboard
EOF

kubectl apply -f rbac-dashboard-admin.yaml
  # serviceaccount/dashboard-admin created
  # clusterrolebinding.rbac.authorization.k8s.io/dashboard-admin created

# 或者 兩條命令搞定
# kubectl create serviceaccount -n devtest devtest-ns-admin
# kubectl create clusterrolebinding devtest-ns-admin --clusterrole=admin --serviceaccount=devtest:devtest-ns-admin 

步驟 04.獲取 sa 建立的 dashboard-admin 使用者的 secrets 名稱並獲取認證 token ,用於上述搭建的dashboard 認證使用。

kubectl get sa -n kubernetes-dashboard dashboard-admin -o yaml | grep "\- name" | awk '{print $3}'
  # dashboard-admin-token-crh7v
kubectl describe secrets -n kubernetes-dashboard dashboard-admin-token-crh7v | grep "^token:" | awk '{print $2}'
  #  獲取到認證Token

步驟 05.利用上述 Token 進行登陸Kubernetes-dashboard的UI,其地址為node節點加上31443,例如此處https://10.20.176.212:31443/#/workloads?namespace=default


4.叢集管理K9S使用者端工具安裝使用

描述: k9s 是用於管理 Kubernetes 叢集的 CLI, K9s 提供了一個終端 UI 來與您的 Kubernetes 叢集進行互動。通過封裝 kubectl 功能 k9s 持續監視 Kubernetes 的變化並提供後續命令來與您觀察到的資源進行互動,直白的說就是k9s可以讓開發者快速檢視並解決執行 Kubernetes 時的日常問題。
官網地址: https://k9scli.io/
參考地址: https://github.com/derailed/k9s

此處,以安裝二進位制包為例進行實踐。

# 1. 利用 wget 命令 -c 短點續傳和 -b 後臺下載
wget -b -c https://github.com/derailed/k9s/releases/download/v0.25.18/k9s_Linux_x86_64.tar.gz

# 2.解壓並刪除多餘檔案
tar -zxf k9s_linux_x86_64.tar.gz
rm  k9s_linux_x86_64.tar.gz  LICENSE  README.md

# 3.拷貝 kubernetes 控制組態檔到加目錄中
mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config
export KUBECONFIG=/etc/kubernetes/admin.conf

# 4.直接執行即可,如果你對vim操作比較熟悉,那麼恭喜你了你很快能上手k9s.
/stroage/nfs# ./k9s

# 5.退出k9s指令
:quit

更多使用技巧請參考: [K9s之K8s叢集管理工具實踐嘗試] (https://blog.weiyigeek.top/2022/1-1-582.html)


5.叢集服務Service七層負載均衡ingress環境搭建部署

Q: 什麼是Ingress?
A: Ingress 是管理對叢集中服務的提供外部存取的 API 物件,Ingress 控制器負責實現 Ingress,通常使用負載均衡器,但它也可以設定邊緣路由器或其他前端來幫助處理流量,它可以將來自叢集外部的 HTTP 和 HTTPS 路由轉發到叢集內部的 Service 中。

Ingress 只是一個統稱,其由 Ingress 和 Ingress Controller 兩部分組成。

  • Ingress 用作將原來需要手動設定的規則抽象成一個 Ingress 物件,使用 YAML 格式的檔案來建立和管理。
  • Ingress Controller 用作通過與 Kubernetes API 互動,動態的去感知叢集中 Ingress 規則變化。

使用 Ingress 控制器可以輕鬆實現外部URL存取叢集內部服務、負載均衡、代理轉發、支援設定SSL/TLS並提供基於名稱的虛擬主機,值得注意的是 Ingress 不會暴露任意埠或協定,通過使用 Service.Type=NodePortService.Type=LoadBalancer型別的服務向向 Internet 公開 HTTP 和 HTTPS 的存取服務

Q: 常用 Ingress 控制器有那些?
其中ingress controller目前主要有兩種基於nginx服務的ingress controller (四層或者七層)和基於traefik的ingress controller(目前支援http和https協定),其它更多適用於Kubernetes的ingress控制器可以參考地址[https://kubernetes.io/zh/docs/concepts/services-networking/ingress-controllers/#其他控制器]

  • ingress-Nginx : 用於 Nginx Kubernetes Ingress 控制器能夠與 NGINX Web 伺服器(作為代理)一起使用 (推薦)
  • ingress-Traefik :由 Traefik Kubernetes Ingress 提供程式是一個用於 Traefik 代理的Ingress控制器。
  • ingress-istio : Istio Ingress 是一個基於Istio的Ingress控制器。

溫馨提示: 理想情況下所有 Ingress 控制器都應符合參考規範。實際上各種 Ingress 控制器的操作略有不同,請參考相應Ingress的控制器官方檔案。

如下圖所示的一個簡單的範例,使用者端請求存取外部URL地址, Ingress 將其所有流量傳送到一個Service中, 後端 Pod 提供伺服器端響應通過路由進行返回給使用者端。

溫馨提示: 基於nginx服務的ingress controller根據不同的開發公司,又分為k8s社群的ingres-nginx和nginx公司的nginx-ingress,在此根據github上的活躍度和關注人數,我們選擇的是k8s社群的ingres-nginx。


Q: K8S社群提供 Ingress 規則有哪些?

  • host : 虛擬主機名稱, 主機名萬用字元主機可以是精確匹配(例如"foo.bar.com")或萬用字元(例如「 *.foo.com」)
  • paths : URL存取路徑。
  • pathType : Ingress 中的每個路徑都需要有對應的路徑型別(Path Type)
  • backend : 是 Service 檔案中所述的服務和埠名稱的組合與規則的 host 和 path 匹配的對 Ingress 的 HTTP(和 HTTPS )請求將傳送到列出的 backend, 一般情況可以單獨為路徑設定Backend以及未匹配的url預設存取的後端defaultBackend。

Ingress 中的每個路徑都需要有對應的路徑型別(Path Type),未明確設定 pathType 的路徑無法通過合法性檢查,當前支援的路徑型別有三種:

  • Exact:精確匹配 URL 路徑,且區分大小寫。
  • Prefix:基於以/分隔的URL路徑字首匹配, 且區分大小寫,並且對路徑中的元素逐個完成。
  • ImplementationSpecific:此路徑型別匹配方法取決於 IngressClass, 具體實現可以將其作為單獨的 pathType 處理或者與 Prefix 、 Exact 型別作相同處理。

說明: 如果路徑的最後一個元素是請求路徑中最後一個元素的子字串,則不會匹配 (例如:/foo/bar 匹配 /foo/bar/baz, 但不匹配 /foo/barbaz)。

溫馨提示: defaultBackend 通常在 Ingress 控制器中設定,以服務與規範中的路徑不匹配的任何請求。

tee > test.yaml << 'EOF'
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: test-ingress
spec:
  defaultBackend:
    service:
      name: test
      port:
        number: 80
EOF
kubectl apply -f 

注意, 入口控制器和負載平衡器可能需要一兩分鐘才能分配 IP 地址。 在此之前,你通常會看到位址列位的值被設定為 <pending>

溫馨提示: ingress控制器資源清單在v1.19以及之後版本叢集中寫法如下

cat <<-EOF | kubectl apply -f -
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: foo.bar.com
  namespace: default
  annotations:
    #URL重定向。
    nginx.ingress.kubernetes.io/rewrite-target: /$1
spec:
  rules:
  - host: foo.bar.com
    http:
      paths:
    # 在Ingress Controller的版本≥0.22.0之後,path中需要使用正規表示式定義路徑,並在rewrite-target中結合捕獲組一起使用。
      - path: /svc(/|$)(.*)
        backend:
          service: 
            name: web1-service
            port: 
              number: 80
        pathType: ImplementationSpecific
EOF

Q: Nginx Ingress Controller與K8S叢集版本對應關係
參考地址: https://github.com/kubernetes/ingress-nginx#support-versions-table

Support Versions table
Ingress-NGINX version 	k8s supported version 	Alpine Version 	Nginx Version
v1.2.1 	1.23, 1.22, 1.21, 1.20, 1.19 	3.14.6 	1.19.10†

快速安裝設定
環境依賴說明: Chart version 4.x.x and above: Kubernetes v1.19+

步驟 01.如果您有 Helm,則可以使用以下命令部署入口控制器:

helm3 repo add ingress-nginx https://kubernetes.github.io/ingress-nginx
helm3 repo update
helm3 search repo ingress-nginx -l
  # NAME                            CHART VERSION   APP VERSION     DESCRIPTION
  # ingress-nginx/ingress-nginx     4.1.4           1.2.1           Ingress controller for Kubernetes using NGINX a...
  # ingress-nginx/ingress-nginx     4.1.3           1.2.1           Ingress controller for Kubernetes using NGINX a...

# ingress-nginx Chart 模板引數設定
helm3 show values --version 4.1.4 ingress-nginx/ingress-nginx > values.yaml

#  values.yaml 設定修改完畢後安裝 ingress-nginx
helm3 install ingress-nginx -f values.yaml --version 4.1.4 ingress-nginx/ingress-nginx  --namespace ingress-nginx --create-namespace --debug

溫馨提示: 上面在不需進行可用引數設定時可採用一條命令搞定(注意提前拉取相關映象)

helm3 upgrade --install ingress-nginx ingress-nginx \
  --repo https://kubernetes.github.io/ingress-nginx \
  --namespace ingress-nginx --create-namespace

溫馨提示: 使用如下更新helm圖表部署的應用以更新修改為國內映象源。

$ crictl pull registry.cn-hangzhou.aliyuncs.com/google_containers/nginx-ingress-controller:v1.2.1
$ crictl pull registry.cn-hangzhou.aliyuncs.com/google_containers/kube-webhook-certgen:v1.1.1

helm3 upgrade ingress-nginx --namespace ingress-nginx --version 4.1.4 -f values.yaml ingress-nginx/ingress-nginx --debug

步驟 02.檢視ingress-nginx的部署情況,一些 pod 應該在 ingress-nginx 名稱空間中啟動:

helm3 list -n ingress-nginx
  # NAME            NAMESPACE       REVISION        UPDATED                                 STATUS          CHART                  APP VERSION
  # ingress-nginx   ingress-nginx   1               2022-06-24 13:12:36.692931823 +0800 CST deployed        ingress-nginx-4.1.4    1.2.1
helm3 history ingress-nginx  -n ingress-nginx
  # REVISION        UPDATED                         STATUS          CHART                   APP VERSION     DESCRIPTION
  # 1               Fri Jun 24 13:20:49 2022        deployed        ingress-nginx-4.1.4     1.2.1           Install complete

# 等待 Pod 應用部署為正常
kubectl wait --namespace ingress-nginx \
  --for=condition=ready pod \
  --selector=app.kubernetes.io/component=controller \
  --timeout=120s
  # pod/ingress-nginx-controller-7cfd586878-fkdb5 condition met

# 檢視 ingress-nginx 的 Pod 與 SVC 
kubectl get pod,svc -n ingress-nginx
  # NAME                                               READY   STATUS      RESTARTS   AGE
  # pod/ingress-ingress-nginx-admission-create-pjm6x   0/1     Completed   0          7m47s
  # pod/ingress-nginx-controller-7cfd586878-fkdb5      1/1     Running     0          18m

  # NAME                                         TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)                      AGE
  # service/ingress-nginx-controller             NodePort    10.107.81.40     <none>        80:30080/TCP,443:30443/TCP   18m
  # service/ingress-nginx-controller-admission   ClusterIP   10.106.154.244   <none>        443/TCP                      18m

# 檢視 ingress 的 ingressclasses 名稱後續才能使用。
kubectl get ingressclasses.networking.k8s.io
  NAME    CONTROLLER             PARAMETERS   AGE
  nginx   k8s.io/ingress-nginx   <none>       19m

步驟 03.針對搭建的 ingress-nginx 服務驗證, 此處存取應該是NGINX標準404錯誤頁面,因為

# Get the application URL by running these commands:
export HTTP_NODE_PORT=30080
export HTTPS_NODE_PORT=30443
export NODE_IP=$(kubectl --namespace ingress-nginx get nodes -o jsonpath="{.items[0].status.addresses[1].address}")
echo "Visit http://$NODE_IP:$HTTP_NODE_PORT to access your application via HTTP."
echo "Visit https://$NODE_IP:$HTTPS_NODE_PORT to access your application via HTTPS."

# 嘗試存取 ingress - nginx
$ curl -I --insecure http://devtest-master-212:30080
$ curl -I --insecure https://devtest-master-212:30443
  # HTTP/2 404
  # date: Fri, 24 Jun 2022 07:07:12 GMT
  # content-type: text/html
  # content-length: 146
  # strict-transport-security: max-age=15724800; includeSubDomains

步驟 04.優化ingress Pod核心引數以及擴容Pod到每個節點之上, 更多優化可以參考 [https://blog.weiyigeek.top/2020/5-28-588.html#0x07-Kubernetes中ingress-nginx優化設定]

# 編輯 ingress-nginx-controller資源清單新增一個 initContainers 進行核心引數初始化
$ kubectl edit deployments.apps -n ingress-nginx ingress-nginx-controller
....
  initContainers:
  - command:
    - sh
    - -c
    - |
      mount -o remount rw /proc/sys
      sysctl -w net.core.somaxconn=65535
      sysctl -w net.ipv4.tcp_tw_reuse=1
      sysctl -w net.ipv4.ip_local_port_range="1024 65535"
      sysctl -w fs.file-max=1048576
      sysctl -w fs.inotify.max_user_instances=16384
      sysctl -w fs.inotify.max_user_watches=524288
      sysctl -w fs.inotify.max_queued_events=16384
    image: alpine:3.10
    imagePullPolicy: IfNotPresent
    name: sysctl
    resources: {}
    securityContext:
      privileged: true
    terminationMessagePath: /dev/termination-log
    terminationMessagePolicy: File
....

# 擴容 ingress-nginx-controller 副本為節點數量 (注意此處已去除master節點汙點)
kubectl scale deployment --replicas=4 -n ingress-nginx ingress-nginx-controller

# 檢視 ingress-controller 的Pod
kubectl get pod -n ingress-nginx -l app.kubernetes.io/component=controller -o wide
  NAME                                        READY   STATUS    RESTARTS   AGE     IP              NODE                 NOMINATED NODE   READINESS GATES
  ingress-nginx-controller-7f8cd9c4fc-6lqgw   1/1     Running   0          5m33s   10.66.55.65     devtest-master-213   <none>           <none>
  ingress-nginx-controller-7f8cd9c4fc-8svfj   1/1     Running   0          3m16s   10.66.53.79     devtest-work-215     <none>           <none>
  ingress-nginx-controller-7f8cd9c4fc-g75fz   1/1     Running   0          6m40s   10.66.237.129   devtest-master-212   <none>           <none>
  ingress-nginx-controller-7f8cd9c4fc-jl5qg   1/1     Running   0          5m33s   10.66.35.67     devtest-master-214   <none>           <none>


本章完整原文地址:

本文至此完畢,更多技術文章,盡情期待下一章節!
歡迎各位志同道合的朋友一起學習交流,如文章有誤請在下方留下您寶貴的經驗知識!

更多文章來源於【WeiyiGeek Blog 個人部落格 - 為了能到遠方,腳下的每一步都不能少 】

個人主頁: 【 https://weiyigeek.top

部落格地址: 【 https://blog.weiyigeek.top 】

專欄書寫不易,如果您覺得這個專欄還不錯的,請給這篇專欄 【點個贊、投個幣、收個藏、關個注,轉個發,留個言】(人間六大情),這將對我的肯定,謝謝!。

  • echo "【點個贊】,動動你那粗壯的拇指或者芊芊玉手,親!"

  • printf("%s", "【投個幣】,萬水千山總是情,投個硬幣行不行,親!")

  • fmt.Printf("【收個藏】,閱後即焚不吃灰,親!")

  • console.info("【轉個發】,讓更多的志同道合的朋友一起學習交流,親!")

  • System.out.println("【關個注】,後續瀏覽檢視不迷路喲,親!")

  • cout << "【留個言】,文章寫得好不好、有沒有錯誤,一定要留言喲,親! " << endl;

更多網路安全、系統運維、應用開發、物聯網開發、網路工程、全棧文章,盡在【個人部落格 - https://blog.weiyigeek.top】站點,謝謝支援!