Kubernetes 資源對象

在k8s中全部的對象都叫作資源,例如:pod,service等前端

Pod 資源

pod是在k8s中最小單元,前面有提到,k8s支持自愈,彈性擴容等高級特性,那麼若是單純的在k8s節點中跑業務docker是沒有辦法支持這些高級特性,必需要有定製化的容器,那麼,pod就是這個官方已經定製化好的支持高級特性的容器,當啓動一個pod時,至少會有兩個容器,pod容器``和業務容器,多個業務容器會共享一個pod容器(一組容器的集合),那麼一個Pod中的容器共享網絡命名空間,node

Pod容器分類nginx

  • Infrastructure Container:基礎容器,維護整個Pod網絡空間
  • InitContainers:初始化容器,先於業務容器開始執行
  • Containers:業務容器,並行啓動

Pod存在的意義:爲親密性應用而存在web

  • 兩個應用之間發生文件交互
  • 兩個應用須要經過127.0.0.1或socker通訊
  • 兩個應用須要發生頻繁的調用

鏡像拉取策略算法

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的關係後端

  • controllers:在集羣上管理和運行容器的對象
  • 經過label-selector相關聯
  • Pod經過控制器實現應用的運維,如伸縮,滾動升級等。

RC 副本控制器

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 資源

deployment也是保證pod高可用的一種方式,明明有RC爲什麼還要引入deployment呢?
由於deployment解決了RC的一個痛點,當使用RC升級容器版本後,標籤會發生變化,那麼svc的標籤仍是原來的,這樣就須要手動修改svc配置文件。

Deployment 爲PodReplicaSet之上,提供了一個聲明式定義(declarative)方法,用來替代之前的ReplicationController來方便的管理應用。
你只須要在Deployment中描述您想要的目標狀態是什麼,Deployment controller就會幫您將PodReplicaSet的實際狀態改變到您的目標狀態。您能夠定義一個全新的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

Headless Service

在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,發現ClusterIPNone

$ 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的列表

StatefulSet

首先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

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 資源文件格式

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(滾動升級)。

Service 資源

咱們都知道在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  
  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

ipvs和iptables工做原理

service底層流量轉發與負載均衡實現:

  • iptables
  • ipvs

一、一個service會建立不少的iptables規則(更新,非增量式)
二、iptables規則是從上到下逐條匹配(延時大)。

救世主:IPVS(內核態)

LVS基於IPVS內核調度模塊實現的負載均衡,如:阿里雲SLB,基於LVS實現四層負載均衡。

iptables:

  • 靈活,功能強大(能夠在數據包不一樣階段對包進行操做)
  • 規則遍歷匹配和更新,呈線性時延

IPVS:

  • 工做在內核態,有更好的性能
  • 調度算法豐富:rr,wrr,lc,wlc,ip hash ....
相關文章
相關標籤/搜索