摘要:寫在前面最近在研究集群的監(jiān)控,為了徹底弄清楚,簡(jiǎn)單看了一點(diǎn)源碼。如何調(diào)用上述的監(jiān)控功能的監(jiān)控采用了組件。隨后,會(huì)在監(jiān)控機(jī)器的性能時(shí),分為磁盤使用情況的監(jiān)控和磁盤讀寫情況的監(jiān)控。
寫在前面
最近在研究docker集群(kubernetes)的監(jiān)控,為了徹底弄清楚,簡(jiǎn)單看了一點(diǎn)源碼。這里分享一下我學(xué)到的東西。
docker api: stats首先是docker的api,stats的具體使用場(chǎng)景如:
http://$dockerip:2375/containers/$containerid/stats
可以獲取docker機(jī)器上某一個(gè)容器的狀態(tài),該請(qǐng)求的response會(huì)持續(xù)的寫響應(yīng)報(bào)文回來(lái)(每秒一次)
http://$dockerip:2375/containers/$containerid/stats?stream=false
參數(shù)stream默認(rèn)是true,設(shè)為false后,response只寫一次。
docker中該api對(duì)應(yīng)的操作,就相當(dāng)于docker stats $CID 這條命令,它調(diào)用到了ContainerStats()方法(位于docker項(xiàng)目目錄的/daemon/stats.go 第19行),函數(shù)中啟動(dòng)了一個(gè)收集器:
daemon.SubscribeToContainerStats(name)
收集器定時(shí)寫數(shù)據(jù)到update變量中。
然后啟動(dòng)一個(gè)協(xié)程讀數(shù)據(jù),獲取數(shù)據(jù)的途徑包括:
update := v.(*execdriver.ResourceStats)
和
nwStats, err := daemon.getNetworkStats(name)
可以看到網(wǎng)絡(luò)狀態(tài)是另外讀的,而cpu,內(nèi)存狀態(tài)在哪讀呢?我們一步步跳轉(zhuǎn),看到在這里:
/daemon/execdriver/driver_linux.go 112行:
func Stats(containerDir string, containerMemoryLimit int64, machineMemory int64) (*ResourceStats, error)
在這個(gè)函數(shù)里我們看得到,其實(shí)所謂的獲取容器狀態(tài),就是讀文件而已。我們舉一個(gè)已經(jīng)在docker運(yùn)行的容器來(lái)說(shuō):
cat /run/docker/execdriver/native/$containerID/state.json
這里面記錄了一個(gè)cgroup_paths字段,他的值是一個(gè)路徑,通過(guò)cstats, err := mgr.GetStats()程序才真正拿到了監(jiān)控?cái)?shù)據(jù),如cpu的狀態(tài)信息,存儲(chǔ)在一個(gè)如下的路徑中:
cd /sys/fs/cgroup/cpu,cpuacct/system.slice/docker-9b479ceaf3bef1caee2c37dfdc982a968144700a2c42991b238b938788a8a91f.scope
又比如內(nèi)存的大致信息存在:
cat /sys/fs/cgroup/memory/system.slice/docker-9b479ceaf3bef1caee2c37dfdc982a968144700a2c42991b238b938788a8a91f.scope/memory.stat
具體里面放了什么數(shù)據(jù),大家就自己看咯。
還剩下一個(gè)數(shù)據(jù),也是我們討論的重點(diǎn):網(wǎng)絡(luò)IO。
我們回到/daemon/stats.go:
看看函數(shù)getNetworkStats(name string):
每個(gè)docker容器創(chuàng)建后都會(huì)又docker創(chuàng)建一個(gè)網(wǎng)卡,網(wǎng)卡名以veth開頭,后面是一串隨機(jī)生成的十六進(jìn)制碼。
我們只要找到該網(wǎng)卡,然后,像上文的cpu,內(nèi)存狀態(tài)獲取的方法一樣,去找文件就行了。
然而這個(gè)網(wǎng)卡名似乎是存在內(nèi)存中,至少我沒(méi)有看到docker將這個(gè)網(wǎng)卡名存到別的地方。
代碼中:
nw, err := daemon.netController.NetworkByID(c.NetworkSettings.NetworkID)
可以看出獲取了網(wǎng)卡(network),爾后有一個(gè)Statistics()方法,我們繼續(xù)跟蹤會(huì)發(fā)現(xiàn),docker調(diào)用了一個(gè)組件包:
github.com/docker/libcontainer
其中有statistics方法,并執(zhí)行了一個(gè)cat的命令(該組件包的/sandbox/interface_linux.go 第174行):
data, err := exec.Command("cat", netStatsFile).Output()
是的,又是讀文件。
這次讀的文件在:/sys/class/net/目錄下,
我們進(jìn)入該目錄可以看到有許多子目錄,其中就包括了docker啟動(dòng)容器時(shí)生成的網(wǎng)卡。
個(gè)人猜測(cè):docker在內(nèi)存中保存了容器到網(wǎng)卡的映射關(guān)系。通過(guò)這個(gè)映射關(guān)系可以找到網(wǎng)卡的統(tǒng)計(jì)數(shù)據(jù)(數(shù)據(jù)由內(nèi)核生成,記錄在機(jī)器的文件中)
我們可以看到如下的數(shù)據(jù):
將這些數(shù)據(jù)統(tǒng)一起來(lái),就是docker stats 這條命令干的事。
kubernetes如何調(diào)用上述的監(jiān)控功能kubernetes的監(jiān)控采用了cAdvisor組件。因?yàn)閗ubernetes中記錄了容器的信息(但是沒(méi)有記錄容器-網(wǎng)卡的映射關(guān)系),所以運(yùn)行在節(jié)點(diǎn)上的cAdvisor不需要通過(guò)docker stats去獲取容器的cpu和內(nèi)存使用數(shù)據(jù)。
而網(wǎng)絡(luò)IO數(shù)據(jù)呢?
我們知道k8s部署運(yùn)行一個(gè)容器是會(huì)先生成一個(gè)pause容器。
是的,網(wǎng)絡(luò)IO都記錄在pause容器中。這里大家可以在自己的k8s環(huán)境中驗(yàn)證。
所以只要我們獲取某容器對(duì)應(yīng)的pause容器的containerID,我們就可以用如上的方式去抓到網(wǎng)絡(luò)IO。
因?yàn)閏Advisor并不是為k8s專門設(shè)計(jì)的,不會(huì)特地在獲取網(wǎng)絡(luò)IO時(shí)去遍歷查找容器對(duì)應(yīng)的pause容器。所以當(dāng)前的cAdvisor沒(méi)有辦法獲取容器的網(wǎng)絡(luò)IO。
所以如果在使用k8s集群,想要加入網(wǎng)絡(luò)IO監(jiān)控功能的時(shí)候,可以從k8s自帶的cAdvisor入手。
cAdvisor上面講到cAdvisor,那么cAdvisor是如何獲取網(wǎng)絡(luò)的IO的呢?
首先,在k8s(1.0.6版本)的/pkg/kubelet/cadvisor/cadvisor_linux.go中51行,New(port int)方法,這是kubelet調(diào)用cAdvisor的入口。實(shí)例化一個(gè)cAdvisorClient,并執(zhí)行他的Start()方法,我們可以進(jìn)入cAdvisor項(xiàng)目中找到該方法(github.com/google/cadvisor/manager/manager.go 195行)。
我們看到有一句
err := docker.Register(self, self.fsInfo)
先mark之。繼續(xù)看:
glog.Infof("Starting recovery of all containers") err = self.detectSubcontainers("/")
這里程序程序檢查所有在運(yùn)行的容器,同內(nèi)存中記錄的容器作比較,有新的容器就新建一個(gè)相關(guān)的處理機(jī)制:一個(gè)Container的結(jié)構(gòu)(有減少的,就刪除),然后執(zhí)行cont.Start() (github.com/google/cadvisor/manager/manager.go 766行)
持續(xù)追蹤我們就可以知道每秒它收集一次監(jiān)控信息,收集方法即
stats, statsErr := c.handler.GetStats()
(/cadvisor/manager/container.go 401行)
handler是一個(gè)接口。我們得知道當(dāng)時(shí)是如何給他賦值的。這里不贅述了,我們直接找關(guān)鍵的方法:
func (self *dockerContainerHandler) GetStats() (*info.ContainerStats, error)
(cadvisor/container/docker/handler.go 第305行)
它又調(diào)用了:
func GetStats(cgroupManager cgroups.Manager, networkInterfaces []string) (*info.ContainerStats, error) (cadvisor/container/libcontainer/helpers.go 第77行)
這里就是真正獲取監(jiān)控信息的地方,它引入了libcontainer包中的同名方法,
最終是導(dǎo)入了"github.com/docker/libcontainer/cgroups"這個(gè)第三方包中的方法。是不是很熟悉?對(duì)就是上文中提到的docker stats獲取網(wǎng)絡(luò)IO用到的包。我們到這個(gè)包里找到函數(shù):
(/libcontainer/cgroups/fs/apply_raw.go 第148行)
func (m *Manager) GetStats() (*cgroups.Stats, error) { m.mu.Lock() defer m.mu.Unlock() stats := cgroups.NewStats() for name, path := range m.Paths { //m.Paths中包括了cpu,memory,network等字段,根據(jù)這些字段找到相應(yīng)的目錄 sys, ok := subsystems[name] if !ok || !cgroups.PathExists(path) { continue } //讀目錄里的文件獲取監(jiān)控信息 if err := sys.GetStats(path, stats); err != nil { return nil, err } } return stats, nil }
我們可以看到libcontainer/cgroups/fs目錄下有cpu.go,memory.go等文件,每一個(gè)文件中都有一個(gè)集成了GetStats()的結(jié)構(gòu),我們可以獲取到任何數(shù)據(jù)。
我們?cè)倩氐絚advisor項(xiàng)目中cadvisor/container/libcontainer/helpers.go 第77行,
往下看:
// TODO(rjnagal): Use networking stats directly from libcontainer. stats.Network.Interfaces = make([]info.InterfaceStats, len(networkInterfaces)) for i := range networkInterfaces { interfaceStats, err := sysinfo.GetNetworkStats(networkInterfaces[i]) if err != nil { return stats, err } stats.Network.Interfaces[i] = interfaceStats }
這里官方還用了別的手段再去找network的數(shù)據(jù),雖然不知道是處于什么理由,也不管這里是去找哪個(gè)系統(tǒng)文件看狀態(tài),但是這樣依然是拿不到數(shù)據(jù)的。因?yàn)楦緵](méi)有找到容器對(duì)應(yīng)的網(wǎng)卡。這里找網(wǎng)卡的方法在cadvisor/container/docker/handler.go 第311行:
var networkInterfaces []string if len(config.Networks) > 0 { // ContainerStats only reports stat for one network device. // TODO(vmarmol): Handle multiple physical network devices. for _, n := range config.Networks { // Take the first non-loopback. if n.Type != "loopback" { networkInterfaces = []string{n.HostInterfaceName} break } } } stats, err := containerLibcontainer.GetStats(self.cgroupManager, networkInterfaces)
很顯然這里是要改進(jìn)的(在k8s的環(huán)境下)。
注:隨著版本更新,新版本的cAdvisor采用github.com/opencontainers包。詳見(jiàn):github.com/opencontainers/runc/libcontainer/container_linux.go line 151:
另外,cadvisor獲取網(wǎng)絡(luò)監(jiān)控?cái)?shù)據(jù)的正確途徑應(yīng)該是:
監(jiān)控pause容器,在其Pid對(duì)應(yīng)的/proc/$pid/net/dev文件中即可得到容器內(nèi)部網(wǎng)絡(luò)監(jiān)控?cái)?shù)據(jù)
cadvisor在主函數(shù)初始化時(shí),通過(guò)一些init方法在內(nèi)存中構(gòu)建了機(jī)器上的文件系統(tǒng)的結(jié)構(gòu)(有哪些磁盤、分別掛載目錄是啥、maj和min號(hào)是啥)。隨后,cadvisor會(huì)在監(jiān)控機(jī)器的性能時(shí),分為磁盤使用情況的監(jiān)控和磁盤讀寫情況的監(jiān)控。
磁盤使用情況的監(jiān)控cadvisor會(huì)執(zhí)行syscall.Statfs方法,通過(guò)linux系統(tǒng)調(diào)用,獲得磁盤的總大小、可用空間、inodes總數(shù)和使用數(shù)等信息
磁盤讀寫情況的監(jiān)控通過(guò)讀取機(jī)器的/proc/diskstats文件內(nèi)容,形如:
cat /proc/diskstats 254 0 vda 48560 0 994278 64304 2275295 70286 18962312 6814364 0 1205480 6877464 254 1 vda1 48177 0 991034 64008 1865714 70286 18962304 6777592 0 1170880 6840740 254 16 vdb 700 0 4955 284 0 0 0 0 0 284 284
通過(guò)這些數(shù)據(jù)計(jì)算出各個(gè)存儲(chǔ)設(shè)備的讀寫次數(shù)、讀寫速度。(這里文件內(nèi)容釋義和計(jì)算方式可以參見(jiàn)http://www.udpwork.com/item/1...)
暴露接口當(dāng)我們調(diào)用cadvisor的接口:
/api/v2.1/machinestats 時(shí),就能從返回的json結(jié)構(gòu)中找到filesystem字段,包含了磁盤讀寫性能和磁盤使用情況的監(jiān)控?cái)?shù)據(jù)
上文提到,cadvisor在初始化階段就生成了機(jī)器文件系統(tǒng)的抽象結(jié)構(gòu),但是這個(gè)結(jié)構(gòu)不會(huì)動(dòng)態(tài)檢查和更新,當(dāng)機(jī)器上動(dòng)態(tài)掛載了一個(gè)數(shù)據(jù)盤(比如使用ceph rbd做pod的pv),cadvisor不會(huì)感知,這個(gè)新掛的盤的監(jiān)控?cái)?shù)據(jù)也無(wú)法被感知。
目前社區(qū)暫時(shí)沒(méi)有對(duì)這個(gè)功能進(jìn)行優(yōu)化
應(yīng)用說(shuō)了這么多,其實(shí)給大家在實(shí)現(xiàn)k8s容器網(wǎng)絡(luò)IO監(jiān)控這個(gè)需求時(shí)提供一點(diǎn)想法:
1.從cadvisor入手,找到對(duì)應(yīng)pause容器的containerID,那么就可以用libcontainer包去獲取到數(shù)據(jù)(也即用docker stats的方式)。
2.從docker入手,創(chuàng)建容器時(shí)記錄網(wǎng)卡信息,能否提供一個(gè)接口,根據(jù)容器名找到對(duì)應(yīng)網(wǎng)卡名,那么cadvisor只要通過(guò)這個(gè)docker API得到網(wǎng)卡名,就可以自己讀文件獲取網(wǎng)絡(luò)IO。
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/32425.html
摘要:寫在前面最近在研究集群的監(jiān)控,為了徹底弄清楚,簡(jiǎn)單看了一點(diǎn)源碼。如何調(diào)用上述的監(jiān)控功能的監(jiān)控采用了組件。隨后,會(huì)在監(jiān)控機(jī)器的性能時(shí),分為磁盤使用情況的監(jiān)控和磁盤讀寫情況的監(jiān)控。 寫在前面 最近在研究docker集群(kubernetes)的監(jiān)控,為了徹底弄清楚,簡(jiǎn)單看了一點(diǎn)源碼。這里分享一下我學(xué)到的東西。 docker api: stats 首先是docker的api,stats的具體...
摘要:馬拉松會(huì)匹配每個(gè)和提供的資源,然后通過(guò)將任務(wù)下發(fā)下去。對(duì)外暴露的就是負(fù)載均衡的某個(gè)服務(wù),后面自動(dòng)將流量轉(zhuǎn)發(fā)到某個(gè)容器的端口上。還有一直辦法是用內(nèi)網(wǎng)的,這個(gè)會(huì)維護(hù)現(xiàn)有的容器列表端口,并且返回任意一個(gè)的端口,頁(yè)實(shí)現(xiàn)了負(fù)載均衡和服務(wù)發(fā)現(xiàn)功能。 演講嘉賓 數(shù)人云COO 謝樂(lè)冰 在德國(guó)工作十年,回國(guó)后加入惠普電信運(yùn)營(yíng)商部門,擁有多年項(xiàng)目經(jīng)驗(yàn)和創(chuàng)業(yè)公司工作經(jīng)驗(yàn)。在數(shù)人云負(fù)責(zé)產(chǎn)品售前和運(yùn)營(yíng),專注行...
摘要:基于年底或年初沒(méi)有推廣的現(xiàn)狀,唯品會(huì)部門目前已經(jīng)做了兩年的時(shí)間。唯品會(huì)現(xiàn)狀唯品會(huì)目前線上有一千多個(gè)域,每個(gè)域之間相互的依賴比較復(fù)雜,每次的部署發(fā)布困難。這是唯品會(huì)的架構(gòu),主要包含持續(xù)集成和持續(xù)部署。 數(shù)人云上海&深圳兩地容器之Mesos/K8S/Swarm三國(guó)演義的嘉賓精彩實(shí)錄第三更來(lái)啦。唯品會(huì)是數(shù)人云Meetup的老朋友,去年曾做過(guò)RPC服務(wù)框架和Mesos容器化的分享。本次分享中,...
摘要:去年換工作后,開始真正在生產(chǎn)環(huán)境中接觸容器與。今天想先談?wù)劊依斫獾娜萜魇鞘裁矗约盀槭裁此鼈兡芑鹌饋?lái)。一個(gè)容器鏡像的實(shí)質(zhì)就是程序進(jìn)程加所有運(yùn)行時(shí)環(huán)境及配置依賴的集合。這里再談?wù)勎依斫獾摹6褪悄壳暗娜萜骶幣诺钠脚_(tái)的事實(shí)標(biāo)準(zhǔn)了。 去年換工作后,開始真正在生產(chǎn)環(huán)境中接觸容器與Kubernetes。邊惡補(bǔ)相關(guān)知識(shí)的同時(shí),也想把學(xué)到的內(nèi)容和自己的理解整理出來(lái)。學(xué)習(xí)的途徑包括k8s官方文檔...
摘要:去年換工作后,開始真正在生產(chǎn)環(huán)境中接觸容器與。今天想先談?wù)劊依斫獾娜萜魇鞘裁矗约盀槭裁此鼈兡芑鹌饋?lái)。一個(gè)容器鏡像的實(shí)質(zhì)就是程序進(jìn)程加所有運(yùn)行時(shí)環(huán)境及配置依賴的集合。這里再談?wù)勎依斫獾摹6褪悄壳暗娜萜骶幣诺钠脚_(tái)的事實(shí)標(biāo)準(zhǔn)了。 去年換工作后,開始真正在生產(chǎn)環(huán)境中接觸容器與Kubernetes。邊惡補(bǔ)相關(guān)知識(shí)的同時(shí),也想把學(xué)到的內(nèi)容和自己的理解整理出來(lái)。學(xué)習(xí)的途徑包括k8s官方文檔...
閱讀 2048·2019-08-30 15:52
閱讀 2440·2019-08-29 18:37
閱讀 790·2019-08-29 12:33
閱讀 2839·2019-08-29 11:04
閱讀 1522·2019-08-27 10:57
閱讀 2092·2019-08-26 13:38
閱讀 2759·2019-08-26 12:25
閱讀 2445·2019-08-26 12:23