天天看點

Kubernetes 資源對象kubectl run nginx --image=nginx:1.13 --replicas=3 --recordkubectl rollout history deployment nginxkubectl set image deployment nginx nginx=nginx:1.15deployservice

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
    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),例如如下場景:

每個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/87865283

2.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

繼續閱讀