Kubernetes 從入門(mén)到進(jìn)階實(shí)戰(zhàn)教程 (2021 最新萬(wàn)字干貨版)
公眾號(hào)關(guān)注“杰哥的IT之旅”,
選擇“星標(biāo)”,重磅干貨,第一時(shí)間送達(dá)!

原文:來(lái)源騰訊技術(shù)工程,https://tinyurl.com/ya3ennxf
寫(xiě)在前面
筆者今年 9 月從端側(cè)開(kāi)發(fā)轉(zhuǎn)到后臺(tái)開(kāi)發(fā),第一個(gè)系統(tǒng)開(kāi)發(fā)任務(wù)就強(qiáng)依賴(lài)了 K8S,加之項(xiàng)目任務(wù)重、排期緊,必須馬上對(duì) K8S 有概念上的了解。然而,很多所謂“K8S 入門(mén)\概念”的文章看的一頭霧水,對(duì)于大部分新手來(lái)說(shuō)并不友好。經(jīng)歷了幾天痛苦地學(xué)習(xí)之后,回顧來(lái)看,K8S 根本不復(fù)雜。于是,決心有了這一系列的文章:一方面希望對(duì)新手同學(xué)有幫助;另一方面,以文會(huì)友,希望能夠有機(jī)會(huì)交流討論技術(shù)。
本文組織方式:
1. K8S 是什么,即作用和目的。涉及 K8S 架構(gòu)的整理,Master 和 Node 之間的關(guān)系,以及 K8S 幾個(gè)重要的組件:API Server、Scheduler、Controller、etcd 等。
2. K8S 的重要概念,即 K8S 的 API 對(duì)象,也就是常常聽(tīng)到的 Pod、Deployment、Service 等。
3. 如何配置 kubectl,介紹kubectl工具和配置辦法。
4. 如何用kubectl 部署服務(wù)。
5. 如何用kubectl 查看、更新/編輯、刪除服務(wù)。
6.?如何用kubectl?排查部署在K8S集群上的服務(wù)出現(xiàn)的問(wèn)題
I. K8S 概覽
1.1 K8S 是什么?
K8S 是Kubernetes的全稱(chēng),官方稱(chēng)其是:
Kubernetes is an open source system for managing?containerized applications?across multiple hosts. It provides basic mechanisms for deployment, maintenance, and scaling of applications.
用于自動(dòng)部署、擴(kuò)展和管理“容器化(containerized)應(yīng)用程序”的開(kāi)源系統(tǒng)。
翻譯成大白話就是:“K8S 是 負(fù)責(zé)自動(dòng)化運(yùn)維管理多個(gè) Docker 程序的集群”。那么問(wèn)題來(lái)了:Docker 運(yùn)行可方便了,為什么要用 K8S,它有什么優(yōu)勢(shì)?
插一句題外話:
為什么 Kubernetes 要叫 Kubernetes 呢?維基百科已經(jīng)交代了(老美對(duì)星際是真的癡迷):
Kubernetes(在希臘語(yǔ)意為“舵手”或“駕駛員”)由 Joe Beda、Brendan Burns 和 Craig McLuckie 創(chuàng)立,并由其他谷歌工程師,包括 Brian Grant 和 Tim Hockin 等進(jìn)行加盟創(chuàng)作,并由谷歌在 2014 年首次對(duì)外宣布 。該系統(tǒng)的開(kāi)發(fā)和設(shè)計(jì)都深受谷歌的 Borg 系統(tǒng)的影響,其許多頂級(jí)貢獻(xiàn)者之前也是 Borg 系統(tǒng)的開(kāi)發(fā)者。在谷歌內(nèi)部,Kubernetes 的原始代號(hào)曾經(jīng)是Seven,即星際迷航中的 Borg(博格人)。Kubernetes 標(biāo)識(shí)中舵輪有七個(gè)輪輻就是對(duì)該項(xiàng)目代號(hào)的致意。
為什么 Kubernetes 的縮寫(xiě)是 K8S 呢?我個(gè)人贊同Why Kubernetes is Abbreviated k8s中說(shuō)的觀點(diǎn)“嘛,寫(xiě)全稱(chēng)也太累了吧,不如整個(gè)縮寫(xiě)”。其實(shí)只保留首位字符,用具體數(shù)字來(lái)替代省略的字符個(gè)數(shù)的做法,還是比較常見(jiàn)的。
1.2 為什么是 K8S?
試想下傳統(tǒng)的后端部署辦法:把程序包(包括可執(zhí)行二進(jìn)制文件、配置文件等)放到服務(wù)器上,接著運(yùn)行啟動(dòng)腳本把程序跑起來(lái),同時(shí)啟動(dòng)守護(hù)腳本定期檢查程序運(yùn)行狀態(tài)、必要的話重新拉起程序。
有問(wèn)題嗎?顯然有!最大的一個(gè)問(wèn)題在于:**如果服務(wù)的請(qǐng)求量上來(lái),已部署的服務(wù)響應(yīng)不過(guò)來(lái)怎么辦?**傳統(tǒng)的做法往往是,如果請(qǐng)求量、內(nèi)存、CPU 超過(guò)閾值做了告警,運(yùn)維馬上再加幾臺(tái)服務(wù)器,部署好服務(wù)之后,接入負(fù)載均衡來(lái)分擔(dān)已有服務(wù)的壓力。
問(wèn)題出現(xiàn)了:從監(jiān)控告警到部署服務(wù),中間需要人力介入!那么,有沒(méi)有辦法自動(dòng)完成服務(wù)的部署、更新、卸載和擴(kuò)容、縮容呢?
這,就是 K8S 要做的事情:自動(dòng)化運(yùn)維管理 Docker(容器化)程序。
1.3 K8S 怎么做?
我們已經(jīng)知道了 K8S 的核心功能:自動(dòng)化運(yùn)維管理多個(gè)容器化程序。那么 K8S 怎么做到的呢?這里,我們從宏觀架構(gòu)上來(lái)學(xué)習(xí) K8S 的設(shè)計(jì)思想。首先看下圖,圖片來(lái)自文章Components of Kubernetes Architecture:

K8S 是屬于主從設(shè)備模型(Master-Slave 架構(gòu)),即有 Master 節(jié)點(diǎn)負(fù)責(zé)核心的調(diào)度、管理和運(yùn)維,Slave 節(jié)點(diǎn)則在執(zhí)行用戶(hù)的程序。但是在 K8S 中,主節(jié)點(diǎn)一般被稱(chēng)為Master Node 或者 Head Node(本文采用 Master Node 稱(chēng)呼方式),而從節(jié)點(diǎn)則被稱(chēng)為Worker Node 或者 Node(本文采用 Worker Node 稱(chēng)呼方式)。
要注意一點(diǎn):Master Node 和 Worker Node 是分別安裝了 K8S 的 Master 和 Woker 組件的實(shí)體服務(wù)器,每個(gè) Node 都對(duì)應(yīng)了一臺(tái)實(shí)體服務(wù)器(雖然 Master Node 可以和其中一個(gè) Worker Node 安裝在同一臺(tái)服務(wù)器,但是建議 Master Node 單獨(dú)部署),所有 Master Node 和 Worker Node 組成了 K8S 集群,同一個(gè)集群可能存在多個(gè) Master Node 和 Worker Node。
首先來(lái)看Master Node都有哪些組件:
API Server。K8S 的請(qǐng)求入口服務(wù)。API Server 負(fù)責(zé)接收 K8S 所有請(qǐng)求(來(lái)自 UI 界面或者 CLI 命令行工具),然后,API Server 根據(jù)用戶(hù)的具體請(qǐng)求,去通知其他組件干活。 Scheduler。K8S 所有 Worker Node 的調(diào)度器。當(dāng)用戶(hù)要部署服務(wù)時(shí),Scheduler 會(huì)選擇最合適的 Worker Node(服務(wù)器)來(lái)部署。 Controller Manager。K8S 所有 Worker Node 的監(jiān)控器。Controller Manager 有很多具體的 Controller,在文章Components of Kubernetes Architecture中提到的有 Node Controller、Service Controller、Volume Controller 等。Controller 負(fù)責(zé)監(jiān)控和調(diào)整在 Worker Node 上部署的服務(wù)的狀態(tài),比如用戶(hù)要求 A 服務(wù)部署 2 個(gè)副本,那么當(dāng)其中一個(gè)服務(wù)掛了的時(shí)候,Controller 會(huì)馬上調(diào)整,讓 Scheduler 再選擇一個(gè) Worker Node 重新部署服務(wù)。 etcd。K8S 的存儲(chǔ)服務(wù)。etcd 存儲(chǔ)了 K8S 的關(guān)鍵配置和用戶(hù)配置,K8S 中僅 API Server 才具備讀寫(xiě)權(quán)限,其他組件必須通過(guò) API Server 的接口才能讀寫(xiě)數(shù)據(jù)(見(jiàn)Kubernetes Works Like an Operating System)。
接著來(lái)看Worker Node的組件,筆者更贊同HOW DO APPLICATIONS RUN ON KUBERNETES文章中提到的組件介紹:
Kubelet。Worker Node 的監(jiān)視器,以及與 Master Node 的通訊器。Kubelet 是 Master Node 安插在 Worker Node 上的“眼線”,它會(huì)定期向 Worker Node 匯報(bào)自己 Node 上運(yùn)行的服務(wù)的狀態(tài),并接受來(lái)自 Master Node 的指示采取調(diào)整措施。 Kube-Proxy。K8S 的網(wǎng)絡(luò)代理。私以為稱(chēng)呼為 Network-Proxy 可能更適合?Kube-Proxy 負(fù)責(zé) Node 在 K8S 的網(wǎng)絡(luò)通訊、以及對(duì)外部網(wǎng)絡(luò)流量的負(fù)載均衡。 Container Runtime。Worker Node 的運(yùn)行環(huán)境。即安裝了容器化所需的軟件環(huán)境確保容器化程序能夠跑起來(lái),比如 Docker Engine。大白話就是幫忙裝好了 Docker 運(yùn)行環(huán)境。 Logging Layer。K8S 的監(jiān)控狀態(tài)收集器。私以為稱(chēng)呼為 Monitor 可能更合適?Logging Layer 負(fù)責(zé)采集 Node 上所有服務(wù)的 CPU、內(nèi)存、磁盤(pán)、網(wǎng)絡(luò)等監(jiān)控項(xiàng)信息。 Add-Ons。K8S 管理運(yùn)維 Worker Node 的插件組件。有些文章認(rèn)為 Worker Node 只有三大組件,不包含 Add-On,但筆者認(rèn)為 K8S 系統(tǒng)提供了 Add-On 機(jī)制,讓用戶(hù)可以擴(kuò)展更多定制化功能,是很不錯(cuò)的亮點(diǎn)。
總結(jié)來(lái)看,K8S 的 Master Node 具備:請(qǐng)求入口管理(API Server),Worker Node 調(diào)度(Scheduler),監(jiān)控和自動(dòng)調(diào)節(jié)(Controller Manager),以及存儲(chǔ)功能(etcd);而 K8S 的 Worker Node 具備:狀態(tài)和監(jiān)控收集(Kubelet),網(wǎng)絡(luò)和負(fù)載均衡(Kube-Proxy)、保障容器化運(yùn)行環(huán)境(Container Runtime)、以及定制化功能(Add-Ons)。
到這里,相信你已經(jīng)對(duì) K8S 究竟是做什么的,有了大概認(rèn)識(shí)。接下來(lái),再來(lái)認(rèn)識(shí)下 K8S 的 Deployment、Pod、Replica Set、Service 等,但凡談到 K8S,就繞不開(kāi)這些名詞,而這些名詞也是最讓 K8S 新手們感到頭疼、困惑的。
II. K8S 重要概念
2.1 Pod 實(shí)例
官方對(duì)于Pod的解釋是:
Pod是可以在 Kubernetes 中創(chuàng)建和管理的、最小的可部署的計(jì)算單元。
這樣的解釋還是很難讓人明白究竟 Pod 是什么,但是對(duì)于 K8S 而言,Pod 可以說(shuō)是所有對(duì)象中最重要的概念了!因此,我們必須首先清楚地知道“Pod 是什么”,再去了解其他的對(duì)象。
從官方給出的定義,聯(lián)想下“最小的 xxx 單元”,是不是可以想到本科在學(xué)校里學(xué)習(xí)“進(jìn)程”的時(shí)候,教科書(shū)上有一段類(lèi)似的描述:資源分配的最小單位;還有”線程“的描述是:CPU 調(diào)度的最小單位。什么意思呢?”最小 xx 單位“要么就是事物的衡量標(biāo)準(zhǔn)單位,要么就是資源的閉包、集合。前者比如長(zhǎng)度米、時(shí)間秒;后者比如一個(gè)”進(jìn)程“是存儲(chǔ)和計(jì)算的閉包,一個(gè)”線程“是 CPU 資源(包括寄存器、ALU 等)的閉包。
同樣的,Pod 就是 K8S 中一個(gè)服務(wù)的閉包。這么說(shuō)的好像還是有點(diǎn)玄乎,更加云里霧里了。簡(jiǎn)單來(lái)說(shuō),Pod 可以被理解成一群可以共享網(wǎng)絡(luò)、存儲(chǔ)和計(jì)算資源的容器化服務(wù)的集合。再打個(gè)形象的比喻,在同一個(gè) Pod 里的幾個(gè) Docker 服務(wù)/程序,好像被部署在同一臺(tái)機(jī)器上,可以通過(guò) localhost 互相訪問(wèn),并且可以共用 Pod 里的存儲(chǔ)資源(這里是指 Docker 可以掛載 Pod 內(nèi)的數(shù)據(jù)卷,數(shù)據(jù)卷的概念,后文會(huì)詳細(xì)講述,暫時(shí)理解為“需要手動(dòng) mount 的磁盤(pán)”)。筆者總結(jié) Pod 如下圖,可以看到:同一個(gè) Pod 之間的 Container 可以通過(guò) localhost 互相訪問(wèn),并且可以掛載 Pod 內(nèi)所有的數(shù)據(jù)卷;但是不同的 Pod 之間的 Container 不能用 localhost 訪問(wèn),也不能掛載其他 Pod 的數(shù)據(jù)卷。

對(duì) Pod 有直觀的認(rèn)識(shí)之后,接著來(lái)看 K8S 中 Pod 究竟長(zhǎng)什么樣子,具體包括哪些資源?
K8S 中所有的對(duì)象都通過(guò) yaml 來(lái)表示,筆者從官方網(wǎng)站摘錄了一個(gè)最簡(jiǎn)單的 Pod 的 yaml:
apiVersion:?v1
kind:?Pod
metadata:
??name:?memory-demo
??namespace:?mem-example
spec:
??containers:
??-?name:?memory-demo-ctr
????image:?polinux/stress
????resources:
??????limits:
????????memory:?"200Mi"
??????requests:
????????memory:?"100Mi"
????command:?["stress"]
????args:?["--vm",?"1",?"--vm-bytes",?"150M",?"--vm-hang",?"1"]
????volumeMounts:
????-?name:?redis-storage
??????mountPath:?/data/redis
??volumes:
??-?name:?redis-storage
????emptyDir:?{}
看不懂不必慌張,且耐心聽(tīng)下面的解釋?zhuān)?/p>
apiVersion記錄 K8S 的 API Server 版本,現(xiàn)在看到的都是v1,用戶(hù)不用管。kind記錄該 yaml 的對(duì)象,比如這是一份 Pod 的 yaml 配置文件,那么值內(nèi)容就是Pod。metadata記錄了 Pod 自身的元數(shù)據(jù),比如這個(gè) Pod 的名字、這個(gè) Pod 屬于哪個(gè) namespace(命名空間的概念,后文會(huì)詳述,暫時(shí)理解為“同一個(gè)命名空間內(nèi)的對(duì)象互相可見(jiàn)”)。spec記錄了 Pod 內(nèi)部所有的資源的詳細(xì)信息,看懂這個(gè)很重要:containers記錄了 Pod 內(nèi)的容器信息,containers包括了:name容器名,image容器的鏡像地址,resources容器需要的 CPU、內(nèi)存、GPU 等資源,command容器的入口命令,args容器的入口參數(shù),volumeMounts容器要掛載的 Pod 數(shù)據(jù)卷等。可以看到,上述這些信息都是啟動(dòng)容器的必要和必需的信息。volumes記錄了 Pod 內(nèi)的數(shù)據(jù)卷信息,后文會(huì)詳細(xì)介紹 Pod 的數(shù)據(jù)卷。
2.2 Volume 數(shù)據(jù)卷
K8S 支持很多類(lèi)型的 volume 數(shù)據(jù)卷掛載,具體請(qǐng)參見(jiàn)K8S 卷。前文就“如何理解 volume”提到:“需要手動(dòng) mount 的磁盤(pán)”,此外,有一點(diǎn)可以幫助理解:數(shù)據(jù)卷 volume 是 Pod 內(nèi)部的磁盤(pán)資源。
其實(shí),單單就 Volume 來(lái)說(shuō),不難理解。但是上面還看到了volumeMounts,這倆是什么關(guān)系呢?
volume 是 K8S 的對(duì)象,對(duì)應(yīng)一個(gè)實(shí)體的數(shù)據(jù)卷;而 volumeMounts 只是 container 的掛載點(diǎn),對(duì)應(yīng) container 的其中一個(gè)參數(shù)。但是,volumeMounts 依賴(lài)于 volume,只有當(dāng) Pod 內(nèi)有 volume 資源的時(shí)候,該 Pod 內(nèi)部的 container 才可能有 volumeMounts。
2.3 Container 容器
本文中提到的鏡像 Image、容器 Container,都指代了 Pod 下的一個(gè)container。關(guān)于 K8S 中的容器,在 2.1Pod 章節(jié)都已經(jīng)交代了,這里無(wú)非再啰嗦一句:一個(gè) Pod 內(nèi)可以有多個(gè)容器 container。
在 Pod 中,容器也有分類(lèi),對(duì)這個(gè)感興趣的同學(xué)歡迎自行閱讀更多資料:
標(biāo)準(zhǔn)容器 Application Container。 初始化容器 Init Container。 邊車(chē)容器 Sidecar Container。 臨時(shí)容器 Ephemeral Container。
一般來(lái)說(shuō),我們部署的大多是標(biāo)準(zhǔn)容器( Application Container)。
2.4 Deployment 和 ReplicaSet(簡(jiǎn)稱(chēng) RS)
除了 Pod 之外,K8S 中最常聽(tīng)到的另一個(gè)對(duì)象就是 Deployment 了。那么,什么是 Deployment 呢?官方給出了一個(gè)要命的解釋?zhuān)?/p>
一個(gè)?Deployment?控制器為 Pods 和 ReplicaSets 提供聲明式的更新能力。
你負(fù)責(zé)描述 Deployment 中的?目標(biāo)狀態(tài),而 Deployment 控制器以受控速率更改實(shí)際狀態(tài), 使其變?yōu)槠谕麪顟B(tài)。你可以定義 Deployment 以創(chuàng)建新的 ReplicaSet,或刪除現(xiàn)有 Deployment,并通過(guò)新的 Deployment 收養(yǎng)其資源。
翻譯一下:Deployment 的作用是管理和控制 Pod 和 ReplicaSet,管控它們運(yùn)行在用戶(hù)期望的狀態(tài)中。哎,打個(gè)形象的比喻,Deployment 就是包工頭,主要負(fù)責(zé)監(jiān)督底下的工人 Pod 干活,確保每時(shí)每刻有用戶(hù)要求數(shù)量的 Pod 在工作。如果一旦發(fā)現(xiàn)某個(gè)工人 Pod 不行了,就趕緊新拉一個(gè) Pod 過(guò)來(lái)替換它。
新的問(wèn)題又來(lái)了:那什么是 ReplicaSets 呢?
ReplicaSet 的目的是維護(hù)一組在任何時(shí)候都處于運(yùn)行狀態(tài)的 Pod 副本的穩(wěn)定集合。因此,它通常用來(lái)保證給定數(shù)量的、完全相同的 Pod 的可用性。
再來(lái)翻譯下:ReplicaSet 的作用就是管理和控制 Pod,管控他們好好干活。但是,ReplicaSet 受控于 Deployment。形象來(lái)說(shuō),ReplicaSet 就是總包工頭手下的小包工頭。
筆者總結(jié)得到下面這幅圖,希望能幫助理解:

新的問(wèn)題又來(lái)了:如果都是為了管控 Pod 好好干活,為什么要設(shè)置 Deployment 和 ReplicaSet 兩個(gè)層級(jí)呢,直接讓 Deployment 來(lái)管理不可以嗎?
回答:不清楚,但是私以為是因?yàn)橄扔?ReplicaSet,但是使用中發(fā)現(xiàn) ReplicaSet 不夠滿(mǎn)足要求,于是又整了一個(gè) Deployment(有清楚 Deployment 和 ReplicaSet 聯(lián)系和區(qū)別的小伙伴歡迎留言啊)。
但是,從 K8S 使用者角度來(lái)看,用戶(hù)會(huì)直接操作 Deployment 部署服務(wù),而當(dāng) Deployment 被部署的時(shí)候,K8S 會(huì)自動(dòng)生成要求的 ReplicaSet 和 Pod。在K8S 官方文檔中也指出用戶(hù)只需要關(guān)心 Deployment 而不操心 ReplicaSet:
This actually means that you may never need to manipulate ReplicaSet objects: use a Deployment instead, and define your application in the spec section.
這實(shí)際上意味著您可能永遠(yuǎn)不需要操作 ReplicaSet 對(duì)象:直接使用 Deployments 并在規(guī)范部分定義應(yīng)用程序。
補(bǔ)充說(shuō)明:在 K8S 中還有一個(gè)對(duì)象 ---?ReplicationController(簡(jiǎn)稱(chēng) RC),官方文檔對(duì)它的定義是:
ReplicationController?確保在任何時(shí)候都有特定數(shù)量的 Pod 副本處于運(yùn)行狀態(tài)。換句話說(shuō),ReplicationController 確保一個(gè) Pod 或一組同類(lèi)的 Pod 總是可用的。
怎么樣,和 ReplicaSet 是不是很相近?在Deployments, ReplicaSets, and pods教程中說(shuō)“ReplicationController 是 ReplicaSet 的前身”,官方也推薦用 Deployment 取代 ReplicationController 來(lái)部署服務(wù)。
2.5 Service 和 Ingress
吐槽下 K8S 的概念/對(duì)象/資源是真的多?。?strong style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">前文介紹的 Deployment、ReplicationController 和 ReplicaSet 主要管控 Pod 程序服務(wù);那么,Service 和 Ingress 則負(fù)責(zé)管控 Pod 網(wǎng)絡(luò)服務(wù)。
我們先來(lái)看看官方文檔中 Service 的定義:
將運(yùn)行在一組 Pods 上的應(yīng)用程序公開(kāi)為網(wǎng)絡(luò)服務(wù)的抽象方法。
使用 Kubernetes,您無(wú)需修改應(yīng)用程序即可使用不熟悉的服務(wù)發(fā)現(xiàn)機(jī)制。Kubernetes 為 Pods 提供自己的 IP 地址,并為一組 Pod 提供相同的 DNS 名, 并且可以在它們之間進(jìn)行負(fù)載均衡。
翻譯下:K8S 中的服務(wù)(Service)并不是我們常說(shuō)的“服務(wù)”的含義,而更像是網(wǎng)關(guān)層,是若干個(gè) Pod 的流量入口、流量均衡器。
那么,為什么要 Service 呢?
私以為在這一點(diǎn)上,官方文檔講解地非常清楚:
Kubernetes Pod 是有生命周期的。它們可以被創(chuàng)建,而且銷(xiāo)毀之后不會(huì)再啟動(dòng)。如果您使用 Deployment 來(lái)運(yùn)行您的應(yīng)用程序,則它可以動(dòng)態(tài)創(chuàng)建和銷(xiāo)毀 Pod。
每個(gè) Pod 都有自己的 IP 地址,但是在 Deployment 中,在同一時(shí)刻運(yùn)行的 Pod 集合可能與稍后運(yùn)行該應(yīng)用程序的 Pod 集合不同。
這導(dǎo)致了一個(gè)問(wèn)題:如果一組 Pod(稱(chēng)為“后端”)為群集內(nèi)的其他 Pod(稱(chēng)為“前端”)提供功能, 那么前端如何找出并跟蹤要連接的 IP 地址,以便前端可以使用工作量的后端部分?
補(bǔ)充說(shuō)明:K8S 集群的網(wǎng)絡(luò)管理和拓?fù)湟灿刑貏e的設(shè)計(jì),以后會(huì)專(zhuān)門(mén)出一章節(jié)來(lái)詳細(xì)介紹 K8S 中的網(wǎng)絡(luò)。這里需要清楚一點(diǎn):K8S 集群內(nèi)的每一個(gè) Pod 都有自己的 IP(是不是很類(lèi)似一個(gè) Pod 就是一臺(tái)服務(wù)器,然而事實(shí)上是多個(gè) Pod 存在于一臺(tái)服務(wù)器上,只不過(guò)是 K8S 做了網(wǎng)絡(luò)隔離),在 K8S 集群內(nèi)部還有 DNS 等網(wǎng)絡(luò)服務(wù)(一個(gè) K8S 集群就如同管理了多區(qū)域的服務(wù)器,可以做復(fù)雜的網(wǎng)絡(luò)拓?fù)洌?/p>
此外,筆者推薦k8s 外網(wǎng)如何訪問(wèn)業(yè)務(wù)應(yīng)用對(duì)于 Service 的介紹,不過(guò)對(duì)于新手而言,推薦閱讀前半部分對(duì)于 service 的介紹即可,后半部分就太復(fù)雜了。我這里做了簡(jiǎn)單的總結(jié):
Service 是 K8S 服務(wù)的核心,屏蔽了服務(wù)細(xì)節(jié),統(tǒng)一對(duì)外暴露服務(wù)接口,真正做到了“微服務(wù)”。舉個(gè)例子,我們的一個(gè)服務(wù) A,部署了 3 個(gè)備份,也就是 3 個(gè) Pod;對(duì)于用戶(hù)來(lái)說(shuō),只需要關(guān)注一個(gè) Service 的入口就可以,而不需要操心究竟應(yīng)該請(qǐng)求哪一個(gè) Pod。優(yōu)勢(shì)非常明顯:一方面外部用戶(hù)不需要感知因?yàn)?Pod 上服務(wù)的意外崩潰、K8S 重新拉起 Pod 而造成的 IP 變更,外部用戶(hù)也不需要感知因升級(jí)、變更服務(wù)帶來(lái)的 Pod 替換而造成的 IP 變化,另一方面,Service 還可以做流量負(fù)載均衡。
但是,Service 主要負(fù)責(zé) K8S 集群內(nèi)部的網(wǎng)絡(luò)拓?fù)?。那么集群外部怎么訪問(wèn)集群內(nèi)部呢?這個(gè)時(shí)候就需要 Ingress 了,官方文檔中的解釋是:
Ingress 是對(duì)集群中服務(wù)的外部訪問(wèn)進(jìn)行管理的 API 對(duì)象,典型的訪問(wèn)方式是 HTTP。
Ingress 可以提供負(fù)載均衡、SSL 終結(jié)和基于名稱(chēng)的虛擬托管。
翻譯一下:Ingress 是整個(gè) K8S 集群的接入層,復(fù)雜集群內(nèi)外通訊。
最后,筆者把 Ingress 和 Service 的關(guān)系繪制網(wǎng)絡(luò)拓?fù)潢P(guān)系圖如下,希望對(duì)理解這兩個(gè)概念有所幫助:

2.6 namespace 命名空間
和前文介紹的所有的概念都不一樣,namespace 跟 Pod 沒(méi)有直接關(guān)系,而是 K8S 另一個(gè)維度的對(duì)象?;蛘哒f(shuō),前文提到的概念都是為了服務(wù) Pod 的,而 namespace 則是為了服務(wù)整個(gè) K8S 集群的。
那么,namespace 是什么呢?
上官方文檔定義:
Kubernetes 支持多個(gè)虛擬集群,它們底層依賴(lài)于同一個(gè)物理集群。這些虛擬集群被稱(chēng)為名字空間。
翻譯一下:namespace 是為了把一個(gè) K8S 集群劃分為若干個(gè)資源不可共享的虛擬集群而誕生的。
也就是說(shuō),可以通過(guò)在 K8S 集群內(nèi)創(chuàng)建 namespace 來(lái)分隔資源和對(duì)象。比如我有 2 個(gè)業(yè)務(wù) A 和 B,那么我可以創(chuàng)建 ns-a 和 ns-b 分別部署業(yè)務(wù) A 和 B 的服務(wù),如在 ns-a 中部署了一個(gè) deployment,名字是 hello,返回用戶(hù)的是“hello a”;在 ns-b 中也部署了一個(gè) deployment,名字恰巧也是 hello,返回用戶(hù)的是“hello b”(要知道,在同一個(gè) namespace 下 deployment 不能同名;但是不同 namespace 之間沒(méi)有影響)。前文提到的所有對(duì)象,都是在 namespace 下的;當(dāng)然,也有一些對(duì)象是不隸屬于 namespace 的,而是在 K8S 集群內(nèi)全局可見(jiàn)的,官方文檔提到的可以通過(guò)命令來(lái)查看,具體命令的使用辦法,筆者會(huì)出后續(xù)的實(shí)戰(zhàn)文章來(lái)介紹,先貼下命令:
#?位于名字空間中的資源
kubectl?api-resources?--namespaced=true
#?不在名字空間中的資源
kubectl?api-resources?--namespaced=false
不在 namespace 下的對(duì)象有:

在 namespace 下的對(duì)象有(部分):

2.7 其他
K8S 的對(duì)象實(shí)在太多了,2.1-2.6 介紹的是在實(shí)際使用 K8S 部署服務(wù)最常見(jiàn)的。其他的還有 Job、CronJob 等等,在對(duì) K8S 有了比較清楚的認(rèn)知之后,再去學(xué)習(xí)更多的 K8S 對(duì)象,不是難事。
III. 配置 kubectl
3.1 什么是 kubectl?
官方文檔中介紹 kubectl 是:
Kubectl 是一個(gè)命令行接口,用于對(duì) Kubernetes 集群運(yùn)行命令。Kubectl 的配置文件在$HOME/.kube 目錄。我們可以通過(guò)設(shè)置 KUBECONFIG 環(huán)境變量或設(shè)置命令參數(shù)--kubeconfig 來(lái)指定其他位置的 kubeconfig 文件。
也就是說(shuō),可以通過(guò) kubectl 來(lái)操作 K8S 集群,基本語(yǔ)法:
使用以下語(yǔ)法?
kubectl?從終端窗口運(yùn)行命令:kubectl?[command]?[TYPE]?[NAME]?[flags]其中?
command、TYPE、NAME?和?flags?分別是:
command:指定要對(duì)一個(gè)或多個(gè)資源執(zhí)行的操作,例如?create、get、describe、delete。
TYPE:指定資源類(lèi)型。資源類(lèi)型不區(qū)分大小寫(xiě),可以指定單數(shù)、復(fù)數(shù)或縮寫(xiě)形式。例如,以下命令輸出相同的結(jié)果:```shell
kubectl?get?pod?pod1
kubectl?get?pods?pod1
kubectl?get?po?pod1
-?`NAME`:指定資源的名稱(chēng)。名稱(chēng)區(qū)分大小寫(xiě)。如果省略名稱(chēng),則顯示所有資源的詳細(xì)信息?`kubectl get pods`。
在對(duì)多個(gè)資源執(zhí)行操作時(shí),您可以按類(lèi)型和名稱(chēng)指定每個(gè)資源,或指定一個(gè)或多個(gè)文件:
-?要按類(lèi)型和名稱(chēng)指定資源:
??-?要對(duì)所有類(lèi)型相同的資源進(jìn)行分組,請(qǐng)執(zhí)行以下操作:`TYPE1 name1 name2 name<#>`。
?例子:`kubectl get pod example-pod1 example-pod2`
??-?分別指定多個(gè)資源類(lèi)型:`TYPE1/name1 TYPE1/name2 TYPE2/name3 TYPE<#>/name<#>`。
?例子:`kubectl get pod/example-pod1 replicationcontroller/example-rc1`
-?用一個(gè)或多個(gè)文件指定資源:`-f file1 -f file2 -f file<#>`
??-?[使用?YAML?而不是?JSON](https://kubernetes.io/zh/docs/concepts/configuration/overview/#general-config-tips)?因?yàn)?YAML 更容易使用,特別是用于配置文件時(shí)。
?例子:`kubectl get -f ./pod.yaml`
-?`flags`:?指定可選的參數(shù)。例如,可以使用?`-s`?或?`-server`?參數(shù)指定 Kubernetes API 服務(wù)器的地址和端口。
就如何使用 kubectl 而言,官方文檔已經(jīng)說(shuō)得非常清楚。不過(guò)對(duì)于新手而言,還是需要解釋幾句:
kubectl 是 K8S 的命令行工具,并不需要 kubectl 安裝在 K8S 集群的任何 Node 上,但是,需要確保安裝 kubectl 的機(jī)器和 K8S 的集群能夠進(jìn)行網(wǎng)絡(luò)互通。 kubectl 是通過(guò)本地的配置文件來(lái)連接到 K8S 集群的,默認(rèn)保存在$HOME/.kube 目錄下;也可以通過(guò) KUBECONFIG 環(huán)境變量或設(shè)置命令參數(shù)--kubeconfig 來(lái)指定其他位置的 kubeconfig 文件【官方文檔】。
接下來(lái),一起看看怎么使用 kubectl 吧,切身感受下 kubectl 的使用。
請(qǐng)注意,如何安裝 kubectl 的辦法有許多非常明確的教程,比如《安裝并配置 kubectl》,本文不再贅述。
3.2 怎么配置 kubectl?
第一步,必須準(zhǔn)備好要連接/使用的 K8S 的配置文件,筆者給出一份杜撰的配置:
apiVersion:?v1
clusters:
-?cluster:
????certificate-authority-data:?thisisfakecertifcateauthoritydata00000000000
????server:?https://1.2.3.4:1234
??name:?cls-dev
contexts:
-?context:
????cluster:?cls-dev
????user:?kubernetes-admin
??name:?kubernetes-admin@test
current-context:?kubernetes-admin@test
kind:?Config
preferences:?{}
users:
-?name:?kubernetes-admin
??user:
????token:?thisisfaketoken00000
解讀如下:
clusters記錄了 clusters(一個(gè)或多個(gè) K8S 集群)信息:name是這個(gè) cluster(K8S 集群)的名稱(chēng)代號(hào)server是這個(gè) cluster(K8S 集群)的訪問(wèn)方式,一般為 IP+PORTcertificate-authority-data是證書(shū)數(shù)據(jù),只有當(dāng) cluster(K8S 集群)的連接方式是 https 時(shí),為了安全起見(jiàn)需要證書(shū)數(shù)據(jù)users記錄了訪問(wèn) cluster(K8S 集群)的賬號(hào)信息:name是用戶(hù)賬號(hào)的名稱(chēng)代號(hào)user/token是用戶(hù)的 token 認(rèn)證方式,token 不是用戶(hù)認(rèn)證的唯一方式,其他還有賬號(hào)+密碼等。contexts是上下文信息,包括了 cluster(K8S 集群)和訪問(wèn) cluster(K8S 集群)的用戶(hù)賬號(hào)等信息:name是這個(gè)上下文的名稱(chēng)代號(hào)cluster是 cluster(K8S 集群)的名稱(chēng)代號(hào)user是訪問(wèn) cluster(K8S 集群)的用戶(hù)賬號(hào)代號(hào)current-context記錄當(dāng)前 kubectl 默認(rèn)使用的上下文信息kind和apiVersion都是固定值,用戶(hù)不需要關(guān)心preferences則是配置文件的其他設(shè)置信息,筆者沒(méi)有使用過(guò),暫時(shí)不提。
第二步,給 kubectl 配置上配置文件。
--kubeconfig參數(shù)。第一種辦法是每次執(zhí)行 kubectl 的時(shí)候,都帶上--kubeconfig=${CONFIG_PATH}。給一點(diǎn)溫馨小提示:每次都帶這么一長(zhǎng)串的字符非常麻煩,可以用 alias 別名來(lái)簡(jiǎn)化碼字量,比如alias k=kubectl --kubeconfig=${CONFIG_PATH}。KUBECONFIG環(huán)境變量。第二種做法是使用環(huán)境變量KUBECONFIG把所有配置文件都記錄下來(lái),即export KUBECONFIG=$KUBECONFIG:${CONFIG_PATH}。接下來(lái)就可以放心執(zhí)行 kubectl 命令了。$HOME/.kube/config 配置文件。第三種做法是把配置文件的內(nèi)容放到$HOME/.kube/config 內(nèi)。具體做法為: 如果$HOME/.kube/config 不存在,那么 cp ${CONFIG_PATH} $HOME/.kube/config即可;如果如果 $HOME/.kube/config已經(jīng)存在,那么需要把新的配置內(nèi)容加到 $HOME/.kube/config 下。單單只是 cat ${CONFIG_PATH} >> $HOME/.kube/config是不行的,正確的做法是:KUBECONFIG=$HOME/.kube/config:${CONFIG_PATH} kubectl config view --flatten > $HOME/.kube/config?。解釋下這個(gè)命令的意思:先把所有的配置文件添加到環(huán)境變量KUBECONFIG中,然后執(zhí)行kubectl config view --flatten打印出有效的配置文件內(nèi)容,最后覆蓋$HOME/.kube/config 即可。
請(qǐng)注意,上述操作的優(yōu)先級(jí)分別是 1>2>3,也就是說(shuō),kubectl 會(huì)優(yōu)先檢查--kubeconfig,若無(wú)則檢查KUBECONFIG,若無(wú)則最后檢查$HOME/.kube/config,如果還是沒(méi)有,報(bào)錯(cuò)。但凡某一步找到了有效的 cluster,就中斷檢查,去連接 K8S 集群了。
第三步:配置正確的上下文
按照第二步的做法,如果配置文件只有一個(gè) cluster 是沒(méi)有任何問(wèn)題的,但是對(duì)于有多個(gè) cluster 怎么辦呢?到這里,有幾個(gè)關(guān)于配置的必須掌握的命令:
kubectl config get-contexts。列出所有上下文信息。
kubectl config current-context。查看當(dāng)前的上下文信息。其實(shí),命令 1 線束出來(lái)的*所指示的就是當(dāng)前的上下文信息。
kubectl config use-context ${CONTEXT_NAME}。更改上下文信息。
kubectl config set-context ${CONTEXT_NAME}|--current --${KEY}=${VALUE}。修改上下文的元素。比如可以修改用戶(hù)賬號(hào)、集群信息、連接到 K8S 后所在的 namespace。
關(guān)于該命令,還有幾點(diǎn)要啰嗦的:
config set-context可以修改任何在配置文件中的上下文信息,只需要在命令中指定上下文名稱(chēng)就可以。而--current 則指代當(dāng)前上下文。上下文信息所包括的內(nèi)容有:cluster 集群(名稱(chēng))、用戶(hù)賬號(hào)(名稱(chēng))、連接到 K8S 后所在的 namespace,因此有
config set-context嚴(yán)格意義上的用法:kubectl config set-context [NAME|--current] [--cluster=cluster_nickname] [--user=user_nickname] [--namespace=namespace] [options](備注:[options]可以通過(guò) kubectl options 查看)
綜上,如何操作 kubectl 配置都已交代。
IV. kubectl 部署服務(wù)
K8S 核心功能就是部署運(yùn)維容器化服務(wù),因此最重要的就是如何又快又好地部署自己的服務(wù)了。本章會(huì)介紹如何部署 Pod 和 Deployment。
4.1 如何部署 Pod?
通過(guò) kubectl 部署 Pod 的辦法分為兩步:1). 準(zhǔn)備 Pod 的 yaml 文件;2). 執(zhí)行 kubectl 命令部署
第一步:準(zhǔn)備 Pod 的 yaml 文件。關(guān)于 Pod 的 yaml 文件初步解釋?zhuān)鞠盗猩弦黄恼隆禟8S 系列一:概念入門(mén)》已經(jīng)有了初步介紹,這里再?gòu)?fù)習(xí)下:
apiVersion:?v1
kind:?Pod
metadata:
??name:?memory-demo
??namespace:?mem-example
spec:
??containers:
??-?name:?memory-demo-ctr
????image:?polinux/stress
????resources:
??????limits:
????????memory:?"200Mi"
??????requests:
????????memory:?"100Mi"
????command:?["stress"]
????args:?["--vm",?"1",?"--vm-bytes",?"150M",?"--vm-hang",?"1"]
????volumeMounts:
????-?name:?redis-storage
??????mountPath:?/data/redis
??volumes:
??-?name:?redis-storage
????emptyDir:?{}
繼續(xù)解讀:
metadata,對(duì)于新入門(mén)的同學(xué)來(lái)說(shuō),需要重點(diǎn)掌握的兩個(gè)字段:name。這個(gè) Pod 的名稱(chēng),后面到 K8S 集群中查找 Pod 的關(guān)鍵字段。namespace。命名空間,即該 Pod 隸屬于哪個(gè) namespace 下,關(guān)于 Pod 和 namespace 的關(guān)系,上一篇文章已經(jīng)交代了。spec記錄了 Pod 內(nèi)部所有的資源的詳細(xì)信息,這里我們重點(diǎn)查看containers下的幾個(gè)重要字段:name。Pod 下該容器名稱(chēng),后面查找 Pod 下的容器的關(guān)鍵字段。image。容器的鏡像地址,K8S 會(huì)根據(jù)這個(gè)字段去拉取鏡像。resources。容器化服務(wù)涉及到的 CPU、內(nèi)存、GPU 等資源要求??梢钥吹接?code style="margin-right: 2px;margin-left: 2px;padding: 2px 4px;max-width: 100%;border-radius: 4px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);word-break: break-all;font-family: 'Microsoft YaHei';box-sizing: border-box !important;overflow-wrap: break-word !important;">limits和requests兩個(gè)子項(xiàng),那么這兩者有什么區(qū)別嗎,該怎么使用?在What's the difference between Pod resources.limits and resources.requests in Kubernetes?回答了:limits是 K8S 為該容器至多分配的資源配額;而requests則是 K8S 為該容器至少分配的資源配額。打個(gè)比方,配置中要求了 memory 的requests為 100M,而此時(shí)如果 K8S 集群中所有的 Node 的可用內(nèi)存都不足 100M,那么部署服務(wù)會(huì)失敗;又如果有一個(gè) Node 的內(nèi)存有 16G 充裕,可以部署該 Pod,而在運(yùn)行中,該容器服務(wù)發(fā)生了內(nèi)存泄露,那么一旦超過(guò) 200M 就會(huì)因?yàn)?OOM 被 kill,盡管此時(shí)該機(jī)器上還有 15G+的內(nèi)存。command。容器的入口命令。對(duì)于這個(gè)筆者還存在很多困惑不解的地方,暫時(shí)挖個(gè)坑,有清楚的同學(xué)歡迎留言。args。容器的入口參數(shù)。同上,有清楚的同學(xué)歡迎留言。volumeMounts。容器要掛載的 Pod 數(shù)據(jù)卷等。請(qǐng)務(wù)必記住:Pod 的數(shù)據(jù)卷只有被容器掛載后才能使用!
第二步:執(zhí)行 kubectl 命令部署。有了 Pod 的 yaml 文件之后,就可以用 kubectl 部署了,命令非常簡(jiǎn)單:kubectl create -f ${POD_YAML}。
隨后,會(huì)提示該命令是否執(zhí)行成功,比如 yaml 內(nèi)容不符合要求,則會(huì)提示哪一行有問(wèn)題:

修正后,再次部署:

4.2 如何部署 Deployment?
第一步:準(zhǔn)備 Deployment 的 yaml 文件。首先來(lái)看 Deployment 的 yaml 文件內(nèi)容:
?apiVersion:?extensions/v1beta1
?kind:?Deployment
?metadata:
???name:?rss-site
???namespace:?mem-example
?spec:
???replicas:?2
???template:
?????metadata:
???????labels:
?????????app:?web
?????spec:
??????containers:
???????-?name:?memory-demo-ctr
?????????image:?polinux/stress
?????????resources:
?????????limits:
???????????emory:?"200Mi"
?????????requests:
???????????memory:?"100Mi"
?????????command:?["stress"]
?????????args:?["--vm",?"1",?"--vm-bytes",?"150M",?"--vm-hang",?"1"]
?????????volumeMounts:
?????????-?name:?redis-storage
???????????mountPath:?/data/redis
?????volumes:
?????-?name:?redis-storage
???????emptyDir:?{}
繼續(xù)來(lái)看幾個(gè)重要的字段:
metadata同 Pod 的 yaml,這里提一點(diǎn):如果沒(méi)有指明 namespace,那么就是用 kubectl 默認(rèn)的 namespace(如果 kubectl 配置文件中沒(méi)有指明 namespace,那么就是 default 空間)。spec,可以看到 Deployment 的spec字段是在 Pod 的spec內(nèi)容外“包了一層”,那就來(lái)看 Deployment 有哪些需要注意的:metadata,新手同學(xué)先不管這邊的信息。spec,會(huì)發(fā)現(xiàn)這完完全全是上文提到的 Pod 的spec內(nèi)容,在這里寫(xiě)明了 Deployment 下屬管理的每個(gè) Pod 的具體內(nèi)容。replicas。副本個(gè)數(shù)。也就是該 Deployment 需要起多少個(gè)相同的 Pod,如果用戶(hù)成功在 K8S 中配置了 n(n>1)個(gè),那么 Deployment 會(huì)確保在集群中始終有 n 個(gè)服務(wù)在運(yùn)行。template。
第二步:執(zhí)行 kubectl 命令部署。Deployment 的部署辦法同 Pod:kubectl create -f ${DEPLOYMENT_YAML}。由此可見(jiàn),K8S 會(huì)根據(jù)配置文件中的kind字段來(lái)判斷具體要?jiǎng)?chuàng)建的是什么資源。
這里插一句題外話:部署完 deployment 之后,可以查看到自動(dòng)創(chuàng)建了 ReplicaSet 和 Pod,如下圖所示:

還有一個(gè)有趣的事情:通過(guò) Deployment 部署的服務(wù),其下屬的 RS 和 Pod 命名是有規(guī)則的。讀者朋友們自己總結(jié)發(fā)現(xiàn)哦。
綜上,如何部署一個(gè) Pod 或者 Deployment 就結(jié)束了。
V. kubectl 查看、更新/編輯、刪除服務(wù)
作為 K8S 使用者而言,更關(guān)心的問(wèn)題應(yīng)該是本章所要討論的話題:如何通過(guò) kubectl 查看、更新/編輯、刪除在 K8S 上部署著的服務(wù)。
5.1 如何查看服務(wù)?
請(qǐng)務(wù)必記得一個(gè)事情:在 K8S 中,一個(gè)獨(dú)立的服務(wù)即對(duì)應(yīng)一個(gè) Pod。即,當(dāng)我們說(shuō)要 xxx 一個(gè)服務(wù)的就是,也就是操作一個(gè) Pod。而與 Pod 服務(wù)相關(guān)的且需要用戶(hù)關(guān)心的,有 Deployment。
通過(guò) kubectl 查看服務(wù)的基本命令是:
$?kubectl?get|describe?${RESOURCE}?[-o?${FORMAT}]?-n=${NAMESPACE}
#?${RESOURCE}有:?pod、deployment、replicaset(rs)
在此之前,還有一個(gè)需要回憶的事情是:Deployment、ReplicaSet 和 Pod 之間的關(guān)系 - 層層隸屬;以及這些資源和 namespace 的關(guān)系是 - 隸屬。如下圖所示。

因此,要查看一個(gè)服務(wù),也就是一個(gè) Pod,必須首先指定 namespace!那么,如何查看集群中所有的 namespace 呢?kubectl get ns:

于是,只需要通過(guò)-n=${NAMESPACE}就可以指定自己要操作的資源所在的 namespace。比如查看 Pod:kubectl get pod -n=oona-test,同理,查看 Deployment:kubectl get deployment -n=oona-test。
問(wèn)題又來(lái)了:如果已經(jīng)忘記自己所部屬的服務(wù)所在的 namespace 怎么辦?這么多 namespace,一個(gè)一個(gè)查看過(guò)來(lái)嗎?
kubectl get pod --all-namespaces

這樣子就可以看到所有 namespace 下面部署的 Pod 了!同理,要查找所有的命名空間下的 Deployment 的命令是:kubectl get deployment --all-namespaces。
于是,就可以開(kāi)心地查看 Pod:kubectl get pod [-o wide] -n=oona-test,或者查看 Deployment:kubectl get deployment [-o wide] -n=oona-test。
哎,這里是否加-o wide有什么區(qū)別嗎?實(shí)際操作下就明白了,其他資源亦然:

哎,我們看到之前部署的 Pod 服務(wù) memory-demo 顯示的“ImagePullBackOff”是怎么回事呢?先不著急,我們慢慢看下去。
5.2 如何更新/編輯服務(wù)?
兩種辦法:1). 修改 yaml 文件后通過(guò) kubectl 更新;2). 通過(guò) kubectl 直接編輯 K8S 上的服務(wù)。
方法一:修改 yaml 文件后通過(guò) kubectl 更新。我們看到,創(chuàng)建一個(gè) Pod 或者 Deployment 的命令是kubectl create -f ${YAML}。但是,如果 K8S 集群當(dāng)前的 namespace 下已經(jīng)有該服務(wù)的話,會(huì)提示資源已經(jīng)存在:

通過(guò) kubectl 更新的命令是kubectl apply -f ${YAML},我們?cè)賮?lái)試一試:

(備注:命令kubectl apply -f ${YAML}也可以用于首次創(chuàng)建一個(gè)服務(wù)哦)
方法二:通過(guò) kubectl 直接編輯 K8S 上的服務(wù)。命令為kubectl edit ${RESOURCE} ${NAME},比如修改剛剛的 Pod 的命令為kubectl edit pod memory-demo,然后直接編輯自己要修改的內(nèi)容即可。
但是請(qǐng)注意,無(wú)論方法一還是方法二,能修改的內(nèi)容還是有限的,從筆者實(shí)戰(zhàn)下來(lái)的結(jié)論是:只能修改/更新鏡像的地址和個(gè)別幾個(gè)字段。如果修改其他字段,會(huì)報(bào)錯(cuò):
The Pod "memory-demo" is invalid: spec: Forbidden: pod updates may not change fields other than?
spec.containers[*].image,?spec.initContainers[*].image,?spec.activeDeadlineSeconds?or?spec.tolerations?(only additions to existing tolerations)
如果真的要修改其他字段怎么辦呢?恐怕只能刪除服務(wù)后重新部署了。
5.3 如何刪除服務(wù)?
在 K8S 上刪除服務(wù)的操作非常簡(jiǎn)單,命令為kubectl delete ${RESOURCE} ${NAME}。比如刪除一個(gè) Pod 是:kubectl delete pod memory-demo,再比如刪除一個(gè) Deployment 的命令是:kubectl delete deployment ${DEPLOYMENT_NAME}。但是,請(qǐng)注意:
如果只部署了一個(gè) Pod,那么直接刪除該 Pod 即可;

如果是通過(guò) Deployment 部署的服務(wù),那么僅僅刪除 Pod 是不行的,正確的刪除方式應(yīng)該是:先刪除 Deployment,再刪除 Pod。

關(guān)于第二點(diǎn)應(yīng)該不難想象:僅僅刪除了 Pod 但是 Deployment 還在的話,Deployment 定時(shí)會(huì)檢查其下屬的所有 Pod,如果發(fā)現(xiàn)失敗了則會(huì)再拉起。因此,會(huì)發(fā)現(xiàn)過(guò)一會(huì)兒,新的 Pod 又被拉起來(lái)了。
另外,還有一個(gè)事情:有時(shí)候會(huì)發(fā)現(xiàn)一個(gè) Pod 總也刪除不了,這個(gè)時(shí)候很有可能要實(shí)施強(qiáng)制刪除措施,命令為kubectl delete pod --force --grace-period=0 ${POD_NAME}。
VI. kubectl 排查服務(wù)問(wèn)題
上文說(shuō)道:部署的服務(wù) memory-demo 失敗了,是怎么回事呢?本章就會(huì)帶大家一起來(lái)看看常見(jiàn)的 K8S 中服務(wù)部署失敗、服務(wù)起來(lái)了但是不正常運(yùn)行都怎么排查呢?
首先,祭出筆者最?lèi)?ài)的一張 K8S 排查手冊(cè),來(lái)自博客《Kubernetes Deployment 故障排除圖解指南》:

哈哈哈,對(duì)于新手同學(xué)來(lái)說(shuō),上圖還是不夠友好,下面我們簡(jiǎn)單來(lái)看兩個(gè)例子:
6.1 K8S 上部署服務(wù)失敗了怎么排查?
請(qǐng)一定記住這個(gè)命令:kubectl describe ${RESOURCE} ${NAME}。比如剛剛的 Pod 服務(wù) memory-demo,我們來(lái)看:

拉到最后看到Events部分,會(huì)顯示出 K8S 在部署這個(gè)服務(wù)過(guò)程的關(guān)鍵日志。這里我們可以看到是拉取鏡像失敗了,好吧,大家可以換一個(gè)可用的鏡像再試試。
一般來(lái)說(shuō),通過(guò)kubectl describe pod ${POD_NAME}已經(jīng)能定位絕大部分部署失敗的問(wèn)題了,當(dāng)然,具體問(wèn)題還是得具體分析。大家如果遇到具體的報(bào)錯(cuò),歡迎分享交流。
6.2 K8S 上部署的服務(wù)不正常怎么排查?
如果服務(wù)部署成功了,且狀態(tài)為running,那么就需要進(jìn)入 Pod 內(nèi)部的容器去查看自己的服務(wù)日志了:
查看 Pod 內(nèi)部某個(gè) container 打印的日志: kubectl log ${POD_NAME} -c ${CONTAINER_NAME}。進(jìn)入 Pod 內(nèi)部某個(gè) container: kubectl exec -it [options] ${POD_NAME} -c ${CONTAINER_NAME} [args],嗯,這個(gè)命令的作用是通過(guò) kubectl 執(zhí)行了docker exec xxx進(jìn)入到容器實(shí)例內(nèi)部。之后,就是用戶(hù)檢查自己服務(wù)的日志來(lái)定位問(wèn)題。
顯然,線上可能會(huì)遇到更復(fù)雜的問(wèn)題,需要借助更多更強(qiáng)大的命令和工具。
寫(xiě)在后面
本文希望能夠幫助對(duì) K8S 不了解的新手快速了解 K8S。筆者一邊寫(xiě)文章,一邊查閱和整理 K8S 資料,過(guò)程中越發(fā)感覺(jué) K8S 架構(gòu)的完備、設(shè)計(jì)的精妙,是值得深入研究的,K8S 大受歡迎是有道理的。
本文轉(zhuǎn)載自:「騰訊技術(shù)工程」,原文:https://tinyurl.com/ya3ennxf,版權(quán)歸原作者所有。
往期資源回顧 需要可自取
推薦閱讀
點(diǎn)個(gè)[在看],是對(duì)杰哥最大的支持!

