摘要:從年以來,谷歌基于容器研發三個容器管理系統,分別是和。這篇論文由這三個容器集群管理系統長年開發維護的谷歌工程師和于近日發表,闡述了谷歌從到這個旅程中所獲得的知識和經驗教訓。和完全是谷歌內部系統相比,是開源的。
從2000年以來,谷歌基于容器研發三個容器管理系統,分別是Borg、Omega和Kubernetes。這篇論文由這三個容器集群管理系統長年開發維護的谷歌工程師Brendan Burns、Brian Grant、David Oppenheimer、Eric Brewer和John Wilkes于近日發表,闡述了谷歌從Borg到Kubernetes這個旅程中所獲得的知識和經驗教訓。
盡管對軟件容器廣泛傳播的興趣是最近的現象,但在谷歌我們大規模使用Linux容器已經有10多年了,而且期間我們建了三種不同的容器管理系統。每一個系統都受之前的系統影響頗深,盡管它們的誕生是出于不同原因。這篇文章描述了我們在研發和使用它們的過程中得到的經驗教訓。
第一個在谷歌被開發出來的統一的容器管理系統,在我們內部稱之為“Borg”,它管理著長時間運行的生產服務和批處理服務。這兩類任務之前是由兩個分離開的系統來管理的:Babysitter和Global Work Queue。Global Work Queue的構架極大地影響了Borg,但卻只是針對批量服務的,且兩者都在Linux control groups誕生之前。Borg將這兩種應用所用的機器統一成一個池子,這樣得以提高資源利用率,進而降低成本。之所以可以實現這樣的機器資源共享,是因為可以拿到Linux內核的容器支持(確實,Google對Linux內核的容器代碼貢獻了很多),這使得在對時限敏感的、且面對用戶的服務和占用很多CPU資源的批處理進程提供了更好的隔離。
由于越來越多的應用被開發并運行在Borg上,我們的應用和底層團隊開發了一個廣泛的工具和服務的生態系統。這些系統提供了配置和更新job的機制,能夠預測資源需求,動態地對在運行中的程序推送配置文件、服務發現、負載均衡、自動擴容、機器生命周期的管理、額度管理以及更多。這個生態系統的發展源自谷歌內部不同團隊的需求,發展的結果成為了異構的、ad-hoc系統的集合,Borg的使用者能夠用幾種不同的配置語言和進程來配置和溝通。由于Borg的規模、功能的廣泛性和超高的穩定性,Borg在谷歌內部依然是主要的容器管理系統。
Omega,作為Borg的延伸,它的出現是出于提升Borg生態系統軟件工程的愿望。Omega應用到了很多在Borg內已經被認證的成功的模式,但是是從頭開始來搭建以期更為一致的構架。Omega存儲了基于Paxos、圍繞transaction的集群的狀態,能夠被集群的控制面板(比如調度器)接觸到,使用了優化的進程控制來解決偶爾發生的沖突。這種分離允許Borgmaster的功能被區分成幾個并列的組建,而不是把所有變化都放到一個多帶帶的、巨石型的master里。許多Omega的創新(包括多個調度器)都被收錄進了Borg。
谷歌研發的第三個容器管理系統是Kubernetes。Kubernetes的研發和認知背景,是針對在谷歌外部的對Linux容器感興趣的開發者以及谷歌在公有云底層商業增長的考慮。和Borg、Omega完全是谷歌內部系統相比,Kubernetes是開源的。像Omega一樣,Kubernetes在其核心有一個被分享的持久存儲,有組件來檢測相關ojbect的變化。跟Omega不同的是,Omega把存儲直接暴露給信任的控制面板的組件,而在Kubernete中,是要完全由domain-specific的提供更高一層的版本控制認證、語義、政策的REST API來接觸,以服務更多的用戶。更重要的是,Kubernetes是由一支在集群層面應用開發能力更強的開發者開發的,他們主要的設計目標是用更容易的方法去部署和管理復雜的分布式系統,同時仍然能通過容器所提升的使用效率來受益。
這篇文章描述了谷歌從Borg到Kubernetes這個旅程中所獲得知識和經驗教訓。
容器歷史上,第一個容器提供的僅僅是root file system的隔離(通過chroot),再加上FreeBSD jails提供額外的例如process ID這樣的namespaces。Solaris后來成為先鋒并且做了很多加強的探索。Linux control groups(cgroups)運用了很多這些想法,在這個領域的發展一直延續到今天。
容器的資源隔離特性使得谷歌的資源使用率遠遠高出業界同行。例如,Borg使用容器將對延遲敏感、面向用戶的任務和批量任務放在相通的物理機上,并會為它們預留更多的資源,這樣可以解決load spikes、fail-over等問題。容器提供的資源管理工具使這些得以實現,穩定的內核層面的資源隔離也使進程之間不互相干擾。我們通過在研發Borg的同時加強Linux容器的方式來獲得成功。然而,隔離并不是完美的,容器在內核操作系統不能管理的資源隔離方面鞭長莫及,比如level 3 processor caches、內存帶寬、以及容器需要被一個額外的安全層支持以抵抗云端的各種惡意攻擊。
現代的容器不僅僅是隔離機制:它也包括鏡像,即包含了在容器內能夠讓應用跑起來的文件。在谷歌內部,MPM(Midas Package Manager)被用來建造和部署容器鏡像。在隔離機制和MPM之間同樣的共生關系,也可以在Docker daemon和Docker鏡像之間被發現。在這篇文章剩余的篇幅中,我們會使用“容器”這個詞來包含這兩方面:運行時隔離和鏡像。
面向應用的架構(Application-oriented infrastructure)隨著時間的推移,我們越來越清楚容器在更高一層使用時的好處。容器化能使數據中心從面向機器轉為面向應用。這個部分討論兩個例子:
容器封裝了應用環境,把很多機器和操作系統的細節從應用開發者和部署底層那里抽象了出來。
因為設計良好的容器和鏡像的作用范圍是一個很小的應用,因此管理容器意味著管理應用而非機器,極大簡化了應用的部署和管理。
應用環境Linux內核里的cgroup、chroot和namespace的原本是為了保護應用不受周邊雜亂鄰里的影響。把這些和容器鏡像組合起來創建一個抽象事物把應用從運行它們的(紛雜的)操作系統里隔離出來,提高了部署可靠性,也通過減少不一致性和沖突而加快了開發速度。
能讓這個抽象事物得以實現的關鍵在于有一個自包含的鏡像,它把一個應用幾乎所有的依賴環境都打包然后部署在一個容器里。
如果這個過程做的正確,本地的外部環境就只剩下Linux內核的system-call interface. 這個有限制的interface極大提高了鏡像的便攜性,它并不完美:應用仍然暴露給了OS interface,尤其是在socket選項的廣泛表面上、/proc、和給ioctl call的所傳參數上。我們希望后面類似Open Container Initiative(OCI:點這里)的努力能繼續把容器抽象的表層能理清。
然而,容器提供的隔離和對環境依賴的最低性在谷歌內部頗為有效,容器也是谷歌內部底層唯一支持的應用程序運行實體。這樣的好處之一就是在任何時候,谷歌在它一整臺機器上只有很少量的OS版本部署,只需要很少量的人員來管理或升級。
有很多種方式可以實現這些自包含的鏡像。在Borg里,程序的二進制文件在構建時靜態地連接到公司范圍內repo庫里已知的library版本。即便這樣,Borg容器鏡像也并非100%的自包含:因為應用會共享一個所謂的基礎鏡像,而不是將這個基礎鏡像打包在每個容器中。這個基礎鏡像包含了一些容器需要用到的utilities,比如tar和libc library,因此對基礎鏡像的升級會影響運行中的應用,偶爾也會變成一個比較嚴重的問題產生來源。
現在的容器鏡像格式,比如Docker和ACI把容器進一步抽象,通過消除內在的主機OS環境依賴和要求外在的user命令來共享容器之間的鏡像數據,使得距離理想的自包含性又近了一步。
容器作為管理的單位搭建面向容器而非機器的管理API把數據中心的關鍵字從機器轉向了應用。這樣有很多好處:(1)減輕應用開發者和運維團隊操心機器和系統具體細節的壓力;(2)提供底層團隊彈性,得以升級新硬件和操作系統,但同時對在跑的應用和開發者影響甚??;(3)它把管理系統收集的telemetry(比如CPU和內存用量的metrics)和應用而非機器綁在一起,極大提升了應用監測和檢查,尤其是在擴容、機器失敗或者運維導致應用實例遷移的時候。
容器能夠注冊通用的API使得管理系統和應用之間盡管互相不甚明了對方的實現細節,但也能信息流通。在Borg里,這個API是一系列HTTP終端銜接到每一個容器上。舉例來說,/healthz終端對編排器報告應用的健康狀態。當一個不健康的應用被發現,它就被自動終止和重啟。這種自我修復對可靠的分布式系統而言是一個關鍵的磚頭塊。(Kubernetes提供了類似的功能;健康檢查使用了一個用戶指定的HTTP終端或者跑在容器里的exec命令。)
容器也能提供其他面向應用的監測:舉例來說,Linux內核cgroups提供關于應用的資源利用數據,這些可以和先前提到的由HTTP API導出的客戶metrics一起被延伸。這些數據能夠實現例如自動擴容或cAdvisor這樣一般工具的開發,這些開發記錄或者使用這些metrics,不需要理解每個應用的細節。因為容器就是應用,就不再需要從在一個物理機或者虛擬機上跑的多個應用來多路分配信號。這個更簡單、更穩定一些,而且也允許對metrics和日志進行更細粒度的報告和控制。拿這個跟需要ssh到一臺機器去跑top去比一下。盡管對開發者來說,ssh到他們的容器是可能的,但程序員很少會需要這么去做。
監測,只是一個例子。面向應用的這個變化在管理底層上是有連帶效果的。我們的負載均衡器并不平衡機器間的傳輸,它們是針對應用實例來平衡。日志也是根據應用,而非機器,因此它們可以很容易的被收集以及在實例之間集合,而不受到多個應用或者操作系統的影響。我們可以查探到應用失敗,更容易對這些失敗的原因來歸類,而不需要對它們進行機器層面信號的分離。
最后,盡管到目前為止,我們對應用的關注和對容器的關注是1:1,但在現實中我們使用在同一臺機器上聯動的容器:最外面的容器提供一個資源池,里面的這些容器提供部署隔離。在Borg,最外面那層容器被稱為資源調配器(或者alloc),在Kubernetes里,被稱為pod。Borg也允許最頂端的應用容器跑在alloc的外面,這個帶來了很多不方便,所以Kubernetes把這些規范化并且總是在一個頂端的pod里來跑應用容器,即便這個pod只有單一的一個容器。
一個普遍的使用樣式,是用一個pod來裝一個復雜應用的實例。應用的主要部分在它其中一個容器(child containers)里,其他容器跑著支持功能,例如日志處理。跟把這些功能組合到一個單一的二進制相比,這使得開發團隊開發不同功能的部件容易很多,也提高了穩定性(即便主體應用有新的東西進來,日志發送依然可以繼續運行)和可編輯性。
編排只是開始,不是結束原始的Borg系統可以在共享的機器上跑不同的工作負荷來提高資源利用率。但在Borg內支持服務的迅速進化顯示,容器管理的本質只是開發和管理可靠的分布式系統的開始,很多不同的系統在Borg上和周邊被開發,用來提高Borg所提供的基本的容器管理服務。下面這個不完整的列表給出了這些服務大概的一個范圍和多樣性:
命名和服務發現(Borg Name Service或BNS);
Master election(用Chubby);
面向應用的負載均衡;
橫向(實例數量)和縱向(實例尺寸)的自動擴容;
發布工具,用來管理新二進制和配置數據;
工作流程工具(例如允許跑分析多任務的pipelines在不同階段有互相環境依賴);
監測工具用來收集關于容器的信息,集合這些信息、發布到dashboard上,或者用它來激發預警。
構建這些服務是用來解決應用開發團隊所經歷的問題。成功的服務被廣泛采用,那其他開發者就受益。不幸的是,這些工具常常選一些怪癖的API,conventions(比如文件位置)和Borg的深度結合。一個副作用就是增加了Borg生態系統部署應用的復雜性。
Kubernetes企圖通過對API采用一種一致的方法來避免這種增加的復雜性。比如說,每一個Kubernetes的對象在它的描述里有三個基本的屬性:對象的metadata、spec和狀態(status)。
對象的metadata對系統中的所有對象都是一樣的,它包含了例如對象名稱、UID(特殊標示)、一個對象的版本號碼(為了樂觀的進程控制)以及標簽(key-value對,見下面描述)。Spec和status的內容根據不同的對象類型會不同,但它們的概念是一樣的:spec時用來描述對象的理想狀態,而status提供了該對象目前當下的只讀信息。
這種統一的API帶來很多好處,可以讓我們更容易的了解系統,因為系統中所有對象都有類似的信息。另外,統一的API可以更容易地編寫通用的工具來作用于所有對象,這樣反過來也讓使用者感覺更為連貫。通過對Borg和Omega的總結,Kubernetes建立在一整套可自由拆裝的部件之上,可以由開發者任意延展。一個有共識的API和對象metadata結構可以使這個過程更為簡單。
一致性還可以通過在Kubernetes API內解構來完成。在API組建之間考慮進行一些分離意味著在更高層的服務上需要共享一些基本的構建組件。一個很好的例子是在Kubernetes的RC(replication controller)和它水平自動擴容系統之間的分離。一個RC保證了對某個角色(比如“前端”)理想的pod數量的存在。自動擴容器,反過來,需要依賴這個能力并且簡單地調整理想的pod數量,不需要擔心pod如何生成和刪除。自動擴容器的實現能夠把精力集中在需求和使用的預測,忽略如何實現這些決定的細節。
分離保證了多個關聯但不同的組件共享一個相似的外表和感覺。舉個例子,Kubernetes有三個不同的pod副本模式:
ReplicationController:永遠在運行的容器副本(比如web服務器);
DaemonSet:確保在集群里的每個節點上有一個多帶帶的實例(例如日志代理);
Job:一個知道如何從開始到結束運行一個(可能是并行的)批處理任務的run-to-completion的控制器。
盡管在規則上有區別,所有這三個控制器都依賴共同的pod對象來制定它們想要運行在上面的容器。
一致性也可以通過不同Kubernetes組件上共同的設計形式來達到。在Borg、Omega和Kubernetes上用來提高系統彈性,有一個概念:“reconciliation controller loop”(清理控制器循環),這個概念是來比較一個理想的狀態(比如需要多少個pod才能來達到一個標簽選擇的query,即 label-selector query),和相對于觀測到的狀態(可以發現的這樣的pod數量)來進行比較,然后采取行動去把這兩個狀態做到一致。
需要避免的事情在研發這些系統的時候,我們也學到了許多關于哪些事情不該做,哪些事情值得去做的經驗。我們把其中的一些寫出來,期望后來者不再重蹈覆轍,而是集中精力去解決新問題
別讓容器系統來管理port端口所有跑在Borg機器上的容器都共享主機的IP地址,所以Borg給容器分發了獨特的port端口作為調度過程的一部分。一個容器當它移到一個新的機器上(有時候)在同樣的機器上重啟的話,會拿到一個新的端口號碼。這意味著傳統的例如像DNS(Domain Name System)網絡服務需要被home-brew版本取代;因為服務的客戶不會先驗地知道給到服務的port端口,需要被告知;port端口號碼不能被嵌在URL里,就需要以名字為基礎的再次導向(redirection)機制;而且依賴于簡單的IP地址的工具需要被重寫來搞定IP:端口對的形式(port pairs)。
從我們在Borg的經驗來看,我們決定Kubernetes可以來給每個pod制定IP地址,這樣把網絡身份(即IP地址)和應用身份能統一起來。這會使得在Kubernetes上跑現成的軟件容易的多:應用可以隨意使用靜態已知的端口(比如80作為HTTP端口),已經存在的、熟悉的工具可以被用來做網絡分段、帶寬調節管理。所有流行的云平臺提供網絡的基礎層,能夠有每個pod的IP,在裸機上,可以使用SDN覆蓋層或者配置L3路由來管理每個機器上的多個IP.
別僅僅只是給容器編號:給它們打標簽如果你讓用戶很容易地創建容器,他們會傾向于創建很多,那么很快就會需要一種方式來管理和組織它們。Borg對于群組的相同的task提供了jobs(對于容器而言任務的名稱)。一個job是一個壓縮的容器(vector)裝了一個或多個相同的task,從0開始計數。這提供了許多能量,而且很簡單直白,但時間長了我們又會后悔它過于死板。比如說,當一個task死掉了,需要在另一臺機器上被重新啟動,在task這個vector上的相同的slot就要雙倍的工作:既要指認這個新的備份,同時還要指向舊的那個,萬一可能需要做debug。當task出現在vector的當中,那vector就有洞。因此vector很難去支持在Borg的一層上跨越多個集群的job.同時,也有潛在的、不期而遇的在Borg更新job的語意上(典型的是在做滾動升級的時候按照index標記來重啟)和應用使用的task index標記(比如做一些sharding活著跨task的數據的分區)的互動:如果應用使用基于task index的range sharding,那么Borg的重啟政策會導致拿不到數據,因為它會拉掉附近的任務。Borg也沒有簡單的辦法去job里面增加跟應用有關的metadata,比如角色屬性(比如“前端”)或者展示的狀態(比如是canary),所以人們要把這些信息寫到job名稱里,這樣他們可以用常規表達式(regular expression)來解析。
相比之下,Kubernetes主要使用標簽(labels)來識別成組的容器。一個標簽是一對key/value組,包含著容器信息可以用來識別對象。一個pod可能有這樣的標簽:role=frontend 和 stage=production,表明這個容器服務于前端生產。標簽可以動態地被自動工具、用戶來添加、移除和修改,也可以被其他不同的團隊獨立地來管理他們自己的標簽。成組的對象,可以由label selectors來定義(比如 stage==production && role==frontend)。這些組(set)可以重疊,而且一個對象可以在多個的組(set)里,因此標簽本身要比明確的對象列表或簡單靜態的屬性更靈活。因為一個組(set)是由一個動態隊列來定義的,一個新的組可以在任何時候被生成。在Kubernetes里label selectors是grouping(成組)的機制,來定義跨越多個實體的管理操作的范圍。
即便在那樣的環境里知道在一個set里的一個task的身份是很有幫助的(比如說靜態角色的分配和工作分區或分片),適當的每個pod有標簽可以被用來再次產生任務標示的效果,盡管這個是應用的責任(或者一些其他在Kubernetes外部的管理系統的責任)來提供這樣的標簽。標簽和標簽選擇器提供了一個對這兩者的最好的通用機制。
對所有權要謹慎在Borg里,tasks并不是獨立于jobs存在的。生成一個job,也會生成它的task,那些tasks永遠和特定的job是有關聯的,如果刪除job,也會刪除task。這樣很方便,但也會有一個主要的缺點:因為只有一個成組的機制,需要來解決所有出現的情況。舉例來說,一個job需要存儲參數,這些參數或者是對應服務(service)或者是對應批量工作(batch job)但不會是兩者同時,而且用戶必須要寫出workarounds當job的抽象無法來解決某個情況的時候(比如一個DaemonSet對這個集群里的所有節點都去復制一個簡單的pod)。
在Kubernetes里,pod生命周期的管理組件例如RC決定了哪個pod它們有責任要用標簽選擇器,因此多個控制器都可能會認為它們自己對于一個單一的pod有管轄權。通過適當的配置選擇來預防這樣的沖突就非常重要。但是標簽的彈性也有額外的好處,比如說,控制器和pod的分離意味著可以孤立和啟用一些容器。考慮到一個負載均衡的服務使用一個標簽選擇器去標示一組pod去發送請求。如果這些pod中的一個行為異常,那這個pod的被Kubernetes服務負載均衡器識別出來的標簽會被刪除、這個pod被隔離不再進行服務。這個pod不再服務接受請求,但它會保持線上的狀態,在原處可以被debug.同時,管理pod的RC自動實現服務,為有問題的pod創建一個復制的pod.
不要暴露raw stateBorg、Omega和Kubernetes之間一個關鍵的差別在于它們的API構架。Borgmaster是一個單一的組件,它知道每一個API運作的語義。它包含了諸如關于jobs、tasks和機器的狀態機器的集群管理的邏輯;它跑基于Paxos的復制存儲系統用來記錄master的狀態。反觀Omega,Omega除了存儲之外沒有集中的部件,存儲也是簡單地匯集了被動的狀態信息以及加強樂觀的并行進程控制:所有的邏輯和語義都被推進存儲的client里,直接讀寫存儲的內容。在實踐中,每一個Omega的部件為了存儲使用同樣的客戶端library,來打包或者解體數據結構、重新嘗試活著加強語義的一致性。
Kubernetes選擇了一個中間地提供了像Omega部件結構的彈性和可擴容性,同時還能加強系統層面的無變化、政策和數據傳輸。它通過強制所有存儲接觸必須通過一個中央的API服務器來隱藏存儲的實現細節和給對象驗證、版本控制提供服務來做到這些。在Omega里,client的部件互相之間是分離的,可以進化或者多帶帶被替換(這對開源環境而言尤其重要),但中央化對加強共同語義、不變性和政策會容易很多。
一些開放性的難題有了八年的容器管理經驗,我們感覺依然還有大量的問題我們沒有很好的解決方案。這個部分描述了一些我們感到特別棘手的問題,作為拋磚引玉吧。
配置在所有我們面對的問題中,最多的心思和筆墨涉及到的都是關于管理配置,即一整套的提供給應用的配置,而非硬生生寫進應用里去。我們完全可以把整篇文章都拿來寫這個主題(可能都說不完)。下面這些是一些我們想要強調的內容。
首先,應用配置變成了一個關聯一切的抓手,來實現所有的東西,所有這些容器管理系統(尚且)不做的事情,包括:
樣板化簡約(比如把tast重啟的政策調整到相適應的負載工作量,例如服務或者批處理工作);
調整和驗證應用參數以及command-line參數;
實現例如打包鏡像管理的缺失API抽象的替代解決方法;
應用配置模版的library;
發布管理工具;
鏡像版本說明。
為了解決這些要求、配置管理系統趨向于發明一個domain-specific的配置語言,最終具有圖靈完備性,起源于希望能夠在配置的數據里進行計算(比如對一個服務調整給它的內存,作為在一個服務里進行分區的功能)。結果就產生一個難以理解的“配置是代碼”,大家都通過不在應用當中hardcode參數來盡量避免的這種情況。它并沒有減少操作上的復雜性或者使得配置更容易debug或改變,它只是把計算從一個真正的編程語言挪到了一個特殊領域。
我們相信最有效的方法是去接受這個需求,擁抱無所不在的程序配置和在計算和數據之間保持一個清楚的界線。代表數據的語言應該是簡單的、僅數據格式的,比如像JSON或者YAML,對這種數據的程序化修改應該在一個真實的編程語言里,有被很好理解的語義和工具。有趣的是,同樣的在計算和數據之間的分離在前端開發的不同領域是雷同的,比如像Angular在markup(數據)和JavaScript(計算)之間是有清晰的劃分的。
依賴條件的管理起一個服務往往也意味著提供一系列相關的服務(監控、存儲、CI/CD等等)。如果一個應用對其他應用有依賴,其他這些依賴條件(和任何它們可能有涉及的依賴條件)能夠被集群系統自動管理,是不是很好呢?
更麻煩的是,對依賴條件的實例化很少會像起一個新的備份這么簡單,比如說,它可能會需要對現有的服務注冊一個新的消費者(比如Bigtable as a service)然后通過這些間接的依賴環境來傳遞認證、授權以及賬號信息。然而,基本上沒有系統會抓、保持或者透露這些依賴信息,所以在底層自動化這些即便是非常常見的情況都是近乎不可能的。起來一個新的應用對用戶來說就很復雜,對開發者而言來建新的服務就變難,經常導致一些最佳實踐無法進行,影響服務的可靠性。
一個標準的問題是:如果是手動更新,很難保持依賴信息的及時更新。而且同時,能自動地(比如跟蹤access)決定它的這種企圖也無法掌握需要了解結果的語義信息。(比如是否這個acess要給那個實例?或者任何一個實例就足夠了?)一個能夠改進的可能是要求應用枚舉它所依賴的服務,然后讓底層拒絕對其他服務的接觸(我們在我們的build system里對compiler imports這么做過)。這個動機是讓底層做有用的事情,比如自動的setup、認證和連接。
不幸的是,我們所觀察到的系統在表達、分析和使用系統依賴這方面的復雜性都太高,所以它們還沒有被夾到一個主流的容器管理系統里。我們依然希望Kubernetes可能可以成為一個這樣的平臺,在這個平臺上有這樣的工具,但這么做是一個很大的挑戰。
結語十多年搭建容器管理系統的經驗教會了我們很多。而且我們把很多已有的經驗融入進了Kubernetes,谷歌最近的這個容器管理系統。它的目標是基于容器的能力來提供編程生產力方面的極大收獲,簡化人工和自動化系統管理。我們希望你會來加入我們來延伸和提高這個項目。
(如果需要轉載,請聯系我們哦,尊重知識產權人人有責;)
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/32448.html
摘要:這里我想從我在谷歌內部使用容器,并基于容器研發大規模生產平臺的經驗中談談現有和谷歌容器環境的差別,并通過的實際案例落地經驗總結下自身所帶來的一些謊言和誤區。 我與容器的緣分起源于我在 Google 內部研發容器集群管理系: Cluster Management。谷歌內部一切皆容器,搜索、視頻、大數據、內部工具等核心業務都以容器的方式運行在容器編排系統 Borg 上。2014年,隨著公司...
摘要:因此,也是運行谷歌的一種方式,所以本質上來說,你注冊就是為了能夠訪問一組指定的設計原則,這組原則會讓你的應用程序有效運作,像谷歌那樣輕松建立和管理您的應用程序。 今天我們來聊聊,但不從技術細節角度,聊為什么容器、Kubernetes是值得使用和整合到你的項目堆棧中的。我們的目標是給你們提供一個關于應該如何思考你的底層構架以及將它可視化問題,從這個角度來談我們的話題:Kubernetes...
摘要:然而在中國和美國,不同的語言和文化共通的卻是對女工程師的偏見和挑戰。因為谷歌是一家技術驅動的公司,所以我可以做很多決定。我認為這是一個傳遞途徑的問題,最起碼在美國是這樣。谷歌本身是很重視這一點的。 非商業轉載請注明作譯者、出處,并保留本文的原始鏈接:http://www.ituring.com.cn/article/203525 Dawn Chen是谷歌云平臺軟件工程師,目前負責Kub...
摘要:然而在中國和美國,不同的語言和文化共通的卻是對女工程師的偏見和挑戰。因為谷歌是一家技術驅動的公司,所以我可以做很多決定。我認為這是一個傳遞途徑的問題,最起碼在美國是這樣。谷歌本身是很重視這一點的。 非商業轉載請注明作譯者、出處,并保留本文的原始鏈接:http://www.ituring.com.cn/article/203525 Dawn Chen是谷歌云平臺軟件工程師,目前負責Kub...
摘要:然而在中國和美國,不同的語言和文化共通的卻是對女工程師的偏見和挑戰。因為谷歌是一家技術驅動的公司,所以我可以做很多決定。我認為這是一個傳遞途徑的問題,最起碼在美國是這樣。谷歌本身是很重視這一點的。 非商業轉載請注明作譯者、出處,并保留本文的原始鏈接:http://www.ituring.com.cn/article/203525 Dawn Chen是谷歌云平臺軟件工程師,目前負責Kub...
閱讀 2636·2021-11-11 16:55
閱讀 1279·2021-09-22 15:25
閱讀 1793·2019-08-29 16:26
閱讀 925·2019-08-29 13:21
閱讀 2306·2019-08-23 16:19
閱讀 2795·2019-08-23 15:10
閱讀 761·2019-08-23 14:24
閱讀 1850·2019-08-23 13:48