系列文章:
此為2024年最新版本建置K8s Cluster的步驟。
建置版本環境
Linux Ubuntu - 24.04
Docker - 27.2.0
Docker - 27.2.0
Containerd - 1.7.21
K8s - 1.31
K8s - CNI(Calico) - 3.28.1
在Control Plane和Node上安裝K8s
安裝起手勢
sudo su
apt update
VM工具包
apt install -y open-vm-tools-desktop
apt update
💡 針對VMware虛擬機環境優化的工具包,專門用於Linux桌面環境。它是open-vm-tools的延伸包,提供了與VMware桌面虛擬化平台(如:VMware Workstation 和VMware Fusion)集成所需的額外功能。若是使用VMware可以安裝此工具。
安裝工具套件
apt update
apt install -y vim openssh-server net-tools nfs-common
apt update
💡 其中net-tools和nfs-common分別為可選的,他們分別用於:網路管理的工具包和使用NFS文件系統必要工具包。
關閉Swap
在Ubuntu24.04中,將swap.img關閉。
swapoff -a
vim /etc/fstab
修改HostName(選擇性)
vim /etc/hostname
💡 正確的命名HostName有利於我們後續管理K8s的集群。
安裝Docker和Containerd
apt update
apt install -y ca-certificates curl
install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc
chmod a+r /etc/apt/keyrings/docker.asc
echo \
"deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/ubuntu \
$(. /etc/os-release && echo "$VERSION_CODENAME") stable" | \
sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
apt update
apt install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
設定Docker的Private Registry受信任名單(可選)
vim /etc/docker/daemon.json
在daemon.json裡面加入信任名單清單。
{
"insecure-registries": [
"xxx.xxx.com"
]
}
設定完成後,需要重啟docker服務。
systemctl daemon-reload
systemctl restart docker
設定Containerd與cgroup驅動程式
mkdir -p /etc/containerd
containerd config default | sudo tee /etc/containerd/config.toml
vim /etc/containerd/config.toml
找到「[plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc.options]」設定,將SystemdCgroup改為「true」。
version = 2
[plugins]
[plugins."io.containerd.grpc.v1.cri"]
[plugins."io.containerd.grpc.v1.cri".containerd]
[plugins."io.containerd.grpc.v1.cri".containerd.runtimes]
[plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc]
runtime_type = "io.containerd.runc.v2"
[plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc.options]
SystemdCgroup = true
設定完成後,需要重啟Containerd服務。
systemctl restart containerd
設定Containerd的Private Registry受信任名單(可選)
vim /etc/containerd/config.toml
將信任的名單加在「[plugins."io.containerd.grpc.v1.cri".registry.mirrors]」底下。
version = 2
[plugins]
[plugins."io.containerd.grpc.v1.cri"]
[plugins."io.containerd.grpc.v1.cri".registry]
[plugins."io.containerd.grpc.v1.cri".registry.mirrors]
[plugins."io.containerd.grpc.v1.cri".registry.mirrors."xxx.xxx.com"]
endpoint = ["https://xxx.xxx.com"]
設定完成後,也是需要重啟Containerd服務。
systemctl restart containerd
💡 若有設定Containerd的受信任名單,建議可以和cgroup驅動程式一起設定好再重啟。
安裝K8s
apt update
apt install -y apt-transport-https ca-certificates curl gpg
curl -fsSL https://pkgs.k8s.io/core:/stable:/v1.31/deb/Release.key | sudo gpg --dearmor -o /etc/apt/keyrings/kubernetes-apt-keyring.gpg
echo 'deb [signed-by=/etc/apt/keyrings/kubernetes-apt-keyring.gpg] https://pkgs.k8s.io/core:/stable:/v1.31/deb/ /' | sudo tee /etc/apt/sources.list.d/kubernetes.list
apt update
apt install -y kubelet kubeadm kubectl
apt-mark hold kubelet kubeadm kubectl
初始化Control Plane和工具安裝
初始化Control Plane
kubeadm init --pod-network-cidr=172.16.0.0/16
💡 注意!初始化時,pod-network-cidr的設定不要和主機的網域相同。例如:主機IP地址位於192.168.0.0/16的範圍區間內,那麼pod-network-cidr就請避開這個區間。
當Pod的IP地址範圍與主機的IP地址範圍相重疊時,K8s的網路系統會無法正確的路由流量。Pod和主機之間的流量在轉發時,如果目標IP屬於重疊的CIDR區域,系統無法辨別該流量是否應該轉發至Pod還是主機本身,導致數據包無法正確送達。
當Pod的IP地址範圍與主機的IP地址範圍相重疊時,K8s的網路系統會無法正確的路由流量。Pod和主機之間的流量在轉發時,如果目標IP屬於重疊的CIDR區域,系統無法辨別該流量是否應該轉發至Pod還是主機本身,導致數據包無法正確送達。
Kubectl命令使用權限設定
非Root權限使用權限設定:
mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config
💡 設定完成後,非Root用戶可以不需要sudo就可以直接使用kubectl的命令。
Root權限使用權限設定:
export KUBECONFIG=/etc/kubernetes/admin.conf
💡 匯出後即可直接使用kubectl的命令,但要注意!每次重開終端機都要再執行一次該命令。
安裝CNI(使用Calico)
在K8s集群中,我們需要額外安裝CNI容器網路接口,Container Network Interface)來實現容器的網路功能,這是因為K8s本身不提供具體的網路實現,而是依賴CNI插件來管理和配置集群中的網路。
kubectl create -f https://raw.githubusercontent.com/projectcalico/calico/<指定版本>/manifests/tigera-operator.yaml
💡 指定版本可以到Calico的GitHub上查看最新的Release版本【點我前往】。
接著需要安裝Calico的Custom Resource,我們需要找到和上方Calico CNI相同版本的Custom Resource,並進行安裝。
kubectl create -f https://raw.githubusercontent.com/projectcalico/calico/<指定版本>/manifests/custom-resources.yaml
如果一開始kubeadm init時,有指定--pod-network-cidr的設定值時,我們就需要將Custom Resource中下載下來,並修改ipPools中的cidr設定值。
該值需要和初始化時的設定一致,最後使用此修改後的檔案進行安裝。
kubectl create -f <修改cidr設定值後的檔案>.yaml
安裝完成後可以使用watch命令監看容器的啟動狀態,直到確定所有的Calico容器都是Running為止就算成功安裝。
watch kubectl get pods -n calico-system
最後,我們要允許K8的Control Plane可以運行CNI的Pod來管理集群網路。
kubectl taint nodes --all node-role.kubernetes.io/control-plane-
💡 移除Control Plane節點上的污點可以適用於所有需要在Control Plane節點上運行的CNI插件。這麼做能確保集群中的網路元件(通常是通過DaemonSet部署的)能夠在所有節點上正常運行,包括Control Plane節點。
節點安裝
kubeadm token create --print-join-command
Ingress-Nginx Controller安裝
kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-<指定版本>/deploy/static/provider/cloud/deploy.yaml
💡 指定版本可以到GitHub上查看最新的Release版本【點我前往】。
💡 注意!若Ingress-Nginx要使用snippet功能,例如:「nginx.ingress.kubernetes.io/configuration-snippet」,必須在Ingress-Nginx的Controller中,將「allow-snippet-annotations」改為true。
由於此設定在多租戶叢集中可能很危險,出於安全原因,預設是關閉的,此時若使用snippet功能,部署時就會發生錯誤:「denied the request: nginx.ingress.kubernetes.io/configura tion-snippet annotation cannot be used. Snippet directives are disabled by the Ingress administrator」。
相關的CVE-2021-25742安全性漏洞問題回報可以【點我前往】
由於此設定在多租戶叢集中可能很危險,出於安全原因,預設是關閉的,此時若使用snippet功能,部署時就會發生錯誤:「denied the request: nginx.ingress.kubernetes.io/configura tion-snippet annotation cannot be used. Snippet directives are disabled by the Ingress administrator」。
相關的CVE-2021-25742安全性漏洞問題回報可以【點我前往】
如果想要查看所有關於Ingress-Nginx的資源則可以使用以下指令。
kubectl get all -n ingress-nginx
非雲端K8s集群負載平衡器的解決方案 - MetalLB安裝
kubectl apply -f https://raw.githubusercontent.com/metallb/metallb/<指定版本>/config/manifests/metallb-native.yaml
💡 指定版本可以到GitHub上查看最新的Release版本【點我前往】。
接著建立一個metallb-addressconfig.yaml的檔案,這個檔案將會分配負載平衡器的實際連線池,設定完成就可以直接部署。
apiVersion: metallb.io/v1beta1
kind: IPAddressPool
metadata:
name: default
namespace: metallb-system
spec:
addresses:
- 192.168.1.80-192.168.1.90
autoAssign: true
---
apiVersion: metallb.io/v1beta1
kind: L2Advertisement
metadata:
name: default
namespace: metallb-system
spec:
ipAddressPools:
- default
💡 注意!負載平衡器的IP範圍請不要設定和Control Plane或Node節點重複的IP,例如Control Plane是192.168.1.10,Node是192.168.1.11,那麼負載平衡的IP範圍請避開10和11,並設定在192.168.1.12-192.168.1.15。
另外,如果你的叢集只有Ingress一個服務要分配IP,我們可以將範圍設定為:192.168.1.80-192.168.1.80,不過通常都還會有其它的LoadBalancer類型的服務會需要使用,因此實物上比較不會這麼設定。
另外,如果你的叢集只有Ingress一個服務要分配IP,我們可以將範圍設定為:192.168.1.80-192.168.1.80,不過通常都還會有其它的LoadBalancer類型的服務會需要使用,因此實物上比較不會這麼設定。
MetalLB進階設定1
如果我們希望可以手動分配Ingress在固定的IP上,例如希望將Ingress的IP分配在192.168.1.80,其餘的192.168.1.81-90則是開給其它LoadBalancer類型的服務時,我們可以使用以下的設定。
apiVersion: metallb.io/v1beta1
kind: IPAddressPool
metadata:
name: ingress-pool
namespace: metallb-system
spec:
addresses:
- 192.168.1.80-192.168.1.80
autoAssign: false
---
apiVersion: metallb.io/v1beta1
kind: L2Advertisement
metadata:
name: ingress-advertisement
namespace: metallb-system
spec:
ipAddressPools:
- ingress-pool
---
apiVersion: metallb.io/v1beta1
kind: IPAddressPool
metadata:
name: default
namespace: metallb-system
spec:
addresses:
- 192.168.1.81-192.168.1.90
autoAssign: true
---
apiVersion: metallb.io/v1beta1
kind: L2Advertisement
metadata:
name: default
namespace: metallb-system
spec:
ipAddressPools:
- default
💡 注意!由於192.168.1.80是專門分配給Ingress使用的,因此需要將autoAssign設定為「false」,以防止這個IP被自動分配給其他服務。
接著我們還需要修改Ingress的服務,我們可以調整「https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-<指定版本>/deploy/static/provider/cloud/deploy.yaml」檔案中的Service,並新增以下設定。
apiVersion: v1
kind: Service
metadata:
labels:
app.kubernetes.io/component: controller
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
app.kubernetes.io/version: 1.11.2
name: ingress-nginx-controller
namespace: ingress-nginx
annotations:
#在這裡指定Ingress使用我們設定的負載平衡器:「ingress-pool」
metallb.universe.tf/address-pool: ingress-pool
spec:
externalTrafficPolicy: Local
ipFamilies:
- IPv4
ipFamilyPolicy: SingleStack
ports:
- appProtocol: http
name: http
port: 80
protocol: TCP
targetPort: http
- appProtocol: https
name: https
port: 443
protocol: TCP
targetPort: https
selector:
app.kubernetes.io/component: controller
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/name: ingress-nginx
type: LoadBalancer
這樣就可以手動分配指定的IP給Ingress使用,其餘的則是當使用LoadBalancer類型的服務時,就會從中自動分配IP。
MetalLB進階設定2
MetalLB預設情況下,會為每個LoadBalancer類型的服務分配一個唯一的IP,也就是說,192.168.1.81-192.168.1.90只能夠分配給9組服務供使用,若是IP不夠用的情況下就很麻煩。此時,就需要使用IP位置共享的方式來進行設定。
若要啟用IP位置共享,我們需要在LoadBalancer服務中加上「metallb.universe.tf/allow-shared-ip」的詮釋資料。加上詮釋資料後還需要滿足以下條件:
若要啟用IP位置共享,我們需要在LoadBalancer服務中加上「metallb.universe.tf/allow-shared-ip」的詮釋資料。加上詮釋資料後還需要滿足以下條件:
- 它們都有相同的共享鍵。
- 它們請求使用不同的埠(例如,一個是 tcp/80,另一個是 tcp/443)。
- 它們都使用 Cluster external traffic policy,或者它們都指向完全相同的一組 pod(即 pod 的選擇器是相同的)。
滿足以上條件後,還需要指定LoadBalancer使用的IP位置,我們可以使用「status.loadBalancer.ingress」設定。
apiVersion: v1
kind: Service
metadata:
name: test1-service
namespace: test-group
annotations:
metallb.universe.tf/allow-shared-ip: "test-group-192.168.1.81" # 共享IP的key
spec:
type: LoadBalancer
ports:
- name: api
port: 1234
targetPort: 6666
selector:
app: test1-api
status:
loadBalancer:
ingress:
- ip: 192.168.1.81
---
apiVersion: v1
kind: Service
metadata:
name: test2-service
namespace: test-group
annotations:
metallb.universe.tf/allow-shared-ip: "test-group-192.168.1.81" # 共享IP的key
spec:
type: LoadBalancer
ports:
- name: api
port: 1235
targetPort: 7777
selector:
app: test2-api
status:
loadBalancer:
ingress:
- ip: 192.168.1.81
這樣就可以在192.168.1.81的位置上讓兩個服務共享,並且使用不同的Port囉!
建立自簽名CA憑證
# 創建一個新的 CA Issuer,使用之前創建的 ca-tls-secret 作為根證書,這個 Issuer 用於簽發其他證書
apiVersion: cert-manager.io/v1
kind: Issuer
metadata:
name: ca-issuer
namespace: test-ca
spec:
ca:
secretName: ca-tls-secret
---
# 創建一個 TLS 憑證,使用上面定義的 CA Issuer 來簽發,這個憑證適用於 *.xxx.xxx.com 的子域名,並存儲在 test-ca-tls secret 中
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: test-ca-tls
namespace: test-ca
spec:
secretName: test-ca-tls
duration: 876000h # 憑證有效期為100年
renewBefore: 720h # 憑證過期前30天自動更新
dnsNames:
- "*.xxx.xxx.com" # 包含 xxx.xxx.com 所有子域名
commonName: "*.xxx.xxx.com"
subject:
organizations:
- MomoChenIsMe Co., Ltd. # 公司名稱
countries:
- TW # 國家代碼:台灣
localities:
- Tainan # 當地城市:台南
organizationalUnits:
- R&D Department # 部門名稱:研發部門
issuerRef:
name: ca-issuer # 使用之前創建的 CA Issuer 來簽發此憑證
kind: Issuer
usages:
- digital signature # 用於數字簽名
- key encipherment # 用於密鑰加密
- server auth # 用於服務器身份驗證
- client auth # 用於客戶端身份驗證
接著在Ingress中就可以使用自簽名憑證。
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: test-ca-ingress
namespace: wad-k8s
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /$2
nginx.ingress.kubernetes.io/ssl-redirect: "true"
spec:
ingressClassName: nginx
tls:
- hosts:
- abc.xxx.xxx.com
secretName: test-ca-tls # TLS 憑證
rules:
- host: abc.xxx.xxx.com
http:
paths:
- path: /testca(/|$)(.*)
pathType: Prefix
backend:
service:
name: test-ca-service
port:
number: 80 # 服務端口
讓Containerd信任的Private Registry使用自簽名憑證
如果Private Registry是架設在K8s集群中,而且Private Registry端點剛好也使用K8s集群中的Ingress,此時Registry上的Image是無法被本身集群或是其它集群拉取的,Pod中會出現「x509: certificate signed by unknown authority」的自簽名憑證不被信任的錯誤。
為了解決這個問題,首先,我們需要從K8s集群中導出這個Registry的自簽名CA憑證。我們可以從上面創建的CA憑證Secret中提取出憑證。
kubectl get secret test-ca-tls -n test-ca -o jsonpath='{.data.ca\.crt}' | base64 -d > ca.crt
接著將導出的憑證擺放到要信任的K8s集群伺服器底下的「/usr/local/share/ca-certificates/」路徑。若是相同的主機則可以直接使用指令複製。
sudo cp ca.crt /usr/local/share/ca-certificates/
擺放到正確路徑後需要更新伺服器憑證。
sudo update-ca-certificates
接著修改Containerd中的憑證設定。
vim /etc/containerd/config.toml
將信任的憑證路徑加在「[plugins."io.containerd.grpc.v1.cri".registry.configs]」底下。
version = 2
[plugins]
[plugins."io.containerd.grpc.v1.cri"]
[plugins."io.containerd.grpc.v1.cri".registry]
[plugins."io.containerd.grpc.v1.cri".registry.configs]
[plugins."io.containerd.grpc.v1.cri".registry.configs."xxx.xxx.com".tls]
ca_file = "/usr/local/share/ca-certificates/ca.crt"
insecure_skip_verify = false
設定完成後,需要重啟Containerd服務才能夠運作。
systemctl restart containerd
💡 注意!若要使用自簽名CA憑證,就必須在所有的K8s集群中都註冊指定的自簽名CA憑證(Control Plane和所有的Node都要)。
以上就是2024年版本的K8上集群安裝方式。
0 Comments
張貼留言