Kubernetes(7)聲明式API

1. 概念

1.1 命令式命令行操作

Docker Swarm的編排操作

$ docker service create --name nginx --replicas 2  nginx
$ docker service update --image nginx:1.7.9 nginx
1.2 命令式配置文件操作

Kubernetes中,通過編寫yaml進行容器的創(chuàng)建與更新

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
spec:
  selector:
    matchLabels:
      app: nginx
  replicas: 2
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx
        ports:
        - containerPort: 80
$ kubectl create -f nginx.yaml

創(chuàng)建出來一個Pod之后,更新容器鏡像版本:修改yaml文件的Pod template部分

...
    spec:
      containers:
      - name: nginx
        image: nginx:1.7.9
$ kubectl replace -f nginx.yaml
1.3 聲明式API

對于1.2中的yaml文件枣申,進行kubectl apply操作

$ kubectl apply -f nginx.yaml

同樣的,修改過鏡像版本后胧洒,執(zhí)行kubectl apply谅海,更新pod,觸發(fā)滾動更新每篷。

$ kubectl apply -f nginx.yaml

kubelet apply和kubelet replace區(qū)別

  • replace 是使用新的yaml文件中的API對象,替換原有API對象
  • apply 是對原有API對象PATCH操作
    此外端圈,kubetcl set image, kubectl edit也是對原有API對象的修改
    這就意味著焦读,kube-apiserver在響應式命令請求的時候,一次只能處理一個舱权,否則多個替換操作的結果就可能導致沖突矗晃,而對于對于聲明式請求來說,一次可以進行多個寫操作宴倍,具備前面提到過的Merge能力张症。

所以什么是“聲明式API”?
其實就是鸵贬,通過給一個配置文件(期望的最終狀態(tài))俗他,然后通過使用支持patch的命令模式,去疊加的演進對象的最終狀態(tài)的這樣一種做事情的方式阔逼。

2. 聲明式API的在實際項目中的重要意義(Istio)

2.1 Isotio概念

是一個基于Kubernetes項目的微服務治理框架兆衅,架構如下所示。


2.2 Envoy容器

從架構圖中看出,Istio項目的最根本組件羡亩,是運行在每個應用Pod中的Envoy容器摩疑。這個應用容器是Lyft公司推出的一個高性能C++網(wǎng)絡代理,它以sidecar容器的方式畏铆,運行在每一個治理的應用Pod中雷袋。他的作用是通過配置Pod中的iptables規(guī)則,把整個Pod的進出流量接管下來辞居。
這樣片排,Istio控制層的Pilot組件,就能夠通過調用每個Envoy容器的API速侈,對這個Envoy進行配置率寡,實現(xiàn)微服務治理。

什么是微服務治理倚搬?

2.3 Enovy的產(chǎn)生與應用場景

舉例灰度發(fā)布冶共。
仍然以2.1中的Istio架構為例,假設左邊的應用是一個正在運行的舊版本應用每界,右邊的應用Pod是這個版本新上線應用捅僵。通過Pilot調節(jié)兩個Pod里Envoy容器的配置,進而調節(jié)外部請求到兩個Pod的流量比例(比如新版本10%眨层,舊版本應用Pod90%)庙楚,之后通過逐步過渡比例,完成灰度發(fā)布的過程趴樱。
在整個微服務治理的過程中馒闷,無論是對Envoy的部署,還是對Envoy代理的配置叁征,這些對于用戶和應用都是完全“無感”的纳账。
這就有一個問題,既然Envoy是在每個應用Pod安裝的(我們知道捺疼,可以把一個Pod疏虫,理解成一個實際的應用,而Envoy容器的聲明和配置修改啤呼,都不會在用戶的yaml文件中寫明卧秘,單Envoy容器最終又是切切實實運行在最終的應用Pod當中),那么對于Envoy在Pod中實現(xiàn)和配置修改官扣,Istio怎么做到無感的翅敌?
實現(xiàn)這種Envoy容器無感修改的技術,是Kubernetes中一個叫做Dynamic Admission Control的功能醇锚,這個功能也叫做Initializer哼御。

后面就可以看到坯临,Dynamic Admission Control焊唬,也就是Initilizer恋昼,其實也是一個容器起來的Pod。他的功能就是將存在Etcd中的ConfigMap類型的關于Envoy容器的配置赶促,和用戶的Pod API對象通過Kubernetes的PATCH API做merge液肌。

實際上,在Kubernetes項目中鸥滨,每當一個Pod或者任何一個API對象通過命令等方式提交給APIServer之后嗦哆,總要有一些“初始化”性質的工作需要他們被Kubernetes項目正式處理之前進行。這個操作婿滓,是一個叫做Admission的功能老速。這是Kubernetes中一段Admission Controller的代碼,可以被選擇性地變異進入API Server凸主,在API對象創(chuàng)建后會被立刻調用橘券。但是,如果Envoy的配置修改想用這個功能的話卿吐,那么每次都要動態(tài)的修改代碼重新build并重啟APIServer旁舰,顯然這是不可接受的。所以就有了“熱更新”方式的Admission機制嗡官,就是上面提到的動態(tài)Admission Control技術(小伙子箭窜,該去看代碼了= =)

具體到例子來分析,看看Istio的效果衍腥。
受限磺樱,用戶有一個應用Pod的配置如下

apiVersion: v1
kind: Pod
metadata:
  name: myapp-pod
  labels:
    app: myapp
spec:
  containers:
  - name: myapp-container
    image: busybox
    command: ['sh', '-c', 'echo Hello Kubernetes! && sleep 3600']

Istio要做的事情,就是上面這個Pod被提交給Kubernetes之后婆咸,在對應的API對象中加上Envoy容器的配置(這里就是無感了)坊罢,使API對象對應的yaml文件如下變成下面這樣

apiVersion: v1
kind: Pod
metadata:
  name: myapp-pod
  labels:
    app: myapp
spec:
  containers:
  - name: myapp-container
    image: busybox
    command: ['sh', '-c', 'echo Hello Kubernetes! && sleep 3600']
  - name: envoy
    image: lyft/envoy:845747b88f102c0fd262ab234308e9e22f693a1
    command: ["/usr/local/bin/envoy"]
    ...

那么,對這個API對象無感的修改擅耽,是怎么通過Initializer來實現(xiàn)的呢活孩?

  • Istio將這個Envoy容器本身的定義,以ConfigMap的方式乖仇,存在Etcd當中憾儒,這個ConfigMap(叫做envoy-initializer)的定義舉例如下:
apiVersion: v1
kind: ConfigMap
metadata:
  name: envoy-initializer
data:
  config: |
    containers:
      - name: envoy
        image: lyft/envoy:845747db88f102c0fd262ab234308e9e22f693a1
        command: ["/usr/local/bin/envoy"]
        args:
          - "--concurrency 4"
          - "--config-path /etc/envoy/envoy.json"
          - "--mode serve"
        ports:
          - containerPort: 80
            protocol: TCP
        resources:
          limits:
            cpu: "1000m"
            memory: "512Mi"
          requests:
            cpu: "100m"
            memory: "64Mi"
        volumeMounts:
          - name: envoy-conf
            mountPath: /etc/envoy
    volumes:
      - name: envoy-conf
        configMap:
          name: envoy

data的部分就是envoy容器的對應配置字段和volumes的配置。而Initializer的工作乃沙,就是把這個部分配置起趾,自動添加到用戶的POD API對象中。這就用到了Kubernetes的PATCH API警儒,而這種patch操作训裆,正是聲明式API的主要能力眶根。

  • Istio把一個編寫好的Initializer作為一個Pod部署在Kubernetes集群中。如下:
apiVersion: v1
kind: Pod
metadata:
  labels:
    app: envoy-initializer
  name: envoy-initializer
spec:
  containers:
    - name: envoy-initializer
      image: envoy-initializer:0.0.1
      imagePullPolicy: Always

這里envoy-initializer的使用的鏡像envoy-initializer:0.0.1就是一個自定義控制器(Custom Controller)边琉,是可以自己事先編寫好的属百。
而這個控制器同樣也是遵循控制器模型的,他的實際狀態(tài)是獲取到的用戶新建的Pod的配置情況变姨,期望狀態(tài)就是這個Pod里被加入了Envoy容器的定義族扰。偽代碼如下:

for {
  // 獲取新創(chuàng)建的 Pod
  pod := client.GetLatestPod()
  // Diff 一下,檢查是否已經(jīng)初始化過
  if !isInitialized(pod) {
    // 沒有定欧?那就來初始化一下
    doSomething(pod)
  }
}

如果獲取到的Pod的API對象中渔呵,沒有Envoy的容器的定義,那么就開始進行doSomething的初始化砍鸠,具體做的事情就是前面提到過的扩氢,把Etcd中存儲的那個關于Envoy容器配置的ConfigMap對象加到一個空的Pod里面去,然后調用Kubernetes的API庫中TwoWayMerge
Patch方法爷辱,把用戶Pod對象和新Pod對象 merge录豺。

  • 至此,Istio對通過聲明式API的Patch特性實現(xiàn)Dynamic Adminssion Control功能托嚣,進而支持Envoy容器在用戶和應用側無感的能力就實現(xiàn)了巩检。
2.4 Dynamic Admission Control的配置

Dynamic Admission Control,即Initializer的相關配置(注意示启,這里不是指的Initializer本身兢哭,而是Initializer的配置文件)。
我們可以通過配置這個配置對象夫嗓,來指明對什么類型的資源進行Initialize的操作迟螺。比如下面這段代碼,就是對全部的pods都做初始化操作舍咖。

apiVersion: admissionregistration.k8s.io/v1alpha1
kind: InitializerConfiguration
metadata:
  name: envoy-config
initializers:
  // 這個名字必須至少包括兩個 "."
  - name: envoy.initializer.kubernetes.io
    rules:
      - apiGroups:
          - "" // 前面說過矩父, "" 就是 core API Group 的意思
        apiVersions:
          - v1
        resources:
          - pods

同時,只要這個對象一杯kubectl apply/create出來之后排霉,Kubernetes就會把這個Initializer的名字(envoy.initializer)打在所有新創(chuàng)建Pod的metada上窍株,如下:

apiVersion: v1
kind: Pod
metadata:
  initializers:
    pending:
      - name: envoy.initializer.kubernetes.io
  name: myapp-pod
  labels:
    app: myapp
...

這個字段,就是在Initializer的控制器模型中攻柠,根據(jù)什么區(qū)判斷有沒有被初始化過的依據(jù)球订,換言之,每當我們自定義的Initialzer在做完Initialize的操作之后瑰钮,要把metadata.initializers.pending標識刪除掉C疤病!浪谴!

除了Kubernetes在我們創(chuàng)建出來kind是InitializerConfiguration的對象后开睡,會自動給所有新建的Pod都打這個標簽之外因苹,如果我們沒有新建這個InitializerConfiguration對象,但是又想讓我的某個Pod去使用某個Initializer的話篇恒,這么干:給對應Pod打metadata.annotations字段實例如下:

apiVersion: v1
kind: Pod
metadata
  annotations:
    "initializer.kubernetes.io/envoy": "true"
    ...

而Istio項目的核心扶檐,就是用無數(shù)個運行在應用Pod中的Envoy容器組成的服務代理網(wǎng)格。這也是Service Mesh的含義婚度。

總地來說蘸秘,從上到下官卡,灰度升級的切流場景->(Service Mesh)->Envoy們組成的服務代理網(wǎng)格->Envoy的實現(xiàn)->Kubernetes通過聲明式API支持的Patch修改Pod的能力->聲明式API好哇蝗茁,聲明式API棒哇(少林功夫好哇,好寻咒!少林功夫棒哇哮翘,棒!我系鐵頭功毛秘,無敵鐵頭功....喂饭寺,跑題了,回來了=行)

3. 小結

聲明式API的獨特之處:

  • 聲明式API赌结,就是說我們來提供一個好的API對象進行聲明绞佩,我們期望的狀態(tài)是啥樣子的
  • 其次,聲明式API允許多個API對象寫端,并在Kubernetes中支持以Patch的方式拿穴,對API對象進行修改以達到最終期望的實際狀態(tài),而無需關心最初的YAML文件的內容
  • 基于以上兩個能力特性(提供API明確的API對象來聲明最終的期望狀態(tài)+支持多個API對象聲明并以PATCH的能力使控制器模型拿到的是最終的期望狀態(tài))案训,Kubernetes能在無需外部干預的情況下凡傅,只要你給我明確的若干個API對象,我就能夠給你無感調諧到你最終期望的狀態(tài)

而在上面我們提到的Initializer的實現(xiàn)時瓶蚂,最核心的糖埋,還是Initializer里面那個image,自定義編程的編寫過程窃这,這是遵循“Kubernetes范式編程”瞳别,即

如何使用控制器模式,同 Kubernetes 里 API 對象的“增杭攻、刪祟敛、改、查”進行協(xié)作朴上,進而完成用戶業(yè)務邏輯的編寫過程垒棋。

所以,之后要學習的一個核心痪宰,就是如何通過“Kuberbetes范式編程”完成使用Kubernetes部署代碼的Kubernetes用戶叼架,到使用Kubernetes編寫代碼的Kubernetes玩家的晉級之路畔裕。

?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市乖订,隨后出現(xiàn)的幾起案子扮饶,更是在濱河造成了極大的恐慌,老刑警劉巖乍构,帶你破解...
    沈念sama閱讀 218,941評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件甜无,死亡現(xiàn)場離奇詭異,居然都是意外死亡哥遮,警方通過查閱死者的電腦和手機岂丘,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,397評論 3 395
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來眠饮,“玉大人奥帘,你說我怎么就攤上這事∫钦伲” “怎么了寨蹋?”我有些...
    開封第一講書人閱讀 165,345評論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長扔茅。 經(jīng)常有香客問我已旧,道長,這世上最難降的妖魔是什么召娜? 我笑而不...
    開封第一講書人閱讀 58,851評論 1 295
  • 正文 為了忘掉前任运褪,我火速辦了婚禮,結果婚禮上萤晴,老公的妹妹穿的比我還像新娘吐句。我一直安慰自己,他們只是感情好店读,可當我...
    茶點故事閱讀 67,868評論 6 392
  • 文/花漫 我一把揭開白布嗦枢。 她就那樣靜靜地躺著,像睡著了一般屯断。 火紅的嫁衣襯著肌膚如雪文虏。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,688評論 1 305
  • 那天殖演,我揣著相機與錄音氧秘,去河邊找鬼。 笑死趴久,一個胖子當著我的面吹牛丸相,可吹牛的內容都是我干的。 我是一名探鬼主播彼棍,決...
    沈念sama閱讀 40,414評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼灭忠,長吁一口氣:“原來是場噩夢啊……” “哼膳算!你這毒婦竟也來了?” 一聲冷哼從身側響起弛作,我...
    開封第一講書人閱讀 39,319評論 0 276
  • 序言:老撾萬榮一對情侶失蹤涕蜂,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后映琳,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體机隙,經(jīng)...
    沈念sama閱讀 45,775評論 1 315
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,945評論 3 336
  • 正文 我和宋清朗相戀三年萨西,在試婚紗的時候發(fā)現(xiàn)自己被綠了有鹿。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,096評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡原杂,死狀恐怖印颤,靈堂內的尸體忽然破棺而出您机,到底是詐尸還是另有隱情穿肄,我是刑警寧澤,帶...
    沈念sama閱讀 35,789評論 5 346
  • 正文 年R本政府宣布际看,位于F島的核電站咸产,受9級特大地震影響,放射性物質發(fā)生泄漏仲闽。R本人自食惡果不足惜脑溢,卻給世界環(huán)境...
    茶點故事閱讀 41,437評論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望赖欣。 院中可真熱鬧屑彻,春花似錦、人聲如沸顶吮。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,993評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽悴了。三九已至搏恤,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間湃交,已是汗流浹背熟空。 一陣腳步聲響...
    開封第一講書人閱讀 33,107評論 1 271
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留搞莺,地道東北人息罗。 一個月前我還...
    沈念sama閱讀 48,308評論 3 372
  • 正文 我出身青樓,卻偏偏與公主長得像才沧,于是被迫代替她去往敵國和親迈喉。 傳聞我的和親對象是個殘疾皇子俏扩,可洞房花燭夜當晚...
    茶點故事閱讀 45,037評論 2 355

推薦閱讀更多精彩內容