kubernetes,也叫k8s,是一個用于自動化部署、擴展、管理容器化應用的開源系統。
基礎概念
-
Cluster
Kubernetes將集群分為一個Master和一些Node。
Master上運行著集群相關的一組進程kube-apiserver 、 kube-controller-manager和kube-scheduler,這些進程實現了整個集群的資源管理、Pod調度、彈性伸縮、安全控制、系統監控和糾錯等管理功能,并且都是自動完成的。
Node作為集群中的工作節點,運行真正的應用程序,在Node上Kubernetes管理的最小運行單元是Pod。在Node上運行著Kubernetes的kubelet、kube-proxy服務進程,這些服務進程負責Pod的創建、啟動、監控、重啟、銷毀,以及實現軟件模式的負載均衡器。
-
Pod
Pod運行在Node上,Node既可以是物理機也可以是虛擬機,通常一個Node上可以運行多個上百個Pod。每個Pod包含一個Pause容器和多個業務容器,業務容器共用Pause Container的網絡棧和Volume掛載卷。通常將一組密切相關的業務放在一個Pod上。
Pod是Kubernetes調度的最小單位,同一Pod中的容器始終被一起調用。
并不是每個Pod和它內部運行的容器都能映射到一個Service上,只有提供服務的Pod才會被映射為一個Service。
-
Service
個人理解Service就是管理一組Pod的網絡訪問。它有如下特點
擁有唯一指定的名稱、擁有一個虛擬IP、提供遠程服務能力、被映射到提供這種服務能力的一組容器應用上(也就是一組提供服務的Pod對應一個Service)。
Service一旦創建就不會再變化。
為了建立Service和Pod之間的關系,Kubernetes首先給每個Pod貼上一個標簽,然后給相應的Service定義標簽選擇器(Label Selector),比如標簽選擇器的選擇條件是name=mysql,意味著該Service要作用于所有包含name=mysql 標簽的Pod。
-
RC(Replication Controller)
RC控制Pod的運行。
在Kubernetes中為服務器擴容,只需為需要擴容的Service關聯的Pod創建一個RC。在一個RC文件中包含以下關鍵信息:
- 目標Pod定義
- 目標Pod需要運行的副本數量
- 要監控的Pod標簽
創建好RC后,K8s通過RC中標簽篩選出對應的Pod實例,并實時監控其狀態和數量。如果實例數量少于定義的副本數量,則會根據在RC中定義的Pod模板創建一個新的Pod,然后將此Pod調度到合適的Node上啟動運行,直到Pod實例的數量達到預定目標。這個過程完全是自動化的,無須人工干預。后續的服務升級也將通過修改RC來自動完成。
Kubernetes安裝
操作系統:CentOS Linux release 7.5.1804 (Core)
Docker版本:19.03.11
Kubernetes版本:
2.1 運行時(Container runtimes)
需要在每個Node上安裝運行時保證Pod可以運行,Kubernetes常用的運行時有:containerd、CPI-O、Docker。本例采用Docker。
安裝Docker
#1. 設置倉庫,安裝需要的包
sudo yum install -y yum-utils device-mapper-persistent-data lvm2
#2. 添加Docker倉庫
sudo yum-config-manager --add-repo \
https://download.docker.com/linux/centos/docker-ce.repo
#3. 安裝Docker CE
sudo yum update -y && sudo yum install -y \
containerd.io-1.2.13 \
docker-ce-19.03.11 \
docker-ce-cli-19.03.11
#4. 創建/etc/docker
sudo mkdir /etc/docker
#5. 設置Docker deamon
cat <<EOF | sudo tee /etc/docker/daemon.json
{
"exec-opts": ["native.cgroupdriver=systemd"],
"log-driver": "json-file",
"log-opts": {
"max-size": "100m"
},
"storage-driver": "overlay2",
"storage-opts": [
"overlay2.override_kernel_check=true"
]
}
EOF
#6. sudo mkdir -p /etc/systemd/system/docker.service.d
7. 重啟Docker
sudo systemctl daemon-reload
sudo systemctl restart docker
#8. 添加至開機啟動
sudo systemctl enable docker
2.2 使用kubeadm引導集群
2.2.1 安裝kubeadm,kubelet,kubectl
- kubeadm 引導集群的命令
- kubelet 在集群中所有計算機上運行的組件,它執行諸如啟動Pod和容器之類的操作。
- kubectl 與集群通信的命令行工具。
cat <<EOF | sudo tee /etc/yum.repos.d/kubernetes.repo
[kubernetes]
name=Kubernetes
baseurl=https://packages.cloud.google.com/yum/repos/kubernetes-el7-\$basearch
enabled=1
gpgcheck=1
repo_gpgcheck=1
gpgkey=https://packages.cloud.google.com/yum/doc/yum-key.gpg https://packages.cloud.google.com/yum/doc/rpm-package-key.gpg
exclude=kubelet kubeadm kubectl
EOF
# Set SELinux in permissive mode (effectively disabling it)允許容器訪問主機文件
sudo setenforce 0
sudo sed -i 's/^SELINUX=enforcing$/SELINUX=permissive/' /etc/selinux/config
sudo yum install -y kubelet kubeadm kubectl --disableexcludes=kubernetes
sudo systemctl enable --now kubelet
現在kubelet每隔幾秒就啟動一次,因為它在一個crashloop中等待kubeadm的指令。
在使用Docker時,Kubeadm將自動監測kubelet的cgroup驅動程序,并在運行時將它設置到/var/lib/kubelet/config.yaml
文件
2.2.2 kubeadm config
注意:配置文件仍然被認為是測試版,在未來的版本中可能會改變。
Kubeadm提供了配置文件用于復雜定制,同時kubeadm將配置文件以ConfigMap的形式保存到集群之中,便于后續的查詢和升級工作。
kubeadm config子命令提供了對這一組功能的支持。
- kubeadm config upload from-file:由配置文件上傳到集群中生成ConfigMap。
- kubeadm config upload from-flags:由配置參數生成ConfigMap。
- kubeadm config print init-defaults:輸出kubeadm init默認參數文件的內容。
- kubeadm config print join-defaults:輸出kubeadm join默認參數文件的內容。
- kubeadm config migrate:在新舊版本之間進行配置轉換。
- kubeadm config images list:列出所需的鏡像列表。
- kubeadm config images pull:拉取鏡像到本地。
#用默認配置生成文件
[root@test-38 ~]# kubeadm config print init-defaults > init.default.yaml
2.2.3 運行kubeadm init 安裝Master
- 關閉Swap
swapoff -a
sed -i 's/.*swap.*/#&/' /etc/fstab
cat /etc/fstab
- 運行Kubeadm init
kubeadm init
//也可自定義kubeadm config ,本例采用默認配置
等待一段時間后,Kubernetes安裝Master成功,顯示如下成功信息,成功信息包含了加入節點的指令和所需要的token(kubeadm join)
按照信息提示執行命令,復制配置文件到普通用戶的home目錄下:
[root@test-38 lib]# mkdir -p $HOME/.kube
[root@test-38 lib]# cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
[root@test-38 lib]# chown $(id -u):$(id -g) $HOME/.kube/config
[root@test-38 lib]#
這樣就在Master上安裝了Kubernetes,但在集群內還沒有可用的工作Node,并缺乏對容器的網絡配置。
此時可以驗證2.2.2提到的configMap
[root@test-38 ~]# kubectl get -n kube-system configmap
NAME DATA AGE
coredns 1 99m
extension-apiserver-authentication 6 99m
kube-proxy 2 99m
kube-root-ca.crt 1 99m
kubeadm-config 2 99m
kubelet-config-1.20 1 99m
可以看到其中生成了kubeadm-config的ConfigMap對象
2.2.4安裝Node,加入集群
對于新節點的添加,系統準備和kubernetes yum源的配置是一樣的
kubeadm join 192.168.1.38:6443 --token qfp9bn.47raj0gk26ug6jlq --discovery-token-ca-cert-hash sha256:ae84e70d9559f21ad42e7d9559706f597654531000ad218d0afa9ed6af83e83a
kubeadm在Master上也安裝了kubelet,在默認情況下并不參與工作負載。如果希望安裝一個單機環境,可以執行下面的命令:
[root@test-38 ~]# kubectl taint nodes --all node-role.kubernetes.io/master-
node/test-38 untainted
這將從任何擁有 node-role.kubernetes.io/master taint 標記的節點中移除該標記, 包括控制平面節點,這意味著調度程序將能夠在任何地方調度 Pods。
2.2.5 安裝網絡插件
執行kubectl get nodes,會發現Master處于NotReady的狀態,這是因為還沒有安裝CNI網絡插件:
[root@test-38 ~]# kubectl get nodes
NAME STATUS ROLES AGE VERSION
test-38 NotReady control-plane,master 24m v1.20.4
安裝CNI網絡插件,這里選擇的是weave
kubectl apply -f "https://cloud.weave.works/k8s/net?k8s-version=$(kubectl version | base64 | tr -d '\n')"
2.2.6 驗證kubernetes集群是否安裝完成
kubectl get pods --all-namespaces
如果發現有狀態錯誤的Pod,則可以執行kubectl --namespace=kube-systemdescribe pod<pod_name>來查看錯誤原因,常見的錯誤原因是鏡像沒有下載完成。
2.2.7 部署應用
使用 kubernetes create deployment
部署應用:
kubectl create deployment kubernetes-bootcamp --image=gcr.io/google-samples/kubernetes-bootcamp:v1
部署應用做了以下兩件事:
- 尋找合適的可以運行應用實例的Node
- 安排應用程序在該節點上運行
- 配置集群以在需要時在新節點上重新安排實例
查看deployment
[root@test-38 ~]# kubectl get deployments
NAME READY UP-TO-DATE AVAILABLE AGE
kubernetes-bootcamp 1/1 1 1 103m
2.2.8 訪問應用
默認情況下,所有Pod只能在集群內部訪問,當使用kubectl時,我們正在通過API端點進行交互來和我們的程序進行通信。
- 通過代理訪問API
kubectl可以創建一個代理,該代理會將通信轉發到集群范圍的專用網絡
[root@test-38 ~]# kubectl proxy
Starting to serve on 127.0.0.1:8001
現在我們有了一個我們主機和kubernetes集群的連接,這個代理允許我們通過API進行訪問。
[root@test-38 ~]# curl http://localhost:8001/version
{
"major": "1",
"minor": "20",
"gitVersion": "v1.20.4",
"gitCommit": "e87da0bd6e03ec3fea7933c432i63d151aafdusj",
"gitTreeState": "clean",
"buildDate": "2021-02-18T16:03:00Z",
"goVersion": "go1.15.8",
"compiler": "gc",
"platform": "linux/amd64"
}
API 服務器將基于Pod名稱自動為每個Pod創建一個端點,該端點也可以通過代理進行訪問。
首先我們要現獲取Pod名稱,然后將名稱存儲在環境變量POD_NAME:
[root@test-38 ~]# export POD_NAME=$(kubectl get pods -o go-template --template '{{range .items}}{{.metadata.name}}{{"\n"}}{{end}}')
[root@test-38 ~]# echo Name of the Pod: $POD_NAME
Name of the Pod: kubernetes-bootcamp-57978f5f5d-jcn7k
使用kubectl logs $POD_NAME查看pod日志
[root@test-38 ~]# kubectl logs kubernetes-bootcamp-57978f5f5d-jcn7k
Kubernetes Bootcamp App Started At: 2021-03-01T08:07:32.804Z | Running On: kubernetes-bootcamp-57978f5f5d-jcn7k
還可以在container內部執行命令,具體可以參考https://kubernetes.io/docs/tutorials/kubernetes-basics/explore/explore-interactive/
-
從外部訪問應用
查看現有的service可以看到,系統有一個默認創建的service。
[root@test-38 ~]# kubectl get services
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 2d17h
要訪問應用只能訪問容器的8080端口,我們要將容器的8080端口映射到節點的端口。
[root@test-38 ~]# kubectl expose deployment/kubernetes-bootcamp --type="NodePort" --port 8080
service/kubernetes-bootcamp exposed
[root@test-38 ~]# kubectl get services
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 2d17h
kubernetes-bootcamp NodePort 10.99.65.217 <none> 8080:30691/TCP 8s
現在可以看到我們新運行了一個叫kubernetes-bootcamp的service,可以看到應用被映射到節點的30691端口,端口號是隨機分配的,可以執行如下命令訪問應用:
[root@test-38 ~]# curl localhost:30691
Hello Kubernetes bootcamp! | Running on: kubernetes-bootcamp-57978f5f5d-jcn7k | v=1
Deployment會自動為我們的Pod創建一個標簽
[root@test-38 ~]# kubectl describe deployments
使用標簽獲取pod列表:
[root@test-38 ~]# kubectl get pods -l app=kubernetes-bootcamp
NAME READY STATUS RESTARTS AGE
kubernetes-bootcamp-57978f5f5d-jcn7k 1/1 Running 0 19h
刪除service——delete service
[root@test-38 ~]# kubectl delete service -l app=kubernetes-bootcamp
service "kubernetes-bootcamp" deleted
2.2.9 Scale 應用
默認情況下只會運行一個副本,可以通過kubectl get deployments
查看副本
[root@test-38 ~]# kubectl get deployments
NAME READY UP-TO-DATE AVAILABLE AGE
kubernetes-bootcamp 1/1 1 1 22h
READY
顯示的是當前副本和所需副本的比率
UP-TO-DATE
顯示的是已更新到所需狀態的副本數量
AVAILABLE
顯示應用程序有多少個副本可供用戶使用
AGE
顯示應用程序已運行的時間
現在我們擴展復制集到4個
[root@test-38 ~]# kubectl scale deployments/kubernetes-bootcamp --replicas=4
deployment.apps/kubernetes-bootcamp scaled
[root@test-38 ~]# kubectl get deployments
NAME READY UP-TO-DATE AVAILABLE AGE
kubernetes-bootcamp 4/4 4 4 22h
現在我們查看pod的情況,可以看到當前Pod已經增加到4個
[root@test-38 ~]# kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
kubernetes-bootcamp-57978f5f5d-42tp5 1/1 Running 0 2m10s 10.32.0.5 test-38 <none> <none>
kubernetes-bootcamp-57978f5f5d-8k4w4 1/1 Running 0 2m10s 10.32.0.7 test-38 <none> <none>
kubernetes-bootcamp-57978f5f5d-jcn7k 1/1 Running 0 22h 10.32.0.4 test-38 <none> <none>
kubernetes-bootcamp-57978f5f5d-pkfgq 1/1 Running 0 2m10s 10.32.0.6 test-38 <none> <none>
可以驗證一下復制集是否進行負載均衡,使用curl進行訪問應用,可以各個請求每次發送到不同的Pod,四個副本輪詢處理,實現負載均衡
[root@test-38 ~]# curl localhost:32230
Hello Kubernetes bootcamp! | Running on: kubernetes-bootcamp-57978f5f5d-pkfgq | v=1
[root@test-38 ~]# curl localhost:32230
Hello Kubernetes bootcamp! | Running on: kubernetes-bootcamp-57978f5f5d-jcn7k | v=1
[root@test-38 ~]# curl localhost:32230
Hello Kubernetes bootcamp! | Running on: kubernetes-bootcamp-57978f5f5d-42tp5 | v=1
2.2.10 滾動更新
使用kubectl describe pods
查看現在的image版本信息,現在將image升級到v2
kubectl set image deployments/kubernetes-bootcamp kubernetes-bootcamp=jocatalin/kubernetes-bootcamp:v2
通過kubectl get pods
可以看到滾動更新的過程:v1的Pod逐漸刪除,同時啟動新的v2 Pod。
回退版本使用kubectl rollout undo
命令,rollout命令將部署還原到先前的已知狀態(映像的v2)。 更新是版本控制的,您可以還原到以前任何已知的部署狀態。
kubectl rollout undo deployments/kubernetes-bootcamp
??????????完結撒花~
參考:《Kubenetes權威指南》、https://kubernetes.io