1. docker
Docker 是一個應用容器引擎,說簡單點就是將你的應用里三層外三層打包成一個鏡像,然后用一條命令將鏡像跑起來,本質(zhì)上它就是一個進程而已,只不過使用了一些隔離技術(shù)(cgroups 、namespace、rootfs、setns)讓其“隱藏”起來,從而感覺上它是一個容器,而且是一個獨立的系統(tǒng)。docker和虛擬機有著本質(zhì)的區(qū)別,虛擬機會占用更多的物理資源,虛擬機比較笨重,重建或釋放都比較費時。例如有個1000平的大房子,如果隔成10個甚至20個小房間都沒問題,而且可以隨時拆掉再隔;但如果在里面蓋房子的話,可能蓋5間就不錯了。
用以下命令揭示“容器”的真實身份
# 查看 a776ea6f142d2819 容器的進程號
[root@node1 ~]# docker inspect --format '{{ .State.Pid }}' a776ea6f142d
2819
# 發(fā)現(xiàn)容器在宿主機中進程
[root@node1 ~]# ps -aux |grep 2819
root 22819 0.0 0.0 109096 6604 ? Sl Apr28 3:40 containerd-shim -namespace moby -workdir /var/lib/containerd/io.containerd.runtime.v1.linux/moby/a2b9a823d8451eaa32c92330599e7167dc69b46930746b536ec018ca91e30914 -address /run/containerd/containerd.sock -containerd-binary /usr/bin/containerd -runtime-root /var/run/docker/runtime-runc -systemd-cgroup
2. kubernetes
Kubernetes是Google開源的一個容器編排引擎,隨著docker的流行,當運行數(shù)百、數(shù)千個容器時,人們就不得不考慮一個問題,如何讓容器更高效的運行、以及如何在分布式環(huán)境下運行容器等。這是k8s就橫空出世了,它簡化了大規(guī)模部署的容器管理問題,而在k8s流行之前,docker公司就有三劍客的另外兩個產(chǎn)品:docker-compose、swarm。swarm是docker公司主推的容器編排工具,也是和k8s一決高下的產(chǎn)品,但最終用戶用腳投票,k8s以完勝收場,這里不得不提的一個大牛就是Tower(高塔),作為k8s的布道師功不可沒。
一、架構(gòu)
(1) kubectl
集群的客戶端命令行工具,請求apiserver的rest接口,查看和維護集群,kubectl需要一個配置文件: kubeconfig,此文件包含用戶、集群上下文、命名空間、認證機制信息等,kubectl可以同時管理多個集群,在請求apiserver需要認證信息。kubectl可以同時管理多個集群。
(2) kube-apiserver
API Server提供了資源對象的唯一操作入口,其他所有組件都必須通過它提供的API來操作資源數(shù)據(jù),只有API Server與存儲通信,其他模塊通過API Server訪問集群狀態(tài)。以RESTFul接口方式提供給外部客戶和內(nèi)部組件進行同一調(diào)用。
(3) kube-controller-manager
實現(xiàn)集群故障檢測和恢復的自動化工作,負責執(zhí)行各種控制器,主要有:
endpoint-controller:定期刷新service和pod(關(guān)聯(lián)信息由endpoint對象維護)的關(guān)聯(lián)關(guān)系,保證service到pod的映射總是最新的。
replication-controller:定期檢查replicationController(新版叫ReplicaSet)中配置的pod數(shù)量和實際運行數(shù)量是否一致,如果不一致會自動啟動或停止pod。
(4) kube-scheduler
Scheduler收集和分析當前Kubernetes集群中所有Work節(jié)點的資源(內(nèi)存、CPU)負載情況,然后分發(fā)Pod到集群中可用的節(jié)點上,并實時監(jiān)測集群中未分發(fā)和已分發(fā)的所有運行的Pod,將已分發(fā)的pod信息寫回到API Server。為了避免頻繁查詢,Scheduler會緩存一份最新的信息在本地。
(5) etcd
和Zookeeper類似,負責存儲各個組件的共享數(shù)據(jù),保證集群高可用。
(6) kube-proxy
負責接收并轉(zhuǎn)發(fā)請求。Kube-proxy的核心功能是將到達Service的訪問請求轉(zhuǎn)發(fā)到后臺的某個具體的Pod。無論是通過ClusterIP+Port的方式還是NodeIP+NodePort的方式訪問Service,最終都會被節(jié)點的Iptables規(guī)則(新版本是通過LVS轉(zhuǎn)發(fā))重定向到Kube-proxy監(jiān)聽服務代理端口,該代理端口實際上就是SocketServer在本地隨機打開的一個端口,SocketServer是Kube-proxy為每一個服務都會創(chuàng)建的“服務代理對象”的一部分。當Kube-proxy監(jiān)聽到Service的訪問請求后,它會找到最適合的Endpoints,然后將請求轉(zhuǎn)發(fā)過去。具體的路由選擇依據(jù)Round Robin算法及Service的Session會話保持這兩個特性。
(7) kubelet
運行在每個work節(jié)點上,作為agent,負責分配該Node上的Pods任務、啟動Pod、管理容器、周期性獲取容器狀態(tài)等,反饋給kube-apiserver。注意:kubelet 與 kube-apiserver 之間的通信是雙向的, kubelet 既需要訪問 kube-apiserver 獲取分配到自己節(jié)點上的 pod 信息, kube-apiserver 也需要主動訪問 kubelet 拉取日志, 狀態(tài), 監(jiān)控數(shù)據(jù)等信息, 所以對兩個組件來說, 認證是雙向的, kube-apiserver 需要持有 kubelet 的客戶端證書, 以完成 kubelet 對自己身份的校驗; kubelet 也需要持有 kube-apiserver 的客戶端證書, 完成 kube-apiserver 對自己身份的認證。
通過kubeadm安裝時,Kubelet是唯一一個運行在宿主機上的服務,因為它負責啟動容器,如果它也運行在容器中,那就成了它在容器中啟動其他容器啦,這樣會有很多不方便。
(8) kube-DNS
一個可選的DNS服務,用于為每個Service對象創(chuàng)建DNS記錄,這樣所有的Pod就可以通過DNS訪問服務了。
(9) CRI
CRI是k8s對容器操作的統(tǒng)一抽象,在1.20版本之前,k8s直接調(diào)用docker的API,所以搞了一個 dockershim的適配器來完成,之前比較熱的話題k8s要廢棄docker,其實是廢棄這個東西。目前k8s最新版對容器操作直接對接OCI(容器統(tǒng)一的開發(fā)標準)來完成,這樣的好處不言而喻,不管什么容器廠家,只要實現(xiàn)了OCI標準,就能和k8s無縫對接,詳細請看我的文章《docker的隕落》。
二、安裝
使用kubeadm安裝k8s非常簡單,但經(jīng)常失敗,大致失敗的原因有幾點:
- 鏡像下載不下來,使用阿里云鏡像,但版本比較老
- 虛擬機,云主機等多網(wǎng)卡環(huán)境,需指定advertiseAddress,calico插件需要指定通信的網(wǎng)卡
- pod網(wǎng)段和service網(wǎng)段和系統(tǒng)網(wǎng)段沖突
- 浮動IP問題
- OpenStack環(huán)境下容器跨節(jié)點無法通行問題,可嘗試關(guān)閉port-security來解決
- 編寫kubeadm配置文件: kubeadm-config.yaml
apiVersion: kubeadm.k8s.io/v1beta2
kind: InitConfiguration
# kubeadm 使用 eth0 的默認網(wǎng)絡接口(通常是內(nèi)網(wǎng)IP,在virtualbox一般是10.0.2.15)做為 Master節(jié)點的advertise address
# 如果是通過虛擬機安裝k8s,那么必須設置advertiseAddress地址,否則導致其他節(jié)點無法正常和master通信
localAPIEndpoint:
# 不能綁定浮動IP
advertiseAddress: 10.0.2.24
bindPort: 6443
---
# 開啟Kube-proxy代理規(guī)則為ipvs,默認是Iptables
apiVersion: kubeproxy.config.k8s.io/v1alpha1
kind: KubeProxyConfiguration
mode: "ipvs"
---
apiVersion: "kubeadm.k8s.io/v1beta2"
kind: ClusterConfiguration
kubernetesVersion: v1.17.4
controlPlaneEndpoint: "apiserver:6443"
apiServer:
extraArgs:
service-node-port-range: 1000-40000
certSANs:
- 10.0.2.24
- 127.0.0.1
networking:
# podSubnet相當于--pod-network-cidr 參數(shù)
podSubnet: 192.244.0.0/16
# serviceSubnet相當于--service-network-cidr 參數(shù)
serviceSubnet: 10.96.0.0/16
- 執(zhí)行kubeadm初始化操作
# 加上此參數(shù):--upload-certs ,其他節(jié)點加入時可以自動獲取證書
$ kubeadm init --config=kubeadm-config.yaml --upload-certs
- 安裝客戶端,執(zhí)行節(jié)點加入操作等
- 安裝網(wǎng)絡插件,推薦安裝 calico 插件。
3. 應用部署
k8s內(nèi)置了多種資源類型,如pod是k8s中最小的單元, ReplicaSet管理pod的多個副本,Deployment 是無狀態(tài)應用。
下面是部署一個nginx到k8s集群,并設置有pod有3個副本
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
labels:
app: nginx
spec:
replicas: 3
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
labels:
app: nginx
spec:
replicas: 3
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: registry.cn-hangzhou.aliyuncs.com/moobox/nginx
ports:
- containerPort: 80---
#service
apiVersion: v1
kind: Service
metadata:
name: nginx
spec:
ports:
- port: 80
protocol: TCP
targetPort: 80
selector:
app: nginx
type: ClusterIP
$ kubectl apply -f nginx.yaml
$ kubectl get pods
NAME READY STATUS RESTARTS AGE
nginx-deployment-6c84b7494d-gj5qk 1/1 Running 0 4m11s
nginx-deployment-6c84b7494d-j8fhz 1/1 Running 0 4m11s
nginx-deployment-6c84b7494d-xbvdf 1/1 Running 0 4m11s
4. 高級
一、監(jiān)控
使用prometheus + Grafana監(jiān)控k8s集群,支持operator的話,可下載kube-prometheus v0.5.0 版(最新版有一個鏡像拉取不了)進行安裝。安裝完如果沒有監(jiān)控數(shù)據(jù),可能是:
問題1: 時間不同步,時區(qū)不對,設置為本地時區(qū)和當前時間,查看
prometheus主頁發(fā)現(xiàn)有警告,可通過timedatectl和date 命令修改
問題2:Grafana 的prometheus數(shù)據(jù)源,默認配置的是k8s內(nèi)部域名地址,所以外部無法訪問,數(shù)據(jù)源需要修改為外部的地址: http://192.168.x.x:39090/
二、藍綠部署
k8s默認就支持滾動升級,藍綠部署也是支持的,加入有個服務之前的版本是V1,新部署了一個版本是V2,那我們就可以通過兩個service來實現(xiàn)一個簡單的藍綠部署
#service
apiVersion: v1
kind: Service
metadata:
name: web-bluegreen-v1
namespace: dev
spec:
ports:
- port: 80
protocol: TCP
targetPort: 8080
# 通過選擇不同版本的webapp,來切換流量
selector:
app: webapp
version: v1.0 #version: v2.0
type: ClusterIP
#service
apiVersion: v1
kind: Service
metadata:
name: web-bluegreen-v2
namespace: dev
spec:
ports:
- port: 80
protocol: TCP
targetPort: 8080
# 通過選擇不同版本的webapp,來切換流量
selector:
app: webapp
version: v2.0
type: ClusterIP
k8s默認是不支持灰度發(fā)布的,想要實現(xiàn)灰度發(fā)布,可使用其他組件,如istio
三、自動擴容
HPA(Horizontal Pod Autoscaler)是k8s的一個資源對象,利用prometheus獲取該資源對象的監(jiān)控指標,可實現(xiàn)Pod自動伸縮。但有幾點必須要注意:
- pod一定要設置資源限制request、limit等,才能開啟HPA
- HPA控制器的時間窗口默認是15秒,即每隔15s拉取一次監(jiān)控指標,可通過–horizontal-pod-autoscaler-sync-period參數(shù)設定
kubernetes集群需要配置好metrics server - 目前是v1版本,從k8s v1.18 支持 v2beta2版本,可支持基于內(nèi)存的伸縮指標,可自定義伸縮指標
基于內(nèi)存/CPU的自動伸縮
下面我們對一個xxx應用進行自動伸縮,當CPU使用超過60%時,會自動增加pod,但不會超過6個
$ kubectl autoscale deployment xxx --cpu-percent=60 --min=2 --max=6
QPS的自動伸縮
下面創(chuàng)建一個HPA來實現(xiàn) 一個QPS的 自動伸縮:
apiVersion: autoscaling/v2beta2
kind: HorizontalPodAutoscaler
metadata:
name: blog-web
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: blog-web
minReplicas: 2
maxReplicas: 8
metrics:
- type: Pods
pods:
metric:
name: http_requests_received
target:
type: AverageValue
averageValue: 10