目錄html
在k8s中全部的對象都叫作資源,例如:pod,service等前端
pod是在k8s中最小單元,前面有提到,k8s支持自愈,彈性擴容等高級特性,那麼若是單純的在k8s節點中跑業務docker是沒有辦法支持這些高級特性,必需要有定製化的容器,那麼,pod就是這個官方已經定製化好的支持高級特性的容器,當啓動一個pod時,至少會有兩個容器,pod容器``和業務容器
,多個業務容器會共享一個pod容器(一組容器的集合),那麼一個Pod中的容器共享網絡命名空間,node
Pod容器分類nginx
Pod存在的意義:爲親密性應用而存在web
鏡像拉取策略算法
imagePullPolicy 一、ifNotPresent:默認值,鏡像在宿主機上不存在時才拉取 二、Always:每次建立Pod都會從新拉取一次鏡像 三、Never:Pod永遠不會主動拉取這個鏡像
1.pod基本操做spring
// 指定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配置文件docker
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的關係後端
label-selector
相關聯Replication Controller 副本控制器,應用託管在Kubernetes以後,Kubernetes須要保證應用可以持續運行,這是RC的工做內容,它會確保任什麼時候間Kubernetes中都有指定數量的Pod正在運行。在此基礎上,RC還提供了一些高級的特性,好比滾動升級、升級回滾等。api
在新版本的 Kubernetes 中建議使用 ReplicaSet(簡稱爲RS )來取代 ReplicationController
1.建立一個rc
apiVersion: v1 kind: ReplicationController metadata: name: myweb spec: 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 metadata: name: nginx-deployment spec: 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 <none> 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 <none> 443/TCP 16h nginx-deployment NodePort 10.96.171.141 <none> 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
,從而達到負載均衡的效果。具體操做以下所示:
一、web-demo.yaml
#deploy apiVersion: apps/v1beta1 kind: StatefulSet metadata: name: web-demo namespace: dev spec: # 指定svc名稱 serviceName: web-demo-svc replicas: 3 template: 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 apiVersion: v1 kind: Service metadata: name: web-demo-svc namespace: dev spec: 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 <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順序性
一、headless-service.yaml
apiVersion: v1 kind: Service metadata: name: springboot-web-svc spec: ports: - port: 80 targetPort: 8080 protocol: TCP clusterIP: None selector: app: springboot-web
二、statefulset.yaml
apiVersion: apps/v1 kind: StatefulSet metadata: name: springboot-web spec: # serviceName 該字段是告訴statefulSet用那個headless server去保證每一個的解析 serviceName: springboot-web-svc replicas: 2 selector: matchLabels: app: springboot-web template: 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
apiVersion: apps/v1 kind: StatefulSet metadata: name: nginx-demo spec: serviceName: springboot-web-svc replicas: 2 selector: matchLabels: app: nginx-demo template: 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: - metadata: name: data spec: accessModes: - 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)
,例如以下場景:
DaemonSet的Pod調度策略與RC很相似,除了使用系統內置的調度算法在每一個Node上進行調度,也能夠在Pod定義中使用NodeSelector或NodeAffinity來指定知足條件的Node範圍進行調度
DaemonSet 資源文件格式
apiVersion: extensions/v1beta1 kind: DaemonSet metadata:
下面例子定義爲在每一個Node上都啓動一個filebeat
容器,其中掛載了宿主機目錄"/var/log/messages"
$ vi k8s-log-filebeat.yaml apiVersion: v1 kind: ConfigMap # 定義一個config文件內容 metadata: 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'] --- apiVersion: apps/v1 kind: DaemonSet # DaemonSet 對象,保證在每一個node節點運行一個副本 metadata: name: k8s-logs namespace: kube-system spec: selector: matchLabels: project: k8s app: filebeat template: 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 <none> 2m15s $ kubectl get pods -n kube-system -o wide | grep "k8s-logs" k8s-logs-gw4bs 0/1 Running 0 87s <none> k8s-node01 <none> <none> k8s-logs-p6r6t 0/1 Running 0 87s <none> k8s-node02 <none> <none>
在kubernetes 1.6之後的版本中,DaemonSet也能執行滾動升級了,即在更新一個DaemonSet模板的時候,舊的Pod副本會被自動刪除,同時新的Pod副本會被自動建立,此時DaemonSet的更新策略(updateStrategy)爲RollingUpdate,以下:
apiVersion: apps/v1 kind: DaemonSet metadata: name: k8s-logs namespace: kube-system spec: 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的關係
每一個Service關聯一個應用
Service類型
1.Cluster IP詳解:
Cluster IP,也叫VIP,主要實現不一樣Pod之間互相訪問
type: NodePort ports: - 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/87865283
2.Node Port詳解:
實現外部用戶能夠訪問節點Node,節點Node會將其流量轉發到內部Pod
訪問流程:用戶 -> 域名 -> 負載均衡器 -> NodeIP:Port ->PodIP:Port
還能夠直接在Node前面部署一個LB負載均衡,如圖:
type: NodePort ports: - 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之間訪問
三、LoadBalancer詳解:
訪問流程:用戶 -> 域名 -> 負載均衡器 -> NodeIP:Port ->PodIP:Port
常規的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
apiVersion: v1 kind: Service metadata: name: myweb spec: type: NodePort ports: - port: 80 nodePort: 30000 targetPort: 80 selector: 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底層流量轉發與負載均衡實現:
一、一個service會建立不少的iptables規則(更新,非增量式)
二、iptables規則是從上到下逐條匹配(延時大)。
救世主:IPVS(內核態)
LVS基於IPVS內核調度模塊實現的負載均衡,如:阿里雲SLB,基於LVS實現四層負載均衡。
iptables:
IPVS: