簡單的 Kubernetes 叢集搭建
一直以來因為機器資源捉襟見肘,使用GitLab CI
配合compose
完成了多數自動化構建和部署的事情,但是隨著執行服務越來越多,管理一大堆docker-compose.yml
和服務的成本也變的越來越高。
作為一個懶人,購置了一臺頂配的ELite Desk G4 800
來作為資源,計劃搭建K8S
配合 GitLab 的Auto DevOps
作為接下來使用的方案。
網上關於K8S
的搭建使用有很多,但是多數都是基於CentOS
、二進位制包的教程,太過陳舊和麻煩。
而且在操作過程中,基本都是一路Next
,缺少除錯驗證,本篇以一個K8S
新手視角,介紹如何快速搭建一套開發可用的 mini 叢集。
我這裡計劃建立一個單 Master 雙子節點的叢集。
官方工具箱 Kubeadm
Kubeadm
作為官方推出的K8S
工具箱,旨在協助開發者能夠快速搭建
和使用
Kubernetes 的各種核心功能,包括:
- 配置並啟動master
節點
- 配置並啟動worker
節點,並加入master
節點,組成叢集
- 升級叢集到最新版本
- 管理你的叢集的詳細配置
- 管理你的叢集token
- …
想要了解更多,可以檢視ofollow,noindex" target="_blank">官方文件 。
為了簡化操作和維護成本,本次叢集的搭建就使用它來進行。不過相比較手動配置的靈活,kubeadm
目前存在一些限制,比如它僅支援部分版本的作業系統,參考官方文件:開始安裝 kubeadm 之前
。
而且每臺主機或者虛擬機器至少要分配2核心
和2GB
的記憶體。
我這裡使用的資源是三臺2核心4GB
的虛擬機器,作業系統為ubuntu
,為了使用docker
官方的軟體包,我將系統版本選擇為16.04
。
我在這裡對這三臺機器分別進行了命名和固定IP分配:
- (Master Node) potato10.11.12.180
- (Worker Node) potato-chips 10.11.12.181
- (Worker Node) potato-salad 10.11.12.182
配置基礎環境
在開始搭建叢集之前,我們需要先進行一些基礎環境的配置。
SSH 認證授信
接下來的操作,包含大量的 ssh 操作,為了避免麻煩,可以將你的使用者祕鑰新增到遠端主機中。
bash
完全關閉SWAP交換分割槽
網上的教程一般都只會引導使用者使用swapoff
命令進行分割槽關閉,但是一旦主機重啟,這個命令的作用就“失效”了,所以這裡建議使用我下面提供的命令一勞永逸的完全關閉swap
分割槽。
bash
配置主機名稱和基礎解析
在建設叢集之前,我們需要確保節點之間的以下要素不同:
product_id MAC
我們先設定主機名,比如設定主機名為potato
:
bash
設定完主機名稱之後,我們需要將主機名稱對應的基礎解析指向本地。
bash
至於MAC
地址,你可以直接使用ifconfig
進行設定,也可以修改/etc/network/interfaces
進行設定。如果你也是虛擬機器使用者,我建議直接在硬體層面進行設定,一勞永逸,另外,如果你在硬體層面設定了MAC
地址,product_id
也會隨之變化。
提了這麼多次product_id
,那麼該如何檢視它的內容呢,很簡單:
bash
安裝docker
在安裝K8S
和各種K8S TOOLBOX
之前,我們需要先對系統進行一些基礎配置,在之前的文章中,我有介紹過如何更優雅的安裝docker
。
但是這裡稍稍有一些不同:這裡必須使用指定版本的docker-ce
,目前 18.0x 的docker-ce
暫時未通過K8S
測試驗證,不能被直接使用。
之前的安裝命令apt install docker-ce
需要被替換為下面的命令來進行指定版本的軟體安裝:
bash
為了避免軟體在後續維護系統的過程中被誤升級,我們可以鎖定它的版本:
bash
加速 docker-ce 的下載和安裝
如果你覺得從官方下載docker-ce
比較慢,可以在添加了gpg
祕鑰後,將新增軟體倉庫地址從官方源改為其他映象源,比如使用下面的命令新增一個新的軟體源:
https://mirrors.aliyun.com/docker-ce/linux/ubuntu $(lsb_release -cs) stable"] bash
然後執行前面說到的安裝命令,進行更快速的安裝。
安裝 Kubeadm、Kubectl、Kubelet
這裡參考了部分官方文件Creating a single master cluster with kubeadm
,但是請注意,目前官方已經關閉了v1
版本的docker
倉庫的介面,所以如果你準備掛代理直接下載軟體映象包,需要修改/etc/docker/daemon.json
,強制停用v1
版本的 API:
bash
由於K8S
搭建之後,升級不是很頻繁,可以直接使用匯入離線的軟體包,進行快速的服務搭建和升級,而對機器上的docker
配置做到使用預設配置不進行改動。
獲取映象並匯出為離線映象包
我們這裡使用到的軟體包映象名稱列表如下:
bash
將列表儲存為檔案,在可以獲取映象的雲機器上,使用下面的命令可以自動將映象下載並進行匯出。
bash
然後將下載並匯出的*.tar
映象包下載到要搭建叢集的機器上,使用下面的命令即可批量匯入映象到系統,避免了要為叢集機器配置代理等操作。
bash
上面的指令碼,我儲存在了 GitHub : soulteary/k8s-images-trans-helper 。
載入 IPVS 核心模組
為了避免IPVS
核心模組沒有載入,而報RequiredIPVSKernelModulesAvailable
的錯誤,我們使用下面的命令載入所有支援的IPVS
模組。
yaml
安裝 K8S 環境
安裝依賴工具、新增GPG
祕鑰、新增軟體倉庫,進行軟體下載:
bash
上面的命令是官方文件提供的,實際上你可能會遇到新增GPG
祕鑰出錯的情況,並且使用官方源進行下載失敗的情況,為此我為你準備了一套適合國內環境使用的命令。
https://mirrors.aliyun.com/kubernetes/apt/ kubernetes-$(lsb_release -cs) main" apt update && apt install -y kubelet kubeadm kubectl] bash
這裡的GPG
祕鑰可以和離線映象包一樣,使用雲主機下載下來,放置於你執行命令的目錄,然後使用cat
命令讀取內容,再使用apt-key
進行新增操作。
和配置docker
一樣,我們需要鎖定軟體版本,避免“意外”的出現。
bash
如果你網速夠快,1分鐘之內,你的K8S
軟體包就都就緒了,接下來就能夠進行叢集的搭建了。
搭建叢集
登入伺服器,使用kubeadm init
命令進行master
節點的初始化,因為我選擇使用flannel
作為組網工具,所以我在初始化命令後面添加了CIDR
引數。
bash
啟動 Master 節點
這裡偷個懶,直接使用root
使用者啟動程式:
using Kubernetes version: v1.11.3 [preflight] running pre-flight checks I0926 04:05:02.988136 1074 kernel_validator.go:81] Validating kernel version I0926 04:05:02.988343 1074 kernel_validator.go:96] Validating kernel config [preflight/images] Pulling images required for setting up a Kubernetes cluster [preflight/images] This might take a minute or two, depending on the speed of your internet connection [preflight/images] You can also perform this action in beforehand using 'kubeadm config images pull' [kubelet] Writing kubelet environment file with flags to file "/var/lib/kubelet/kubeadm-flags.env" [kubelet] Writing kubelet configuration to file "/var/lib/kubelet/config.yaml" [preflight] Activating the kubelet service [certificates] Generated ca certificate and key. [certificates] Generated apiserver certificate and key. [certificates] apiserver serving cert is signed for DNS names [potato kubernetes kubernetes.default kubernetes.default.svc kubernetes.default.svc.cluster.local] and IPs [10.96.0.1 10.11.12.180] [certificates] Generated apiserver-kubelet-client certificate and key. [certificates] Generated sa key and public key. [certificates] Generated front-proxy-ca certificate and key. [certificates] Generated front-proxy-client certificate and key. [certificates] Generated etcd/ca certificate and key. [certificates] Generated etcd/server certificate and key. [certificates] etcd/server serving cert is signed for DNS names [potato localhost] and IPs [127.0.0.1 ::1] [certificates] Generated etcd/peer certificate and key. [certificates] etcd/peer serving cert is signed for DNS names [potato localhost] and IPs [10.11.12.180 127.0.0.1 ::1] [certificates] Generated etcd/healthcheck-client certificate and key. [certificates] Generated apiserver-etcd-client certificate and key. [certificates] valid certificates and keys now exist in "/etc/kubernetes/pki" [kubeconfig] Wrote KubeConfig file to disk: "/etc/kubernetes/admin.conf" [kubeconfig] Wrote KubeConfig file to disk: "/etc/kubernetes/kubelet.conf" [kubeconfig] Wrote KubeConfig file to disk: "/etc/kubernetes/controller-manager.conf" [kubeconfig] Wrote KubeConfig file to disk: "/etc/kubernetes/scheduler.conf" [controlplane] wrote Static Pod manifest for component kube-apiserver to "/etc/kubernetes/manifests/kube-apiserver.yaml" [controlplane] wrote Static Pod manifest for component kube-controller-manager to "/etc/kubernetes/manifests/kube-controller-manager.yaml" [controlplane] wrote Static Pod manifest for component kube-scheduler to "/etc/kubernetes/manifests/kube-scheduler.yaml" [etcd] Wrote Static Pod manifest for a local etcd instance to "/etc/kubernetes/manifests/etcd.yaml" [init] waiting for the kubelet to boot up the control plane as Static Pods from directory "/etc/kubernetes/manifests" [init] this might take a minute or longer if the control plane images have to be pulled [apiclient] All control plane components are healthy after 38.500989 seconds [uploadconfig] storing the configuration used in ConfigMap "kubeadm-config" in the "kube-system" Namespace [kubelet] Creating a ConfigMap "kubelet-config-1.11" in namespace kube-system with the configuration for the kubelets in the cluster [markmaster] Marking the node potato as master by adding the label "node-role.kubernetes.io/master=''" [markmaster] Marking the node potato as master by adding the taints [node-role.kubernetes.io/master:NoSchedule] [patchnode] Uploading the CRI Socket information "/var/run/dockershim.sock" to the Node API object "potato" as an annotation [bootstraptoken] using token: d2y2to.znsihh37rk5calbm [bootstraptoken] configured RBAC rules to allow Node Bootstrap tokens to post CSRs in order for nodes to get long term certificate credentials [bootstraptoken] configured RBAC rules to allow the csrapprover controller automatically approve CSRs from a Node Bootstrap Token [bootstraptoken] configured RBAC rules to allow certificate rotation for all node client certificates in the cluster [bootstraptoken] creating the "cluster-info" ConfigMap in the "kube-public" namespace [addons] Applied essential addon: CoreDNS [addons] Applied essential addon: kube-proxy Your Kubernetes master 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: https://kubernetes.io/docs/concepts/cluster-administration/addons/ You can now join any number of machines by running the following on each node as root: kubeadm join 10.11.12.180:6443 --token d2y2to.znsihh37rk5calbm --discovery-token-ca-cert-hash sha256:ae980b5c80af45b987b2f3e1d343265f3cce7ef66876cf6a6cabaaa4467868d1 root@potato:~# ] bash
這裡如果使用kubectl get nodes
,會出現下面的錯誤,除非你使用上面輸出日誌中的命令,對於當前使用者進行了配置獨立的處理。
bash
但是作為一個懶人,我這裡直接使用預設配置,執行:
bash
然後再次執行剛剛獲取node
節點的命令:
bash
接著,我可以通過kubectl get pods
來看看各個元件是否執行正常:
bash
bash
全部都是Running
,一切就緒,我們開始進行組網,以及附加叢集子節點。
現在master
節點幾乎就緒,我們來配置網路元件:flannel
。
Flannel 組網
剛才有提到,我這裡使用官方推薦的工具之一:flannel
來進行網路組建。
這裡需要先設定/proc/sys/net/bridge/bridge-nf-call-iptables
為1
,讓虛擬網橋上的資料包可以被iptable
處理。
bash
至於配置,使用官方推薦的即可,很簡單一條命令:
bash
執行完畢,你會看到各種created
的資訊。
yaml
再次檢視元件執行狀態,我們可以看到,flannel
已經執行起來了:
yaml
好了,master
節點現在就就緒了,接下來我們來操作其他的worker
節點。
新增子節點
下面的操作可以執行無數多遍,我以一臺worker
為例。
在剛剛建立master
時,命令列輸出告訴我們要執行下面的命令,來組建一個叢集:
yaml
如果你的準備工作一項不拉的都執行過了,那麼你將會得到下面的輸出日誌。
running pre-flight checks I0926 04:23:44.001001 4993 kernel_validator.go:81] Validating kernel version I0926 04:23:44.001206 4993 kernel_validator.go:96] Validating kernel config [discovery] Trying to connect to API Server "10.11.12.180:6443" [discovery] Created cluster-info discovery client, requesting info from "https://10.11.12.180:6443" [discovery] Requesting info from "https://10.11.12.180:6443" again to validate TLS against the pinned public key [discovery] Cluster info signature and contents are valid and TLS certificate validates against pinned roots, will use API Server "10.11.12.180:6443" [discovery] Successfully established connection with API Server "10.11.12.180:6443" [kubelet] Downloading configuration for the kubelet from the "kubelet-config-1.11" ConfigMap in the kube-system namespace [kubelet] Writing kubelet configuration to file "/var/lib/kubelet/config.yaml" [kubelet] Writing kubelet environment file with flags to file "/var/lib/kubelet/kubeadm-flags.env" [preflight] Activating the kubelet service [tlsbootstrap] Waiting for the kubelet to perform the TLS Bootstrap... [patchnode] Uploading the CRI Socket information "/var/run/dockershim.sock" to the Node API object "potato-chips" as an annotation This node has joined the cluster: * Certificate signing request was sent to master and a response was received. * The Kubelet was informed of the new secure connection details. Run 'kubectl get nodes' on the master to see this node join the cluster. ] yaml
嗯,沒錯,你已經組建了一個最小的叢集,一臺master
、一臺worker
。
為了讓我們的叢集更像樣子,你可以把上面的命令,在其他的機器上繼續執行,來給這個叢集新增更多的計算資源。
驗證叢集節點資訊
當你在所有節點執行完畢之後,返回master
節點,還是通過kubectl get nodes
命令,可以檢視到當前叢集的資訊。
yaml
好了,叢集搭建就搞定了。
圖形化控制檯
總是使用命令列太不“環保”了,作為懶人,我們可以使用官方的dashboard
外掛來進行一些圖形化的互動。
搭建圖形控制檯
和配置flannel
一樣,配置dashboard
也可以使用官方推薦的配置,一條命令完成操作。
yaml
同樣的,如果你上面的叢集是就緒的,那麼在執行完命令後,也會得到一堆created
的資訊。
yaml
使用kubectl get pods
檢視當前pod
的狀況。
yaml
嗯,一樣是就緒狀態。
但是由於我們沒有安裝負載均衡的元件,所以我們暫時無法直接訪問dashboard
以及其他的部署的應用,除了系統元件的應用都被分配了K8S
的虛擬內網。
我們可以通過-o wide
引數來檢視所有的pod
分佈情況:
yaml
讓控制檯允許訪問
網上有很多教程是寫在本地如何訪問dashboard
的,所以他們直接使用kubectl proxy
是有效的,但是如果你是真的搭建一個叢集,這時這個命令將會失效,因為它監聽的地址是127.0.0.1
。
這時,命令需要修改為:
bash
然後瀏覽器中訪問:
bash [/crayon]
即可開啟你的K8S
叢集控制檯。
如果你和我一樣,對 固定IP 進行了域名解析,可以這樣使用:
bash
對應的訪問地址也就變成了:
bash
但是這時,你訪問這個控制檯,會遇到要求輸入KubeConfig
或者Token
的要求,如果你是相對正式的環境使用,那麼不妨閱讀許可權控制
相關文件。
當然,如果你真的要使用許可權控制方案進行控制檯登入,當前版本可能會遇到和社群老兄反饋的一樣的問題:
kubectl proxy
對 HTTPS 支援不佳,導致無法登入dashboard
:原文地址
。
我個人沒有遇到這個問題,因為我使用 Traefik 配合K8S
,來對外提供域名訪問服務,dashboard 我直接使用下面的方案免除了登入許可權的認證。
為控制檯免除許可權認證
作為一個懶人用的開發環境,我這裡直接使用官方文件中的給控制檯賬號賦予超級使用者許可權 ,免於配置一大堆內容。
將下面的內容儲存為dashboard-admin.yaml
(僅適用於正式釋出的版本)
yaml
然後和配置flannel
和dashboard
一樣,使用kubectl apply
命令執行啟動。
yaml
再次執行剛剛的proxy
命令,重新整理你瀏覽器中的控制檯登入頁面,點選“跳過”,你便獲得了擁有全部許可權的控制檯。
最後
基礎的搭建部分就是這樣,是不是很簡單。接下來我會寫一篇文章介紹如何整合自建 GitLab ,完成開發、構建、釋出等常規Pipeline
。
—EOF