宜信容器云是一套基于kubernetes的容器管理平臺(tái)。業(yè)務(wù)線用戶在容器云上部署應(yīng)用程序時(shí),常常會(huì)遇到容器無法啟動(dòng)或者應(yīng)用程序運(yùn)行不正常的情況。
宜信容器云是一套基于kubernetes的容器管理平臺(tái)。業(yè)務(wù)線用戶在容器云上部署應(yīng)用程序時(shí),常常會(huì)遇到容器無法啟動(dòng)或者應(yīng)用程序運(yùn)行不正常的情況。為了方便用戶排查在應(yīng)用上云過程中的問題,我們在web端集成了一系列的排錯(cuò)方式,如下圖:
一、終端信息
終端信息查看的是容器實(shí)例運(yùn)行時(shí)的標(biāo)準(zhǔn)輸出日志。
- kubectl logs PODNAME [-c CONTAINER]

應(yīng)用部署時(shí),所屬節(jié)點(diǎn)的kubelet通過grpc調(diào)用容器運(yùn)行時(shí)接口(container runtime interface),來請求docker守護(hù)進(jìn)程創(chuàng)建容器運(yùn)行時(shí)。此時(shí),docker守護(hù)進(jìn)程會(huì)創(chuàng)建一個(gè)協(xié)程來接收容器運(yùn)行時(shí)的標(biāo)準(zhǔn)輸出日志,這個(gè)協(xié)程最終將STDOUT(標(biāo)準(zhǔn)輸出)的日志寫到容器運(yùn)行時(shí)所在節(jié)點(diǎn)的對(duì)應(yīng)目錄下:
- /var/lib/docker/containers/container_id/{container_id-json.log}

在web端查看對(duì)應(yīng)實(shí)例的終端信息時(shí),kubelet將接收的Api-server請求轉(zhuǎn)化成docker client來請求docker守護(hù)進(jìn)程。Docker守護(hù)進(jìn)程到相應(yīng)的目錄下讀取對(duì)應(yīng)容器的日志文件數(shù)據(jù),再由kubelet返回日志數(shù)據(jù)到Api-server,最終顯示到web端,供用戶查看。容器日志的生命周期與容器的生命周期一致,容器銷毀后,其相關(guān)的日志文件也會(huì)銷毀。
二、events
events是kubelet用來記錄容器啟動(dòng)及運(yùn)行過程中的事件。同樣,當(dāng)使用kubectl describe pod來查看pod時(shí),也一樣能看到與該pod相關(guān)的events,從這些信息中可以很清楚看到事件的狀態(tài)變化,從而獲知pod啟動(dòng)失敗的多種原因。比如:1)沒有可用的node供調(diào)度,如調(diào)度的節(jié)點(diǎn)資源不夠;events的基本實(shí)現(xiàn)如下圖:events中包含事件相關(guān)的類型、原因、來源、消息等,會(huì)在kubelet和controller manager等組件中生成,廣播出去后,經(jīng)過一系列的函數(shù)過濾、聚合等,再發(fā)送給Api-server存到etcd中。當(dāng)web端查看events事件時(shí),請求Api-server讀取etcd中相應(yīng)的事件,并返回顯示,供用戶查看異常參數(shù)、錯(cuò)誤狀態(tài)等。
三、web terminal
web terminal可提供一個(gè)交互式的界面shell,可執(zhí)行各種命令。
- kubectl exec -it <podName> -c <containerName> bash

實(shí)現(xiàn)如下:

web terminal主要是通過websocket技術(shù)實(shí)現(xiàn)的,前端交互界面使用的是開源項(xiàng)目container-terminal(https://github.com/kubernetes-ui/container-terminal),其提供了一個(gè)容器的TTY(虛擬終端)。
當(dāng)查看web terminal時(shí),前端web發(fā)起了一個(gè)websocket請求,到Api-server。再由所屬節(jié)點(diǎn)的kubelet響應(yīng)該Api-server的請求,并與容器運(yùn)行時(shí)建立連接。
之所以kubelet能夠與容器運(yùn)行時(shí)建立連接,是因?yàn)閗ubelet 定義了一個(gè) CRI 規(guī)范中的 RuntimeServiceClient 接口,而容器運(yùn)行時(shí)中的RuntimeServiceServer(即Streaming Server,提供了streaming API)實(shí)現(xiàn)了該接口。
kubelet 和容器運(yùn)行時(shí)建立連接后,kubelet返回請求,Api-server將請求升級(jí)為SPDY(SPDY允許在單個(gè)的TCP請求中復(fù)用獨(dú)立的STDIN/STDOUT/STDERR),并將WS的流映射到SPDY相應(yīng)的標(biāo)準(zhǔn)流上,便與目標(biāo)容器運(yùn)行時(shí)Streaming Server建立了流,Api-server便實(shí)現(xiàn)了web與容器運(yùn)行時(shí)的數(shù)據(jù)交互。
此時(shí),在web端輸入命令,下發(fā)執(zhí)行完后,可看到返回的結(jié)果,如此便實(shí)現(xiàn)了交互。
web terminal提供了進(jìn)入容器的便利,用戶可以執(zhí)行任何操作,為了安全,我們做了必要的安全措施:
1)記錄了用戶的操作命令。
待用戶輸入命令后,記錄操作,作為安全審計(jì)。
2)生產(chǎn)環(huán)境使用普通用戶進(jìn)入容器。
即在exec進(jìn)入容器時(shí)的命令/bin/bash -i
更改為/bin/bash –c chmod -R 777 $KUBERNETES_FILELOGS;useradd spider > /dev/null 2>&1;su spider
,其中環(huán)境變量$KUBERNETES_FILELOGS為在容器創(chuàng)建時(shí)需要賦權(quán)的文件目錄。主要是防止用戶誤操作,刪除存儲(chǔ)掛載等。
四、debug容器
debug容器是通過工具容器來對(duì)業(yè)務(wù)容器排障。在使用web terminal來調(diào)試應(yīng)用程序的過程中,業(yè)務(wù)線用戶經(jīng)常需要各式各樣的命令來調(diào)試程序。之前的解決方案要么是給業(yè)務(wù)線定制他們所需的基礎(chǔ)鏡像,盡量涵蓋多的所需命令,要么就是在業(yè)務(wù)線用戶構(gòu)建鏡像時(shí)在Dockerfile中添加命令。但是,因?yàn)闃I(yè)務(wù)線眾多,定制基礎(chǔ)鏡像工作量過大;而在構(gòu)建業(yè)務(wù)鏡像時(shí)添加過多命令,又操作繁瑣,并可能會(huì)帶來安全隱患。這些解決方案實(shí)際上都不符合容器技術(shù)的實(shí)踐原則--盡可能構(gòu)建最簡容器鏡像,而精簡后的鏡像又極度缺失所需的命令工具。鑒于存在這樣的矛盾,我們集成并改造了kubectl-debug(https://github.com/aylei/kubectl-debug)這個(gè)插件。容器實(shí)質(zhì)上是由cgroup和namespace限制的一組進(jìn)程,只要能夠加入到這個(gè)進(jìn)程的各項(xiàng)namespace,就可實(shí)現(xiàn)交互。因此,debug容器的基本思路是:啟動(dòng)一個(gè)包含眾多排障工具命令的容器,來加入到業(yè)務(wù)容器的namespace中,便能夠在工具容器中實(shí)現(xiàn)對(duì)業(yè)務(wù)容器的排障。
- docker run -it --network=container:<container_ID> --pid=container:<container_ID> --ipc=container :<container_ID> -v /log/container _ID:/debugviewlogs <image>
將Debug-agent以DaemonSet的形式部署到kubernetes集群的所有節(jié)點(diǎn)中,并掛載了宿主機(jī)的/var/docker/docker.sock,實(shí)現(xiàn)與docker daemon的通信。1)web端提供pod的cluster、namespace、podname信息,向后端服務(wù)Backend server發(fā)起websocket請求;2)后端服務(wù)Backend server接收到請求后,向Api-server驗(yàn)證該pod是否存在,并返回pod所在的宿主機(jī)Node和pod的容器信息,根據(jù)狀態(tài)判斷是否可以debug;注意:如果pod的狀態(tài)reason是CrashLoopBackOff,那么Backend server將會(huì)請求Api-server讓kubelet復(fù)制一個(gè)pod, 復(fù)制的Pod被改寫了啟動(dòng)命令(sleep)、去掉了label及健康檢查。后續(xù)debug操作是對(duì)復(fù)制后pod進(jìn)行的。3)Backend server傳遞debug的pod信息,發(fā)起debug請求(升級(jí)的SPDY請求,映射了WS的標(biāo)準(zhǔn)流)。4)Debug-agent收到請求后,開始拉取debug工具鏡像,進(jìn)而創(chuàng)建一個(gè)debug容器,并將debug容器的各個(gè)namespace設(shè)置為目標(biāo)業(yè)務(wù)容器app的namespace。再將宿主Node的目錄/log/ 掛載到debug容器的目錄/debugviewlogs中,便可實(shí)現(xiàn)將debug容器中生成的文件在web端下載。創(chuàng)建完debug容器后,Debug-agent將Backend server的SPDY請求中繼到debug容器。debug容器將SPDY的標(biāo)準(zhǔn)流attach到業(yè)務(wù)容器中。如此,web端便可與debug容器實(shí)現(xiàn)交互。在debug操作結(jié)束后,Debug-agent便會(huì)將debug容器清理回收。同樣的,debug的操作也做了安全審計(jì)。因此,我們只要構(gòu)建一個(gè)包含眾多排障工具的鏡像,不僅實(shí)踐了業(yè)務(wù)鏡像盡可能最簡的原則,還提供了調(diào)試應(yīng)用程序所需的各種命令工具。總結(jié)
終端信息、events、web terminal及debug容器都提供了一個(gè)可視化的web,讓用戶能夠方便快速地實(shí)現(xiàn)對(duì)pods排錯(cuò)和對(duì)應(yīng)用程序的排障。
【本文是51CTO專欄機(jī)構(gòu)宜信技術(shù)學(xué)院的原創(chuàng)文章,微信公眾號(hào)“宜信技術(shù)學(xué)院( id: CE_TECH)”】
戳這里,看該作者更多好文