今天來看一下 Kubernetes 的組成元件,然後在本機上用虛擬機器建立一個有多節點的 Kubernetes 叢集。
關於 Kubernetes 組成元件,請參考 https://kubernetes.io/docs/concepts/overview/components/ 的說明。
主元件 (master component) 組成了叢集的控制層,負責叢集中的整體性決策,例如 Pod 排程,以及偵測、回應叢集事件,例如在 replica 數量不足時產生新的 Pod。這些主元件通常都運行於同一台機器中,而這台機器通常不執行使用者的容器。
節點元件 (node component) 則包含了 kubelet、kube-proxy 以及 container runtime (容器執行期)。
addon 這個是附加元件或外掛程式的意思,在這裡是指實作叢集功能的 Pod 和 Service。在叢集的機器中使用 docker container ls
指令會看到很多容器在運行,這些容器中有些就是在執行這裡提到的 addon,一些常見的 addon 如下:
kube-system
的命名空間之中。較詳細的 addon 清單可參考 https://kubernetes.io/docs/concepts/cluster-administration/addons/。這幾天的操作都是透過 Minikube 來進行,它是一個單節點的 Kubernetes 叢集,但是只有一個節點的叢集是無法應付單點失效的狀況的。在雲端供應商的環境,像是 Azure、GCP 應該都有建立 Kubernetes 叢集的功能,只要幾個簡單按鍵就可以完成,但如果想自己建立一個多節點的 Kubernetes 叢集要怎麼做呢?接下來就透過 Kubernetes 提供的 kubeadm 工具來建立一個多節點的叢集。
之前在介紹 Ansible 的時候利用 Vagrant 建立了多台機器的環境,打算以這幾台機器為基礎,回憶一下當時建立了三台機器,在 Vagrantfile 中分別命名為 node1、node2 及 node3。這裡讓 node1 作為主節點。node2、node3 作為一般節點。在這三台機器上必須安裝的套件包括 Docker、kubectl、kubelet、kubeadm。來看一下文件中對 kubeadm 的介紹:它是一個提供 kubeadm init
及 kubeadm join
等命令,作為建立 Kubernetes 節點的快速途徑 (fast paths) 的最佳實踐。其實之前學了 Ansible,所以應用所學的話應該用 Ansible 來做,除了安裝必要的套件,甚至(應該)可以用來處理初始叢集及加入叢集的工作,但在鐵人賽中有時間壓力沒辦法仔細測試,所以這邊就直接安裝,或者也可以用 Vagrant 的 provision 來幫忙完成安裝套件的任務。
Docker 和 Kubernetes 工具在安裝上應該沒有相依性,我是先安裝 Docker 再安裝 Kubernetes 相關工具。Docker 的安裝方式之前提過了,而 Kubernetes 相關套件的安裝說明,可參考 https://kubernetes.io/docs/setup/independent/install-kubeadm/。在 Ubuntu 環境的安裝指令如下:
$ apt-get update && apt-get install -y apt-transport-https curl
$ curl -s https://packages.cloud.google.com/apt/doc/apt-key.gpg | apt-key add -
$ cat <<EOF >/etc/apt/sources.list.d/kubernetes.list
deb https://apt.kubernetes.io/ kubernetes-xenial main
EOF
$ apt-get update
$ apt-get install -y kubelet kubeadm kubectl
$ apt-mark hold kubelet kubeadm kubectl
在 Vagrant 機器中,以 vagrant 帳號登入執行以上命令需要 sudo
,但第三個指令可能無法直接加上 sudo
(應該是因為重導又有 EOF 的關係),這個指令是要在 kubernetes.list
檔案中加入 deb https://apt.kubernetes.io/ kubernetes-xenial main
這串文字。安裝完畢後,就可以來建立叢集了。在安裝說明的最後有一個 configure cgroup driver used by kubelet on Master Node,因為這裡是使用 Docker 作為容器的 runtime,可以跳過這一段的設定。
接下來要設定 master node,在 node1 執行下列指令,結果輸出如下:
$ sudo kubeadm init --pod-network-cidr=10.244.0.0/16 --apiserver-advertise-address=192.168.50.10
[init] using Kubernetes version: v1.12.2
[preflight] running pre-flight checks
[preflight/images] Pulling images required for setting up a Kubernetes 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 192.168.50.10:6443 --token ffvofw.lk2e4prugfrsxqy2 --discovery-token-ca-cert-hash sha256:5d8916483d7b246fbcd81023d4433079984fead7c6cd8e8049e830d998a9643b
--pod-network-cidr
在設定 Kubernetes 叢集中的網路,10.244.0.0/16
這個值是等一下要安裝的網路附加元件中所指定的,而 --apiserver-advertise-address
則是指定 master node 主機 IP。執行要花一點時間,接下來按照輸出進行主節點的設定。
$ mkdir -p $HOME/.kube
$ sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
$ sudo chown $(id -u):$(id -g) $HOME/.kube/config
如果之前有建立過 Kubernetes 叢集而 $HOME/.kube
目錄存在的話,請將它刪除後再執行這三個指令,否則可能會有一些先前的設定 cache 導致連線認證的異常。剛才 kubeadm init
的輸出選項最後面有其他節點要加入此叢集的指令,請先記錄下來。
接下來要安裝網路附加元件,其實有蠻多選項的,請參考 https://kubernetes.io/docs/setup/independent/create-cluster-kubeadm/#pod-network。這裡依照之前看過的教學選擇 flannel ,這也是應試目標能力中有提到要認識的。安裝指令如下:
$ kubectl apply -f https://raw.githubusercontent.com/coreos/flannel/bc79dd1505b0c8681ece4de4c0d86c5cd2643275/Documentation/kube-flannel.yml
關於 flannel 可參考官方 GitHub https://github.com/coreos/flannel 以及 https://blog.laputa.io/kubernetes-flannel-networking-6a1cb1f8ec7c 的說明。
現在應該可以用 kubectl get nodes
來確認叢集的節點狀況。
$ kubectl get nodes
NAME STATUS ROLES AGE VERSION
node-1 Ready master 92m v1.12.2
接下來來安裝 Kubenetes dashboard,第一天已經介紹過了,那時候是用 kubectl proxy
來將 Kubernetes API 代理到本機的 8001 port,但預設它只能在本機存取,它綁定的是 localhost。kubectl proxy
可以用 --address
指定要綁定那個位址,指定本機的 IP (192.168.50.10
),但發現會無法存取,這好像是 Kubernetes 的預設,這些訊息只能在本機存取。所以這裡換一個方式,不要用 kubectl proxy
。
首先先安裝 Dashboard 的附加元件,一樣是使用 kubectl apply
指令,可參考 https://github.com/kubernetes/dashboard/wiki/Installation。這裡提供 recommended setup 以及 alternative setup 兩種方法,其中 recommended setup 必須使用 https,會需要一些憑證的設定,因為只是在本機上架設實驗環境,就用 http 的 alternative setup,安裝指令如下:
$ kubectl apply -f https://raw.githubusercontent.com/kubernetes/dashboard/master/src/deploy/alternative/kubernetes-dashboard.yaml
安裝好了之後來查看一下相關的 Deployment 和 Service,指令如下:
$ kubectl -n kube-system get deployments kubernetes-dashboard
NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE
kubernetes-dashboard 1 1 1 1 2m23s
$ kubectl -n kube-system get services kubernetes-dashboard
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes-dashboard ClusterIP 10.106.116.30 <none> 80/TCP 2m30s
請注意這裡的指令加了 -n kube-system
參數,表示我們要查看的資源位於 kube-system
這個命名空間 (namespace) 之中。可以看到 kubernetes-dashboard
這個 Service 的 type 是 ClusterIP
,要把它改成 NodePort
。執行 kubectl -n kube-system edit services kubernetes-dashboard
後會出現文字編輯器,在下面的片段中,將 .spec.type
的值由 ClusterIP
改成 NodePort
,至於要對應到本機的那個 port 可以讓 Kubernetes 來決定,或自己直接指定。
spec:
clusterIP: 10.106.116.30
ports:
- port: 80
protocol: TCP
targetPort: 9090
selector:
k8s-app: kubernetes-dashboard
sessionAffinity: None
type: ClusterIP
status:
loadBalancer: {}
完成之後,再用 kubectl get services
查看一下這個服務對應到那個 port。
$ kubectl -n kube-system get services kubernetes-dashboard
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes-dashboard NodePort 10.106.116.30 <none> 80:31983/TCP 43m
在我的機器上它對應到 31983 port,因此訪問 http://192.168.50.10:31983
,應該會看到以下的畫面:
發現上面有黃色警告方塊,文字是這樣的
configmaps is forbidden: User "system:serviceaccount:kube-system:kubernetes-dashboard" cannot list resource "configmaps" in API group "" in the namespace "default"
看起來是權限的問題,參考 https://github.com/kubernetes/dashboard/wiki/Access-control,需要有一個足夠權限的角色,請建立 dashboard-admin.yaml
,文字內容如下:
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: kubernetes-dashboard
labels:
k8s-app: kubernetes-dashboard
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: cluster-admin
subjects:
- kind: ServiceAccount
name: kubernetes-dashboard
namespace: kube-system
這裡出現了一個新的資源物件,稱為 ClusterRoleBinding
,總之是一些和權限相關的設定,使用 kubectl create
來建立資源。
$ kubectl create -f dashboard-admin.yaml
clusterrolebinding.rbac.authorization.k8s.io/kubernetes-dashboard created
重新整理頁面,警告訊息應該就會消失了。在左邊的 menu 按一下叢集 -> 節點,可以看到目前這個叢集有一個節點。接下來要將 node2 和 node3 也加入這個節點。請注意 node1、node2、node3 是在 Vagrant 中給機器的名稱,實際上它們的 hostname 應該是 node-1、node-2 以及 node-3,是當初在 Vagrantfile
中的設定值。
先連進 node2,然後執行剛才 kubeadm init
中記錄下來的 kubeadm join
指令,例如:
$ kubeadm join 192.168.50.10:6443 --token ffvofw.lk2e4prugfrsxqy2 --discovery-token-ca-cert-hash sha256:5d8916483d7b246fbcd81023d4433079984fead7c6cd8e8049e830d998a9643b
完成後在 master node 以 kubectl get nodes
來查看新節點是否有加入叢集,或者透過 dashboard 頁面確認。都沒問題的話,dashboard 節點頁面應該類似這樣:
至此為止應該已經使用 kubeadm 建立一個具有三個節點的 Kubernets 叢集,並安裝了 Dashbord 的附加元件,使得查看叢集狀態變得更加容易。
假設今天不再需要此叢集,那要如何結束它呢?必須在 master node 上先將加入此叢集的節點結束掉,請執行下列指令(都在 master node 上作):
$ kubectl drain <node-name> --delete-local-data --force --ignore-daemonsets
$ kubectl delete node <node-name>
應該是先依序執行 worker node,最後再執行 master node。接下來要在每一個節點 (worker node 和 master node 都要) 執行 sudo Kubeadm reset
指令,並將 master node 上 $HOME/.kube
目錄刪除。
這幾天大概瞭解了 Kubernetes 的基本架構,以及其中的主要元件,包括 Pod
、ReplicaSet
、ReplicationController
、Deployment
、Service
等等,也進行了幾項實作,包括利用 Minikube 建立單節點的叢集,以及利用 Vagrant 機器建立具有多節點的叢集,並知道了利用 Volume 來留存資料的方法。其實四天的時間能寫的東西很有限,因為剩下的幾天還想再研究一項工具,所以趕著在四天結束,變成只是挑一些我感覺比較重要的東西來看,有可能遺漏不少也很重要的內容,再請大家自己找資料研究囉。