Kubernetes 資源對象
目錄
1、Pod 資源
2、RC 副本控制器
3、deployment 資源
4、Headless Service
5、StatefulSet
6、DaemonSet
7、Service 資源
8、ipvs和iptables工作原理
在k8s中所有的對象都叫做資源,例如:pod,service等
pod是在k8s中最小單元,前面有提到,k8s支援自愈,彈性擴容等進階特性,那麼如果單純的在k8s節點中跑業務docker是沒有辦法支援這些進階特性,必須要有定制化的容器,那麼,pod就是這個官方已經定制化好的支援進階特性的容器,當啟動一個pod時,至少會有兩個容器,pod容器``和業務容器,多個業務容器會共享一個pod容器(一組容器的集合),那麼一個Pod中的容器共享網絡命名空間,
Pod容器分類
Infrastructure Container:基礎容器,維護整個Pod網絡空間
InitContainers:初始化容器,先于業務容器開始執行
Containers:業務容器,并行啟動
Pod存在的意義:為親密性應用而存在
兩個應用之間發生檔案互動
兩個應用需要通過127.0.0.1或socker通信
兩個應用需要發生頻繁的調用
鏡像拉取政策
imagePullPolicy
1、ifNotPresent:預設值,鏡像在主控端上不存在時才拉取
2、Always:每次建立Pod都會重新拉取一次鏡像
3、Never:Pod永遠不會主動拉取這個鏡像
1.pod基本操作
// 指定yaml檔案建立pod
kubectl create -f [yaml檔案路徑]
// 檢視pod基本資訊
kubectl get pods
// 檢視pod詳細資訊
kubectl describe pod [pod名]
// 更新pod(修改了yaml内容)
kubectl apply -f [yaml檔案路徑]
// 删除指定pod
kubectl delete pod [pod名]
// 強制删除指定pod
kubectl delete pod [pod名] --foce --grace-period=0
2.pod yaml配置檔案
apiVersion: v1
kind: Pod
metadata:
name: nginx01
labels:
app: web
spec:
containers:
- name: nginx01
image: reg.betensh.com/docker_case/nginx:1.13
ports:
- containerPort: 80
Pod與controllers的關系
controllers:在叢集上管理和運作容器的對象
通過label-selector相關聯
Pod通過控制器實作應用的運維,如伸縮,滾動更新等。
Replication Controller 副本控制器,應用托管在Kubernetes之後,Kubernetes需要保證應用能夠持續運作,這是RC的工作内容,它會確定任何時間Kubernetes中都有指定數量的Pod正在運作。在此基礎上,RC還提供了一些進階的特性,比如滾動更新、更新復原等。
在新版本的 Kubernetes 中建議使用 ReplicaSet(簡稱為RS )來取代 ReplicationController
1.建立一個rc
kind: ReplicationController
name: myweb
replicas: 2
selector:
app: myweb
template:
metadata:
labels:
app: myweb
spec:
containers:
- name: nginx01
image: reg.betensh.com/docker_case/nginx:1.13
ports:
- containerPort: 80
預設情況下pod名會以rc名+随機值組成,如下:
[root@k8s-master01 rc]# kubectl get pods
NAME READY STATUS RESTARTS AGE
myweb-0lp57 1/1 Running 0 45s
myweb-zgfcf 1/1 Running 0 45s
RC通過标簽選擇器(labels)來控制pod,RC名稱必須要和标簽選擇器名稱一緻
[root@k8s-master01 rc]# kubectl get rc -o wide
NAME DESIRED CURRENT READY AGE CONTAINER(S) IMAGE(S) SELECTOR
myweb 2 2 2 12m nginx01 reg.betensh.com/docker_case/nginx:1.13 app=myweb
2.RC滾動更新
前面我們已經建立一個v1版本的http-server的pod在k8s環境中,如果我們想要做一次版本更新該怎麼辦呢?難道把原來的pod停掉,再使用新的鏡像拉起來一個新的pod嗎,這樣做明顯是不合适的。
kubectl rolling-update myweb -f nginx_rc_v2.yaml --update-period=30s
3.RC滾動回退
假設現在myweb更新到myweb2,出現了bug,那麼先強制中斷更新
kubectl rolling-update myweb -f nginx_rc_v2.yaml --update-period=50s
然後将myweb2的版本復原到myweb
kubectl rolling-update myweb myweb2 --rollback
deployment也是保證pod高可用的一種方式,明明有RC為何還要引入deployment呢?
因為deployment解決了RC的一個痛點,當使用RC更新容器版本後,标簽會發生變化,那麼svc的标簽還是原來的,這樣就需要手動修改svc配置檔案。
Deployment 為Pod和ReplicaSet之上,提供了一個聲明式定義(declarative)方法,用來替代以前的ReplicationController來友善的管理應用。
你隻需要在Deployment中描述您想要的目标狀态是什麼,Deployment controller就會幫您将Pod和ReplicaSet的實際狀态改變到您的目标狀态。您可以定義一個全新的Deployment來,建立ReplicaSet或者删除已有的 Deployment并建立一個新的來替換。也就是說Deployment是可以管理多個ReplicaSet的,如下圖:
雖然也 ReplicaSet 可以獨立使用,但建議使用 Deployment 來自動管理 ReplicaSet,這樣就無需擔心跟其他機制的不相容問題
1.建立一個deployment
apiVersion: extensions/v1beta1
kind: Deployment
name: nginx-deployment
replicas: 3
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.13
ports:
- containerPort: 80
// 啟動
[root@k8s-master01 deploy]# kubectl create -f nginx_deploy.yaml
檢視deployment啟動狀态
deployment會先啟動一個rs,而後在啟動pod
[root@k8s-master01 deploy]# kubectl get all
NAME READY STATUS RESTARTS AGE
pod/nginx-deployment-fcfcc984f-t2bk4 1/1 Running 0 33s
pod/nginx-deployment-fcfcc984f-vg7qt 1/1 Running 0 33s
pod/nginx-deployment-fcfcc984f-zhwxg 1/1 Running 0 33s
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/kubernetes ClusterIP 10.96.0.1 443/TCP 16h
NAME READY UP-TO-DATE AVAILABLE AGE
deployment.apps/nginx-deployment 3/3 3 3 33s
NAME DESIRED CURRENT READY AGE
replicaset.apps/nginx-deployment-fcfcc984f 3 3 3 33s
2.關聯service
kubectl expose deployment nginx-deployment --port=80 --type=NodePort
檢視svc
[root@k8s-master01 deploy]# kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.96.0.1 443/TCP 16h
nginx-deployment NodePort 10.96.171.141 80:31873/TCP 25s
通路svc位址以及端口
[root@k8s-master01 deploy]# curl -I 10.0.0.33:31873
HTTP/1.1 200 OK
Server: nginx/1.13.12
Date: Thu, 14 Nov 2019 05:44:51 GMT
Content-Type: text/html
Content-Length: 612
Last-Modified: Mon, 09 Apr 2018 16:01:09 GMT
Connection: keep-alive
ETag: "5acb8e45-264"
Accept-Ranges: bytes
3.deployment更新
// 直接編輯對應deployment,并修改鏡像版本
kubectl edit deployment nginx-deployment
// 通過 set image 釋出新的鏡像
kubectl set image deploy nginx-deployment nginx-deployment=nginx:1.17
4.deployment復原
// 復原到上一級版本
kubectl rollout undo deployment nginx-deployment
// 復原到指定版本
kubectl rollout undo deployment nginx-deployment --to-revision=1
// 檢視目前deploy曆史版本
kubectl rollout history deployment nginx-deployment
5.指令行方式實作釋出版本
kubectl run nginx --image=nginx:1.13 --replicas=3 --record
kubectl rollout history deployment nginx
deployment.extensions/nginx
kubectl set image deployment nginx nginx=nginx:1.15
在K8S裡,我們想要通過name來通路服務的方式就是在Deployment上面添加一層Service,這樣我們就可以通過Service name來通路服務了,那其中的原理就是和CoreDNS有關,它将Service name解析成Cluster IP,這樣我們通路Cluster IP的時候就通過Cluster IP作負載均衡,把流量分布到各個POD上面。我想的問題是CoreDNS是否會直接解析POD的name,在Service的服務裡,是不可以的,因為Service有Cluster IP,直接被CoreDNS解析了,那怎麼才能讓它解析POD呢,有大牛提出了可以使用Headless Service,是以我們就來探究一下什麼是Headless Service。
Headless Service也是一種Service,但不同的是會定義spec:clusterIP: None,也就是不需要Cluster IP的Service。
我們首先想想Service的Cluster IP的工作原理:一個Service可能對應多個EndPoint(Pod),client通路的是Cluster IP,通過iptables規則轉到Real Server,進而達到負載均衡的效果。具體操作如下所示:
1、web-demo.yaml
deploy
apiVersion: apps/v1beta1
kind: StatefulSet
name: web-demo
namespace: dev
# 指定svc名稱
serviceName: web-demo-svc
metadata:
labels:
app: web-demo
spec:
containers:
- name: web-demo
image: 10.0.0.33/base_images/web-demo:v1.0
ports:
- containerPort: 8080
resources:
requests:
memory: 1024Mi
cpu: 500m
limits:
memory: 2048Mi
cpu: 2000m
livenessProbe:
tcpSocket:
port: 8080
initialDelaySeconds: 20
periodSeconds: 10
failureThreshold: 3
successThreshold: 1
timeoutSeconds: 5
readinessProbe:
httpGet:
path: /hello
port: 8080
scheme: HTTP
initialDelaySeconds: 20
periodSeconds: 10
failureThreshold: 1
successThreshold: 1
timeoutSeconds: 5
service
kind: Service
name: web-demo-svc
ports:
-
port: 80
targetPort: 8080
protocol: TCP
clusterIP: None
selector:
app: web-demo
檢視svc,發現ClusterIP為None
$ kubectl get svc -n dev | grep "web-demo-svc"
web-demo-svc ClusterIP None 80/TCP 12s
pod會按照順序建立
$ kubectl get pod -n dev
NAME READY STATUS RESTARTS AGE
web-demo-0 1/1 Running 0 7m2s
web-demo-1 1/1 Running 0 6m39s
web-demo-2 1/1 Running 0 6m15s
登入到Cluster的内部pod
$ kubectl exec -it web-demo-0 sh -n dev
/ # nslookup web-demo-svc
Name: web-demo-svc
Address 1: 10.244.2.67 web-demo-0.web-demo-svc.dev.svc.cluster.local
Address 2: 10.244.3.12 web-demo-2.web-demo-svc.dev.svc.cluster.local
Address 3: 10.244.1.214 web-demo-1.web-demo-svc.dev.svc.cluster.local
總結:通過dns通路,會傳回後端pods的清單
首先Deployment隻是用于無狀态服務,無差别并且沒有順序的Pod,而StatefulSet支援多個Pod之間的順序性,用于 每個Pod中有自己的編号,需要互相通路,以及持久存儲區分
Pod順序性
1、headless-service.yaml
name: springboot-web-svc
app: springboot-web
2、statefulset.yaml
apiVersion: apps/v1
name: springboot-web
# serviceName 該字段是告訴statefulSet用那個headless server去保證每個的解析
serviceName: springboot-web-svc
matchLabels:
app: springboot-web
metadata:
labels:
app: springboot-web
spec:
containers:
- name: springboot-web
image: 10.0.0.33/base_images/web-demo:v1.0
ports:
- containerPort: 8080
livenessProbe:
tcpSocket:
port: 8080
initialDelaySeconds: 20
periodSeconds: 10
failureThreshold: 3
successThreshold: 1
timeoutSeconds: 5
檢視pod
$ kubectl get pod
NAME READY STATUS RESTARTS AGE
springboot-web-0 1/1 Running 0 118s
springboot-web-1 1/1 Running 0 116s
進入一個pod,而通過pod name通路另外一個pod
$ kubectl exec -it springboot-web-0 sh
/ # ping springboot-web-1.springboot-web-svc
PING springboot-web-1.springboot-web-svc (10.244.2.68): 56 data bytes
64 bytes from 10.244.2.68: seq=0 ttl=62 time=1.114 ms
64 bytes from 10.244.2.68: seq=1 ttl=62 time=0.698 ms
持久化存儲
自動根據pod建立pvc
name: nginx-demo
matchLabels:
app: nginx-demo
metadata:
labels:
app: springboot-web
spec:
containers:
- name: springboot-web
image: 10.0.0.33/base_images/nginx:1.13
ports:
- containerPort: 8080
volumeMounts:
- name: data
mountPath: /
volumeClaimTemplates:
- name: data
accessModes:spec:
-
ReadWriteOnce
storageClassName: glusterfs-storage-class
resources:
requests:
storage: 1Gi
-
DaemonSet是在Kubernetes1.2 版本新增的一種資源對象
DaemonSet能夠讓所有(或者一些特定)的Node節點僅運作一份Pod。當節點加入到kubernetes叢集中,Pod會被(DaemonSet)排程到該節點上運作,當節點從kubernetes叢集中被移除,被(DaemonSet)排程的Pod會被移除,如果删除DaemonSet,所有跟這個DaemonSet相關的pods都會被删除。
在使用kubernetes來運作應用時,很多時候我們需要在一個區域(zone)或者所有Node上運作同一個守護程序(pod),例如如下場景:
每個Node上運作一個分布式存儲的守護程序,例如glusterd,ceph
運作日志采集器在每個Node上,例如fluentd,logstash
運作監控的采集端在每個Node,例如prometheus node exporter,collectd等
DaemonSet的Pod排程政策與RC很類似,除了使用系統内置的排程算法在每個Node上進行排程,也可以在Pod定義中使用NodeSelector或NodeAffinity來指定滿足條件的Node範圍進行排程
DaemonSet 資源檔案格式
kind: DaemonSet
metadata:
下面例子定義為在每個Node上都啟動一個filebeat容器,其中挂載了主控端目錄"/var/log/messages"
$ vi k8s-log-filebeat.yaml
kind: ConfigMap # 定義一個config檔案内容
name: k8s-logs-filebeat-config
namespace: kube-system
data:
# 填寫filebeat讀取日志相關資訊
filebeat.yml: |-
filebeat.prospectors:
- type: log
paths:
- /messages
fields:
app: k8s
type: module
fields_under_root: true
output.logstash:
# specified logstash port (by default 5044)
hosts: ['10.0.0.100:5044']
kind: DaemonSet # DaemonSet 對象,保證在每個node節點運作一個副本
name: k8s-logs
matchLabels:
project: k8s
app: filebeat
metadata:
labels:
project: k8s
app: filebeat
spec:
containers:
- name: filebeat
image: docker.elastic.co/beats/filebeat:6.8.1
args: [
"-c", "/etc/filebeat.yml",
"-e",
]
resources:
requests:
cpu: 100m
memory: 100Mi
limits:
cpu: 500m
memory: 500Mi
securityContext:
runAsUser: 0
# 進行實際挂載操作
volumeMounts:
# 将configmap裡的配置挂載到 /etc/filebeat.yml 檔案中
- name: filebeat-config
mountPath: /etc/filebeat.yml
subPath: filebeat.yml
# 将主控端 /var/log/messages 路徑挂載到 /messages中
- name: k8s-logs
mountPath: /messages
# 定義卷
volumes:
- name: k8s-logs
hostPath:
path: /var/log/messages
type: File
- name: filebeat-config
configMap:
name: k8s-logs-filebeat-config
使用kubectl create 指令建立該DeamonSet
$ kubectl create -f k8s-log-filebeat.yaml
configmap/k8s-logs-filebeat-config created
daemonset.apps/k8s-logs created
檢視建立好的DeamonSet和Pod,可以看到在每個Node上都建立了一個Pod
$ kubectl get ds -n kube-system | grep "k8s-logs"
NAME DESIRED CURRENT READY UP-TO-DATE AVAILABLE NODE SELECTOR AGE
k8s-logs 2 2 0 2 0 2m15s
$ kubectl get pods -n kube-system -o wide | grep "k8s-logs"
k8s-logs-gw4bs 0/1 Running 0 87s k8s-node01
k8s-logs-p6r6t 0/1 Running 0 87s k8s-node02
在kubernetes 1.6以後的版本中,DaemonSet也能執行滾動更新了,即在更新一個DaemonSet模闆的時候,舊的Pod副本會被自動删除,同時新的Pod副本會被自動建立,此時DaemonSet的更新政策(updateStrategy)為RollingUpdate,如下:
kind: DaemonSet
updateStrategy:
type: RollingUpdate
updateStrategy 的另外一個值是OnDelete,即隻有當手工删除了DaemonSet建立的Pod副本,新的Pod副本才會被建立出來,如果不設定updateStrategy的值,則在kubernetes 1.6之後的版本中會被預設設定為RollingUpdate(滾動更新)。
我們都知道在kubernetes中以Pod為最小排程機關,并且它的特性就是不确定性,即随時會被銷毀和重新建立、不确定性會導緻每個Pod會通過排程器将其部署到不同的N個Node節點,這樣會導緻Pod ip位址會發生變化;
舉個例子,web場景,分為前端後端,前端需要去調用後端資源,如果後端的Pod天生的不确定性導緻IP位址不同,那麼前端肯定是無法做到自動切換連接配接後端的IP位址,是以需要通過Service去發現Pod并擷取其IP位址。
Pod與Service的關系
防止Pod失聯.,擷取Pod資訊(通過label-selector關聯)
定義一組Pod的通路政策(負載均衡 TCP/UDP 4層)
支援ClusterIP,NodePort以及LoadBalancer 三種類型
Server的底層實作主要有iptables和IPVS二種網絡模式
每個Service關聯一個應用
Service類型
ClusterIP:預設,配置設定一個叢集内部可以通路的虛拟IP(vip)
NodePort:在每個Node上配置設定一個端口作為外部通路入口
LoadBalancer:工作在特定的Cloud Provider上,例如Google Cloud, AWS,OpenStack
1.Cluster IP詳解:
Cluster IP,也叫VIP,主要實作不同Pod之間互相通路
type: NodePort
- port: 80
targetPort: 80
protocol: TCP
開啟proxy通路
kubectl proxy 讓外部網絡通路K8S service的ClusterIP
kubectl proxy --address='0.0.0.0' --accept-hosts='^*$' --port=8009
http://[k8s-master]:8009/api/v1/namespaces/[namespace-name]/services/[service-name]/proxy詳細:
https://blog.csdn.net/zwqjoy/article/details/878652832.Node Port詳解:
實作外部使用者可以通路節點Node,節點Node會将其流量轉發到内部Pod
通路流程:使用者 -> 域名 -> 負載均衡器 -> NodeIP:Port ->PodIP:Port
還可以直接在Node前面部署一個LB負載均衡,如圖:
type: NodePort
- port: 80
targetPort: 80
nodePort: 30008
protocol: TCP
參數解釋
spec.ports.port:vip端口(cluster ip)
spec.ports.nodePort:映射到主控端的端口,即提供外部通路的端口
spec.ports.targetPort:pod 端口
spec.selector: 标簽選擇器
建立nodePort類型的時候也會配置設定一個Cluster IP,友善提供給Pod之間通路
3、LoadBalancer詳解:
正常的docker映射場景:
通路 --> node IP:10.0.0.12 --> docker 容器: 172.16.48.2
如果當docker挂掉了後,在重新啟動一個docker,容器IP位址就會發生變化,那麼之前做的node和docker的映射就無效,就需要手動修改映射,這樣就顯得很麻煩
so,在k8s中新增了cluster IP,網段 10.254.0.0/16,series會自動建立這個cluster IP,也叫vip,當pod建立完成後會自動注冊到service裡,并且實作負載均衡(規則預設為rr),如果某個pod挂了後,會自動被剔除
通路 --> node IP:10.0.0.13 --> cluster IP:10.254.0.0/16 (service) --> pod IP:172.16.48.2
建立service
type: NodePort
-
nodePort: 30000
targetPort: 80
app: myweb
kubectl create -f nginx-svc.yaml
檢視Service是否正常接管pod網絡服務:
[root@k8s-master01 svc]# kubectl get endpoints
NAME ENDPOINTS AGE
kubernetes 10.0.0.31:6443 2d
myweb 172.16.12.2:80,172.16.15.4:80 2m
service底層流量轉發與負載均衡實作:
iptables
ipvs
1、一個service會建立很多的iptables規則(更新,非增量式)
2、iptables規則是從上到下逐條比對(延時大)。
救世主:IPVS(核心态)
LVS基于IPVS核心排程子產品實作的負載均衡,如:阿裡雲SLB,基于LVS實作四層負載均衡。
iptables:
靈活,功能強大(可以在資料包不同階段對包進行操作)
規則周遊比對和更新,呈線性時延
IPVS:
工作在核心态,有更好的性能
排程算法豐富:rr,wrr,lc,wlc,ip hash ....
原文位址
https://www.cnblogs.com/jasonminghao/p/12483831.html