容器化技術之K8S


Docker 本身非常適合管理單個容器。但隨着您開始使用越來越多的容器和容器化應用程序,並把它們划分成數百個部分,很可能會導致管理和編排變得非常困難。最終,您需要后退一步,對容器實施分組,以便跨所有容器提供網絡、安全、遙測等服務。於是,Kubernetes 應運而生。

 

一、簡介

Kubernetes,又稱為 k8s(首字母為 k、首字母與尾字母之間有 8 個字符、尾字母為 s,所以簡稱 k8s)或者簡稱為 “kube” ,是一種可自動實施 Linux 容器操作的開源平台。它可以幫助用戶省去應用容器化過程的許多手動部署和擴展操作。也就是說,您可以將運行 Linux 容器的多組主機聚集在一起,由 Kubernetes 幫助您輕松高效地管理這些集群。而且,這些集群可跨公共雲、私有雲或混合雲部署主機。因此,對於要求快速擴展的雲原生應用而言(例如借助 Apache Kafka 進行的實時數據流處理),Kubernetes 是理想的托管平台。

Kubernetes 最初由 Google 的工程師基於 go 語言開發和設計出來並於2014年6月開源。Google 是最早研發 Linux 容器技術的企業之一,曾公開分享介紹 Google 如何將一切都運行於容器之中(這是 Google 雲服務背后的技術)。Google 每周會啟用超過 20 億個容器——全都由內部平台 Borg 支撐。Borg 是 Kubernetes 的前身,多年來開發 Borg 的經驗教訓成了影響 Kubernetes 中許多技術的主要因素。

趣聞:Kubernetes 徽標的七個輪輻代表着項目最初的名稱“九之七項目”(Project Seven of Nine)。

紅帽是第一批與 Google 合作研發 Kubernetes 的公司之一,作為 Kubernetes 上游項目的第二大貢獻者,我們甚至在這個項目啟動之前就已參與其中。2015 年,Google 將 Kubernetes 項目捐贈給了新成立的雲原生計算基金會。

為什么用k8s

docker很難在不同服務器之間互聯。

真正的生產型應用會涉及多個容器。這些容器必須跨多個服務器主機進行部署。Kubernetes 可以提供所需的編排和管理功能,以便您針對這些工作負載大規模部署容器。借助 Kubernetes 編排功能,您可以構建跨多個容器的應用服務、跨集群調度、擴展這些容器,並長期持續管理這些容器的健康狀況。

 

Kubernetes 還需要與聯網、存儲、安全性、遙測和其他服務集成整合,以提供全面的容器基礎架構。

當然,這取決於您如何在您的環境中使用容器。Linux 容器中的基本應用將它們視作高效、快速的虛擬機。一旦把它部署到生產環境或擴展為多個應用,您顯然需要許多托管在相同位置的容器來協同提供各種服務。隨着這些容器的累積,您運行環境中容器的數量會急劇增加,復雜度也隨之增長。

 

Kubernetes 通過將容器分類組成 “容器集” (pod),解決了容器增殖帶來的許多常見問題容器集為分組容器增加了一個抽象層,可幫助您調用工作負載,並為這些容器提供所需的聯網和存儲等服務。Kubernetes 的其它部分可幫助您在這些容器集之間達成負載平衡,同時確保運行正確數量的容器,充分支持您的工作負載。

 容器分組:pod,pod下一組多個docker容器,最小操作單元。

 

如果能正確實施 Kubernetes,再輔以其它開源項目(例如 Atomic 注冊表、Open vSwitch、heapster、OAuth 以及 SELinux),您就能夠輕松編排容器基礎架構的各個部分。

 

用途

在您生產環境中使用 Kubernetes 的主要優勢在於,它提供了一個便捷有效的平台,讓您可以在物理機和虛擬機集群上調度和運行容器。更廣泛一點說,它可以幫助您在生產環境中,完全實施並依托基於容器的基礎架構運營。由於 Kubernetes 的實質在於實現操作任務自動化,所以您可以將其它應用平台或管理系統分配給您的許多相同任務交給容器來執行。

 

利用 Kubernetes,您能夠達成以下目標:

  • l  跨多台主機進行容器編排。
  • l  更加充分地利用硬件,最大程度獲取運行企業應用所需的資源。
  • l  有效管控應用部署和更新,並實現自動化操作。
  • l  掛載和增加存儲,用於運行有狀態的應用。
  • l  快速、按需擴展容器化應用及其資源。
  • l  對服務進行聲明式管理,保證所部署的應用始終按照部署的方式運行。
  • l  利用自動布局、自動重啟、自動復制以及自動擴展功能,對應用實施狀況檢查和自我修復。

 

但是,Kubernetes 需要依賴其它項目來全面提供這些經過編排的服務。因此,借助其它開源項目可以幫助您將 Kubernetes 的全部功用發揮出來。這些功能包括:

  •  注冊表,通過 Atomic 注冊表或 Docker 注冊表等項目實現。
  •  聯網,通過 OpenvSwitch 和智能邊緣路由等項目實現。
  •  遙測,通過 heapster、kibana、hawkular 和 elastic 等項目實現。
  •  安全性,通過 LDAP、SELinux、RBAC 和 OAUTH 等項目以及多租戶層來實現。
  •  自動化,參照 Ansible 手冊進行安裝和集群生命周期管理。
  •  服務,可通過自帶預建版常用應用模式的豐富內容目錄來提供。

 

二、核心概念

Kubernetes 有各類資源對象來描述整個集群的運行狀態(Node、Pod、Replication Controller、Service等都可以看作一種“資源對象”)。這些對象都需要通過調用 kubernetes api 來進行創建、修改、刪除並將其保存在etcd中持久化存儲,可以通過 kubectl 命令工具,也可以直接調用 k8s api,或者使用對象語言的客戶端庫(例如:golang , pythion )。

從這個角度來看,Kubernetes其實是一個高度自動化的資源控制系統,它通過跟蹤對比etcd庫里保存的“資源期望狀態”與當前環境中的“實際資源狀態”的差異來實現自動控制和自動糾錯的高級功能。

每個 kubernetes 對象都會包含兩個關鍵字段:Object Spec 和 Object Status。spec 描述了對象所期望達到的狀態,status 描述了該對象的實際狀態。

 

 

 

2.1  Master

 Kubernetes里的Master指的是集群控制節點,每個Kubernetes集群里需要有一個Master節點來負責整個集群的管理和控制,基本上Kubernetes的所有控制命令都發給它,它來負責具體的執行過程,我們后面執行的所有命令基本都是在Master節點上運行的。Master節點通常會占據一個獨立的服務器(高可用部署建議用3台服務器),其主要原因是它太重要了,是整個集群的“首腦”,如果宕機或者不可用,那么對集群內容器應用的管理都將失效。

 

Master節點上運行着以下一組關鍵進程:

  • Kubernetes API Server (kube-apiserver):提供了HTTP Rest接口的關鍵服務進程,是Kubernetes里所有資源的增、刪、改、查等操作的唯一入口,也是集群控制的入口進程。
  • Kubernetes Controller Manager (kube-controller-manager):Kubernetes里所有資源對象的自動化控制中心,可以理解為資源對象的“大總管”。
  • Kubernetes Scheduler (kube-scheduler):負責資源調度(Pod調度)的進程,相當於公交公司的“調度室”。

 另外,在Master節點上還需要啟動一個etcd服務,因為Kubernetes里的所有資源對象的數據全部是保存在etcd中的。

 

 

比如,你在 bash中輸入

[root@node01 ~]# kubectl get service

k8s的API Server會對其處理,實際調用了k8s的api,k8s操作的唯一入口

kube-controller-manager負責RC機制,當docker容器出錯關閉后,會自動開啟新的

資源調度器和管家聯系在一起,管家查看etcd中的數據,調用資源調度器去進行資源調度,看哪些工作節點符合要求,下發命令給節點

 

2.2.  Node

除了Master,Kubernetes集群中的其他機器被稱為Node節點,在較早的版本中也被稱為Minion。與Master一樣,Node節點可以是一台物理主機,也可以是一台虛擬機。Node節點才是Kubernetes集群中的工作負載節點,每個Node都會被Master分配一些工作負載(Docker容器),當某個Node宕機時,其上的工作負載會被Master自動轉移到其他節點上去。

每個Node節點上都運行着以下一組關鍵進程:

  • kubelet:負責Pod對應的容器的創建、啟停等任務,同時與Master節點密切協作,實現集群管理的基本功能。
  • kube-proxy:實現Kubernetes Service的通信與負載均衡機制的重要組件。
  • Docker Engine (docker):Docker引擎,負責本機的容器創建和管理工作。

fluentd

 Node節點可以在運行期間動態增加到Kubernetes集群中,前提是這個節點上已經正確安裝、配置和啟動了上述關鍵進程,在默認情況下kubelet會向Master注冊自己,這也是Kubernetes推薦的Node管理方式。一旦Node被納入集群管理范圍,kubelet進程就會定時向Master節點匯報自身的情報,例如操作系統、Docker版本、機器的CPU和內存情況,以及當前有哪些Pod在運行等,存在etcd中,這樣Master可以獲知每個Node的資源使用情況,並實現高效均衡等資源調度策略。而某個Node超過指定時間不上報信息時,會被Master判斷為“失聯”,Node的狀態被標記為不可用(Not Ready),隨后Master會觸發“工作負載大轉移”的自動流程。

 

比如,要運行三台nginx,有一台掛了,該台的所有信息都已存在etcd當中了,controller manager會根據rc機制重啟一台,讓調度器去找可用的資源進行重啟。

 

2.3.  Pod

Pod是Kubernetes的最重要也最基本的概念,如下圖所示是Pod的組成示意圖,我們看到每個Pod都有一個特殊的被成為“根容器”的Pause容器。Pause容器對應的鏡像屬於Kubernetes平台的一部分,除了Pause容器,每個Pod還包含一個或多個緊密相關的用戶業務容器。

Pause是打不死的小強,不運行業務,Pod會檢查該容器有沒有掛

Pod的組成

為什么Kubernetes會設計出一個全新的Pod概念並且Pod有這樣特殊的組成結構?

 原因之一:在一組容器作為一個單元的情況下,我們難以對“整體”簡單地進行判斷及有效地進行行動。比如,一個容器死亡了,此時算是整體死亡么?引入業務無關並且不易死亡的Pause容器作為Pod的根容器,以它的狀態代表整體容器組的狀態,就簡單、巧妙地解決了這個難題。

 原因之二:Pod里的多個業務容器共享Pause容器的IP,共享Pause容器掛接的Volume,這樣既簡化了密切關聯的業務容器之間的通信問題,也很好地解決了它們之間的文件共享問題。

 Kubernetes為每個Pod都分配了唯一的IP地址,稱之為Pod IP,一個Pod里的多個容器共享Pod IP地址。Kubernetes要求底層網絡支持集群內任意兩個Pod之間的TCP/IP直接通信,這通常采用虛擬而層網絡技術來實現,例如Flannel、Open vSwitch等,因此我們需要牢記一點:在Kubernetes里,一個Pod里的容器與另外主機上的Pod容器能夠直接通信。

 Pod其實有兩種類型:普通的Pod及靜態Pod(Static Pod),后者比較特殊,它並不存放在Kubernetes的etcd存儲里,而是存放在某個具體的Node上的一個具體文件中,並且只在此Node上啟動運行。而普通的Pod一旦被創建,就會被放入到etcd中存儲,隨后會被Kubernetes Master調度到某個具體的Node上並進行綁定(Binding),隨后該Pod被對應的Node上的kubelet進程實例化成一組相關的Docker容器並且啟動起來。在默認情況下,當Pod里的某個容器停止時,Kubernetes會自動檢測到這個問題並且重新啟動這個Pod(重啟Pod里的所有容器),如果Pod所在的Node宕機,則會將這個Node上的所有Pod重新調度到其他節點上。Pod、容器與Node的關系圖如下圖所示。

 

Pod、容器與Node的關系

 

2.4.  Label(標簽)

 Label是Kubernetes系統中另外一個核心概念。一個Label是一個key=value的鍵值對,其中key與vaue由用戶自己指定。Label可以附加到各種資源對象上,例如Node、Pod、Service、RC等,一個資源對象可以定義任意數量的Label,同一個Label也可以被添加到任意數量的資源對象上去,Label通常在資源對象定義時確定,也可以在對象創建后動態添加或者刪除。

 我們可以通過指定的資源對象捆綁一個或多個不同的Label來實現多維度的資源分組管理功能,以便於靈活、方便地進行資源分配、調度、配置、部署等管理工作。例如:部署不同版本的應用到不同的環境中;或者監控和分析應用(日志記錄、監控、告警)等。一些常用等label示例如下。

  • 版本標簽:"release" : "stable" , "release" : "canary"...
  • 環境標簽:"environment" : "dev" , "environment" : "production"
  • 架構標簽:"tier" : "frontend" , "tier" : "backend" , "tier" : "middleware"
  • 分區標簽:"partition" : "customerA" , "partition" : "customerB"...
  • 質量管控標簽:"track" : "daily" , "track" : "weekly"

 Label相當於我們熟悉的“標簽”,給某個資源對象定義一個Label,就相當於給它打了一個標簽,隨后可以通過Label Selector(標簽選擇器)查詢和篩選擁有某些Label的資源對象,Kubernetes通過這種方式實現了類似SQL的簡單又通用的對象查詢機制。

 mysql打個標簽,mycat打個標簽,放在一個服務器上跑。

2.5.  Replication Controller

 RC是Kubernetes系統中的核心概念之一,簡單來說,它其實是定義了一個期望的場景,即聲明某種Pod的副本數量在任意時刻都符合某個預期值,所以RC的定義包括如下幾個部分。

  • Pod期待的副本數(replicas)。
  • 用於篩選目標Pod的Label Selector。
  • 當Pod的副本數量小於預期數量時,用於創建新Pod的Pod模版(template)。

 

2.6.  Deployment

 Deployment是Kubernetes v1.2引入的概念,引入的目的是為了更好地解決Pod的編排問題。為此,Deployment在內部使用了Replica Set來實現目的,無論從Deployment的作用與目的,它的YAML定義,還是從它的具體命令行操作來看,我們都可以把它看作RC的一次升級,兩者相似度超過90%。

 Deployment相對於RC的一個最大升級是我們隨時知道當前Pod“部署”的進度。實際上由於一個Pod的創建、調度、綁定節點及在目標Node上啟動對應的容器這一完整過程需要一定的時間,所以我們期待系統啟動N個Pod副本的目標狀態,實際上是一個連續變化的“部署過程”導致的最終狀態。

 Deployment的典型使用場景有以下幾個。

  • 創建一個Deployment對象來生成對應的Replica Set並完成Pod副本的創建過程。
  • 檢查Deployment的狀態來看部署動作是否完成(Pod副本的數量是否達到預期的值)。
  • 更新Deployment以創建新的Pod(比如鏡像升級)。
  • 如果當前Deployment不穩定,則回滾到一個早先的Deployment版本。
  • 暫停Deployment以便於一次性修改多個PodTemplateSpec的配置項,之后再恢復Deployment,進行新的發布。
  • 擴展Deployment以應對高負載。
  • 查看Deployment的狀態,以此作為發布是否成功的指標。
  • 清理不再需要的舊版本ReplicaSets。

 

2.7.  StatefulSet

 在Kubernetes系統中,Pod的管理對象RC、Deployment、DaemonSet和Job都是面向無狀態的服務。但現實中有很多服務是有狀態的,特別是一些復雜的中間件集群,例如MySQL集群、MongoDB集群、Kafka集群、Zookeeper集群等,這些應用集群有以下一些共同點。

 

每個節點都有固定的身份ID,通過這個ID,集群中的成員可以相互發現並且通信。

集群的規模是比較固定的,集群規模不能隨意變動。

集群里的每個節點都是有狀態的,通常會持久化數據到永久存儲中。

如果磁盤損壞,則集群里的某個節點無法正常運行,集群功能受損。

 

 如果用RC/Deployment控制Pod副本數的方式來實現上述有狀態的集群,則我們會發現第一點是無法滿足的,因為Pod的名字是隨機產生的,Pod的IP地址也是在運行期才確定且可能有變動的,我們事先無法為每個Pod確定唯一不變的ID,為了能夠在其他節點上恢復某個失敗的節點,這種集群中的Pod需要掛接某種共享存儲,為了解決這個問題,Kubernetes從v1.4版本開始引入了PetSet這個新的資源對象,並且在v1.5版本時更名為StatefulSet,StatefulSet從本質上來說,可以看作Deployment/RC的一個特殊變種,它有如下一些特性。

 

StatefulSet里的每個Pod都有穩定、唯一的網絡標識,可以用來發現集群內的其他成員。假設StatefulSet的名字叫kafka,那么第一個Pod叫kafak-0,第二個Pod叫kafak-1,以此類推。

StatefulSet控制的Pod副本的啟停順序是受控的,操作第n個Pod時,前n-1個Pod已經時運行且准備好的狀態。

StatefulSet里的Pod采用穩定的持久化存儲卷,通過PV/PVC來實現,刪除Pod時默認不會刪除與StatefulSet相關的存儲卷(為了保證數據的安全)。

 

 StatefulSet除了要與PV卷捆綁使用以存儲Pod的狀態數據,還要與Headless Service配合使用,即在每個StatefulSet的定義中要聲明它屬於哪個Headless Service。Headless Service與普通Service的關鍵區別在於,它沒有Cluster IP,如果解析Headless Service的DNS域名,則返回的是該Service對應的全部Pod的Endpoint列表。StatefulSet在Headless Service的基礎上又為StatefulSet控制的每個Pod實例創建了一個DNS域名,這個域名的格式為:

$(podname).$(headless service name)

 

 比如一個3節點的Kafka的StatefulSet集群,對應的Headless Service的名字為kafka,StatefulSet的名字為kafka,則StatefulSet里面的3個Pod的DNS名稱分別為kafka-0.kafka、kafka-1.kafka、kafka-3.kafka,這些DNS名稱可以直接在集群的配置文件中固定下來。

 

2.8.  Service(服務)

 Service也是Kubernetes里的最核心的資源對象之一,Kubernetes里的每個Service其實就是我們經常提起的微服務架構中的一個“微服務”,之前我們所說的Pod、RC等資源對象其實都是為這節所說的“服務”------Kubernetes Service作“嫁衣”的。下圖顯示了Pod、RC與Service的邏輯關系。

 

Pod、RC與Service的關系

 從圖中我們看到,Kubernetes的Service定義了一個服務的訪問入口地址,前端的應用(Pod)通過這個入口地址訪問其背后的一組由Pod副本組成的集群實例,Service與其后端Pod副本集群之間則是通過Label Selector來實現“無縫對接”的。而RC的作用實際上是保證Service的服務能力和服務質量始終處於預期的標准。

 

2.9.  Volume(存儲卷)

 Volume是Pod中能夠被多個容器訪問的共享目錄。Kubernetes的Volume概念、用途和目的與Docker的Volume比較類似,但兩者不能等價。首先,Kubernetes中的Volume定義在Pod上,然后被一個Pod里的多個容器掛載到具體的文件目錄下;其次,Kubernetes中的Volume中的數據也不會丟失。最后,Kubernetes支持多種類型的Volume,例如Gluster、Ceph等先進的分布式文件系統。

 

2.10.  Namespace

 Namespace(命名空間)是Kubernetes系統中的另一個非常重要的概念,Namespace在很多情況下用於實現多租戶的資源隔離。Nameaspace通過將集群內部的資源對象“分配”到不同的Namespce中,形成邏輯上分組的不同項目、小組或用戶組,便於不同的分組在共享使用整個集群的資源的同時還能被分別管理。

 

2.11.  Annotation(注解)

 Annotation與Label類似,也使用key/value鍵值對的形式進行定義。不同的是Label具有嚴格的命名規則,它定義的是Kubernetes對象的元數據(Metadata),並且用於Label Selector。而Annotation則是用戶任意定義的“附加”信息,以便於外部工具進行查找,很多時候,Kubernetes的模塊自身會通過Annotation的方式標記資源對象的特殊信息。

 通常來說,用Annotation來記錄的信息如下。 

  • build信息、release信息、Docker鏡像信息等,例如時間戳、release id號、PR號、鏡像hash值、docker registry地址等。
  • 日志庫、監控庫、分析庫等資源庫的地址信息。
  • 程序調試工具信息,例如工具、版本號等。
  • 團隊等聯系信息,例如電話號碼、負責人名稱、網址等。

 

2.12. 其他

 Kubelet

運行在節點上的服務,可讀取容器清單(container manifest),確保指定的容器啟動並運行。

 kubectl

Kubernetes 的命令行配置工具。

 

上述組件是Kubernetes系統的核心組件,它們共同構成了Kubernetes系統的框架和計算模型。通過對它們進行靈活組合,用戶就可以快速、方便地對容器集群進行配置、創建和管理。除了本章所介紹的核心組件,在Kubernetes系統中還有許多輔助配置的資源對象,例如LimitRange、Resurce。另外,一些系統內部使用的對象Binding、Event等請參考Kubernetes的API文檔。

 

三、術語

官方把 kubernetes 術語分為 12 個分類:

系統結構、社區、核心對象、擴展、基礎、網絡、操作、安全、存儲、工具、用戶類型、工作負載

由於 k8s 的術語實在太多了,想要全部記住作為新學者還是有點壓力,所以我們課程中只講解一些常用的術語。想要了解更多 kubernetes 術語,請參照官方術語表。

地址:https://kubernetes.io/docs/reference/glossary/?fundamental=true

Pods

在Kubernetes中,最小的管理元素不是一個個獨立的容器,而是Pod,Pod是最小的,管理,創建,計划的最小單元。

Labels

標簽其實就一對 key/value ,被關聯到對象上,比如Pod;標簽的使用我們傾向於能夠標示對象的特殊特點,並且對用戶而言是有意義的(就是一眼就看出了這個Pod是數據庫),但是標簽對內核系統是沒有直接意義的。標簽可以用來划分特定組的對象(比如,所有女的),標簽可以在創建一個對象的時候直接給與,也可以在后期隨時修改,每一個對象可以擁有多個標簽,但是,key值必須是唯一的

"labels": {

 "key1" : "value1",

 "key2" : "value2"

 }

Namespace

Namespace 是對一組資源和對象的抽象集合,比如可以用來將系統內部的對象划分為不同的項目組或用戶組。常見的pods, services, replication controllers和deployments等都是屬於某一個namespace的(默認是default),而node, persistentVolumes等則不屬於任何namespace。

 

Namespace常用來隔離不同的用戶,比如Kubernetes自帶的服務一般運行在kube-system namespace中。

Replication Controller

Replication Controller 保證了在所有時間內,都有特定數量的Pod副本正在運行,如果太多了,Replication Controller就殺死幾個,如果太少了,Replication Controller會新建幾個,和直接創建的pod不同的是,Replication Controller會替換掉那些刪除的或者被終止的pod,不管刪除的原因是什么(維護阿,更新啊,Replication Controller都不關心)。基於這個理由,我們建議即使是只創建一個pod,我們也要使用Replication Controller。Replication Controller 就像一個進程管理器,監管着不同node上的多個pod,而不是單單監控一個node上的pod,Replication Controller 會委派本地容器來啟動一些節點上服務(Kubelet ,Docker)。

Node

Node是Pod真正運行的主機,可以物理機,也可以是虛擬機。為了管理Pod,每個Node節點上至少要運行container runtime(比如docker或者rkt)、kubelet和kube-proxy服務。

 

ReplicaSets

ReplicaSet是下一代復本控制器。ReplicaSet和 Replication Controller之間的唯一區別是現在的選擇器支持。Replication Controller只支持基於等式的selector(env=dev或environment!=qa),但ReplicaSet還支持新的,基於集合的selector(version in (v1.0, v2.0)或env notin (dev, qa))。在試用時官方推薦ReplicaSet。

Services

Kubernetes Pod是平凡的,它門會被創建,也會死掉(生老病死),並且他們是不可復活的。 ReplicationControllers動態的創建和銷毀Pods(比如規模擴大或者縮小,或者執行動態更新)。每個pod都由自己的ip,這些IP也隨着時間的變化也不能持續依賴。這樣就引發了一個問題:如果一些Pods(讓我們叫它作后台,后端)提供了一些功能供其它的Pod使用(讓我們叫作前台),在kubernete集群中是如何實現讓這些前台能夠持續的追蹤到這些后台的?

答案是:Service

Kubernete Service 是一個定義了一組Pod的策略的抽象,我們也有時候叫做宏觀服務。這些被服務標記的Pod都是(一般)通過label Selector決定的(下面我們會講到我們為什么需要一個沒有label selector的服務)

舉個例子,我們假設后台是一個圖形處理的后台,並且由3個副本。這些副本是可以相互替代的,並且前台並需要關心使用的哪一個后台Pod,當這個承載前台請求的pod發生變化時,前台並不需要直到這些變化,或者追蹤后台的這些副本,服務是這些去耦

對於Kubernete原生的應用,Kubernete提供了一個簡單的Endpoints API,這個Endpoints api的作用就是當一個服務中的pod發生變化時,Endpoints API隨之變化,對於哪些不是原生的程序,Kubernetes提供了一個基於虛擬IP的網橋的服務,這個服務會將請求轉發到對應的后台pod。

Volumes

容器中的磁盤的生命周期是短暫的,這就帶來了一系列的問題,第一,當一個容器損壞之后,kubelet 會重啟這個容器,但是文件會丟失-這個容器會是一個全新的狀態,第二,當很多容器在同一Pod中運行的時候,很多時候需要數據文件的共享。Kubernete Volume解決了這個問題。

PV/PVC/StorageClass

PersistentVolume(PV)是集群中已由管理員配置的一段網絡存儲。 集群中的資源就像一個節點是一個集群資源。 PV是諸如卷之類的卷插件,但是具有獨立於使用PV的任何單個pod的生命周期。 該API對象捕獲存儲的實現細節,即NFS,iSCSI或雲提供商特定的存儲系統。

PersistentVolumeClaim(PVC)是用戶存儲的請求。 它類似於pod。 Pod消耗節點資源,PVC消耗光伏資源。 莢可以請求特定級別的資源(CPU和內存)。 權利要求可以請求特定的大小和訪問模式(例如,可以一旦讀/寫或只讀許多次安裝)。

雖然PersistentVolumeClaims允許用戶使用抽象存儲資源,但是常見的是,用戶需要具有不同屬性(如性能)的PersistentVolumes,用於不同的問題。 群集管理員需要能夠提供多種不同於PersistentVolumes的PersistentVolumes,而不僅僅是大小和訪問模式,而不會使用戶了解這些卷的實現細節。 對於這些需求,存在StorageClass資源。

StorageClass為管理員提供了一種描述他們提供的存儲的“類”的方法。 不同的類可能映射到服務質量級別,或備份策略,或者由群集管理員確定的任意策略。 Kubernetes本身對於什么類別代表是不言而喻的。 這個概念有時在其他存儲系統中稱為“配置文件”

 

例子

https://kubernetes.io/docs/user-guide/persistent-volumes/walkthrough/

Deployment

Deployment為Pod和ReplicaSet提供了一個聲明式定義(declarative)方法,用來替代以前的ReplicationController來方便的管理應用。典型的應用場景包括:

l  定義Deployment來創建Pod和ReplicaSet

l  滾動升級和回滾應用

l  擴容和縮容

l  暫停和繼續Deployment

比如一個簡單的nginx應用可以定義為:

apiVersion: extensions/v1beta1

kind: Deployment

metadata:

  name: nginx-deployment

spec:

  replicas: 3

  template:

    metadata:

      labels:

        app: nginx

    spec:

      containers:

      - name: nginx

        image: nginx:1.7.9

        ports:

        - containerPort: 80

 

擴容:

kubectl scale deployment nginx-deployment --replicas 10

如果集群支持 horizontal pod autoscaling 的話,還可以為Deployment設置自動擴展:

kubectl autoscale deployment nginx-deployment --min=10 --max=15 --cpu-percent=80

更新鏡像也比較簡單:

kubectl set image deployment/nginx-deployment nginx=nginx:1.9.1

回滾:

kubectl rollout undo deployment/nginx-deployment

Secret

Secret解決了密碼、token、密鑰等敏感數據的配置問題,而不需要把這些敏感數據暴露到鏡像或者Pod Spec中。Secret可以以Volume或者環境變量的方式使用。

Secret有三種類型:

l  Service Account:用來訪問Kubernetes API,由Kubernetes自動創建,並且會自動掛載到Pod的/run/secrets/kubernetes.io/serviceaccount目錄中;

l  Opaque:base64編碼格式的Secret,用來存儲密碼、密鑰等;

l  kubernetes.io/dockerconfigjson:用來存儲私有docker registry的認證信息。

StatefulSet

StatefulSet是為了解決有狀態服務的問題(對應Deployments和ReplicaSets是為無狀態服務而設計),其應用場景包括:

l  穩定的持久化存儲,即Pod重新調度后還是能訪問到相同的持久化數據,基於PVC來實現

l  穩定的網絡標志,即Pod重新調度后其PodName和HostName不變,基於Headless Service(即沒有Cluster IP的Service)來實現

l  有序部署,有序擴展,即Pod是有順序的,在部署或者擴展的時候要依據定義的順序依次依次進行(即從0到N-1,在下一個Pod運行之前所有之前的Pod必須都是Running和Ready狀態),基於init containers來實現

l  有序收縮,有序刪除(即從N-1到0)

 

從上面的應用場景可以發現,StatefulSet由以下幾個部分組成:

l  用於定義網絡標志(DNS domain)的Headless Service

l  用於創建PersistentVolumes的volumeClaimTemplates

l  定義具體應用的StatefulSet

DaemonSet

DaemonSet保證在每個Node上都運行一個容器副本,常用來部署一些集群的日志、監控或者其他系統管理應用。典型的應用包括:

l  日志收集,比如fluentd,logstash等

l  系統監控,比如Prometheus Node Exporter,collectd,New Relic agent,Ganglia gmond等

l  系統程序,比如kube-proxy, kube-dns, glusterd, ceph等

Service Account

Service account是為了方便Pod里面的進程調用Kubernetes API或其他外部服務而設計的。

CronJob

CronJob即定時任務,就類似於Linux系統的crontab,在指定的時間周期運行指定的任務。在Kubernetes 1.5,使用CronJob需要開啟batch/v2alpha1 API,即–runtime-config=batch/v2alpha1。

Job

Job負責批量處理短暫的一次性任務 (short lived one-off tasks),即僅執行一次的任務,它保證批處理任務的一個或多個Pod成功結束。

 

Kubernetes支持以下幾種Job:

l  非並行Job:通常創建一個Pod直至其成功結束

l  固定結束次數的Job:設置.spec.completions,創建多個Pod,直到.spec.completions個Pod成功結束

l  帶有工作隊列的並行Job:設置.spec.Parallelism但不設置.spec.completions,當所有Pod結束並且至少一個成功時,Job就認為是成功

Security Context 和 PSP

Security Context的目的是限制不可信容器的行為,保護系統和其他容器不受其影響。

Kubernetes提供了三種配置Security Context的方法:

l  Container-level Security Context:僅應用到指定的容器

l  Pod-level Security Context:應用到Pod內所有容器以及Volume

l  Pod Security Policies(PSP):應用到集群內部所有Pod以及Volume

 

Pod Security Policies(PSP)是集群級的Pod安全策略,自動為集群內的Pod和Volume設置Security Context。

使用PSP需要API Server開啟extensions/v1beta1/podsecuritypolicy,並且配置PodSecurityPolicyadmission控制器。

Resource Quotas

資源配額(Resource Quotas)是用來限制用戶資源用量的一種機制。

它的工作原理為:

l  資源配額應用在Namespace上,並且每個Namespace最多只能有一個ResourceQuota對象

l  開啟計算資源配額后,創建容器時必須配置計算資源請求或限制(也可以用LimitRange設置默認值)

l  用戶超額后禁止創建新的資源

Network Policy

Network Policy提供了基於策略的網絡控制,用於隔離應用並減少攻擊面。它使用標簽選擇器模擬傳統的分段網絡,並通過策略控制它們之間的流量以及來自外部的流量。

在使用Network Policy之前,需要注意:

l  apiserver開啟extensions/v1beta1/networkpolicies

l  網絡插件要支持Network Policy,如Calico、Romana、Weave Net和trireme等

Ingress

通常情況下,service和pod的IP僅可在集群內部訪問。集群外部的請求需要通過負載均衡轉發到service在Node上暴露的NodePort上,然后再由kube-proxy將其轉發給相關的Pod。

而Ingress就是為進入集群的請求提供路由規則的集合,如下圖所示

 

Ingress可以給service提供集群外部訪問的URL、負載均衡、SSL終止、HTTP路由等。為了配置這些Ingress規則,集群管理員需要部署一個Ingress controller,它監聽Ingress和service的變化,並根據規則配置負載均衡並提供訪問入口。

ThirdPartyResources

ThirdPartyResources是一種無需改變代碼就可以擴展Kubernetes API的機制,可以用來管理自定義對象。

ThirdPartyResources將在v1.7棄用

ThirdPartyResources將在v1.7棄用,並在未來版本中刪除。建議從v1.7開始,遷移到CustomResourceDefinition。

ConfigMap

ConfigMap用於保存配置數據的鍵值對,可以用來保存單個屬性,也可以用來保存配置文件。ConfigMap跟secret很類似,但它可以更方便地處理不包含敏感信息的字符串。

PodPreset

PodPreset用來給指定標簽的Pod注入額外的信息,如環境變量、存儲卷等。這樣,Pod模板就不需要為每個Pod都顯式設置重復的信息。

 

四、安裝

4.1 K8S 集群架構方案

 

 

Kubernetes 集群組件:

l  etcd 一個高可用的K/V鍵值對存儲和服務發現系統

l  flannel 實現誇主機的容器網絡的通信

l  kube-apiserver 提供kubernetes集群的API調用

l  kube-controller-manager 確保集群服務

l  kube-scheduler 調度容器,分配到Node

l  kubelet 在Node節點上按照配置文件中定義的容器規格啟動容器

l  kube-proxy 提供網絡代理服務

Kubernetes 集群部署方案

如下是集群部署策略,1個master + 2個node。存儲集群etcd是單點集群(真實環境不推薦此做法,需要集群)。網絡使用的是flannel虛擬二次網絡。

Kubernetes具有完備的集群管理能力:

  1. 包括多層次的安全防護和准入機制
  2. 多租戶應用支撐能力
  3. 透明的服務注冊和服務發現機制
  4. 內建智能負載均衡器
  5. 強大的故障發現和自我修復能力
  6. 服務滾動升級和在線擴容能力
  7. 可擴展的資源自動調度機制
  8. 以及多粒度的資源管理能力

同時,kubernetes提供了完善的管理工具,這些工具涵蓋了包括開發、部署測試、運維監控在內的各個環節。

在kubernetes中,service(服務)是分布式集群架構的核心,一個service對象擁有如下關鍵特征:

  • 擁有一個唯一指定的名字(比如mysql-service)。
  • 擁有一個虛擬IP(Cluster IP、service IP或VIP)和端口號。
  • 能夠提供某種遠程服務能力。
  • 被映射到了提供這種服務能力的一組容器應用上。

Kubernetes.io開發了一個交互式教程,通過WEB瀏覽器就能使用預先部署好的一個Kubernetes集群,快速體驗kubernetes的功能和應用場景。

鏈接:https://kubernetes.io/docs/tutorials/kubernetes-basics/

K8s官方下載地址:https://github.com/kubernetes

 

 

環境准備

節點

ip 地址

操作系統

master

192.168.100.246

CentOS 7.3-x86_64

node1

192.168.100.247

CentOS 7.3-x86_64

node2

192.168.100.248

CentOS 7.3-x86_64

harbor

192.168.100.241

CentOS 7.3-x86_64

集群詳情

l  OS:CentOS Linux release 7.3.1611 (Core) 3.10.0-514.el7.x86_64

l  Kubernetes 1.6.0+(最低的版本要求是1.6)

l  Docker:建議使用 Docker CE

l  Etcd 3.3.10

l  Flannel 0.7.1 vxlan或者host-gw 網絡

l  TLS 認證通信 (所有組件,如 etcd、kubernetes master 和 node)

l  RBAC 授權

l  kubelet TLS BootStrapping

l  kubedns、dashboard、heapster(influxdb、grafana)、EFK(elasticsearch、fluentd、kibana) 集群插件

l  私有docker鏡像倉庫harbor(請自行部署,harbor提供離線安裝包,直接使用docker-compose啟動即可),不會的請參官文檔:

安裝文檔:https://github.com/goharbor/harbor/blob/master/docs/installation_guide.md

配置 https訪問:https://github.com/goharbor/harbor/blob/master/docs/configure_https.md

 

環境說明

在下面的步驟中,我們將在三台CentOS系統的物理機上部署具有三個節點的kubernetes1.12.3集群。

角色分配如下:

鏡像倉庫:192.168.100.241,為私有鏡像倉庫,請替換為公共倉庫或你自己的鏡像倉庫地址。

Master:192.168.100.246

Node:192.168.100.247192.168.100.248

注意:192.168.100.246 這台主機 master 和 node 復用。所有生成證書、執行 kubectl 命令的操作都在這台節點上執行。一旦 node 加入到 kubernetes 集群之后就不需要再登陸node節點了。

4.2 提醒

本文檔介紹使用二進制部署最新 kubernetes v1.12.3 集群的所有步驟,而不是使用 kubeadm 等自動化方式來部署集群。

在部署的過程中,將詳細列出各組件的啟動參數,它們的含義和可能遇到的問題。

部署完成后,你將理解系統各組件的交互原理,進而能快速解決實際問題。

所以本文檔主要適合於那些有一定 kubernetes 基礎,想通過一步步部署的方式來學習和了解系統配置、運行原理的人。

提醒

  1. 本文檔適用於 CentOS 7.x、Ubuntu 18.x 及以上版本系統
  2. 由於啟用了 TLS 雙向認證、RBAC 授權等嚴格的安全機制,建議從頭開始部署,而不要從中間開始,否則可能會認證、授權等失敗!
  3. 部署過程中需要有很多證書的操作,請大家耐心操作,不明白的操作可以參考本書中的其他章節的解釋。
  4. 該部署操作僅是搭建成了一個可用 kubernetes 集群,而很多地方還需要進行優化,heapster 插件、EFK 插件不一定會用於真實的生產環境中,但是通過部署這些插件,可以讓大家了解到如何部署應用到集群上。

特別提醒

有同學沒有按照本文檔的k8s版本(1.12.3)安裝,自己升級了版本;有些地方k8s升級后官方默認功能做了調整,比如kube-apiserver中的1.14版本不支持Initializers插件等......;由於k8s升級和功能迭代快,所以同學們如果必要請不要自行升級版本,自行升級將可能導致參照文檔安裝提示報錯。

文檔需要根據個人環境修改的地方都用中划線 +【粗體 or 標紅】表示,大家看到這種信息的時候記得修改,務必不能使用文檔相同的信息。。。。。。

 

4.3  組件版本和配置策略

組件版本

l  Kubernetes 1.12.3

l  Docker 18.09.0-ce

l  Etcd 3.3.10

l  Flanneld 0.10.0

l  插件:

m  Coredns

m  Dashboard

m  Heapster (influxdb、grafana)

m  Metrics-Server

m  EFK (elasticsearch、fluentd、kibana)

l  鏡像倉庫:

m  docker registry

m  harbor

 

主要配置策略

kube-apiserver:

l  使用節點本地 nginx 4 層透明代理實現高可用;

l  關閉非安全端口 8080 和匿名訪問;

l  在安全端口 6443 接收 https 請求;

l  嚴格的認證和授權策略 (x509、token、RBAC);

l  開啟 bootstrap token 認證,支持 kubelet TLS bootstrapping;

l  使用 https 訪問 kubelet、etcd,加密通信;

 

kube-controller-manager:

l  3 節點高可用;

l  關閉非安全端口,在安全端口 10252 接收 https 請求;

l  使用 kubeconfig 訪問 apiserver 的安全端口;

l  自動 approve kubelet 證書簽名請求 (CSR),證書過期后自動輪轉;

l  各 controller 使用自己的 ServiceAccount 訪問 apiserver;

 

kube-scheduler:

l  3 節點高可用;

l  使用 kubeconfig 訪問 apiserver 的安全端口;

 

kubelet:

l  使用 kubeadm 動態創建 bootstrap token,而不是在 apiserver 中靜態配置;

l  使用 TLS bootstrap 機制自動生成 client 和 server 證書,過期后自動輪轉;

l  在 KubeletConfiguration 類型的 JSON 文件配置主要參數;

l  關閉只讀端口,在安全端口 10250 接收 https 請求,對請求進行認證和授權,拒絕匿名訪問和非授權訪問;

l  使用 kubeconfig 訪問 apiserver 的安全端口;

 

kube-proxy:

l  使用 kubeconfig 訪問 apiserver 的安全端口;

l  在 KubeProxyConfiguration 類型的 JSON 文件配置主要參數;

l  使用 ipvs 代理模式;

 

集群插件:

l  DNS:使用功能、性能更好的 coredns;

l  Dashboard:支持登錄認證;

l  Metric:heapster、metrics-server,使用 https 訪問 kubelet 安全端口;

l  Log:Elasticsearch、Fluend、Kibana;

l  Registry 鏡像庫:docker-registry、harbor;

 

harbor私有鏡像倉庫:參考:https://github.com/goharbor/harbor

 

4.4 系統初始化和全局變量

 1. 集群機器

master:192.168.100.246

node1:192.168.100.247

node2:192.168.100.248

請提前在 VirtualBox 中安裝三台基於 centos 7 鏡像的虛擬機,本文檔中的 etcd 集群、master 節點、worker 節點均使用這三台機器。

 

注意:

  1. 需要在所有機器上執行本文檔的初始化命令;
  2. 需要使用具有 root 權限的賬號執行這些命令。

 

 2. 主機名

設置永久主機名稱,然后重新登錄:

hostnamectl set-hostname master # 將 master 替換為當前主機名

l  設置的主機名保存在 /etc/hostname 文件中;

 

如果 DNS 不支持解析主機名稱,則需要修改每台機器的 /etc/hosts 文件,添加主機名和 IP 的對應關系:

cat >> /etc/hosts <<EOF

192.168.100.246 master

192.168.100.247 node1

192.168.100.248 node2

EOF

3. 添加 docker 賬戶

在每台機器上添加 docker 賬戶:

useradd -m docker

4. 無密碼 ssh 登錄其它節點

如果沒有特殊指明,本文檔的所有操作均在 master 節點上執行,然后遠程分發文件和執行命令,所以需要添加該節點到其它節點的 ssh 信任關系。

設置 master 可以無密碼登錄所有節點的 root 賬戶:

ssh-keygen -t rsa

ssh-copy-id root@master

ssh-copy-id root@node1

ssh-copy-id root@node2

5. 將可執行文件路徑 /opt/k8s/bin 添加到 PATH 變量中

在每台機器上添加環境變量:

echo 'PATH=/opt/k8s/bin:$PATH' >>/root/.bashrc

source /root/.bashrc

 

6. 安裝依賴包

在每台機器上安裝依賴包:

 

CentOS:

yum install -y epel-release

yum install -y conntrack ntpdate ntp ipvsadm ipset jq iptables curl sysstat libseccomp wget

/usr/sbin/modprobe ip_vs

Ubuntu:

apt-get install -y conntrack ipvsadm ntp ipset jq iptables curl sysstat libseccomp

/usr/sbin/modprobe ip_vs

l  ipvs 依賴 ipset;

l  ntp 保證各機器系統時間同步;

 

7. 關閉防火牆

在每台機器上關閉防火牆,清理防火牆規則,設置默認轉發策略:

systemctl stop firewalld

systemctl disable firewalld

iptables -F && iptables -X && iptables -F -t nat && iptables -X -t nat

iptables -P FORWARD ACCEPT

 

8. 關閉 swap 分區

如果開啟了 swap 分區,kubelet 會啟動失敗(可以通過將參數 --fail-swap-on 設置為 false 來忽略 swap on),故需要在每台機器上關閉 swap 分區。同時注釋 /etc/fstab 中相應的條目,防止開機自動掛載 swap 分區:

swapoff -a

sed -i '/ swap / s/^\(.*\)$/#\1/g' /etc/fstab

 

9. 關閉 SELinux

關閉 SELinux,否則后續 K8S 掛載目錄時可能報錯 Permission denied:

setenforce 0

sed -i 's/^SELINUX=.*/SELINUX=disabled/' /etc/selinux/config

 

10. 關閉 dnsmasq(可選)

linux 系統開啟了 dnsmasq 后(如 GUI 環境),將系統 DNS Server 設置為 127.0.0.1,這會導致 docker 容器無法解析域名,需要關閉它:

systemctl stop dnsmasq

systemctl disable dnsmasq

 

11. 加載內核模塊

modprobe ip_vs_rr

modprobe br_netfilter

 

12. 優化內核參數

這一步如果執行有一些報錯不用理會,繼續往下執行。

cat > kubernetes.conf <<EOF

net.bridge.bridge-nf-call-iptables=1

net.bridge.bridge-nf-call-ip6tables=1

net.ipv4.ip_forward=1

net.ipv4.tcp_tw_recycle=0

vm.swappiness=0 # 禁止使用 swap 空間,只有當系統 OOM 時才允許使用它

vm.overcommit_memory=1 # 不檢查物理內存是否夠用

vm.panic_on_oom=0 # 開啟 OOM

fs.inotify.max_user_instances=8192

fs.inotify.max_user_watches=1048576

fs.file-max=52706963

fs.nr_open=52706963

net.ipv6.conf.all.disable_ipv6=1

net.netfilter.nf_conntrack_max=2310720

EOF

cp kubernetes.conf  /etc/sysctl.d/kubernetes.conf

sysctl -p /etc/sysctl.d/kubernetes.conf

l  必須關閉 tcp_tw_recycle,否則和 NAT 沖突,會導致服務不通;

l  關閉 IPV6,防止觸發 docker BUG;

 

13. 設置系統時區

# 調整系統 TimeZone

timedatectl set-timezone Asia/Shanghai

 

# 將當前的 UTC 時間寫入硬件時鍾

timedatectl set-local-rtc 0

 

# 重啟依賴於系統時間的服務

systemctl restart rsyslog

systemctl restart crond

 

14.  更新系統時間(可選)

ntpdate cn.pool.ntp.org

 

15.  關閉無關的服務

systemctl stop postfix && systemctl disable postfix

 

16.  設置 rsyslogd 和 systemd journal

systemd 的 journald 是 Centos 7 缺省的日志記錄工具,它記錄了所有系統、內核、Service Unit 的日志。

相比 systemd,journald 記錄的日志有如下優勢:

  1. 可以記錄到內存或文件系統;(默認記錄到內存,對應的位置為 /run/log/jounal)
  2. 可以限制占用的磁盤空間、保證磁盤剩余空間;
  3. 可以限制日志文件大小、保存的時間;

journald 默認將日志轉發給 rsyslog,這會導致日志寫了多份,/var/log/messages 中包含了太多無關日志,不方便后續查看,同時也影響系統性能。

mkdir /var/log/journal # 持久化保存日志的目錄

mkdir /etc/systemd/journald.conf.d

cat > /etc/systemd/journald.conf.d/99-prophet.conf <<EOF

[Journal]

# 持久化保存到磁盤

Storage=persistent

 

# 壓縮歷史日志

Compress=yes

 

SyncIntervalSec=5m

RateLimitInterval=30s

RateLimitBurst=1000

 

# 最大占用空間 10G

SystemMaxUse=10G

 

# 單日志文件最大 200M

SystemMaxFileSize=200M

 

# 日志保存時間 2 周

MaxRetentionSec=2week

 

# 不將日志轉發到 syslog

ForwardToSyslog=no

EOF

systemctl restart systemd-journald

 

17.  創建相關目錄

創建目錄:

mkdir -p  /opt/k8s/{bin,work} /etc/{kubernetes,etcd}/cert

 

18.  升級內核(版本低執行該項)

rpm -Uvh http://www.elrepo.org/elrepo-release-7.0-3.el7.elrepo.noarch.rpm

# 安裝完成后檢查 /boot/grub2/grub.cfg 中對應內核 menuentry 中是否包含 initrd16 配置,如果沒有,再安裝一次!

yum --enablerepo=elrepo-kernel install -y kernel-lt

# 設置開機從新內核啟動

grub2-set-default 0

 

安裝內核源文件(可選,在升級完內核並重啟機器后執行):

# yum erase kernel-headers

yum --enablerepo=elrepo-kernel install kernel-lt-devel-$(uname -r) kernel-lt-headers-$(uname -r)

 

19.  關閉 NUMA(可選)

cp /etc/default/grub{,.bak}

vim /etc/default/grub # 在 GRUB_CMDLINE_LINUX 一行添加 `numa=off` 參數,如下所示:

diff /etc/default/grub.bak /etc/default/grub

6c6

< GRUB_CMDLINE_LINUX="crashkernel=auto rd.lvm.lv=centos/root rhgb quiet"

---

> GRUB_CMDLINE_LINUX="crashkernel=auto rd.lvm.lv=centos/root rhgb quiet numa=off"

重新生成 grub2 配置文件:

cp /boot/grub2/grub.cfg{,.bak}

grub2-mkconfig -o /boot/grub2/grub.cfg

 

20.  檢查系統內核和模塊是否適合運行 docker (僅適用於 linux 系統)

curl https://raw.githubusercontent.com/docker/docker/master/contrib/check-config.sh > check-config.sh

bash ./check-config.sh

 

21.  分發集群環境變量定義腳本(擴容時不需要執行該步驟)

后續的部署步驟將使用 environment.sh文件中定義的全局環境變量,請根據自己的機器、網絡情況修改:

#!/usr/bin/bash

# 生成 EncryptionConfig 所需的加密 key
export ENCRYPTION_KEY=$(head -c 32 /dev/urandom | base64)

# 集群各機器 IP 數組
export NODE_IPS=(172.26.106.83 172.26.106.81 172.26.106.82)

# 集群各 IP 對應的 主機名數組
export NODE_NAMES=(node01 node02 node03 )

# etcd 集群服務地址列表
export ETCD_ENDPOINTS="https://172.26.106.83:2379,https://172.26.106.81:2379,https://172.26.106.82:2379"

# etcd 集群間通信的 IP 和端口
export ETCD_NODES="node01=https://172.26.106.83:2380,node02=https://172.26.106.81:2380,node03=https://172.26.106.82:2380"

# kube-apiserver 的反向代理(kube-nginx)地址端口
# export KUBE_APISERVER="https://127.0.0.1:8443"
export KUBE_APISERVER="https://172.26.106.83:8443"

# 節點間互聯網絡接口名稱
export IFACE="eth0"

# etcd 數據目錄
export ETCD_DATA_DIR="/data/k8s/etcd/data"

# etcd WAL 目錄,建議是 SSD 磁盤分區,或者和 ETCD_DATA_DIR 不同的磁盤分區
export ETCD_WAL_DIR="/data/k8s/etcd/wal"

# k8s 各組件數據目錄
export K8S_DIR="/data/k8s/k8s"

# docker 數據目錄
export DOCKER_DIR="/data/k8s/docker"

## 以下參數一般不需要修改

# TLS Bootstrapping 使用的 Token,可以使用命令 head -c 16 /dev/urandom | od -An -t x | tr -d ' ' 生成
BOOTSTRAP_TOKEN="41f7e4ba8b7be874fcff18bf5cf41a7c"

# 最好使用 當前未用的網段 來定義服務網段和 Pod 網段

# 服務網段,部署前路由不可達,部署后集群內路由可達(kube-proxy 保證)
SERVICE_CIDR="10.254.0.0/16"

# Pod 網段,建議 /16 段地址,部署前路由不可達,部署后集群內路由可達(flanneld 保證)
CLUSTER_CIDR="172.30.0.0/16"

# 服務端口范圍 (NodePort Range)
export NODE_PORT_RANGE="30000-32767"

# flanneld 網絡配置前綴
export FLANNEL_ETCD_PREFIX="/kubernetes/network"

# kubernetes 服務 IP (一般是 SERVICE_CIDR 中第一個IP)
export CLUSTER_KUBERNETES_SVC_IP="10.254.0.1"

# 集群 DNS 服務 IP (從 SERVICE_CIDR 中預分配)
export CLUSTER_DNS_SVC_IP="10.254.0.2"

# 集群 DNS 域名(末尾不帶點號)
export CLUSTER_DNS_DOMAIN="cluster.local"

# 將二進制目錄 /opt/k8s/bin 加到 PATH 中
export PATH=/opt/k8s/bin:$PATH

其中IFACE要去查看網卡信息

[root@node03 ~]# ll /etc/sysconfig/network-scripts/
total 228
-rw-r--r--  1 root root    38 Nov 29  2018 ifcfg-eth0
-rw-r--r--  1 root root   254 Jan  3  2018 ifcfg-lo
lrwxrwxrwx  1 root root    24 Nov 29  2018 ifdown -> ../../../usr/sbin/ifdown
-rwxr-xr-x  1 root root   654 Jan  3  2018 ifdown-bnep
-rwxr-xr-x  1 root root  6569 Jan  3  2018 ifdown-eth
-rwxr-xr-x  1 root root   781 Jan  3  2018 ifdown-ippp
-rwxr-xr-x  1 root root  4540 Jan  3  2018 ifdown-ipv6
lrwxrwxrwx  1 root root    11 Nov 29  2018 ifdown-isdn -> ifdown-ippp
-rwxr-xr-x  1 root root  2130 Sep 27  2018 ifdown-post
-rwxr-xr-x  1 root root  1068 Jan  3  2018 ifdown-ppp
-rwxr-xr-x  1 root root   870 Jan  3  2018 ifdown-routes
-rwxr-xr-x  1 root root  1456 Jan  3  2018 ifdown-sit
-rwxr-xr-x. 1 root root  1621 Mar 18  2017 ifdown-Team
-rwxr-xr-x. 1 root root  1556 Mar 18  2017 ifdown-TeamPort
-rwxr-xr-x  1 root root  1462 Jan  3  2018 ifdown-tunnel
lrwxrwxrwx  1 root root    22 Nov 29  2018 ifup -> ../../../usr/sbin/ifup
-rwxr-xr-x  1 root root 12415 Jan  3  2018 ifup-aliases
-rwxr-xr-x  1 root root   910 Jan  3  2018 ifup-bnep
-rwxr-xr-x  1 root root 13475 Sep 27  2018 ifup-eth
-rwxr-xr-x  1 root root 12075 Jan  3  2018 ifup-ippp
-rwxr-xr-x  1 root root 11893 Jan  3  2018 ifup-ipv6
lrwxrwxrwx  1 root root     9 Nov 29  2018 ifup-isdn -> ifup-ippp
-rwxr-xr-x  1 root root   650 Jan  3  2018 ifup-plip
-rwxr-xr-x  1 root root  1064 Jan  3  2018 ifup-plusb
-rwxr-xr-x  1 root root  4997 Sep 27  2018 ifup-post
-rwxr-xr-x  1 root root  4154 Jan  3  2018 ifup-ppp
-rwxr-xr-x  1 root root  2001 Jan  3  2018 ifup-routes
-rwxr-xr-x  1 root root  3303 Jan  3  2018 ifup-sit
-rwxr-xr-x. 1 root root  1755 Mar 18  2017 ifup-Team
-rwxr-xr-x. 1 root root  1876 Mar 18  2017 ifup-TeamPort
-rwxr-xr-x  1 root root  2711 Jan  3  2018 ifup-tunnel
-rwxr-xr-x  1 root root  1836 Jan  3  2018 ifup-wireless
-rwxr-xr-x  1 root root  5419 Jan  3  2018 init.ipv6-global
-rw-r--r--  1 root root 19948 Jan  3  2018 network-functions
-rw-r--r--  1 root root 31027 Jan  3  2018 network-functions-ipv6
[root@node03 ~]# cat /etc/sysconfig/network-scripts/ifcfg-eth0
DEVICE=eth0
BOOTPROTO=dhcp
ONBOOT=yes

然后,把全局變量定義腳本拷貝到所有節點的 /opt/k8s/bin 目錄:

source /opt/k8s/bin/environment.sh

for node_ip in ${NODE_IPS[@]}

  do

    echo ">>> ${node_ip}"

    scp /opt/k8s/bin/environment.sh root@${node_ip}:/opt/k8s/bin/

    ssh root@${node_ip} "chmod +x /opt/k8s/bin/*"

  done

 

22.  參考

系統內核相關參數參考:https://docs.openshift.com/enterprise/3.2/admin_guide/overcommit.html

 

4.5  創建 CA 證書和秘鑰

為確保安全,kubernetes 系統各組件需要使用 x509 證書對通信進行加密和認證。

CA (Certificate Authority) 是自簽名的根證書,用來簽名后續創建的其它證書。

本文檔使用 CloudFlare 的 PKI 工具集 cfssl 創建所有證書。

注意:如果沒有特殊指明,本文檔的所有操作均在 master 節點上執行,然后遠程分發文件和執行命令。

 

1.  安裝 cfssl 工具

sudo mkdir -p /opt/k8s/work/cert && cd /opt/k8s/work

wget https://pkg.cfssl.org/R1.2/cfssl_linux-amd64

mv cfssl_linux-amd64 /opt/k8s/bin/cfssl

 

wget https://pkg.cfssl.org/R1.2/cfssljson_linux-amd64

mv cfssljson_linux-amd64 /opt/k8s/bin/cfssljson

 

wget https://pkg.cfssl.org/R1.2/cfssl-certinfo_linux-amd64

mv cfssl-certinfo_linux-amd64 /opt/k8s/bin/cfssl-certinfo

 

chmod +x /opt/k8s/bin/*

export PATH=/opt/k8s/bin:$PATH

 

2.  創建根證書 (CA)

CA 證書是集群所有節點共享的,只需要創建一個 CA 證書,后續創建的所有證書都由它簽名。

 

3.  創建配置文件

CA 配置文件用於配置根證書的使用場景 (profile) 和具體參數 (usage,過期時間、服務端認證、客戶端認證、加密等),后續在簽名其它證書時需要指定特定場景。

cd /opt/k8s/work/cert

cat > ca-config.json <<EOF

{

  "signing": {

    "default": {

      "expiry": "87600h"

    },

    "profiles": {

      "kubernetes": {

        "usages": [

            "signing",

            "key encipherment",

            "server auth",

            "client auth"

        ],

        "expiry": "87600h"

      }

    }

  }

}

EOF

l  signing:表示該證書可用於簽名其它證書,生成的 ca.pem 證書中 CA=TRUE;

l  server auth:表示 client 可以用該該證書對 server 提供的證書進行驗證;

l  client auth:表示 server 可以用該該證書對 client 提供的證書進行驗證;

 

4. 創建證書簽名請求文件

cd /opt/k8s/work/cert

cat > ca-csr.json <<EOF

{

  "CN": "kubernetes",

  "key": {

    "algo": "rsa",

    "size": 2048

  },

  "names": [

    {

      "C": "CN",

      "ST": "BeiJing",

      "L": "BeiJing",

      "O": "k8s",

      "OU": "study163"

    }

  ]

}

EOF

l  CN:Common Name,kube-apiserver 從證書中提取該字段作為請求的用戶名 (User Name),瀏覽器使用該字段驗證網站是否合法;

l  O:Organization,kube-apiserver 從證書中提取該字段作為請求用戶所屬的組 (Group);

l  kube-apiserver 將提取的 User、Group 作為 RBAC 授權的用戶標識;

 

5. 生成 CA 證書和私鑰

cd /opt/k8s/work/cert

cfssl gencert -initca ca-csr.json | cfssljson -bare ca

ls ca*

 

6.  分發證書文件

將生成的 CA 證書、秘鑰文件、配置文件拷貝到所有節點的 /etc/kubernetes/cert 目錄下:

cd /opt/k8s/work/cert

source /opt/k8s/bin/environment.sh # 導入 NODE_IPS 環境變量

for node_ip in ${NODE_IPS[@]}

  do

    echo ">>> ${node_ip}"

    ssh root@${node_ip} "mkdir -p /etc/kubernetes/cert"

    scp ca*.pem ca-config.json root@${node_ip}:/etc/kubernetes/cert

  done 

7.  參考

各種 CA 證書類型:

https://github.com/kubernetes-incubator/apiserver-builder/blob/master/docs/concepts/auth.md

 

4.6  部署 kubectl 命令行工具

kubectl 是 kubernetes 集群的命令行管理工具,本小節介紹安裝和配置它的步驟。

kubectl 默認從 ~/.kube/config 文件讀取 kube-apiserver 地址、證書、用戶名等信息,如果沒有配置,執行 kubectl 命令時可能會出錯:

kubectl get pods

The connection to the server localhost:8080 was refused - did you specify the right host or port?

注意:

  1. 如果沒有特殊指明,本文檔的所有操作均在 master 節點上執行,然后遠程分發文件和執行命令。
  2. 本文檔只需要部署一次,生成的 kubeconfig 文件是通用的,可以拷貝到需要執行 kubeclt 命令的機器上。

1.  下載和分發 kubectl 命令行工具

下載和解壓:

cd /opt/k8s/work

wget https://dl.k8s.io/v1.12.3/kubernetes-client-linux-amd64.tar.gz

tar -xzvf kubernetes-client-linux-amd64.tar.gz

 

分發到所有使用 kubectl 的節點:

cd /opt/k8s/work

source /opt/k8s/bin/environment.sh

for node_ip in ${NODE_IPS[@]}

  do

    echo ">>> ${node_ip}"

    scp kubernetes/client/bin/kubectl root@${node_ip}:/opt/k8s/bin/

    ssh root@${node_ip} "chmod +x /opt/k8s/bin/*"

  done

 

2.  創建 admin 證書和私鑰

kubectl 與 apiserver https 安全端口通信,apiserver 對提供的證書進行認證和授權。

kubectl 作為集群的管理工具,需要被授予最高權限。這里創建具有最高權限的 admin 證書。

創建證書簽名請求:

cd /opt/k8s/work/cert

cat > admin-csr.json <<EOF

{

  "CN": "admin",

  "hosts": [],

  "key": {

    "algo": "rsa",

    "size": 2048

  },

  "names": [

    {

      "C": "CN",

      "ST": "BeiJing",

      "L": "BeiJing",

      "O": "system:masters",

      "OU": "study163"

    }

  ]

}

EOF

l  為 system:masters,kube-apiserver 收到該證書后將請求的 Group 設置為 system:masters;

l  預定義的 ClusterRoleBinding cluster-admin 將 Group system:masters 與 Role cluster-admin 綁定,該 Role 授予所有 API的權限;

l  該證書只會被 kubectl 當做 client 證書使用,所以 hosts 字段為空;

 

生成證書和私鑰:

cd /opt/k8s/work/cert


cfssl gencert -ca=/opt/k8s/work/cert/ca.pem  -ca-key=/opt/k8s/work/cert/ca-key.pem  -config=/opt/k8s/work/cert/ca-config.json -profile=kubernetes admin-csr.json | cfssljson -bare admin
ls admin*

 

3.  創建 kubeconfig 文件

kubeconfig 為 kubectl 的配置文件,包含訪問 apiserver 的所有信息,如 apiserver 地址、CA 證書和自身使用的證書;

cd /opt/k8s/work

source /opt/k8s/bin/environment.sh

 

# 設置集群參數

kubectl config set-cluster kubernetes --certificate-authority=/opt/k8s/work/cert/ca.pem --embed-certs=true --server=${KUBE_APISERVER} --kubeconfig=kubectl.kubeconfig

 

# 設置客戶端認證參數

kubectl config set-credentials admin --client-certificate=/opt/k8s/work/cert/admin.pem --client-key=/opt/k8s/work/cert/admin-key.pem --embed-certs=true --kubeconfig=kubectl.kubeconfig

 

# 設置上下文參數

kubectl config set-context kubernetes --cluster=kubernetes --user=admin --kubeconfig=kubectl.kubeconfig

 

# 設置默認上下文

kubectl config use-context kubernetes --kubeconfig=kubectl.kubeconfig

l  --certificate-authority:驗證 kube-apiserver 證書的根證書;

l  --client-certificate、--client-key:剛生成的 admin 證書和私鑰,連接 kube-apiserver 時使用;

l  --embed-certs=true:將 ca.pem 和 admin.pem 證書內容嵌入到生成的 kubectl.kubeconfig 文件中(不加時,寫入的是證書文件路徑);

 

4.  分發 kubeconfig 文件

分發到所有使用 kubectl 命令的節點:

cd /opt/k8s/work

source /opt/k8s/bin/environment.sh

for node_ip in ${NODE_IPS[@]}

  do

    echo ">>> ${node_ip}"

    ssh root@${node_ip} "mkdir -p ~/.kube"

    scp kubectl.kubeconfig root@${node_ip}:~/.kube/config

  done

l  保存到用戶的 ~/.kube/config 文件;

 

4.7  部署 etcd 集群

etcd 是基於 Raft 的分布式 key-value 存儲系統,由 CoreOS 開發,常用於服務發現、共享配置以及並發控制(如 leader 選舉、分布式鎖等)。kubernetes 使用 etcd 存儲所有運行數據。

本文檔介紹部署一個三節點高可用 etcd 集群的步驟:

l  下載和分發 etcd 二進制文件;

l  創建 etcd 集群各節點的 x509 證書,用於加密客戶端(如 etcdctl) 與 etcd 集群、etcd 集群之間的數據流;

l  創建 etcd 的 systemd unit 文件,配置服務參數;

l  檢查集群工作狀態;

 

etcd 集群各節點的名稱和 IP 如下:

l  master:192.168.100.246

l  node1:192.168.100.247

l  node2:192.168.100.248

注意:如果沒有特殊指明,本文檔的所有操作均在 master 節點上執行,然后遠程分發文件和執行命令。

 

1. 下載和分發 etcd 二進制文件

https://github.com/coreos/etcd/releases 頁面下載最新版本的發布包:

cd /opt/k8s/work

wget https://github.com/coreos/etcd/releases/download/v3.3.10/etcd-v3.3.10-linux-amd64.tar.gz

tar -xvf etcd-v3.3.10-linux-amd64.tar.gz

 

分發二進制文件到集群所有節點:

cd /opt/k8s/work

source /opt/k8s/bin/environment.sh

for node_ip in ${NODE_IPS[@]}

  do

    echo ">>> ${node_ip}"

    scp etcd-v3.3.10-linux-amd64/etcd* root@${node_ip}:/opt/k8s/bin

    ssh root@${node_ip} "chmod +x /opt/k8s/bin/*"

  done

 

2. 創建 etcd 證書和私鑰

創建證書簽名請求:

cd /opt/k8s/work/cert

cat > etcd-csr.json <<EOF

{

  "CN": "etcd",

  "hosts": [

    "127.0.0.1",

    "192.168.100.246", "192.168.100.247", "192.168.100.248"

  ],

  "key": {

    "algo": "rsa",

    "size": 2048

  },

  "names": [

    {

      "C": "CN",

      "ST": "BeiJing",

      "L": "BeiJing",

      "O": "k8s",

      "OU": "study163"

    }

  ]

}

EOF

l  hosts 字段指定授權使用該證書的 etcd 節點 IP 或域名列表,這里將 etcd 集群的三個節點 IP 都列在其中;

 

生成證書和私鑰:

cd /opt/k8s/work/cert

cfssl gencert -ca=/opt/k8s/work/cert/ca.pem -ca-key=/opt/k8s/work/cert/ca-key.pem -config=/opt/k8s/work/cert/ca-config.json -profile=kubernetes etcd-csr.json | cfssljson -bare etcd

ls etcd*pem

分發生成的證書和私鑰到各 etcd 節點:

cd /opt/k8s/work/cert

source /opt/k8s/bin/environment.sh

for node_ip in ${NODE_IPS[@]}

  do

    echo ">>> ${node_ip}"

    ssh root@${node_ip} "mkdir -p /etc/etcd/cert"

    scp etcd*.pem root@${node_ip}:/etc/etcd/cert/

  done

 

3. 創建 etcd 的 systemd unit 模板文件

是啟動腳本文件

cd /opt/k8s/work
source /opt/k8s/bin/environment.sh
cat > etcd.service.template <<EOF
[Unit]
Description=Etcd Server
After=network.target
After=network-online.target
Wants=network-online.target
Documentation=https://github.com/coreos

[Service]
Type=notify
WorkingDirectory=${ETCD_DATA_DIR}
ExecStart=/opt/k8s/bin/etcd \\
  --data-dir=${ETCD_DATA_DIR} \\
  --wal-dir=${ETCD_WAL_DIR} \\
  --name=##NODE_NAME## \\
  --cert-file=/etc/etcd/cert/etcd.pem \\
  --key-file=/etc/etcd/cert/etcd-key.pem \\
  --trusted-ca-file=/etc/kubernetes/cert/ca.pem \\
  --peer-cert-file=/etc/etcd/cert/etcd.pem \\
  --peer-key-file=/etc/etcd/cert/etcd-key.pem \\
  --peer-trusted-ca-file=/etc/kubernetes/cert/ca.pem \\
  --peer-client-cert-auth \\
  --client-cert-auth \\
  --listen-peer-urls=https://##NODE_IP##:2380 \\
  --initial-advertise-peer-urls=https://##NODE_IP##:2380 \\
  --listen-client-urls=https://##NODE_IP##:2379,http://127.0.0.1:2379 \\
  --advertise-client-urls=https://##NODE_IP##:2379 \\
  --initial-cluster-token=etcd-cluster-0 \\
  --initial-cluster=${ETCD_NODES} \\
  --initial-cluster-state=new \\
  --auto-compaction-mode=periodic \\
  --auto-compaction-retention=1 \\
  --max-request-bytes=33554432 \\
  --quota-backend-bytes=6442450944 \\
  --heartbeat-interval=250 \\
  --election-timeout=2000
Restart=on-failure
RestartSec=5
LimitNOFILE=65536

[Install]
WantedBy=multi-user.target
EOF

l  WorkingDirectory、--data-dir:指定工作目錄和數據目錄為 ${ETCD_DATA_DIR},需在啟動服務前創建這個目錄;

l  --wal-dir:指定 wal 目錄,為了提高性能,一般使用 SSD 或者和 --data-dir 不同的磁盤;

l  --name:指定節點名稱,當 --initial-cluster-state 值為 new 時,--name 的參數值必須位於 --initial-cluster 列表中;

l  --cert-file、--key-file:etcd server 與 client 通信時使用的證書和私鑰;

l  --trusted-ca-file:簽名 client 證書的 CA 證書,用於驗證 client 證書;

l  --peer-cert-file、--peer-key-file:etcd 與 peer 通信使用的證書和私鑰;

l  --peer-trusted-ca-file:簽名 peer 證書的 CA 證書,用於驗證 peer 證書;

 

好多服務的.service文件在下面目錄

[root@node01 work]# cd /usr/lib/systemd/system
[root@node01 system]# ll

 

4. 為各節點創建和分發 etcd systemd unit 文件

替換模板文件中的變量,為各節點創建 systemd unit 文件:

cd /opt/k8s/work

source /opt/k8s/bin/environment.sh

for (( i=0; i < 3; i++ ))

  do

    sed -e "s/##NODE_NAME##/${NODE_NAMES[i]}/" -e "s/##NODE_IP##/${NODE_IPS[i]}/" etcd.service.template > etcd-${NODE_IPS[i]}.service

  done

ls *.service

l  NODE_NAMES 和 NODE_IPS 為相同長度的 bash 數組,分別為節點名稱和對應的 IP;

 

分發生成的 systemd unit 文件:

cd /opt/k8s/work

source /opt/k8s/bin/environment.sh

for node_ip in ${NODE_IPS[@]}

  do

    echo ">>> ${node_ip}"

    scp etcd-${node_ip}.service root@${node_ip}:/usr/lib/systemd/system/etcd.service

  done

l  文件重命名為 etcd.service;

 

5. 啟動 etcd 服務

cd /opt/k8s/work

source /opt/k8s/bin/environment.sh

for node_ip in ${NODE_IPS[@]}

  do

    echo ">>> ${node_ip}"

    ssh root@${node_ip} "mkdir -p ${ETCD_DATA_DIR} ${ETCD_WAL_DIR}"

    ssh root@${node_ip} "systemctl daemon-reload && systemctl enable etcd && systemctl restart etcd " &

  done

l  必須創建 etcd 數據目錄和工作目錄;

l  etcd 進程首次啟動時會等待其它節點的 etcd 加入集群,命令 systemctl start etcd 會卡住一段時間,為正常現象。

 

6.  檢查啟動結果

cd /opt/k8s/work

source /opt/k8s/bin/environment.sh

for node_ip in ${NODE_IPS[@]}

  do

    echo ">>> ${node_ip}"

    ssh root@${node_ip} "systemctl status etcd|grep Active"

  done

確保狀態為 active (running),否則查看日志,確認原因:

journalctl -u etcd

 

7. 驗證服務狀態

部署完 etcd 集群后,在任一 etc 節點上執行如下命令:

cd /opt/k8s/work

source /opt/k8s/bin/environment.sh

for node_ip in ${NODE_IPS[@]}
  do
    echo ">>> ${node_ip}"
    ETCDCTL_API=3 /opt/k8s/bin/etcdctl --endpoints=https://${node_ip}:2379 --cacert=/opt/k8s/work/cert/ca.pem --cert=/etc/etcd/cert/etcd.pem --key=/etc/etcd/cert/etcd-key.pem endpoint health
  done

預期輸出:

>>> 192.168.100.246

https://192.168.100.246:2379 is healthy: successfully committed proposal: took = 3.5037ms

>>> 192.168.100.247

https://192.168.100.247:2379 is healthy: successfully committed proposal: took = 17.918242ms

>>> 192.168.100.248

https://192.168.100.248:2379 is healthy: successfully committed proposal: took = 10.445815ms

 

輸出均為 healthy 時表示集群服務正常。

 

8. 查看當前的 leader

 

source /opt/k8s/bin/environment.sh

ETCDCTL_API=3 /opt/k8s/bin/etcdctl -w table --cacert=/opt/k8s/work/cert/ca.pem \
  --cert=/etc/etcd/cert/etcd.pem \
  --key=/etc/etcd/cert/etcd-key.pem \
  --endpoints=${ETCD_ENDPOINTS} endpoint status

輸出:

 

 

可見,當前的 leader 為 172.26.106.83

 

4.8  部署 flannel 網絡

kubernetes 要求集群內各節點(包括 master 節點)能通過 Pod 網段互聯互通。flannel 使用 vxlan 技術為各節點創建一個可以互通的 Pod 網絡,使用的端口為 UDP 8472,需要開放該端口(如公有雲 AWS 等)。

flanneld 第一次啟動時,從 etcd 獲取配置的 Pod 網段信息,為本節點分配一個未使用的地址段,然后創建 flannedl.1 網絡接口(也可能是其它名稱,如 flannel1 等)。

flannel 將分配給自己的 Pod 網段信息寫入 /run/flannel/docker 文件,docker 后續使用這個文件中的環境變量設置 docker0 網橋,從而從這個地址段為本節點的所有 Pod 容器分配 IP。

注意:如果沒有特殊指明,本文檔的所有操作均在 master 節點上執行,然后遠程分發文件和執行命令。

1. 下載和分發 flanneld 二進制文件

到 https://github.com/coreos/flannel/releases 頁面下載最新版本的發布包:

cd /opt/k8s/work

mkdir flannel

wget https://github.com/coreos/flannel/releases/download/v0.10.0/flannel-v0.10.0-linux-amd64.tar.gz

tar -xzvf flannel-v0.10.0-linux-amd64.tar.gz -C flannel 

分發 flanneld 二進制文件到集群所有節點:

cd /opt/k8s/work

source /opt/k8s/bin/environment.sh

for node_ip in ${NODE_IPS[@]}

  do

    echo ">>> ${node_ip}"

    scp flannel/{flanneld,mk-docker-opts.sh} root@${node_ip}:/opt/k8s/bin/

    ssh root@${node_ip} "chmod +x /opt/k8s/bin/*"

  done

2. 創建 flannel 證書和私鑰

flannel 從 etcd 集群存取網段分配信息,而 etcd 集群啟用了雙向 x509 證書認證,所以需要為 flanneld 生成證書和私鑰。

 

創建證書簽名請求:

cd /opt/k8s/work/cert

cat > flanneld-csr.json <<EOF

{

  "CN": "flanneld",

  "hosts": [],

  "key": {

    "algo": "rsa",

    "size": 2048

  },

  "names": [

    {

      "C": "CN",

      "ST": "BeiJing",

      "L": "BeiJing",

      "O": "k8s",

      "OU": "study163"

    }

  ]

}

EOF

l  該證書只會被 kubectl 當做 client 證書使用,所以 hosts 字段為空;

 

生成證書和私鑰:

 

cfssl gencert -ca=/opt/k8s/work/cert/ca.pem \
  -ca-key=/opt/k8s/work/cert/ca-key.pem \
  -config=/opt/k8s/work/cert/ca-config.json \
  -profile=kubernetes flanneld-csr.json | cfssljson -bare flanneld

ls flannel*pem

將生成的證書和私鑰分發到所有節點(master 和 worker):

cd /opt/k8s/work/cert

source /opt/k8s/bin/environment.sh

for node_ip in ${NODE_IPS[@]}

  do

    echo ">>> ${node_ip}"

    ssh root@${node_ip} "mkdir -p /etc/flanneld/cert"

    scp flanneld*.pem root@${node_ip}:/etc/flanneld/cert

  done

 

3.  向 etcd 寫入集群 Pod 網段信息

注意:本步驟只需執行一次。

 

cd /opt/k8s/work

source /opt/k8s/bin/environment.sh

etcdctl \
  --endpoints=${ETCD_ENDPOINTS} \
  --ca-file=/opt/k8s/work/cert/ca.pem \
  --cert-file=/opt/k8s/work/cert/flanneld.pem \
  --key-file=/opt/k8s/work/cert/flanneld-key.pem \
  set ${FLANNEL_ETCD_PREFIX}/config '{"Network":"'${CLUSTER_CIDR}'", "SubnetLen": 21, "Backend": {"Type": "vxlan"}}'

 

l  flanneld 當前版本 (v0.10.0) 不支持 etcd v3,故使用 etcd v2 API 寫入配置 key 和網段數據;

l  寫入的 Pod 網段 ${CLUSTER_CIDR} 地址段如 /16 必須小於 SubnetLen,必須與 kube-controller-manager 的 --cluster-cidr 參數值一致;

 

4. 創建 flanneld 的 systemd unit 文件

cd /opt/k8s/work
source /opt/k8s/bin/environment.sh
cat > flanneld.service << EOF
[Unit]
Description=Flanneld overlay address etcd agent
After=network.target
After=network-online.target
Wants=network-online.target
After=etcd.service
Before=docker.service

[Service]
Type=notify
ExecStart=/opt/k8s/bin/flanneld \\
  -etcd-cafile=/etc/kubernetes/cert/ca.pem \\
  -etcd-certfile=/etc/flanneld/cert/flanneld.pem \\
  -etcd-keyfile=/etc/flanneld/cert/flanneld-key.pem \\
  -etcd-endpoints=${ETCD_ENDPOINTS} \\
  -etcd-prefix=${FLANNEL_ETCD_PREFIX} \\
  -iface=${IFACE} \\
  -ip-masq
ExecStartPost=/opt/k8s/bin/mk-docker-opts.sh -k DOCKER_NETWORK_OPTIONS -d /run/flannel/docker
Restart=always
RestartSec=5
StartLimitInterval=0

[Install]
WantedBy=multi-user.target
RequiredBy=docker.service
EOF

l  mk-docker-opts.sh 腳本將分配給 flanneld 的 Pod 子網網段信息寫入 /run/flannel/docker 文件,后續 docker 啟動時使用這個文件中的環境變量配置 docker0 網橋;

l  flanneld 使用系統缺省路由所在的接口與其它節點通信,對於有多個網絡接口(如內網和公網)的節點,可以用 -iface 參數指定通信接口;

l  flanneld 運行時需要 root 權限;

l  -ip-masq: flanneld 為訪問 Pod 網絡外的流量設置 SNAT 規則,同時將傳遞給 Docker 的變量 --ip-masq(/run/flannel/docker 文件中)設置為 false,這樣 Docker 將不再創建 SNAT 規則; Docker 的 --ip-masq 為 true 時,創建的 SNAT 規則比較“暴力”:將所有本節點 Pod 發起的、訪問非 docker0 接口的請求做 SNAT,這樣訪問其他節點 Pod 的請求來源 IP 會被設置為 flannel.1 接口的 IP,導致目的 Pod 看不到真實的來源 Pod IP。 flanneld 創建的 SNAT 規則比較溫和,只對訪問非 Pod 網段的請求做 SNAT。

 

5. 分發 flanneld systemd unit 文件到所有節點

source /opt/k8s/bin/environment.sh

for node_ip in ${NODE_IPS[@]}
  do
    echo ">>> ${node_ip}"
    scp flanneld.service root@${node_ip}:/usr/lib/systemd/system/
  done

 

6. 啟動 flanneld 服務

source /opt/k8s/bin/environment.sh

for node_ip in ${NODE_IPS[@]}
  do
    echo ">>> ${node_ip}"
    ssh root@${node_ip} "systemctl daemon-reload && systemctl enable flanneld && systemctl restart flanneld"
  done

 

7. 檢查啟動結果

source /opt/k8s/bin/environment.sh

for node_ip in ${NODE_IPS[@]}
  do
    echo ">>> ${node_ip}"
    ssh root@${node_ip} "systemctl status flanneld|grep Active"
  done

 

確保狀態為 active (running),否則查看日志,確認原因:

journalctl -u flanneld

 

8. 檢查分配給各 flanneld 的 Pod 網段信息

查看集群 Pod 網段(/16):

source /opt/k8s/bin/environment.sh

etcdctl \
  --endpoints=${ETCD_ENDPOINTS} \
  --ca-file=/etc/kubernetes/cert/ca.pem \
  --cert-file=/etc/flanneld/cert/flanneld.pem \
  --key-file=/etc/flanneld/cert/flanneld-key.pem \
  get ${FLANNEL_ETCD_PREFIX}/config

輸出:

{"Network":"172.30.0.0/16", "SubnetLen": 21, "Backend": {"Type": "vxlan"}}

 

查看已分配的 Pod 子網段列表(/24):

source /opt/k8s/bin/environment.sh

etcdctl \
  --endpoints=${ETCD_ENDPOINTS} \
  --ca-file=/etc/kubernetes/cert/ca.pem \
  --cert-file=/etc/flanneld/cert/flanneld.pem \
  --key-file=/etc/flanneld/cert/flanneld-key.pem \
  ls ${FLANNEL_ETCD_PREFIX}/subnets

輸出(結果是部署情況而定,網段可能與下面不一樣):

/kubernetes/network/subnets/172.30.240.0-21

/kubernetes/network/subnets/172.30.120.0-21

/kubernetes/network/subnets/172.30.192.0-21

 

查看某一 Pod 網段對應的節點 IP 和 flannel 接口地址:

source /opt/k8s/bin/environment.sh

etcdctl \
  --endpoints=${ETCD_ENDPOINTS} \
  --ca-file=/etc/kubernetes/cert/ca.pem \
  --cert-file=/etc/flanneld/cert/flanneld.pem \
  --key-file=/etc/flanneld/cert/flanneld-key.pem \
  get ${FLANNEL_ETCD_PREFIX}/subnets/172.30.240.0-21

輸出(結果是部署情況而定,網段可能與下面不一樣):

{"PublicIP":"192.168.100.246","BackendType":"vxlan","BackendData":{"VtepMAC":"fa:32:14:34:86:74"}}

l  172.30.240.0/21 被分配給節點 node2(192.168.100.252);

l  VtepMAC 為 node2 節點的 flannel.1 網卡 MAC 地址;

 

9. 檢查節點 flannel 網絡信息

ip addr show

1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000

    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00

    inet 127.0.0.1/8 scope host lo

       valid_lft forever preferred_lft forever

2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000

    link/ether 00:22:0d:33:89:75 brd ff:ff:ff:ff:ff:ff

    inet 172.27.137.240/20 brd 172.27.143.255 scope global dynamic eth0

       valid_lft 100647283sec preferred_lft 100647283sec

3: flannel.1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1450 qdisc noqueue state UNKNOWN group default

    link/ether ce:9c:a9:08:50:03 brd ff:ff:ff:ff:ff:ff

    inet 172.30.80.0/32 scope global flannel.1

       valid_lft forever preferred_lft forever

l  flannel.1 網卡的地址為分配的 Pod 子網段的第一個 IP(.0),且是 /32 的地址;

 

ip route show |grep flannel.1

172.30.32.0/21 via 172.30.32.0 dev flannel.1 onlink

172.30.184.0/21 via 172.30.184.0 dev flannel.1 onlink

l  到其它節點 Pod 網段請求都被轉發到 flannel.1 網卡;

l  flanneld 根據 etcd 中子網段的信息,如 ${FLANNEL_ETCD_PREFIX}/subnets/172.30.80.0-21 ,來決定進請求發送給哪個節點的互聯 IP;

 

10.  驗證各節點能通過 Pod 網段互通

在各節點上部署 flannel 后,檢查是否創建了 flannel 接口(名稱可能為 flannel0、flannel.0、flannel.1 等):

source /opt/k8s/bin/environment.sh

for node_ip in ${NODE_IPS[@]}
  do
    echo ">>> ${node_ip}"
    ssh ${node_ip} "/usr/sbin/ip addr show flannel.1|grep -w inet"
  done

輸出:

>>> 192.168.100.246

    inet 172.30.240.0/32 scope global flannel.1

>>> 192.168.100.247

    inet 172.30.120.0/32 scope global flannel.1

>>> 192.168.100.248

    inet 172.30.192.0/32 scope global flannel.1

 

在各節點上 ping 所有 flannel 接口 IP,確保能通:

source /opt/k8s/bin/environment.sh

for node_ip in ${NODE_IPS[@]}
  do
    echo ">>> ${node_ip}"
    ssh ${node_ip} "ping -c 1 172.30.240.0"
    ssh ${node_ip} "ping -c 1 172.30.120.0"
    ssh ${node_ip} "ping -c 1 172.30.192.0"
  done

4.9  kube-apiserver 高可用之 nginx 代理

kuebectl 的配置文件中靜態指定了某個 kube-apiserver IP,如果該 apiserver 實例掛掉,可能引起服務異常。

本章節講解使用 nginx 4 層透明代理功能實現 K8S 節點( master 節點和 worker 節點)高可用訪問 kube-apiserver 的方案。

注意:如果沒有特殊指明,本文檔的所有操作均在 master 節點上執行,然后遠程分發文件和執行命令。

 

1.  基於 nginx 代理的 kube-apiserver 高可用方案

l  控制節點的 kube-controller-manager、kube-scheduler 是多實例部署,所以只要有一個實例正常,就可以保證高可用;

l  集群內的 Pod 使用域名 kubernetes 訪問 kube-apiserver, kube-dns 會自動解析出多個 kube-apiserver 節點的 IP,所以也是高可用的;

l  kubelet、kube-proxy、controller-manager、scheduler 通過本地的 kube-nginx(監聽 127.0.0.1)訪問 kube-apiserver,從而實現 kube-apiserver 的高可用。

l  kube-nginx 會對所有 kube-apiserver 實例做健康檢查和負載均衡;

 

2.  下載和編譯 nginx

下載源碼:

cd /opt/k8s/work

wget http://nginx.org/download/nginx-1.15.3.tar.gz

tar -xzvf nginx-1.15.3.tar.gz

 

安裝nginx必須的依賴包

yum -y install gcc openssl-devel pcre-devel zlib-devel

 

配置編譯參數:

cd /opt/k8s/work/nginx-1.15.3

mkdir /opt/k8s/kube-nginx

./configure --prefix=/opt/k8s/kube-nginx --with-stream --without-http --without-http_uwsgi_module --without-http_scgi_module --without-http_fastcgi_module

l  --with-stream:開啟 4 層透明轉發(TCP Proxy)功能;

l  --without-xxx:關閉所有其他功能,這樣生成的動態鏈接二進制程序依賴最小;

輸出:

Configuration summary

  + PCRE library is not used

  + OpenSSL library is not used

  + zlib library is not used

  nginx path prefix: "/opt/k8s/kube-nginx"

  nginx binary file: "/opt/k8s/kube-nginx/sbin/nginx"

  nginx modules path: "/opt/k8s/kube-nginx/modules"

  nginx configuration prefix: "/opt/k8s/kube-nginx/conf"

  nginx configuration file: "/opt/k8s/kube-nginx/conf/nginx.conf"

  nginx pid file: "/opt/k8s/kube-nginx/logs/nginx.pid"

  nginx error log file: "/opt/k8s/kube-nginx/logs/error.log"

  nginx http access log file: "/opt/k8s/kube-nginx/logs/access.log"

  nginx http client request body temporary files: "client_body_temp"

  nginx http proxy temporary files: "proxy_temp"

 

編譯和安裝:

cd /opt/k8s/work/nginx-1.15.3

make && make install

 

3. 驗證編譯的 nginx

cd /opt/k8s/kube-nginx

./sbin/nginx -v

輸出:

nginx version: nginx/1.15.3

 

查看 nginx 動態鏈接的庫:

ldd ./sbin/nginx
linux-vdso.so.1 =>  (0x00007ffe11794000) libdl.so.2 => /lib64/libdl.so.2 (0x00007f29eb5d5000) libpthread.so.0 => /lib64/libpthread.so.0 (0x00007f29eb3b9000) libc.so.6 => /lib64/libc.so.6 (0x00007f29eafeb000) /lib64/ld-linux-x86-64.so.2 (0x00007f29eb7e0000)

由於只開啟了 4 層透明轉發功能,所以除了依賴 libc 等操作系統核心 lib 庫外,沒有對其它 lib 的依賴(如 libz、libssl 等),這樣可以方便部署到各版本操作系統中;

 

4.  安裝和部署 nginx

配置 nginx,開啟 4 層透明轉發功能:

cat > /opt/k8s/kube-nginx/conf/nginx.conf <<EOF

worker_processes 1;
 
events {
    worker_connections  1024;
}
 
stream {

    upstream backend {
        hash $remote_addr consistent;
        server 192.168.100.246:6443   max_fails=3 fail_timeout=30s;
        server 192.168.100.247:6443   max_fails=3 fail_timeout=30s;
        server 192.168.100.248:6443   max_fails=3 fail_timeout=30s;
    }

    server {
        listen 8443;
        proxy_connect_timeout 1s;
        proxy_pass backend;
    }
}

EOF

l  需要根據集群 kube-apiserver 的實際情況,替換 backend 中 server 列表;

 

5. 配置 systemd unit 文件,啟動服務

配置 kube-nginx systemd unit 文件:

cd /opt/k8s/work

cat > kube-nginx.service <<EOF
[Unit]
Description=kube-apiserver nginx proxy
After=network.target
After=network-online.target
Wants=network-online.target 

[Service]
Type=forking
ExecStartPre=/opt/k8s/kube-nginx/sbin/nginx -c /opt/k8s/kube-nginx/conf/nginx.conf -p /opt/k8s/kube-nginx -t
ExecStart=/opt/k8s/kube-nginx/sbin/nginx -c /opt/k8s/kube-nginx/conf/nginx.conf -p /opt/k8s/kube-nginx
ExecReload=/opt/k8s/kube-nginx/sbin/nginx -c /opt/k8s/kube-nginx/conf/nginx.conf -p /opt/k8s/kube-nginx -s reload
PrivateTmp=true
Restart=always
RestartSec=5
StartLimitInterval=0
LimitNOFILE=65536

 

[Install]
WantedBy=multi-user.target

EOF

啟動 kube-nginx 服務:

cp kube-nginx.service /usr/lib/systemd/system/

systemctl daemon-reload && systemctl enable kube-nginx && systemctl restart kube-nginx

 

6.  檢查 kube-nginx 服務運行狀態

systemctl status kube-nginx |grep 'Active:'

確保狀態為 active (running),否則查看日志,確認原因:

journalctl -u kube-nginx

 

4.10 部署 master 節點

kubernetes master 節點運行如下組件:

l  kube-apiserver

l  kube-scheduler

l  kube-controller-manager

l  kube-nginx

  1. kube-scheduler 和 kube-controller-manager 會自動選舉產生一個 leader 實例,其它實例處於阻塞模式,當 leader 掛了后,重新選舉產生新的 leader,從而保證服務可用性;
  2. kube-apiserver 是無狀態的,需要通過 kube-nginx 進行代理訪問,從而保證服務可用性;

注意:如果沒有特殊指明,本文檔的所有操作均在 master 節點上執行,然后遠程分發文件和執行命令。

 

1. 安裝和配置 kube-nginx

參考 apiserver高可用之nginx代理

 

2. 下載最新版本二進制文件

CHANGELOG頁面 下載 server tarball 文件。

cd /opt/k8s/work

wget https://dl.k8s.io/v1.12.3/kubernetes-server-linux-amd64.tar.gz

tar -xzvf kubernetes-server-linux-amd64.tar.gz

cd kubernetes

tar -xzvf  kubernetes-src.tar.gz

 

將二進制文件拷貝到所有 master 節點:

cd /opt/k8s/work/kubernetes

source /opt/k8s/bin/environment.sh

for node_ip in ${NODE_IPS[@]}

  do

    echo ">>> ${node_ip}"

    scp server/bin/* root@${node_ip}:/opt/k8s/bin/

    ssh root@${node_ip} "chmod +x /opt/k8s/bin/*"

  done

 

3. apiserver 集群

本章節講解部署一個三實例 kube-apiserver 集群的步驟,它們通過 kube-nginx 進行代理訪問,從而保證服務可用性。

注意:如果沒有特殊指明,本文檔的所有操作均在 master 節點上執行,然后遠程分發文件和執行命令。

3.1 准備工作

注意:下載最新版本的二進制文件、安裝和配置 flanneld 參考:部署master節點

3.2. 創建 kubernetes 證書和私鑰

創建證書簽名請求:

cd /opt/k8s/work/cert

source /opt/k8s/bin/environment.sh

cat > kubernetes-csr.json <<EOF

{
  "CN": "kubernetes",

  "hosts": [
    "127.0.0.1",
    "172.26.106.83", "172.26.106.81", "172.26.106.82", "${CLUSTER_KUBERNETES_SVC_IP}",
    "kubernetes",
    "kubernetes.default",
    "kubernetes.default.svc",
    "kubernetes.default.svc.cluster",
    "kubernetes.default.svc.cluster.local"
  ],

  "key": {
    "algo": "rsa",
    "size": 2048

  },

  "names": [
    {
      "C": "CN",
      "ST": "BeiJing",
      "L": "BeiJing",
      "O": "k8s",
      "OU": "study163"
    }
  ]
}

EOF

l  hosts 字段指定授權使用該證書的 IP 或域名列表,這里列出了 VIP 、apiserver 節點 IP、kubernetes 服務 IP 和域名;

l  域名最后字符不能是 .(如不能為 kubernetes.default.svc.cluster.local.),否則解析時失敗,提示: x509: cannot parse dnsName "kubernetes.default.svc.cluster.local.";

l  如果使用非 cluster.local 域名,如 opsnull.com,則需要修改域名列表中的最后兩個域名為:kubernetes.default.svc.opsnull、kubernetes.default.svc.opsnull.com

l  kubernetes 服務 IP 是 apiserver 自動創建的,一般是 --service-cluster-ip-range 參數指定的網段的第一個IP,后續可以通過如下命令獲取:

kubectl get svc kubernetes

NAME         CLUSTER-IP   EXTERNAL-IP   PORT(S)   AGE

kubernetes   10.254.0.1   <none>        443/TCP   1d

 

生成證書和私鑰:

cfssl gencert -ca=/opt/k8s/work/cert/ca.pem \
  -ca-key=/opt/k8s/work/cert/ca-key.pem \
  -config=/opt/k8s/work/cert/ca-config.json \
  -profile=kubernetes kubernetes-csr.json | cfssljson -bare kubernetes
ls kubernetes*pem

將生成的證書和私鑰文件拷貝到 master 節點:

cd /opt/k8s/work/cert

source /opt/k8s/bin/environment.sh
for node_ip in ${NODE_IPS[@]}
  do
    echo ">>> ${node_ip}"
    ssh root@${node_ip} "mkdir -p /etc/kubernetes/cert"
    scp kubernetes*.pem root@${node_ip}:/etc/kubernetes/cert/
  done
3.3 創建加密配置文件
cat > encryption-config.yaml <<EOF
kind: EncryptionConfig
apiVersion: v1
resources:
  - resources:
      - secrets
    providers:
      - aescbc:
          keys:
            - name: key1
              secret: ${ENCRYPTION_KEY}
      - identity: {}
EOF

將加密配置文件拷貝到 master 節點的 /etc/kubernetes 目錄下:

cd /opt/k8s/work

source /opt/k8s/bin/environment.sh

for node_ip in ${NODE_IPS[@]}
  do
    echo ">>> ${node_ip}"
    scp encryption-config.yaml root@${node_ip}:/etc/kubernetes/
  done

 

3.4 創建 kube-apiserver systemd unit 模板文件

特別提醒:有同學沒有按照老師的k8s版本安裝,自己升級了版本,有些地方k8s升級后官方默認功能做了調整,比如kube-apiserver中的1.14版本不支持Initializers插件。

cd /opt/k8s/work
source /opt/k8s/bin/environment.sh
cat > kube-apiserver.service.template <<EOF
[Unit]
Description=Kubernetes API Server
Documentation=https://github.com/GoogleCloudPlatform/kubernetes
After=network.target

[Service]
WorkingDirectory=${K8S_DIR}/kube-apiserver
ExecStart=/opt/k8s/bin/kube-apiserver \\
  --enable-admission-plugins=Initializers,NamespaceLifecycle,NodeRestriction,LimitRanger,ServiceAccount,DefaultStorageClass,ResourceQuota \\
  --anonymous-auth=false \\
  --experimental-encryption-provider-config=/etc/kubernetes/encryption-config.yaml \\
  --advertise-address=##NODE_IP## \\
  --bind-address=##NODE_IP## \\
  --insecure-port=0 \\
  --authorization-mode=Node,RBAC \\
  --runtime-config=api/all \\
  --enable-bootstrap-token-auth \\
  --service-cluster-ip-range=${SERVICE_CIDR} \\
  --service-node-port-range=${NODE_PORT_RANGE} \\
  --tls-cert-file=/etc/kubernetes/cert/kubernetes.pem \\
  --tls-private-key-file=/etc/kubernetes/cert/kubernetes-key.pem \\
  --client-ca-file=/etc/kubernetes/cert/ca.pem \\
  --kubelet-certificate-authority=/etc/kubernetes/cert/ca.pem \\
  --kubelet-client-certificate=/etc/kubernetes/cert/kubernetes.pem \\
  --kubelet-client-key=/etc/kubernetes/cert/kubernetes-key.pem \\
  --kubelet-https=true \\
  --service-account-key-file=/etc/kubernetes/cert/ca.pem \\
  --etcd-cafile=/etc/kubernetes/cert/ca.pem \\
  --etcd-certfile=/etc/kubernetes/cert/kubernetes.pem \\
  --etcd-keyfile=/etc/kubernetes/cert/kubernetes-key.pem \\
  --etcd-servers=${ETCD_ENDPOINTS} \\
  --enable-swagger-ui=true \\
  --allow-privileged=true \\
  --max-mutating-requests-inflight=2000 \\
  --max-requests-inflight=4000 \\
  --apiserver-count=3 \\
  --audit-log-maxage=30 \\
  --audit-log-maxbackup=3 \\
  --audit-log-maxsize=100 \\
  --audit-log-path=${K8S_DIR}/kube-apiserver/audit.log \\
  --event-ttl=168h \\
  --logtostderr=true \\
  --v=2
Restart=on-failure
RestartSec=5
Type=notify
LimitNOFILE=65536

[Install]
WantedBy=multi-user.target
EOF

l  --experimental-encryption-provider-config:啟用加密特性;

l  --authorization-mode=Node,RBAC: 開啟 Node 和 RBAC 授權模式,拒絕未授權的請求;

l  --enable-admission-plugins:啟用 ServiceAccount 和 NodeRestriction;

l  --service-account-key-file:簽名 ServiceAccount Token 的公鑰文件,kube-controller-manager 的 --service-account-private-key-file 指定私鑰文件,兩者配對使用;

l  --tls-*-file:指定 apiserver 使用的證書、私鑰和 CA 文件。--client-ca-file 用於驗證 client (kue-controller-manager、kube-scheduler、kubelet、kube-proxy 等)請求所帶的證書;

l  --kubelet-client-certificate、--kubelet-client-key:如果指定,則使用 https 訪問 kubelet APIs;需要為證書對應的用戶(上面 kubernetes*.pem 證書的用戶為 kubernetes) 用戶定義 RBAC 規則,否則訪問 kubelet API 時提示未授權;

l  --bind-address: 不能為 127.0.0.1,否則外界不能訪問它的安全端口 6443;

l  --insecure-port=0:關閉監聽非安全端口(8080);

l  --service-cluster-ip-range: 指定 Service Cluster IP 地址段;

l  --service-node-port-range: 指定 NodePort 的端口范圍;

l  --runtime-config=api/all=true: 啟用所有版本的 APIs,如 autoscaling/v2alpha1;

l  --enable-bootstrap-token-auth:啟用 kubelet bootstrap 的 token 認證;

l  --apiserver-count=3:指定 apiserver 的實例數量;

 

3.5 為各節點創建和分發 kube-apiserver systemd unit 文件

替換模板文件中的變量,為各節點創建 systemd unit 文件:

cd /opt/k8s/work

source /opt/k8s/bin/environment.sh

for (( i=0; i < 3; i++ ))
  do
    sed -e "s/##NODE_NAME##/${NODE_NAMES[i]}/" -e "s/##NODE_IP##/${NODE_IPS[i]}/" kube-apiserver.service.template > kube-apiserver-${NODE_IPS[i]}.service
  done
ls kube-apiserver*.service

l  NODE_NAMES 和 NODE_IPS 為相同長度的 bash 數組,分別為節點名稱和對應的 IP;

 

分發生成的 systemd unit 文件:

cd /opt/k8s/work

source /opt/k8s/bin/environment.sh

for node_ip in ${NODE_IPS[@]}
  do
    echo ">>> ${node_ip}"
    scp kube-apiserver-${node_ip}.service root@${node_ip}:/usr/lib/systemd/system/kube-apiserver.service
  done

l  文件重命名為 kube-apiserver.service;

 

3.6 啟動 kube-apiserver 服務
source /opt/k8s/bin/environment.sh

for node_ip in ${NODE_IPS[@]}

  do
    echo ">>> ${node_ip}"
    ssh root@${node_ip} "mkdir -p ${K8S_DIR}/kube-apiserver"
    ssh root@${node_ip} "systemctl daemon-reload && systemctl enable kube-apiserver && systemctl restart kube-apiserver"
  done

l  必須創建工作目錄;

 

3.7 檢查 kube-apiserver 運行狀態
source /opt/k8s/bin/environment.sh

for node_ip in ${NODE_IPS[@]}
  do
    echo ">>> ${node_ip}"
    ssh root@${node_ip} "systemctl status kube-apiserver |grep 'Active:'"
  done

確保狀態為 active (running),否則到 master 節點查看日志,確認原因:

journalctl -u kube-apiserver

 

3.8 打印 kube-apiserver 寫入 etcd 的數據
source /opt/k8s/bin/environment.sh
ETCDCTL_API=3 etcdctl \
    --endpoints=${ETCD_ENDPOINTS} \
    --cacert=/opt/k8s/work/cert/ca.pem \
    --cert=/opt/k8s/work/cert/etcd.pem \
    --key=/opt/k8s/work/cert/etcd-key.pem \
    get /registry/ --prefix --keys-only

 

3.9 檢查集群信息
kubectl cluster-info

Kubernetes master is running at https://127.0.0.1:8443

 

To further debug and diagnose cluster problems, use 'kubectl cluster-info dump'.

 

kubectl get all --all-namespaces

NAMESPACE   NAME                 TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)   AGE

default     service/kubernetes   ClusterIP   10.254.0.1   <none>        443/TCP   4m27s

 

kubectl get componentstatuses

NAME                 STATUS      MESSAGE                                                                                     ERROR

controller-manager   Unhealthy   Get http://127.0.0.1:10252/healthz: dial tcp 127.0.0.1:10252: connect: connection refused

scheduler            Unhealthy   Get http://127.0.0.1:10251/healthz: dial tcp 127.0.0.1:10251: connect: connection refused

etcd-2               Healthy     {"health":"true"}

etcd-0               Healthy     {"health":"true"}

etcd-1               Healthy     {"health":"true"}

 

注意:

  1. 如果執行 kubectl 命令式時輸出如下錯誤信息,則說明使用的 ~/.kube/config 文件不對,請切換到正確的賬戶后再執行該命令:

The connection to the server localhost:8080 was refused - did you specify the right host or port?

2.執行 kubectl get componentstatuses 命令時,apiserver 默認向 127.0.0.1 發送請求。當 controller-manager、scheduler 以集群模式運行時,有可能和 kube-apiserver 不在一台機器上,這時 controller-manager 或 scheduler 的狀態為 Unhealthy,但實際上它們工作正常

 

3.10  檢查 kube-apiserver 監聽的端口
sudo netstat -lnpt|grep kube-api

tcp        0      0 192.168.100.246:6443     0.0.0.0:*               LISTEN      51903/kube-apiserve

l  6443: 接收 https 請求的安全端口,對所有請求做認證和授權;

l  由於關閉了非安全端口,故沒有監聽 8080;

 

3.11 授予 kubernetes 證書訪問 kubelet API 的權限

在執行 kubectl exec、run、logs 等命令時,apiserver 會轉發到 kubelet。這里定義 RBAC 規則,授權 apiserver 調用 kubelet API。

kubectl create clusterrolebinding kube-apiserver:kubelet-apis --clusterrole=system:kubelet-api-admin --user kubernetes

 

3.12 參考

關於證書域名最后字符不能是 . 的問題,實際和 Go 的版本有關,1.9 不支持這種類型的證書:https://github.com/kubernetes/ingress-nginx/issues/2188

 

 

4. controller-manager 集群

本文檔介紹部署高可用 kube-controller-manager 集群的步驟。

 

該集群包含 3 個節點,啟動后將通過競爭選舉機制產生一個 leader 節點,其它節點為阻塞狀態。當 leader 節點不可用后,剩余節點將再次進行選舉產生新的 leader 節點,從而保證服務的可用性。

 

為保證通信安全,本文檔先生成 x509 證書和私鑰,kube-controller-manager 在如下兩種情況下使用該證書:

  1. 與 kube-apiserver 的安全端口通信時;
  2. 在安全端口(https,10252) 輸出 prometheus 格式的 metrics;

 

注意:如果沒有特殊指明,本文檔的所有操作均在 master 節點上執行,然后遠程分發文件和執行命令。

 

4.1 准備工作

下載最新版本的二進制文件、安裝和配置 flanneld 參考:部署master節點

 

4.2  創建 kube-controller-manager 證書和私鑰
cd /opt/k8s/work/cert
cat > kube-controller-manager-csr.json <<EOF
{
    "CN": "system:kube-controller-manager",
    "key": {
        "algo": "rsa",
        "size": 2048
    },
    "hosts": [
      "127.0.0.1",
      "172.26.106.83",
      "172.26.106.81",
      "172.26.106.82"
    ],
    "names": [
      {
        "C": "CN",
        "ST": "BeiJing",
        "L": "BeiJing",
        "O": "system:kube-controller-manager",
        "OU": "study163"
      }
    ]
}
EOF

l  hosts 列表包含所有 kube-controller-manager 節點 IP;

l  CN 為 system:kube-controller-manager、O 為 system:kube-controller-manager,kubernetes 內置的 ClusterRoleBindings system:kube-controller-manager 賦予 kube-controller-manager 工作所需的權限。

 

生成證書和私鑰:

cd /opt/k8s/work/cert

cfssl gencert -ca=/opt/k8s/work/cert/ca.pem \
  -ca-key=/opt/k8s/work/cert/ca-key.pem \
  -config=/opt/k8s/work/cert/ca-config.json \
  -profile=kubernetes kube-controller-manager-csr.json | cfssljson -bare kube-controller-manager

ls kube-controller-manager*pem

 

 

將生成的證書和私鑰分發到所有 master 節點:

cd /opt/k8s/work/cert

source /opt/k8s/bin/environment.sh

for node_ip in ${NODE_IPS[@]}
  do
    echo ">>> ${node_ip}"
    scp kube-controller-manager*.pem root@${node_ip}:/etc/kubernetes/cert/
  done

 

4.3 創建和分發 kubeconfig 文件

kubeconfig 文件包含訪問 apiserver 的所有信息,如 apiserver 地址、CA 證書和自身使用的證書;

cd /opt/k8s/work
source /opt/k8s/bin/environment.sh
kubectl config set-cluster kubernetes \
  --certificate-authority=/opt/k8s/work/cert/ca.pem \
  --embed-certs=true \
  --server=${KUBE_APISERVER} \
  --kubeconfig=kube-controller-manager.kubeconfig

kubectl config set-credentials system:kube-controller-manager \
  --client-certificate=cert/kube-controller-manager.pem \
  --client-key=cert/kube-controller-manager-key.pem \
  --embed-certs=true \
  --kubeconfig=kube-controller-manager.kubeconfig

kubectl config set-context system:kube-controller-manager \
  --cluster=kubernetes \
  --user=system:kube-controller-manager \
  --kubeconfig=kube-controller-manager.kubeconfig

kubectl config use-context system:kube-controller-manager --kubeconfig=kube-controller-manager.kubeconfig

分發 kubeconfig 到所有 master 節點:

cd /opt/k8s/work

source /opt/k8s/bin/environment.sh

for node_ip in ${NODE_IPS[@]}
  do
    echo ">>> ${node_ip}"
    scp kube-controller-manager.kubeconfig root@${node_ip}:/etc/kubernetes/
  done

 

 

4.4  創建和分發 kube-controller-manager systemd unit 文件
cd /opt/k8s/work
source /opt/k8s/bin/environment.sh
cat > kube-controller-manager.service <<EOF
[Unit]
Description=Kubernetes Controller Manager
Documentation=https://github.com/GoogleCloudPlatform/kubernetes

[Service]
WorkingDirectory=${K8S_DIR}/kube-controller-manager
ExecStart=/opt/k8s/bin/kube-controller-manager \\
  --port=0 \\
  --secure-port=10252 \\
  --bind-address=127.0.0.1 \\
  --kubeconfig=/etc/kubernetes/kube-controller-manager.kubeconfig \\
  --authentication-kubeconfig=/etc/kubernetes/kube-controller-manager.kubeconfig \\
  --authorization-kubeconfig=/etc/kubernetes/kube-controller-manager.kubeconfig \\
  --service-cluster-ip-range=${SERVICE_CIDR} \\
  --cluster-name=kubernetes \\
  --cluster-signing-cert-file=/etc/kubernetes/cert/ca.pem \\
  --cluster-signing-key-file=/etc/kubernetes/cert/ca-key.pem \\
  --experimental-cluster-signing-duration=8760h \\
  --root-ca-file=/etc/kubernetes/cert/ca.pem \\
  --service-account-private-key-file=/etc/kubernetes/cert/ca-key.pem \\
  --leader-elect=true \\
  --controllers=*,bootstrapsigner,tokencleaner \\
  --horizontal-pod-autoscaler-use-rest-clients=true \\
  --horizontal-pod-autoscaler-sync-period=10s \\
  --tls-cert-file=/etc/kubernetes/cert/kube-controller-manager.pem \\
  --tls-private-key-file=/etc/kubernetes/cert/kube-controller-manager-key.pem \\
  --use-service-account-credentials=true \\
  --kube-api-qps=1000 \\
  --kube-api-burst=2000 \\
  --logtostderr=true \\
  --v=2
Restart=on-failure
RestartSec=5

[Install]
WantedBy=multi-user.target
EOF

l  --port=0:關閉監聽 http /metrics 的請求,同時 --address 參數無效,--bind-address 參數有效;

l  --secure-port=10252、--bind-address=0.0.0.0: 在所有網絡接口監聽 10252 端口的 https /metrics 請求;

l  --kubeconfig:指定 kubeconfig 文件路徑,kube-controller-manager 使用它連接和驗證 kube-apiserver;

l  --authentication-kubeconfig 和 --authorization-kubeconfig:kube-controller-manager 使用它連接 apiserver,對 client 的請求進行認證和授權。kube-controller-manager 不再使用 --tls-ca-file 對請求 https metrics 的 Client 證書進行校驗。如果沒有配置這兩個 kubeconfig 參數,則 client 連接 kube-controller-manager https 端口的請求會被拒絕(提示權限不足)。

l  --cluster-signing-*-file:簽名 TLS Bootstrap 創建的證書;

l  --experimental-cluster-signing-duration:指定 TLS Bootstrap 證書的有效期;

l  --root-ca-file:放置到容器 ServiceAccount 中的 CA 證書,用來對 kube-apiserver 的證書進行校驗;

l  --service-account-private-key-file:簽名 ServiceAccount 中 Token 的私鑰文件,必須和 kube-apiserver 的 --service-account-key-file 指定的公鑰文件配對使用;

l  --service-cluster-ip-range :指定 Service Cluster IP 網段,必須和 kube-apiserver 中的同名參數一致;

l  --leader-elect=true:集群運行模式,啟用選舉功能;被選為 leader 的節點負責處理工作,其它節點為阻塞狀態;

l  --controllers=*,bootstrapsigner,tokencleaner:啟用的控制器列表,tokencleaner 用於自動清理過期的 Bootstrap token;

l  --horizontal-pod-autoscaler-*:custom metrics 相關參數,支持 autoscaling/v2alpha1;

l  --tls-cert-file、--tls-private-key-file:使用 https 輸出 metrics 時使用的 Server 證書和秘鑰;

l  --use-service-account-credentials=true: kube-controller-manager 中各 controller 使用 serviceaccount 訪問 kube-apiserver;

 

分發 systemd unit 文件到所有 master 節點:

cd /opt/k8s/work

source /opt/k8s/bin/environment.sh

for node_ip in ${NODE_IPS[@]}
  do
    echo ">>> ${node_ip}"
    scp kube-controller-manager.service root@${node_ip}:/usr/lib/systemd/system/
  done
4.5 kube-controller-manager 的權限

ClusteRole: system:kube-controller-manager 的權限很小,只能創建 secret、serviceaccount 等資源對象,各 controller 的權限分散到 ClusterRole system:controller:XXX 中。

 

需要在 kube-controller-manager 的啟動參數中添加 --use-service-account-credentials=true 參數,這樣 main controller 會為各 controller 創建對應的 ServiceAccount XXX-controller。

 

內置的 ClusterRoleBinding system:controller:XXX 將賦予各 XXX-controller ServiceAccount 對應的 ClusterRole system:controller:XXX 權限。

 

另外,--authentication-kubeconfig 和 --authorization-kubeconfig 參數指定的證書需要有創建 "subjectaccessreviews" 的權限,否則提示:

curl --cacert /opt/k8s/work/cert/ca.pem --cert /opt/k8s/work/cert/admin.pem --key /opt/k8s/work/cert/admin-key.pem https://127.0.0.1:10252/metrics

Internal Server Error: "/metrics": subjectaccessreviews.authorization.k8s.io is forbidden: User "system:kube-controller-manager" cannot create resource "subjectaccessreviews" in API group "authorization.k8s.io" at the cluster scope

 

解決辦法是創建一個 ClusterRoleBinding,賦予相應的權限:

kubectl create clusterrolebinding controller-manager:system:auth-delegator --user system:kube-controller-manager --clusterrole system:auth-delegator

 

clusterrolebinding.rbac.authorization.k8s.io/controller-manager:system:auth-delegator created

 

參考:https://github.com/kubernetes/kubeadm/issues/1285

 

4.6 啟動 kube-controller-manager 服務
source /opt/k8s/bin/environment.sh

for node_ip in ${NODE_IPS[@]}
  do
    echo ">>> ${node_ip}"
    ssh root@${node_ip} "mkdir -p ${K8S_DIR}/kube-controller-manager"
    ssh root@${node_ip} "systemctl daemon-reload && systemctl enable kube-controller-manager && systemctl restart kube-controller-manager"
  done

l  必須創建工作目錄;

 

4.7  檢查服務運行狀態
source /opt/k8s/bin/environment.sh

for node_ip in ${NODE_IPS[@]}
  do
    echo ">>> ${node_ip}"
    ssh root@${node_ip} "systemctl status kube-controller-manager|grep Active"
  done

確保狀態為 active (running),否則查看日志,確認原因:

journalctl -u kube-controller-manager

 

4.8  查看輸出的 metric

注意:以下命令在 kube-controller-manager 節點上執行。

kube-controller-manager 監聽 10252 端口,接收 https 請求:

sudo netstat -lnpt|grep kube-controll

tcp        0      0 127.0.0.1:10252         0.0.0.0:*               LISTEN      55755/kube-controll

 

curl --cacert /opt/k8s/work/cert/ca.pem --cert /opt/k8s/work/cert/admin.pem --key /opt/k8s/work/cert/admin-key.pem https://127.0.0.1:10252/metrics

{

  "kind": "Status",

  "apiVersion": "v1",

  "metadata": {

  },

  "status": "Failure",

  "message": "forbidden: User \"system:anonymous\" cannot get path \"/metrics\"",

  "reason": "Forbidden",

  "details": {

  },

  "code": 403

}

 

將 kube-controller-manager 的日志級別設置為 4 后,可以看到原因是:

journalctl -u kube-controller-manager -f |grep /metrics

2月 22 19:07:28 m7-inf-prod01 kube-controller-manager[1416748]: I0222 19:07:28.003325 1416748 authorization.go:73] Forbidden: "/metrics", Reason: "no RBAC policy matched"

2月 22 19:07:28 m7-inf-prod01 kube-controller-manager[1416748]: I0222 19:07:28.003472 1416748 wrap.go:42] GET /metrics: (2.600519ms) 403 [curl/7.29.0 127.0.0.1:36324]

 

這是由於沒有部署 metrics-server 的緣故。后續在 metrics-server插件 一文中將介紹部署 metrics-server 的步驟。

 

參考:https://github.com/kubernetes-incubator/metrics-server/issues/85

 

4.9  測試 kube-controller-manager 集群的高可用

停掉一個或兩個節點的 kube-controller-manager 服務,觀察其它節點的日志,看是否獲取了 leader 權限。

 

4.10 查看當前的 leader
kubectl get endpoints kube-controller-manager --namespace=kube-system  -o yaml

apiVersion: v1

kind: Endpoints

metadata:

  annotations:

    control-plane.alpha.kubernetes.io/leader: '{"holderIdentity":"node1_084534e2-6cc4-11e8-a418-5254001f5b65","leaseDurationSeconds":15,"acquireTime":"2018-06-10T15:40:33Z","renewTime":"2018-06-10T16:19:08Z","leaderTransitions":12}'

  creationTimestamp: 2018-06-10T13:59:42Z

  name: kube-controller-manager

  namespace: kube-system

  resourceVersion: "4540"

  selfLink: /api/v1/namespaces/kube-system/endpoints/kube-controller-manager

  uid: 862cc048-6cb6-11e8-96fa-525400ba84c6

可見,當前的 leader 為 master 節點。

4.11   參考

關於 controller 權限和 use-service-account-credentials 參數:

https://github.com/kubernetes/kubernetes/issues/48208

kublet 認證和授權:

https://kubernetes.io/docs/admin/kubelet-authentication-authorization/#kubelet-authorization

 

5.  scheduler 集群

本章節介紹部署高可用 kube-scheduler 集群的步驟。

 

該集群包含 3 個節點,啟動后將通過競爭選舉機制產生一個 leader 節點,其它節點為阻塞狀態。當 leader 節點不可用后,剩余節點將再次進行選舉產生新的 leader 節點,從而保證服務的可用性。

 

為保證通信安全,本文檔先生成 x509 證書和私鑰,kube-scheduler 在如下兩種情況下使用該證書:

  1. 與 kube-apiserver 的安全端口通信;
  2. 安全端口(https,10251) 輸出 prometheus 格式的 metrics;

 

注意:如果沒有特殊指明,本文檔的所有操作均在 master 節點上執行,然后遠程分發文件和執行命令。

 

5.1 准備工作

下載最新版本的二進制文件、安裝和配置 flanneld 參考:部署master節點

 

5.2 創建 kube-scheduler 證書和私鑰

創建證書簽名請求:

cd /opt/k8s/work/cert
cat > kube-scheduler-csr.json <<EOF
{
    "CN": "system:kube-scheduler",
    "hosts": [
      "127.0.0.1",
      "192.168.100.246",
      "192.168.100.247",
      "192.168.100.248"
    ],
    "key": {
        "algo": "rsa",
        "size": 2048
    },
    "names": [
      {
        "C": "CN",
        "ST": "BeiJing",
        "L": "BeiJing",
        "O": "system:kube-scheduler",
        "OU": "study163"
      }
    ]
}
EOF

l  hosts 列表包含所有 kube-scheduler 節點 IP;

l  CN 為 system:kube-scheduler、O 為 system:kube-scheduler,kubernetes 內置的 ClusterRoleBindings system:kube-scheduler 將賦予 kube-scheduler 工作所需的權限。

 

生成證書和私鑰:

cd /opt/k8s/work/cert
cfssl gencert -ca=/opt/k8s/work/cert/ca.pem \
  -ca-key=/opt/k8s/work/cert/ca-key.pem \
  -config=/opt/k8s/work/cert/ca-config.json \
  -profile=kubernetes kube-scheduler-csr.json | cfssljson -bare kube-scheduler
ls kube-scheduler*pem

 

5.3 創建和分發 kubeconfig 文件

kubeconfig 文件包含訪問 apiserver 的所有信息,如 apiserver 地址、CA 證書和自身使用的證書;

cd /opt/k8s/work
source /opt/k8s/bin/environment.sh
 
kubectl config set-cluster kubernetes \
  --certificate-authority=cert/ca.pem \
  --embed-certs=true \
  --server=${KUBE_APISERVER} \
  --kubeconfig=kube-scheduler.kubeconfig
 
kubectl config set-credentials system:kube-scheduler \
  --client-certificate=cert/kube-scheduler.pem \
  --client-key=cert/kube-scheduler-key.pem \
  --embed-certs=true \
  --kubeconfig=kube-scheduler.kubeconfig
 
kubectl config set-context system:kube-scheduler \
  --cluster=kubernetes \
  --user=system:kube-scheduler \
  --kubeconfig=kube-scheduler.kubeconfig
 
kubectl config use-context system:kube-scheduler --kubeconfig=kube-scheduler.kubeconfig

l  上一步創建的證書、私鑰以及 kube-apiserver 地址被寫入到 kubeconfig 文件中;

 

分發 kubeconfig 到所有 master 節點:

cd /opt/k8s/work
source /opt/k8s/bin/environment.sh
for node_ip in ${NODE_IPS[@]}
  do
    echo ">>> ${node_ip}"
    scp kube-scheduler.kubeconfig root@${node_ip}:/etc/kubernetes/
  done

 

5.4 創建 kube-scheduler 配置文件
cat <<EOF | sudo tee kube-scheduler.yaml
apiVersion: componentconfig/v1alpha1
kind: KubeSchedulerConfiguration
clientConnection:
  kubeconfig: "/etc/kubernetes/kube-scheduler.kubeconfig"
leaderElection:
  leaderElect: true
EOF

l  --kubeconfig:指定 kubeconfig 文件路徑,kube-scheduler 使用它連接和驗證 kube-apiserver;

l  --leader-elect=true:集群運行模式,啟用選舉功能;被選為 leader 的節點負責處理工作,其它節點為阻塞狀態;

 

分發 kube-scheduler 配置文件到所有 master 節點:

cd /opt/k8s/work
source /opt/k8s/bin/environment.sh
for node_ip in ${NODE_IPS[@]}
  do
    echo ">>> ${node_ip}"
    scp kube-scheduler.yaml root@${node_ip}:/etc/kubernetes/
  done

 

5.5 創建和分發 kube-scheduler systemd unit 文件
cd /opt/k8s/work
cat > kube-scheduler.service <<EOF
[Unit]
Description=Kubernetes Scheduler
Documentation=https://github.com/GoogleCloudPlatform/kubernetes
 
[Service]
WorkingDirectory=${K8S_DIR}/kube-scheduler
ExecStart=/opt/k8s/bin/kube-scheduler \\
  --config=/etc/kubernetes/kube-scheduler.yaml \\
  --address=127.0.0.1 \\
  --kube-api-qps=100 \\
  --logtostderr=true \\
  --v=2
Restart=always
RestartSec=5
StartLimitInterval=0
 
[Install]
WantedBy=multi-user.target
EOF

l  --address:在 127.0.0.1:10251 端口接收 http /metrics 請求;kube-scheduler 目前還不支持接收 https 請求;

 

分發 systemd unit 文件到所有 master 節點:

cd /opt/k8s/work
source /opt/k8s/bin/environment.sh
for node_ip in ${NODE_IPS[@]}
  do
    echo ">>> ${node_ip}"
    scp kube-scheduler.service root@${node_ip}:/etc/systemd/system/
  done

 

5.6 啟動 kube-scheduler 服務
source /opt/k8s/bin/environment.sh
for node_ip in ${NODE_IPS[@]}
  do
    echo ">>> ${node_ip}"
    ssh root@${node_ip} "mkdir -p ${K8S_DIR}/kube-scheduler"
    ssh root@${node_ip} "systemctl daemon-reload && systemctl enable kube-scheduler && systemctl restart kube-scheduler"
  done

l  必須先創建工作目錄;

 

5.7 檢查服務運行狀態
source /opt/k8s/bin/environment.sh
for node_ip in ${NODE_IPS[@]}
  do
    echo ">>> ${node_ip}"
    ssh root@${node_ip} "systemctl status kube-scheduler|grep Active"
  done 

確保狀態為 active (running),否則查看日志,確認原因:

journalctl -u kube-scheduler

 

5.8 查看輸出的 metric

注意:以下命令在 kube-scheduler 節點上執行。

 

kube-scheduler 監聽 10251 端口,接收 http 請求:

sudo netstat -lnpt|grep kube-sche

tcp        0      0 127.0.0.1:10251         0.0.0.0:*               LISTEN      23783/kube-schedule

curl -s http://127.0.0.1:10251/metrics |head

# HELP apiserver_audit_event_total Counter of audit events generated and sent to the audit backend.

# TYPE apiserver_audit_event_total counter

apiserver_audit_event_total 0

# HELP apiserver_client_certificate_expiration_seconds Distribution of the remaining lifetime on the certificate used to authenticate a request.

# TYPE apiserver_client_certificate_expiration_seconds histogram

apiserver_client_certificate_expiration_seconds_bucket{le="0"} 0

apiserver_client_certificate_expiration_seconds_bucket{le="21600"} 0

apiserver_client_certificate_expiration_seconds_bucket{le="43200"} 0

apiserver_client_certificate_expiration_seconds_bucket{le="86400"} 0

apiserver_client_certificate_expiration_seconds_bucket{le="172800"} 0

 

5.9  測試 kube-scheduler 集群的高可用

隨便找一個或兩個 master 節點,停掉 kube-scheduler 服務,看其它節點是否獲取了 leader 權限(systemd 日志)。

 

5.10 查看當前的 leader
kubectl get endpoints kube-scheduler --namespace=kube-system  -o yaml

apiVersion: v1

kind: Endpoints

metadata:

  annotations:

    control-plane.alpha.kubernetes.io/leader: '{"holderIdentity":"k8s-1_1ea20a43-4f8e-11e9-9ac5-000c2955d204","leaseDurationSeconds":15,"acquireTime":"2019-03-26T06:12:24Z","renewTime":"2019-03-26T06:23:54Z","leaderTransitions":0}'

  creationTimestamp: 2019-03-26T06:12:24Z

  name: kube-scheduler

  namespace: kube-system

  resourceVersion: "72504"

  selfLink: /api/v1/namespaces/kube-system/endpoints/kube-scheduler

  uid: 1f4b7394-4f8e-11e9-a869-000c2955d204

可見,當前的 leader 為 master 節點。

 

4.11  部署 worker 節點

kubernetes work 節點運行如下組件:

l  docker

l  kubelet

l  kube-proxy

l  flanneld

l  kube-nginx

注意:如果沒有特殊指明,本文檔的所有操作均在 master 節點上執行,然后遠程分發文件和執行命令。

 

前提條件

安裝和配置 flanneld

參考 部署flannel網絡

 

安裝和配置 kube-nginx

參考 apiserver高可用之nginx代理

 

安裝依賴包:

ssh root@${node_ip} "yum install -y epel-release"
ssh root@${node_ip} "yum install -y conntrack ipvsadm ipset jq iptables curl sysstat libseccomp && /usr/sbin/modprobe ip_vs"

1. 部署 docker 組件

docker 是容器的運行環境,管理它的生命周期。kubelet 通過 Container Runtime Interface (CRI) 與 docker 進行交互。

 

注意:如果沒有特殊指明,本文檔的所有操作均在 master 節點上執行,然后遠程分發文件和執行命令。

 

docker 有多種安裝方式:本章節中我們使用最簡單的安裝方式 腳本安裝,使用腳本安裝不需要我們關注依賴運行腳本就能自動安裝。

 

不過這種方式不安全,而且必須要依賴網絡,不推薦在生產環境中使用;生成環境建議使用二進制腳本安裝。

 

1.1. 安裝依賴包

參考 部署worker節點

 

1.2.  下載和分發 docker 安裝文件

使用腳本安裝docker:

curl -fLsS https://get.docker.com/ | sh

等待安裝完成,也可以指定使用 Aliyun 鏡像

curl -fsSL https://get.docker.com | bash -s docker --mirror Aliyun

 

使用二進制文件安裝docker:

https://download.docker.com/linux/static/stable/x86_64/ 頁面下載最新發布包:

cd /opt/k8s/work
wget https://download.docker.com/linux/static/stable/x86_64/docker-18.09.0.tgz
tar -xvf docker-18.09.0.tgz

 

分發二進制文件到所有 worker 節點:

cd /opt/k8s/work
source /opt/k8s/bin/environment.sh
for node_ip in ${NODE_IPS[@]}
  do
    echo ">>> ${node_ip}"
    scp docker/*  root@${node_ip}:/opt/k8s/bin/
    ssh root@${node_ip} "chmod +x /opt/k8s/bin/*"
  done

 

1.3 創建和分發 systemd unit 文件
cd /opt/k8s/work
cat > docker.service <<"EOF"
[Unit]
Description=Docker Application Container Engine
Documentation=http://docs.docker.io
 
[Service]
WorkingDirectory=##DOCKER_DIR##
Environment="PATH=/opt/k8s/bin:/bin:/sbin:/usr/bin:/usr/sbin"
EnvironmentFile=-/run/flannel/docker
ExecStart=/opt/k8s/bin/dockerd $DOCKER_NETWORK_OPTIONS
ExecReload=/bin/kill -s HUP $MAINPID
Restart=on-failure
RestartSec=5
LimitNOFILE=infinity
LimitNPROC=infinity
LimitCORE=infinity
Delegate=yes
KillMode=process
[Install]
WantedBy=multi-user.target
EOF

l  EOF 前后有雙引號,這樣 bash 不會替換文檔中的變量,如 $DOCKER_NETWORK_OPTIONS;

l  dockerd 運行時會調用其它 docker 命令,如 docker-proxy,所以需要將 docker 命令所在的目錄加到 PATH 環境變量中;

l  flanneld 啟動時將網絡配置寫入 /run/flannel/docker 文件中,dockerd 啟動前讀取該文件中的環境變量 DOCKER_NETWORK_OPTIONS ,然后設置 docker0 網橋網段;

l  如果指定了多個 EnvironmentFile 選項,則必須將 /run/flannel/docker 放在最后(確保 docker0 使用 flanneld 生成的 bip 參數);

l  docker 需要以 root 用於運行;

l  docker 從 1.13 版本開始,可能將 iptables FORWARD chain的默認策略設置為DROP,從而導致 ping 其它 Node 上的 Pod IP 失敗,遇到這種情況時,需要手動設置策略為 ACCEPT:

sudo iptables -P FORWARD ACCEPT

並且把以下命令寫入 /etc/rc.local 文件中,防止節點重啟iptables FORWARD chain的默認策略又還原為DROP

/sbin/iptables -P FORWARD ACCEPT

 

分發 systemd unit 文件到所有 worker 機器:

cd /opt/k8s/work
source /opt/k8s/bin/environment.sh
sed -i -e "s|##DOCKER_DIR##|${DOCKER_DIR}|" docker.service
for node_ip in ${NODE_IPS[@]}
  do
    echo ">>> ${node_ip}"
    scp docker.service root@${node_ip}:/usr/lib/systemd/system/
  done

 

1.4  配置和分發 docker 配置文件

使用國內的倉庫鏡像服務器以加快 pull image 的速度,同時增加下載的並發數 (需要重啟 dockerd 生效):

cd /opt/k8s/work
cat > docker-daemon.json <<EOF
{
    "registry-mirrors": ["https://hub-mirror.c.163.com", "https://docker.mirrors.ustc.edu.cn"],
    "insecure-registries": ["docker02:35000"],
    "max-concurrent-downloads": 20,
    "live-restore": true,
    "max-concurrent-uploads": 10,
    "debug": true,
    "data-root": "/data/k8s/docker/data",
    "exec-root": "/data/k8s/docker/exec",
    "log-opts": {
      "max-size": "100m",
      "max-file": "5"
    }
}
EOF

 

分發 docker 配置文件到所有 work 節點:

cd /opt/k8s/work
source /opt/k8s/bin/environment.sh
for node_ip in ${NODE_IPS[@]}
  do
    echo ">>> ${node_ip}"
    ssh root@${node_ip} "mkdir -p  /etc/docker/ ${DOCKER_DIR}/{data,exec}"
    scp docker-daemon.json root@${node_ip}:/etc/docker/daemon.json
  done

 

1.5  啟動 docker 服務
source /opt/k8s/bin/environment.sh
for node_ip in ${NODE_IPS[@]}
  do
    echo ">>> ${node_ip}"
    ssh root@${node_ip} "systemctl stop firewalld && systemctl disable firewalld"
    ssh root@${node_ip} "/usr/sbin/iptables -F && /usr/sbin/iptables -X && /usr/sbin/iptables -F -t nat && /usr/sbin/iptables -X -t nat"
    ssh root@${node_ip} "/usr/sbin/iptables -P FORWARD ACCEPT"
    ssh root@${node_ip} "systemctl daemon-reload && systemctl enable docker && systemctl restart docker"
    #ssh root@${node_ip} 'for intf in /sys/devices/virtual/net/docker0/brif/*; do echo 1 > $intf/hairpin_mode; done'
    ssh root@${node_ip} "sudo sysctl -p /etc/sysctl.d/kubernetes.conf"
  done 

l  關閉 firewalld(centos7)/ufw(ubuntu16.04),否則可能會重復創建 iptables 規則;

l  清理舊的 iptables rules 和 chains 規則;

l  開啟 docker0 網橋下虛擬網卡的 hairpin 模式;

 

1.6  檢查服務運行狀態
source /opt/k8s/bin/environment.sh
for node_ip in ${NODE_IPS[@]}
  do
    echo ">>> ${node_ip}"
    ssh root@${node_ip} "systemctl status docker|grep Active"
  done

確保狀態為 active (running),否則查看日志,確認原因:

journalctl -u docker
1.7 檢查 docker0 網橋
source /opt/k8s/bin/environment.sh
for node_ip in ${NODE_IPS[@]}
  do
    echo ">>> ${node_ip}"
    ssh root@${node_ip} "/usr/sbin/ip addr show flannel.1 && /usr/sbin/ip addr show docker0"
  done

確認各 work 節點的 docker0 網橋和 flannel.1 接口的 IP 處於同一個網段中(如下 172.30.112.0/32 位於 172.30.112.1/21 中):

>>> 192.168.100.246

4: flannel.1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1450 qdisc noqueue state UNKNOWN group default

    link/ether fa:32:14:34:86:74 brd ff:ff:ff:ff:ff:ff

    inet 172.30.240.0/32 scope global flannel.1

       valid_lft forever preferred_lft forever

3: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN group default

    link/ether 02:42:7f:58:af:18 brd ff:ff:ff:ff:ff:ff

    inet 172.30.240.1/21 brd 172.30.247.255 scope global docker0

       valid_lft forever preferred_lft forever

 

2.      部署kubelet組件

kublet 運行在每個 worker 節點上,接收 kube-apiserver 發送的請求,管理 Pod 容器,執行交互式命令,如 exec、run、logs 等。

kublet 啟動時自動向 kube-apiserver 注冊節點信息,內置的 cadvisor 統計和監控節點的資源使用情況。

為確保安全,本文檔只開啟接收 https 請求的安全端口,對請求進行認證和授權,拒絕未授權的訪問(如 apiserver、heapster)。

注意:如果沒有特殊指明,本文檔的所有操作均在 master 節點上執行,然后遠程分發文件和執行命令。

 

2.1.          下載和分發 kubelet 二進制文件

參考 部署master節點

 

2.2.          安裝依賴包

參考 部署worker節點

 

2.3.          創建 kubelet bootstrap kubeconfig 文件
cd /opt/k8s/work
source /opt/k8s/bin/environment.sh
for node_name in ${NODE_NAMES[@]}
  do
    echo ">>> ${node_name}"
 
    # 創建 token
    export BOOTSTRAP_TOKEN=$(kubeadm token create \
      --description kubelet-bootstrap-token \
      --groups system:bootstrappers:${node_name} \
      --kubeconfig ~/.kube/config)
 
    # 設置集群參數
    kubectl config set-cluster kubernetes \
      --certificate-authority=/etc/kubernetes/cert/ca.pem \
      --embed-certs=true \
      --server=${KUBE_APISERVER} \
      --kubeconfig=kubelet-bootstrap-${node_name}.kubeconfig
 
    # 設置客戶端認證參數
    kubectl config set-credentials kubelet-bootstrap \
      --token=${BOOTSTRAP_TOKEN} \
      --kubeconfig=kubelet-bootstrap-${node_name}.kubeconfig
 
    # 設置上下文參數
    kubectl config set-context default \
      --cluster=kubernetes \
      --user=kubelet-bootstrap \
      --kubeconfig=kubelet-bootstrap-${node_name}.kubeconfig
 
    # 設置默認上下文
    kubectl config use-context default --kubeconfig=kubelet-bootstrap-${node_name}.kubeconfig
  done

l  證書中寫入 Token 而非證書,證書后續由 kube-controller-manager 創建。

 

查看 kubeadm 為各節點創建的 token:

kubeadm token list --kubeconfig ~/.kube/config

TOKEN                     TTL       EXPIRES                     USAGES                   DESCRIPTION               EXTRA GROUPS

33xdd2.b04al5zmia3tnnf8   23h       2019-04-01T14:06:46+08:00   authentication,signing   kubelet-bootstrap-token   system:bootstrappers:node2

ch6fro.v9nps3d5z0lcmyrd   23h       2019-04-01T14:06:25+08:00   authentication,signing   kubelet-bootstrap-token   system:bootstrappers:master

napqqj.wi1qhq2gjel1dvia   23h       2019-04-01T14:06:35+08:00   authentication,signing   kubelet-bootstrap-token   system:bootstrappers:node1

l  創建的 token 有效期為 1 天,超期后將不能再被使用,且會被 kube-controller-manager 的 tokencleaner 清理(如果啟用該 controller 的話);

l  kube-apiserver 接收 kubelet 的 bootstrap token 后,將請求的 user 設置為 system:bootstrap:,group 設置為 system:bootstrappers;

 

查看各 token 關聯的 Secret:

kubectl get secrets -n kube-system|grep bootstrap-token

bootstrap-token-503xx3                           bootstrap.kubernetes.io/token         7      40m

bootstrap-token-cjadiv                           bootstrap.kubernetes.io/token         7      45m

bootstrap-token-iifyk9                           bootstrap.kubernetes.io/token         7      40m

 

2.4.          分發 bootstrap kubeconfig 文件到所有 worker 節點
cd /opt/k8s/work
source /opt/k8s/bin/environment.sh
for node_name in ${NODE_NAMES[@]}
  do
    echo ">>> ${node_name}"
    scp kubelet-bootstrap-${node_name}.kubeconfig root@${node_name}:/etc/kubernetes/kubelet-bootstrap.kubeconfig
  done

 

2.5.          創建和分發 kubelet 參數配置文件

從 v1.10 開始,kubelet 部分參數需在配置文件中配置,kubelet --help 會提示:

DEPRECATED: This parameter should be set via the config file specified by the Kubelet's --config flag

 

創建 kubelet 參數配置模板文件:

cd /opt/k8s/work
source /opt/k8s/bin/environment.sh
cat <<EOF | tee kubelet-config.yaml.template
kind: KubeletConfiguration
apiVersion: kubelet.config.k8s.io/v1beta1
authentication:
  anonymous:
    enabled: false
  webhook:
    enabled: true
  x509:
    clientCAFile: "/etc/kubernetes/cert/ca.pem"
authorization:
  mode: Webhook
clusterDomain: "${CLUSTER_DNS_DOMAIN}"
clusterDNS:
  - "${CLUSTER_DNS_SVC_IP}"
podCIDR: "${CLUSTER_CIDR}"
maxPods: 220
serializeImagePulls: false
hairpinMode: promiscuous-bridge
cgroupDriver: cgroupfs
runtimeRequestTimeout: "15m"
rotateCertificates: true
serverTLSBootstrap: true
readOnlyPort: 0
port: 10250
address: "##NODE_IP##"
EOF

l  address:API 監聽地址,不能為 127.0.0.1,否則 kube-apiserver、heapster 等不能調用 kubelet 的 API;

l  readOnlyPort=0:關閉只讀端口(默認 10255),等效為未指定;

l  authentication.anonymous.enabled:設置為 false,不允許匿名訪問 10250 端口;

l  authentication.x509.clientCAFile:指定簽名客戶端證書的 CA 證書,開啟 HTTP 證書認證;

l  authentication.webhook.enabled=true:開啟 HTTPs bearer token 認證;

l  對於未通過 x509 證書和 webhook 認證的請求(kube-apiserver 或其他客戶端),將被拒絕,提示 Unauthorized;

l  authroization.mode=Webhook:kubelet 使用 SubjectAccessReview API 查詢 kube-apiserver 某 user、group 是否具有操作資源的權限(RBAC);

l  featureGates.RotateKubeletClientCertificate、featureGates.RotateKubeletServerCertificate:自動 rotate 證書,證書的有效期取決於 kube-controller-manager 的 --experimental-cluster-signing-duration 參數;

l  需要 root 賬戶運行;

 

為各節點創建和分發 kubelet 配置文件:

cd /opt/k8s/work
source /opt/k8s/bin/environment.sh
for node_ip in ${NODE_IPS[@]}
  do 
    echo ">>> ${node_ip}"
    sed -e "s/##NODE_IP##/${node_ip}/" kubelet-config.yaml.template > kubelet-config-${node_ip}.yaml.template
    scp kubelet-config-${node_ip}.yaml.template root@${node_ip}:/etc/kubernetes/kubelet-config.yaml
  done

 

2.6.          創建和分發 kubelet systemd unit 文件

創建 kubelet systemd unit 文件模板:

cd /opt/k8s/work
cat > kubelet.service.template <<EOF
[Unit]
Description=Kubernetes Kubelet
Documentation=https://github.com/GoogleCloudPlatform/kubernetes
After=docker.service
Requires=docker.service
 
[Service]
WorkingDirectory=${K8S_DIR}/kubelet
ExecStart=/opt/k8s/bin/kubelet \\
  --root-dir=${K8S_DIR}/kubelet \\
  --bootstrap-kubeconfig=/etc/kubernetes/kubelet-bootstrap.kubeconfig \\
  --cert-dir=/etc/kubernetes/cert \\
  --kubeconfig=/etc/kubernetes/kubelet.kubeconfig \\
  --config=/etc/kubernetes/kubelet-config.yaml \\
  --hostname-override=##NODE_NAME## \\
  --pod-infra-container-image=xiaochunping/pause:3.1
  --allow-privileged=true \\
  --event-qps=0 \\
  --kube-api-qps=1000 \\
  --kube-api-burst=2000 \\
  --registry-qps=0 \\
  --image-pull-progress-deadline=30m \\
  --logtostderr=true \\
  --v=2
Restart=always
RestartSec=5
StartLimitInterval=0
 
[Install]
WantedBy=multi-user.target
EOF

l  如果設置了 --hostname-override 選項,則 kube-proxy 也需要設置該選項,否則會出現找不到 Node 的情況;

l  --bootstrap-kubeconfig:指向 bootstrap kubeconfig 文件,kubelet 使用該文件中的用戶名和 token 向 kube-apiserver 發送 TLS Bootstrapping 請求;

l  K8S approve kubelet 的 csr 請求后,在 --cert-dir 目錄創建證書和私鑰文件,然后寫入 --kubeconfig 文件;

l  --pod-infra-container-image 不使用 redhat 的 pod-infrastructure:latest 鏡像,它不能回收容器的僵屍;

 

為各節點創建和分發 kubelet systemd unit 文件:

cd /opt/k8s/work
source /opt/k8s/bin/environment.sh
for node_name in ${NODE_NAMES[@]}
  do 
    echo ">>> ${node_name}"
    sed -e "s/##NODE_NAME##/${node_name}/" kubelet.service.template > kubelet-${node_name}.service
    scp kubelet-${node_name}.service root@${node_name}:/usr/lib/systemd/system/kubelet.service
  done

 

2.7.          Bootstrap Token Auth 和授予權限

kublet 啟動時查找配置的 --kubeletconfig 文件是否存在,如果不存在則使用 --bootstrap-kubeconfig 向 kube-apiserver 發送證書簽名請求 (CSR)。

 

kube-apiserver 收到 CSR 請求后,對其中的 Token 進行認證(事先使用 kubeadm 創建的 token),認證通過后將請求的 user 設置為 system:bootstrap:<TokenID>,group 設置為 system:bootstrappers,這一過程稱為 Bootstrap Token Auth。

 

默認情況下,這個 user 和 group 沒有創建 CSR 的權限,kubelet 啟動失敗,錯誤日志如下:

sudo journalctl -u kubelet -a |grep -A 2 'certificatesigningrequests'

May 06 06:42:36 k8s-1 kubelet[26986]: F0506 06:42:36.314378   26986 server.go:233] failed to run Kubelet: cannot create certificate signing request: certificatesigningrequests.certificates.k8s.io is forbidden: User "system:bootstrap:lemy40" cannot create certificatesigningrequests.certificates.k8s.io at the cluster scope

May 06 06:42:36 k8s-1 systemd[1]: kubelet.service: Main process exited, code=exited, status=255/n/a

May 06 06:42:36 k8s-1 systemd[1]: kubelet.service: Failed with result 'exit-code'.

 

解決辦法是:創建一個 clusterrolebinding,將 group system:bootstrappers 和 clusterrole system:node-bootstrapper 綁定:

kubectl create clusterrolebinding kubelet-bootstrap --clusterrole=system:node-bootstrapper --group=system:bootstrappers

 

2.8.          啟動 kubelet 服務
source /opt/k8s/bin/environment.sh
for node_ip in ${NODE_IPS[@]}
  do
    echo ">>> ${node_ip}"
    ssh root@${node_ip} "mkdir -p ${K8S_DIR}/kubelet"
    ssh root@${node_ip} "/usr/sbin/swapoff -a"
    ssh root@${node_ip} "systemctl daemon-reload && systemctl enable kubelet && systemctl restart kubelet"
  done

l  必須創建工作目錄;

l  關閉 swap 分區,否則 kubelet 會啟動失敗;

 

journalctl -u kubelet |tail

3月 29 15:01:53 k8s-1 systemd[1]: Job kubelet.service/start failed with result 'dependency'.

3月 29 15:03:23 k8s-1 systemd[1]: Dependency failed for Kubernetes Kubelet.

3月 29 15:03:23 k8s-1 systemd[1]: Job kubelet.service/start failed with result 'dependency'.

-- Reboot --

3月 30 18:48:42 k8s-1 systemd[1]: Cannot add dependency job for unit kubelet.service, ignoring: Unit not found.

3月 31 14:41:17 k8s-1 systemd[1]: [/usr/lib/systemd/system/kubelet.service:10] Unknown lvalue '--allow-privileged' in section 'Service'

3月 31 14:41:17 k8s-1 systemd[1]: [/usr/lib/systemd/system/kubelet.service:10] Unknown lvalue '--allow-privileged' in section 'Service'

3月 31 14:41:17 k8s-1 systemd[1]: Started Kubernetes Kubelet.

3月 31 14:41:17 k8s-1 kubelet[29768]: I0331 14:41:17.880649   29768 server.go:408] Version: v1.12.3

3月 31 14:41:17 k8s-1 kubelet[29768]: I0331 14:41:17.881049   29768 plugins.go:99] No cloud provider specified.

 

kubelet 啟動后使用 --bootstrap-kubeconfig 向 kube-apiserver 發送 CSR 請求,當這個 CSR 被 approve 后,kube-controller-manager 為 kubelet 創建 TLS 客戶端證書、私鑰和 --kubeletconfig 文件。

 

注意:kube-controller-manager 需要配置 --cluster-signing-cert-file 和 --cluster-signing-key-file 參數,才會為 TLS Bootstrap 創建證書和私鑰。

kubectl get csr

NAME                                                   AGE   REQUESTOR                 CONDITION

node-csr-7YSbJGsZGmAH5IrdOmJVcGDrUK3iGtFiDHuRMVdJk5M   22h   system:bootstrap:f9isxw   Pending

node-csr-IHHUpaUceWdFY7QPRw48ICdr_pyt1VC-KgLM9SfNWE8   23h   system:bootstrap:8w1g0a   Pending

node-csr-xqKuMm_MsfUGrMiwti1EaaJMsOpWwvlOQIT_N_3a02k   22h   system:bootstrap:2b84b8

 

kubectl get nodes

No resources found.

 

l  三個 work 節點的 csr 均處於 pending 狀態;

 

2.9.          檢查服務運行狀態
source /opt/k8s/bin/environment.sh
for node_ip in ${NODE_IPS[@]}
  do
    echo ">>> ${node_ip}"
    ssh root@${node_ip} "systemctl status kubelet|grep Active"
  done

確保狀態為 active (running),否則查看日志,確認原因:

journalctl -u kubelet

 

2.10.      approve kubelet CSR 請求

可以手動或自動 approve CSR 請求。推薦使用自動的方式,因為從 v1.8 版本開始,可以自動輪轉approve csr 后生成的證書。

2.10.1.     手動 approve CSR 請求

查看 SCR 列表:

kubectl get csr

NAME                                                   AGE   REQUESTOR                 CONDITION

node-csr-7YSbJGsZGmAH5IrdOmJVcGDrUK3iGtFiDHuRMVdJk5M   22h   system:bootstrap:f9isxw   Pending

node-csr-IHHUpaUceWdFY7QPRw48ICdr_pyt1VC-KgLM9SfNWE8   23h   system:bootstrap:8w1g0a   Pending

node-csr-xqKuMm_MsfUGrMiwti1EaaJMsOpWwvlOQIT_N_3a02k   22h   system:bootstrap:2b84b8   

 

approve SCR:

kubectl certificate approve node-csr-7YSbJGsZGmAH5IrdOmJVcGDrUK3iGtFiDHuRMVdJk5M

certificatesigningrequest.certificates.k8s.io "node-csr-7YSbJGsZGmAH5IrdOmJVcGDrUK3iGtFiDHuRMVdJk5M" approved

 

查看 Approve 結果:

kubectl describe csr node-csr-7YSbJGsZGmAH5IrdOmJVcGDrUK3iGtFiDHuRMVdJk5M
2.10.2.     自動 approve CSR 請求

創建三個 ClusterRoleBinding,分別用於自動 approve client、renew client、renew server 證書:

cd /opt/k8s/work
cat > csr-crb.yaml <<EOF
 # Approve all CSRs for the group "system:bootstrappers"
 kind: ClusterRoleBinding
 apiVersion: rbac.authorization.k8s.io/v1
 metadata:
   name: auto-approve-csrs-for-group
 subjects:
 - kind: Group
   name: system:bootstrappers
   apiGroup: rbac.authorization.k8s.io
 roleRef:
   kind: ClusterRole
   name: system:certificates.k8s.io:certificatesigningrequests:nodeclient
   apiGroup: rbac.authorization.k8s.io
---
 # To let a node of the group "system:nodes" renew its own credentials
 kind: ClusterRoleBinding
 apiVersion: rbac.authorization.k8s.io/v1
 metadata:
   name: node-client-cert-renewal
 subjects:
 - kind: Group
   name: system:nodes
   apiGroup: rbac.authorization.k8s.io
 roleRef:
   kind: ClusterRole
   name: system:certificates.k8s.io:certificatesigningrequests:selfnodeclient
   apiGroup: rbac.authorization.k8s.io
---
# A ClusterRole which instructs the CSR approver to approve a node requesting a
# serving cert matching its client cert.
kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: approve-node-server-renewal-csr
rules:
- apiGroups: ["certificates.k8s.io"]
  resources: ["certificatesigningrequests/selfnodeserver"]
  verbs: ["create"]
---
 # To let a node of the group "system:nodes" renew its own server credentials
 kind: ClusterRoleBinding
 apiVersion: rbac.authorization.k8s.io/v1
 metadata:
   name: node-server-cert-renewal
 subjects:
 - kind: Group
   name: system:nodes
   apiGroup: rbac.authorization.k8s.io
 roleRef:
   kind: ClusterRole
   name: approve-node-server-renewal-csr
   apiGroup: rbac.authorization.k8s.io
EOF

l  auto-approve-csrs-for-group:自動 approve node 的第一次 CSR; 注意第一次 CSR 時,請求的 Group 為 system:bootstrappers;

l  node-client-cert-renewal:自動 approve node 后續過期的 client 證書,自動生成的證書 Group 為 system:nodes;

l  node-server-cert-renewal:自動 approve node 后續過期的 server 證書,自動生成的證書 Group 為 system:nodes;

 

生效配置:

kubectl apply -f csr-crb.yaml

clusterrolebinding.rbac.authorization.k8s.io/auto-approve-csrs-for-group created

clusterrolebinding.rbac.authorization.k8s.io/node-client-cert-renewal created

clusterrole.rbac.authorization.k8s.io/approve-node-server-renewal-csr created

clusterrolebinding.rbac.authorization.k8s.io/node-server-cert-renewal created

 

2.11.      查看 kublet 的情況

等待一段時間(1-10 分鍾),三個節點的 CSR 都被自動 approved:

kubectl get csr

NAME                                                   AGE       REQUESTOR                 CONDITION

node-csr--BjlTzxB5Y4op_6wYlDKbbQj1NtX-IOBMLmWhkupEWA   4m        system:bootstrap:8galm1   Approved,Issued

node-csr-a68FhmUgprTJkaLwnJOLQLOkDQuAviDdBy91ByVtWt0   4m        system:bootstrap:4ef7hj   Approved,Issued

node-csr-a7DI6d0QjBiPh58IBGYFPUKAZvKs6sfbqlnoc22erRs   4m        system:bootstrap:ai162m   Approved,Issued

l  Pending 的 CSR 用於創建 kubelet server 證書,需要手動 approve,下文介紹。

 

所有節點均 ready:

kubectl get nodes

NAME     STATUS   ROLES    AGE     VERSION

master   Ready    <none>   2m58s   v1.12.3

node1    Ready    <none>   2m54s   v1.12.3

node2    Ready    <none>   2m56s   v1.12.3

 

kube-controller-manager 為各 node 生成了 kubeconfig 文件和公私鑰:

ls -l /etc/kubernetes/kubelet.kubeconfig

-rw------- 1 root root 2298 3月  28 17:45 /etc/kubernetes/kubelet.kubeconfig

ls -l /etc/kubernetes/cert/|grep kubelet

-rw------- 1 root root 1265 3月  28 17:45 kubelet-client-2019-03-28-17-45-48.pem

lrwxrwxrwx 1 root root   58 3月  28 17:45 kubelet-client-current.pem -> /etc/kubernetes/cert/kubelet-client-2019-03-28-17-45-48.pem

l  沒有自動生成 kubelet server 證書;

 

2.12.      手動 approve server cert csr

基於安全性考慮,CSR approving controllers 默認不會自動 approve kubelet server 證書簽名請求,需要手動 approve。

kubectl get csr

NAME                                                   AGE     REQUESTOR                 CONDITION

csr-42fr8                                              7m45s   system:node:master        Pending

csr-5gwjj                                              7m43s   system:node:node2         Pending

csr-klkcp                                              7m41s   system:node:node1         Pending

node-csr-7YSbJGsZGmAH5IrdOmJVcGDrUK3iGtFiDHuRMVdJk5M   23h     system:bootstrap:f9isxw   Approved,Issued

node-csr-IHHUpaUceWdFY7QPRw48ICdr_pyt1VC-KgLM9SfNWE8   24h     system:bootstrap:8w1g0a   Approved,Issued

node-csr-xqKuMm_MsfUGrMiwti1EaaJMsOpWwvlOQIT_N_3a02k   23h     system:bootstrap:2b84b8   Approved,Issued

 

kubectl certificate approve csr-42fr8
kubectl certificate approve csr-5gwjj
kubectl certificate approve csr-klkcp

certificatesigningrequest.certificates.k8s.io/csr-42fr8 approved

certificatesigningrequest.certificates.k8s.io/csr-5gwjj approved

certificatesigningrequest.certificates.k8s.io/csr-klkcp approved

ls -l /etc/kubernetes/cert/kubelet-*

-rw------- 1 root root 1265 3月  28 17:45 /etc/kubernetes/cert/kubelet-client-2019-03-28-17-45-48.pem

lrwxrwxrwx 1 root root   58 3月  28 17:45 /etc/kubernetes/cert/kubelet-client-current.pem -> /etc/kubernetes/cert/kubelet-client-2019-03-28-17-45-48.pem

-rw------- 1 root root 1301 3月  28 17:58 /etc/kubernetes/cert/kubelet-server-2019-03-28-17-58-23.pem

lrwxrwxrwx 1 root root   58 3月  28 17:58 /etc/kubernetes/cert/kubelet-server-current.pem -> /etc/kubernetes/cert/kubelet-server-2019-03-28-17-58-23.pem

 

2.13.      kubelet 提供的 API 接口

kublet 啟動后監聽多個端口,用於接收 kube-apiserver 或其它組件發送的請求:

sudo netstat -lnpt|grep kubelet

tcp        0      0 192.168.100.246:10250   0.0.0.0:*               LISTEN      8958/kubelet       

tcp        0      0 127.0.0.1:41848         0.0.0.0:*               LISTEN      8958/kubelet       

tcp        0      0 127.0.0.1:10248         0.0.0.0:*               LISTEN      8958/kubelet

l  10248: healthz http 服務;

l  10250: https API 服務;注意:未開啟只讀端口 10255;

 

例如執行 kubectl exec -it nginx-ds-5rmws -- sh 命令時,kube-apiserver 會向 kubelet 發送如下請求:

POST /exec/default/nginx-ds-5rmws/my-nginx?command=sh&input=1&output=1&tty=1

 

kubelet 接收 10250 端口的 https 請求:

l  /pods、/runningpods

l  /metrics、/metrics/cadvisor、/metrics/probes

l  /spec

l  /stats、/stats/container

l  /logs

l  /run/、"/exec/", "/attach/", "/portForward/", "/containerLogs/" 等管理;

詳情參考:https://github.com/kubernetes/kubernetes/blob/master/pkg/kubelet/server/server.go#L434:3

 

由於關閉了匿名認證,同時開啟了 webhook 授權,所有訪問 10250 端口 https API 的請求都需要被認證和授權。

 

預定義的 ClusterRole system:kubelet-api-admin 授予訪問 kubelet 所有 API 的權限(kube-apiserver 使用的 kubernetes 證書 User 授予了該權限):

kubectl describe clusterrole system:kubelet-api-admin

Name:         system:kubelet-api-admin

Labels:       kubernetes.io/bootstrapping=rbac-defaults

Annotations:  rbac.authorization.kubernetes.io/autoupdate: true

PolicyRule:

  Resources      Non-Resource URLs  Resource Names  Verbs

  ---------      -----------------  --------------  -----

  nodes/log      []                 []              [*]

  nodes/metrics  []                 []              [*]

  nodes/proxy    []                 []              [*]

  nodes/spec     []                 []              [*]

  nodes/stats    []                 []              [*]

  nodes          []                 []              [get list watch proxy]

 

2.14.      kublet api 認證和授權

kublet 配置了如下認證參數:

l  authentication.anonymous.enabled:設置為 false,不允許匿名訪問 10250 端口;

l  authentication.x509.clientCAFile:指定簽名客戶端證書的 CA 證書,開啟 HTTPs 證書認證;

l  authentication.webhook.enabled=true:開啟 HTTPs bearer token 認證;

 

同時配置了如下授權參數:

l  authroization.mode=Webhook:開啟 RBAC 授權;

 

kubelet 收到請求后,使用 clientCAFile 對證書簽名進行認證,或者查詢 bearer token 是否有效。如果兩者都沒通過,則拒絕請求,提示 Unauthorized:

curl -s --cacert /etc/kubernetes/cert/ca.pem https://192.168.100.246:10250/metrics

Unauthorized

curl -s --cacert /etc/kubernetes/cert/ca.pem -H "Authorization: Bearer 123456" https://192.168.100.246:10250/metrics

Unauthorized

通過認證后,kubelet 使用 SubjectAccessReview API 向 kube-apiserver 發送請求,查詢證書或 token 對應的 user、group 是否有操作資源的權限(RBAC);

 

2.14.1.     證書認證和授權
# 權限不足的證書
sudo curl -s --cacert /etc/kubernetes/cert/ca.pem --cert /etc/kubernetes/cert/kube-controller-manager.pem --key /etc/kubernetes/cert/kube-controller-manager-key.pem https://192.168.100.246:10250/metrics

Forbidden (user=system:kube-controller-manager, verb=get, resource=nodes, subresource=metrics)

# 使用部署 kubectl 命令行工具時創建的、具有最高權限的 admin 證書;
sudo curl -s --cacert /etc/kubernetes/cert/ca.pem --cert /opt/k8s/work/cert/admin.pem --key /opt/k8s/work/cert/admin-key.pem https://192.168.100.246:10250/metrics|head

# HELP apiserver_client_certificate_expiration_seconds Distribution of the remaining lifetime on the certificate used to authenticate a request.

# TYPE apiserver_client_certificate_expiration_seconds histogram

apiserver_client_certificate_expiration_seconds_bucket{le="0"} 0

apiserver_client_certificate_expiration_seconds_bucket{le="21600"} 0

apiserver_client_certificate_expiration_seconds_bucket{le="43200"} 0

apiserver_client_certificate_expiration_seconds_bucket{le="86400"} 0

apiserver_client_certificate_expiration_seconds_bucket{le="172800"} 0

apiserver_client_certificate_expiration_seconds_bucket{le="345600"} 0

apiserver_client_certificate_expiration_seconds_bucket{le="604800"} 0

apiserver_client_certificate_expiration_seconds_bucket{le="2.592e+06"} 0

l  --cacert、--cert、--key 的參數值必須是文件路徑,如上面的 ./admin.pem 不能省略 ./,否則返回 401 Unauthorized;

 

2.14.2.     bear token 認證和授權

創建一個 ServiceAccount,將它和 ClusterRole system:kubelet-api-admin 綁定,從而具有調用 kubelet API 的權限:

kubectl create sa kubelet-api-test
kubectl create clusterrolebinding kubelet-api-test --clusterrole=system:kubelet-api-admin --serviceaccount=default:kubelet-api-test
SECRET=$(kubectl get secrets | grep kubelet-api-test | awk '{print $1}')
TOKEN=$(kubectl describe secret ${SECRET} | grep -E '^token' | awk '{print $2}')
echo ${TOKEN}
 
curl -s --cacert /etc/kubernetes/cert/ca.pem -H "Authorization: Bearer ${TOKEN}" https://172.26.106.83:10250/metrics|head

# HELP apiserver_client_certificate_expiration_seconds Distribution of the remaining lifetime on the certificate used to authenticate a request.

# TYPE apiserver_client_certificate_expiration_seconds histogram

apiserver_client_certificate_expiration_seconds_bucket{le="0"} 0

apiserver_client_certificate_expiration_seconds_bucket{le="21600"} 0

apiserver_client_certificate_expiration_seconds_bucket{le="43200"} 0

apiserver_client_certificate_expiration_seconds_bucket{le="86400"} 0

apiserver_client_certificate_expiration_seconds_bucket{le="172800"} 0

apiserver_client_certificate_expiration_seconds_bucket{le="345600"} 0

apiserver_client_certificate_expiration_seconds_bucket{le="604800"} 0

apiserver_client_certificate_expiration_seconds_bucket{le="2.592e+06"} 0

 

2.14.3.     cadvisor 和 metrics

cadvisor 統計所在節點各容器的資源(CPU、內存、磁盤、網卡)使用情況,分別在自己的 http web 頁面(4194 端口)和 10250 以 promehteus metrics 的形式輸出。

 

瀏覽器訪問 :

https://192.168.100.246:10250/metrics  和

https://192.168.100.246:10250/metrics/cadvisor

分別返回 kublet 和 metrics 和 cadvisor 。

 

 

 

注意:

l  kublet.config.json 設置 authentication.anonymous.enabled 為 false,不允許匿名證書訪問 10250 的 https 服務;

l  參考 瀏覽器訪問kube-apiserver安全端口,創建和導入相關證書,然后訪問上面的 10250 端口;

 

2.15.      獲取 kublet 的配置

從 kube-apiserver 獲取各 node 的配置:

# 使用部署 kubectl 命令行工具時創建的、具有最高權限的 admin 證書;
sudo curl -sSL --cacert /etc/kubernetes/cert/ca.pem --cert /opt/k8s/work/cert/admin.pem --key /opt/k8s/work/cert/admin-key.pem ${KUBE_APISERVER}/api/v1/nodes/master/proxy/configz | jq  '.kubeletconfig|.kind="KubeletConfiguration"|.apiVersion="kubelet.config.k8s.io/v1beta1"'

{

  "syncFrequency": "1m0s",

  "fileCheckFrequency": "20s",

  "httpCheckFrequency": "20s",

  "address": "192.168.100.246",

  "port": 10250,

  "rotateCertificates": true,

  "serverTLSBootstrap": true,

  "authentication": {

    "x509": {

      "clientCAFile": "/etc/kubernetes/cert/ca.pem"

    },

    "webhook": {

      "enabled": true,

      "cacheTTL": "2m0s"

    },

    "anonymous": {

      "enabled": false

    }

  },

  "authorization": {

    "mode": "Webhook",

    "webhook": {

      "cacheAuthorizedTTL": "5m0s",

      "cacheUnauthorizedTTL": "30s"

    }

  },

  "registryPullQPS": 0,

  "registryBurst": 10,

  "eventRecordQPS": 0,

  "eventBurst": 10,

  "enableDebuggingHandlers": true,

  "healthzPort": 10248,

  "healthzBindAddress": "127.0.0.1",

  "oomScoreAdj": -999,

  "clusterDomain": "cluster.local",

  "clusterDNS": [

    "10.254.0.2"

  ],

  "streamingConnectionIdleTimeout": "4h0m0s",

  "nodeStatusUpdateFrequency": "10s",

  "nodeLeaseDurationSeconds": 40,

  "imageMinimumGCAge": "2m0s",

  "imageGCHighThresholdPercent": 85,

  "imageGCLowThresholdPercent": 80,

  "volumeStatsAggPeriod": "1m0s",

  "cgroupsPerQOS": true,

  "cgroupDriver": "cgroupfs",

  "cpuManagerPolicy": "none",

  "cpuManagerReconcilePeriod": "10s",

  "runtimeRequestTimeout": "15m0s",

  "hairpinMode": "promiscuous-bridge",

  "maxPods": 220,

  "podCIDR": "172.30.0.0/16",

  "podPidsLimit": -1,

  "resolvConf": "/etc/resolv.conf",

  "cpuCFSQuota": true,

  "cpuCFSQuotaPeriod": "100ms",

  "maxOpenFiles": 1000000,

  "contentType": "application/vnd.kubernetes.protobuf",

  "kubeAPIQPS": 1000,

  "kubeAPIBurst": 2000,

  "serializeImagePulls": false,

  "evictionHard": {

    "imagefs.available": "15%",

    "memory.available": "100Mi",

    "nodefs.available": "10%",

    "nodefs.inodesFree": "5%"

  },

  "evictionPressureTransitionPeriod": "5m0s",

  "enableControllerAttachDetach": true,

  "makeIPTablesUtilChains": true,

  "iptablesMasqueradeBit": 14,

  "iptablesDropBit": 15,

  "failSwapOn": true,

  "containerLogMaxSize": "10Mi",

  "containerLogMaxFiles": 5,

  "configMapAndSecretChangeDetectionStrategy": "Watch",

  "enforceNodeAllocatable": [

    "pods"

  ],

  "kind": "KubeletConfiguration",

  "apiVersion": "kubelet.config.k8s.io/v1beta1"

}

或者參考代碼中的注釋:

https://github.com/kubernetes/kubernetes/blob/master/pkg/kubelet/apis/kubeletconfig/v1beta1/types.go

 

2.16.      參考

kubelet 認證和授權:

https://kubernetes.io/docs/reference/command-line-tools-reference/kubelet-authentication-authorization/

 

 

3.      部署 kube-proxy 組件

kube-proxy 運行在所有 worker 節點上,,它監聽 apiserver 中 service 和 Endpoint 的變化情況,創建路由規則來進行服務負載均衡。

本文檔講解部署 kube-proxy 的部署,使用 ipvs 模式。

注意:如果沒有特殊指明,本文檔的所有操作均在 master 節點上執行,然后遠程分發文件和執行命令。

 

3.1.          下載和分發 kube-proxy 二進制文件

參考 部署master節點

 

3.2.          安裝依賴包

各節點需要安裝 ipvsadm 和 ipset 命令,加載 ip_vs 內核模塊。

參考 部署worker節點

 

3.3.          創建 kube-proxy 證書

創建證書簽名請求:

cd /opt/k8s/work/cert
cat > kube-proxy-csr.json <<EOF
{
  "CN": "system:kube-proxy",
  "key": {
    "algo": "rsa",
    "size": 2048
  },
  "names": [
    {
      "C": "CN",
      "ST": "BeiJing",
      "L": "BeiJing",
      "O": "k8s",
      "OU": "study163"
    }
  ]
}
EOF

l  CN:指定該證書的 User 為 system:kube-proxy;

l  預定義的 RoleBinding system:node-proxier 將User system:kube-proxy 與 Role system:node-proxier 綁定,該 Role 授予了調用 kube-apiserver Proxy 相關 API 的權限;

l  該證書只會被 kube-proxy 當做 client 證書使用,所以 hosts 字段為空;

 

生成證書和私鑰:

cd /opt/k8s/work/cert
cfssl gencert -ca=/opt/k8s/work/cert/ca.pem \
  -ca-key=/opt/k8s/work/cert/ca-key.pem \
  -config=/opt/k8s/work/cert/ca-config.json \
  -profile=kubernetes  kube-proxy-csr.json | cfssljson -bare kube-proxy
ls kube-proxy*

 

3.4.          創建和分發 kubeconfig 文件
cd /opt/k8s/work
source /opt/k8s/bin/environment.sh
kubectl config set-cluster kubernetes \
  --certificate-authority=/opt/k8s/work/cert/ca.pem \
  --embed-certs=true \
  --server=${KUBE_APISERVER} \
  --kubeconfig=kube-proxy.kubeconfig
 
kubectl config set-credentials kube-proxy \
  --client-certificate=/opt/k8s/work/cert/kube-proxy.pem \
  --client-key=/opt/k8s/work/cert/kube-proxy-key.pem \
  --embed-certs=true \
  --kubeconfig=kube-proxy.kubeconfig
 
kubectl config set-context default \
  --cluster=kubernetes \
  --user=kube-proxy \
  --kubeconfig=kube-proxy.kubeconfig
 
kubectl config use-context default --kubeconfig=kube-proxy.kubeconfig

l  --embed-certs=true:將 ca.pem 和 admin.pem 證書內容嵌入到生成的 kubectl-proxy.kubeconfig 文件中(不加時,寫入的是證書文件路徑);

 

分發 kubeconfig 文件:

cd /opt/k8s/work
source /opt/k8s/bin/environment.sh
for node_name in ${NODE_NAMES[@]}
  do
    echo ">>> ${node_name}"
    scp kube-proxy.kubeconfig root@${node_name}:/etc/kubernetes/
  done

 

 

3.5.          創建 kube-proxy 配置文件

從 v1.10 開始,kube-proxy 部分參數可以配置文件中配置。可以使用 --write-config-to 選項生成該配置文件,或者參考 kubeproxyconfig 的類型定義源文件

 

創建 kube-proxy config 文件模板:

cd /opt/k8s/work
cat <<EOF | tee kube-proxy-config.yaml.template
kind: KubeProxyConfiguration
apiVersion: kubeproxy.config.k8s.io/v1alpha1
clientConnection:
  kubeconfig: "/etc/kubernetes/kube-proxy.kubeconfig"
bindAddress: ##NODE_IP##
clusterCIDR: ${CLUSTER_CIDR}
healthzBindAddress: ##NODE_IP##:10256
hostnameOverride: ##NODE_NAME##
metricsBindAddress: ##NODE_IP##:10249
mode: "ipvs"
EOF

l  bindAddress: 監聽地址;

l  clientConnection.kubeconfig: 連接 apiserver 的 kubeconfig 文件;

l  clusterCIDR: kube-proxy 根據 --cluster-cidr 判斷集群內部和外部流量,指定 --cluster-cidr 或 --masquerade-all 選項后 kube-proxy 才會對訪問 Service IP 的請求做 SNAT;

l  hostnameOverride: 參數值必須與 kubelet 的值一致,否則 kube-proxy 啟動后會找不到該 Node,從而不會創建任何 ipvs 規則;

l  mode: 使用 ipvs 模式;

 

為各節點創建和分發 kube-proxy 配置文件:

cd /opt/k8s/work
source /opt/k8s/bin/environment.sh
for (( i=0; i < 3; i++ ))
  do 
    echo ">>> ${NODE_NAMES[i]}"
    sed -e "s/##NODE_NAME##/${NODE_NAMES[i]}/" -e "s/##NODE_IP##/${NODE_IPS[i]}/" kube-proxy-config.yaml.template > kube-proxy-config-${NODE_NAMES[i]}.yaml.template
    scp kube-proxy-config-${NODE_NAMES[i]}.yaml.template root@${NODE_NAMES[i]}:/etc/kubernetes/kube-proxy-config.yaml
  done

 

3.6.          創建和分發 kube-proxy systemd unit 文件
cd /opt/k8s/work
cat > kube-proxy.service <<EOF
[Unit]
Description=Kubernetes Kube-Proxy Server
Documentation=https://github.com/GoogleCloudPlatform/kubernetes
After=network.target
 
[Service]
WorkingDirectory=/data/k8s/k8s/kube-proxy
ExecStart=/opt/k8s/bin/kube-proxy \\
  --config=/etc/kubernetes/kube-proxy-config.yaml \\
  --logtostderr=true \\
  --v=2
Restart=on-failure
RestartSec=5
LimitNOFILE=65536
 
[Install]
WantedBy=multi-user.target
EOF

 

分發 kube-proxy systemd unit 文件:

cd /opt/k8s/work
source /opt/k8s/bin/environment.sh
for node_name in ${NODE_NAMES[@]}
  do 
    echo ">>> ${node_name}"
    scp kube-proxy.service root@${node_name}:/usr/lib/systemd/system/
  done

 

3.7.          啟動 kube-proxy 服務
cd /opt/k8s/work
source /opt/k8s/bin/environment.sh
for node_ip in ${NODE_IPS[@]}
  do
    echo ">>> ${node_ip}"
    ssh root@${node_ip} "mkdir -p ${K8S_DIR}/kube-proxy"
    ssh root@${node_ip} "systemctl daemon-reload && systemctl enable kube-proxy && systemctl restart kube-proxy"
  done

l  必須先創建工作目錄;

 

3.8.          檢查啟動結果
source /opt/k8s/bin/environment.sh
for node_ip in ${NODE_IPS[@]}
  do
    echo ">>> ${node_ip}"
    ssh root@${node_ip} "systemctl status kube-proxy|grep Active"
  done

確保狀態為 active (running),否則查看日志,確認原因:

journalctl -u kube-proxy

 

3.9.          查看監聽端口和 metrics
sudo netstat -lnpt|grep kube-prox

tcp        0      0 192.168.100.246:10256   0.0.0.0:*               LISTEN      20482/kube-proxy   

tcp        0      0 192.168.100.246:10249   0.0.0.0:*               LISTEN      20482/kube-proxy

l  10249:http prometheus metrics port;

l  10256:http healthz port;

 

3.10.      查看 ipvs 路由規則
source /opt/k8s/bin/environment.sh
for node_ip in ${NODE_IPS[@]}
  do
    echo ">>> ${node_ip}"
    ssh root@${node_ip} "/usr/sbin/ipvsadm -ln"
  done

預期輸出:

>>> 192.168.100.246

IP Virtual Server version 1.2.1 (size=4096)

Prot LocalAddress:Port Scheduler Flags

  -> RemoteAddress:Port           Forward Weight ActiveConn InActConn

TCP  10.254.0.1:443 rr

  -> 192.168.100.246:6443         Masq    1      0          0        

  -> 192.168.100.247:6443         Masq    1      0          0        

  -> 192.168.100.248:6443         Masq    1      0          0        

>>> 192.168.100.247

IP Virtual Server version 1.2.1 (size=4096)

Prot LocalAddress:Port Scheduler Flags

  -> RemoteAddress:Port           Forward Weight ActiveConn InActConn

TCP  10.254.0.1:443 rr

  -> 192.168.100.246:6443         Masq    1      0          0        

  -> 192.168.100.247:6443         Masq    1      0          0        

  -> 192.168.100.248:6443         Masq    1      0          0        

>>> 192.168.100.248

IP Virtual Server version 1.2.1 (size=4096)

Prot LocalAddress:Port Scheduler Flags

  -> RemoteAddress:Port           Forward Weight ActiveConn InActConn

TCP  10.254.0.1:443 rr

  -> 192.168.100.246:6443         Masq    1      0          0        

  -> 192.168.100.247:6443         Masq    1      0          0        

  -> 192.168.100.248:6443         Masq    1      0          0

可見將所有到 kubernetes cluster ip 443 端口的請求都轉發到 kube-apiserver 的 6443 端口;

 

4.12 驗證集群功能

本文檔使用 daemonset 驗證 master 和 worker 節點是否工作正常。

 

注意:如果沒有特殊指明,本文檔的所有操作均在 master 節點上執行,然后遠程分發文件和執行命令。

 

1.      檢查節點狀態

kubectl get nodes

NAME     STATUS   ROLES    AGE     VERSION

master   Ready    <none>   4h35m   v1.12.3

node1    Ready    <none>   4h35m   v1.12.3

node2    Ready    <none>   4h35m   v1.12.3

都為 Ready 時正常。

 

2.      創建測試文件

cd /opt/k8s/work
cat > nginx-ds.yml <<EOF
apiVersion: v1
kind: Service
metadata:
  name: nginx-ds
  labels:
    app: nginx-ds
spec:
  type: NodePort
  selector:
    app: nginx-ds
  ports:
  - name: http
    port: 80
    targetPort: 80
---
apiVersion: extensions/v1beta1
kind: DaemonSet
metadata:
  name: nginx-ds
  labels:
    addonmanager.kubernetes.io/mode: Reconcile
spec:
  template:
    metadata:
      labels:
        app: nginx-ds
    spec:
      containers:
      - name: my-nginx
        image: nginx:1.7.9
        ports:
        - containerPort: 80
EOF

 

3.      執行定義文件

kubectl create -f nginx-ds.yml

 

4.      檢查各 Node 上的 Pod IP 連通性

kubectl get pods  -o wide|grep nginx-ds

nginx-ds-69hp5   1/1     Running   0          2m19s   172.30.8.5   node1    <none>

nginx-ds-rm744   1/1     Running   0          2m19s   172.30.48.7   master   <none>

nginx-ds-vpzk2   1/1     Running   0          2m19s   172.30.144.6   node2    <none>

 

可見,nginx-ds 的 Pod IP 分別是 172.30.8.5、172.30.48.7、172.30.144.6,在所有 Node 上分別 ping 這三個 IP,看是否連通:

source /opt/k8s/bin/environment.sh
for node_ip in ${NODE_IPS[@]}
  do
    echo ">>> ${node_ip}"
    ssh ${node_ip} "ping -c 1 172.30.8.5"
    ssh ${node_ip} "ping -c 1 172.30.48.7"
    ssh ${node_ip} "ping -c 1 172.30.144.6"
  done

 

5.      檢查服務 IP 和端口可達性

kubectl get svc |grep nginx-ds

nginx-ds     NodePort    10.254.242.170   <none>        80:30437/TCP   5m

 

可見:

l  Service Cluster IP:10.254.242.170

l  服務端口:80

l  NodePort 端口:30437

 

在所有 Node 上 curl Service IP:

source /opt/k8s/bin/environment.sh
for node_ip in ${NODE_IPS[@]}
  do
    echo ">>> ${node_ip}"
    ssh ${node_ip} "curl 10.254.242.170"
  done

預期輸出 nginx 歡迎頁面內容。

 

6.      檢查服務的 NodePort 可達性

在所有 Node 上執行:

source /opt/k8s/bin/environment.sh
for node_ip in ${NODE_IPS[@]}
  do
    echo ">>> ${node_ip}"
    ssh ${node_ip} "curl ${node_ip}:30437"
  done

預期輸出 nginx 歡迎頁面內容。

 

service ip(虛擬ip):

nodeport(虛擬ip):物理ip:nodeport虛擬端口

pod:fuent設置的網段的ip

 

五、部署集群插件

可視化自動化工具、日志收集

插件是集群的附件組件,豐富和完善了集群的功能。下面章節我們來學習一些常用的插件:

coredns

Dashboard

Heapster (influxdb、grafana)

Metrics Server

EFK (elasticsearch、fluentd、kibana)

 

5.1 dns 插件

特別重要:

source /opt/k8s/bin/environment.sh
for node_ip in ${NODE_IPS[@]}
  do
    echo ">>> ${node_ip}"
    ssh ${node_ip} "docker pull coredns/coredns:1.2.2 && docker tag coredns/coredns:1.2.2 k8s.gcr.io/coredns:1.2.2"
  done

注意:如果沒有特殊指明,本文檔的所有操作均在 master 節點上執行。

 

5.1.1.    修改配置文件

將下載的 kubernetes-server-linux-amd64.tar.gz 解壓后,再解壓其中的 kubernetes-src.tar.gz 文件。

coredns 對應的目錄是:cluster/addons/dns。

cd /opt/k8s/work/kubernetes/cluster/addons/dns/coredns
cp coredns.yaml.base coredns.yaml
source /opt/k8s/bin/environment.sh
sed -i -e "s/__PILLAR__DNS__DOMAIN__/${CLUSTER_DNS_DOMAIN}/" -e "s/__PILLAR__DNS__SERVER__/${CLUSTER_DNS_SVC_IP}/" coredns.yaml

 

5.1.2.    插件 coredns
kubectl create -f coredns.yaml

 

5.1.3.    檢查 coredns 功能
kubectl get all -n kube-system

NAME                           READY   STATUS             RESTARTS   AGE

pod/coredns-779ffd89bd-v75k9   0/1     ImagePullBackOff   0          4m54s

 

NAME               TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)         AGE

service/kube-dns   ClusterIP   10.254.0.2   <none>        53/UDP,53/TCP   4m54s

 

NAME                      DESIRED   CURRENT   UP-TO-DATE   AVAILABLE   AGE

deployment.apps/coredns   1         1         1            0           4m54s

 

NAME                                 DESIRED   CURRENT   READY   AGE

replicaset.apps/coredns-779ffd89bd   1         1         0       4m54sa

 

新建一個 Deployment

cd /opt/k8s/work
cat > my-nginx.yaml <<EOF
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  name: my-nginx
spec:
  replicas: 2
  template:
    metadata:
      labels:
        run: my-nginx
    spec:
      containers:
      - name: my-nginx
        image: nginx:1.7.9
        ports:
        - containerPort: 80
EOF
kubectl create -f my-nginx.yaml

 

 

Export 該 Deployment, 生成 my-nginx 服務:

kubectl expose deploy my-nginx

service "my-nginx" exposed

 

kubectl get services --all-namespaces |grep my-nginx

default       my-nginx     ClusterIP   10.254.206.78    <none>        80/TCP          7s

 

創建另一個 Pod,查看 /etc/resolv.conf 是否包含 kubelet 配置的 --cluster-dns 和 --cluster-domain,是否能夠將服務 my-nginx 解析到上面顯示的 Cluster IP 10.254.206.78

cd /opt/k8s/work
cat > dnsutils-ds.yml <<EOF
apiVersion: v1
kind: Service
metadata:
  name: dnsutils-ds
  labels:
    app: dnsutils-ds
spec:
  type: NodePort
  selector:
    app: dnsutils-ds
  ports:
  - name: http
    port: 80
    targetPort: 80
---
apiVersion: extensions/v1beta1
kind: DaemonSet
metadata:
  name: dnsutils-ds
  labels:
    addonmanager.kubernetes.io/mode: Reconcile
spec:
  template:
    metadata:
      labels:
        app: dnsutils-ds
    spec:
      containers:
      - name: my-dnsutils
        image: tutum/dnsutils:latest
        command:
          - sleep
          - "3600"
        ports:
        - containerPort: 80
EOF
kubectl create -f dnsutils-ds.yml

 

 

查看 pod 節點:

kubectl get pods
 
kubectl exec dnsutils-ds-9rm5v nslookup kubernetes

Server:         10.254.0.2

Address:        10.254.0.2#53

 

Name:   kubernetes.default.svc.cluster.local

Address: 10.254.0.1

kubectl exec dnsutils-ds-9rm5v nslookup www.baidu.com  # 解析外部域名時,需要以 . 結尾

Server:         10.254.0.2

Address:        10.254.0.2#53

 

Non-authoritative answer:

*** Can't find www.baidu.com: No answer

kubectl exec dnsutils-ds-9rm5v nslookup www.baidu.com.

Server:         10.254.0.2

Address:        10.254.0.2#53

 

Non-authoritative answer:

www.baidu.com   canonical name = www.a.shifen.com.

Name:   www.a.shifen.com

Address: 61.135.169.125

Name:   www.a.shifen.com

Address: 61.135.169.121

kubectl exec dnsutils-ds-9rm5v nslookup my-nginx

Server:         10.254.0.2

Address:        10.254.0.2#53

 

Name:   my-nginx.default.svc.cluster.local

Address: 10.254.229.163

kubectl exec dnsutils-ds-9rm5v nslookup kube-dns.kube-system.svc.cluster

Server:         10.254.0.2

Address:        10.254.0.2#53

 

Non-authoritative answer:

*** Can't find kube-dns.kube-system.svc.cluster: No answer

kubectl exec dnsutils-ds-9rm5v nslookup kube-dns.kube-system.svc

Server:         10.254.0.2

Address:        10.254.0.2#53

 

Name:   kube-dns.kube-system.svc.cluster.local

Address: 10.254.0.2

kubectl exec dnsutils-ds-9rm5v nslookup kube-dns.kube-system.svc.cluster.local

Server:         10.254.0.2

Address:        10.254.0.2#53

 

Non-authoritative answer:

*** Can't find kube-dns.kube-system.svc.cluster.local: No answer

kubectl exec dnsutils-ds-9rm5v nslookup kube-dns.kube-system.svc.cluster.local.

 

Server:         10.254.0.2

Address:        10.254.0.2#53

 

Name:   kube-dns.kube-system.svc.cluster.local

Address: 10.254.0.2

 

5.2 dashboard 插件

特別重要:

source /opt/k8s/bin/environment.sh
for node_ip in ${NODE_IPS[@]}
  do
    echo ">>> ${node_ip}"
    ssh ${node_ip} "docker pull registry.cn-hangzhou.aliyuncs.com/google_containers/kubernetes-dashboard-amd64:v1.8.3 && docker tag registry.cn-hangzhou.aliyuncs.com/google_containers/kubernetes-dashboard-amd64:v1.8.3 k8s.gcr.io/kubernetes-dashboard-amd64:v1.8.3"
  done

注意:如果沒有特殊指明,本文檔的所有操作均在 master 節點上執行。

 

修改配置文件

將下載的 kubernetes-server-linux-amd64.tar.gz 解壓后,再解壓其中的 kubernetes-src.tar.gz 文件。

 

dashboard 對應的目錄是:cluster/addons/dashboard。

cd /opt/k8s/work/kubernetes/cluster/addons/dashboard

 

5.2.1.    修改配置文件
cat dashboard-service.yaml
apiVersion: v1
kind: Service
metadata:
  name: kubernetes-dashboard
  namespace: kube-system
  labels:
    k8s-app: kubernetes-dashboard
    kubernetes.io/cluster-service: "true"
    addonmanager.kubernetes.io/mode: Reconcile
spec:
  type: NodePort # 增加這一行
  selector:
    k8s-app: kubernetes-dashboard
  ports:
  - port: 443
    targetPort: 8443

 

l  指定端口類型為 NodePort,這樣外界可以通過地址 nodeIP:nodePort 訪問 dashboard;

 

5.2.2.    執行所有定義文件
$ ls *.yaml
dashboard
-configmap.yaml dashboard-controller.yaml dashboard-rbac.yaml dashboard-secret.yaml dashboard-service.yaml $ kubectl create -f .

 

 

5.2.3.    查看分配的 NodePort
$ kubectl get deployment kubernetes-dashboard -n kube-system

NAME                   DESIRED   CURRENT   UP-TO-DATE   AVAILABLE   AGE

kubernetes-dashboard   1         1         1            1           2m

 
$ kubectl --namespace kube-system get pods -o wide

NAME                                    READY     STATUS    RESTARTS   AGE       IP             NODE              NOMINATED NODE

coredns-77cd44d8df-4fmfc                1/1       Running   0          1h        172.30.200.2   node2   <none>

kubernetes-dashboard-69db8c7745-jtvpj   1/1       Running   0          55s       172.30.112.3   master   <none>

 
$ kubectl get services kubernetes-dashboard -n kube-system

NAME                   TYPE       CLUSTER-IP     EXTERNAL-IP   PORT(S)         AGE

kubernetes-dashboard   NodePort   10.254.9.198   <none>        443:32014/TCP   1m

l  NodePort 32014 映射到 dashboard pod 443 端口;

 

dashboard 的 --authentication-mode 支持 token、basic,默認為 token。如果使用 basic,則 kube-apiserver 必須配置 '--authorization-mode=ABAC' 和 '--basic-auth-file' 參數。

 

5.2.4.    查看 dashboard 支持的命令行參數
kubectl exec --namespace kube-system -it kubernetes-dashboard-659798bd99-x5j6d  -- /dashboard --help # kubernetes-dashboard-659798bd99-x5j6d 為 pod 名稱

2019/04/01 13:12:03 Starting overwatch

Usage of /dashboard:

      --alsologtostderr                   log to standard error as well as files

      --apiserver-host string             The address of the Kubernetes Apiserver to connect to in the format of protocol://address:port, e.g., http://localhost:8080. If not specified, the assumption is that the binary runs inside a Kubernetes cluster and local discovery is attempted.

      --authentication-mode stringSlice   Enables authentication options that will be reflected on login screen. Supported values: token, basic. Default: token.Note that basic option should only be used if apiserver has '--authorization-mode=ABAC' and '--basic-auth-file' flags set. (default [token])

      --auto-generate-certificates        When set to true, Dashboard will automatically generate certificates used to serve HTTPS. Default: false.

      --bind-address ip                   The IP address on which to serve the --secure-port (set to 0.0.0.0 for all interfaces). (default 0.0.0.0)

      --default-cert-dir string           Directory path containing '--tls-cert-file' and '--tls-key-file' files. Used also when auto-generating certificates flag is set. (default "/certs")

      --disable-settings-authorizer       When enabled, Dashboard settings page will not require user to be logged in and authorized to access settings page.

      --enable-insecure-login             When enabled, Dashboard login view will also be shown when Dashboard is not served over HTTPS. Default: false.

      --heapster-host string              The address of the Heapster Apiserver to connect to in the format of protocol://address:port, e.g., http://localhost:8082. If not specified, the assumption is that the binary runs inside a Kubernetes cluster and service proxy will be used.

      --insecure-bind-address ip          The IP address on which to serve the --port (set to 0.0.0.0 for all interfaces). (default 127.0.0.1)

      --insecure-port int                 The port to listen to for incoming HTTP requests. (default 9090)

      --kubeconfig string                 Path to kubeconfig file with authorization and master location information.

      --log_backtrace_at traceLocation    when logging hits line file:N, emit a stack trace (default :0)

      --log_dir string                    If non-empty, write log files in this directory

      --logtostderr                       log to standard error instead of files

      --metric-client-check-period int    Time in seconds that defines how often configured metric client health check should be run. Default: 30 seconds. (default 30)

      --port int                          The secure port to listen to for incoming HTTPS requests. (default 8443)

      --stderrthreshold severity          logs at or above this threshold go to stderr (default 2)

      --system-banner string              When non-empty displays message to Dashboard users. Accepts simple HTML tags. Default: ''.

      --system-banner-severity string     Severity of system banner. Should be one of 'INFO|WARNING|ERROR'. Default: 'INFO'. (default "INFO")

      --tls-cert-file string              File containing the default x509 Certificate for HTTPS.

      --tls-key-file string               File containing the default x509 private key matching --tls-cert-file.

      --token-ttl int                     Expiration time (in seconds) of JWE tokens generated by dashboard. Default: 15 min. 0 - never expires (default 900)

  -v, --v Level                           log level for V logs

      --vmodule moduleSpec                comma-separated list of pattern=N settings for file-filtered logging

command terminated with exit code 2

 

5.2.5.    訪問 dashboard

為了集群安全,從 1.7 開始,dashboard 只允許通過 https 訪問,如果使用 kube proxy 則必須監聽 localhost 或 127.0.0.1,對於 NodePort 沒有這個限制,但是僅建議在開發環境中使用。

 

對於不滿足這些條件的登錄訪問,在登錄成功后瀏覽器不跳轉,始終停在登錄界面。

 

參考: https://github.com/kubernetes/dashboard/wiki/Accessing-Dashboard---1.7.X-and-above https://github.com/kubernetes/dashboard/issues/2540

 

  1. kubernetes-dashboard 服務暴露了 NodePort,可以使用 https://NodeIP:NodePort 地址訪問 dashboard;
  2. 通過 kube-apiserver 訪問 dashboard;
  3. 通過 kubectl proxy 訪問 dashboard:

 

如果使用了 VirtualBox,需要啟用 VirtualBox 的 ForworadPort 功能將虛機監聽的端口和 Host 的本地端口綁定。

 

1.  通過 kubectl proxy 訪問 dashboard

啟動代理:

kubectl proxy --address='localhost' --port=8086 --accept-hosts='^*$'

Starting to serve on 127.0.0.1:8086

l  --address 必須為 localhost 或 127.0.0.1;

l  需要指定 --accept-hosts 選項,否則瀏覽器訪問 dashboard 頁面時提示 “Unauthorized”;

瀏覽器訪問 URL:

http://47.92.173.105:8086/api/v1/namespaces/kube-system/services/https:kubernetes-dashboard:/proxy

 

2.5.2.  通過 kube-apiserver 訪問 dashboard

獲取集群服務地址列表:

kubectl cluster-info

Kubernetes master is running at https://192.168.100.246:8443

CoreDNS is running at https://192.168.100.246:8443/api/v1/namespaces/kube-system/services/kube-dns:dns/proxy

kubernetes-dashboard is running at https://192.168.100.246:8443/api/v1/namespaces/kube-system/services/https:kubernetes-dashboard:/proxy

 

To further debug and diagnose cluster problems, use 'kubectl cluster-info dump'.

 

l  由於 apiserver 通過本地的 kube-nginx 做了代理,所以上面顯示的 127.0.0.1:8443 為本地的 kube-nginx 的 IP 和 Port,瀏覽器訪問時需要替換為 kube-apiserver 實際監聽的 IP 和端口,如 192.168.100.246:6443;

l  必須通過 kube-apiserver 的安全端口(https)訪問 dashbaord,訪問時瀏覽器需要使用自定義證書,否則會被 kube-apiserver 拒絕訪問。

l  創建和導入自定義證書的步驟,參考:瀏覽器訪問kube-apiserver安全端口

 

瀏覽器訪問 URL:

https://192.168.100.246:6443/api/v1/namespaces/kube-system/services/https:kubernetes-dashboard:/proxy  對於 virtuabox 做了端口映射:

http://127.0.0.1:6443/api/v1/namespaces/kube-system/services/https:kubernetes-dashboard:/proxy/

 

 

 

5.2.6.    創建登錄 dashboard 的 token 和 kubeconfig 配置文件

上面提到,Dashboard 默認只支持 token 認證,所以如果使用 KubeConfig 文件,需要在該文件中指定 token,不支持使用 client 證書認證。

 

5.2.7.    創建登錄 token
kubectl create sa dashboard-admin -n kube-system
kubectl create clusterrolebinding dashboard-admin --clusterrole=cluster-admin --serviceaccount=kube-system:dashboard-admin
ADMIN_SECRET=$(kubectl get secrets -n kube-system | grep dashboard-admin | awk '{print $1}')
DASHBOARD_LOGIN_TOKEN=$(kubectl describe secret -n kube-system ${ADMIN_SECRET} | grep -E '^token' | awk '{print $2}')
echo ${DASHBOARD_LOGIN_TOKEN}

eyJhbGciOiJSUzI1NiIsImtpZCI6IiJ9.eyJpc3MiOiJrdWJlcm5ldGVzL3NlcnZpY2VhY2NvdW50Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9uYW1lc3BhY2UiOiJrdWJlLXN5c3RlbSIsImt1YmVybmV0ZXMuaW8vc2VydmljZWFjY291bnQvc2VjcmV0Lm5hbWUiOiJkYXNoYm9hcmQtYWRtaW4tdG9rZW4tOHE4bWoiLCJrdWJlcm5ldGVzLmlvL3NlcnZpY2VhY2NvdW50L3NlcnZpY2UtYWNjb3VudC5uYW1lIjoiZGFzaGJvYXJkLWFkbWluIiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9zZXJ2aWNlLWFjY291bnQudWlkIjoiMWU4NmM2ZmMtNTZkNy0xMWU5LWE5Y2EtMDAwYzI5NWJhMDYzIiwic3ViIjoic3lzdGVtOnNlcnZpY2VhY2NvdW50Omt1YmUtc3lzdGVtOmRhc2hib2FyZC1hZG1pbiJ9.CKm0cnBGmKvW19TdLWprxHqSAMYClIDRxfvMagA4_J_ogi2QGXQGWVcd9n0rV_QL_s98E1I3A2399aK-FJTBAw5ZyrwiyNVYYa8aSS3ROI7zyKr1xcubGCgvdKGv1WETTPjH6xcYGXhtdR0P6MReuqft6wX0ZucjmlaRtMjpEba_N4YmLG_YOI-qjziAqgE1vv9NU6DjWM8Enyh6cN6CzeI3qtEkt25PPFfE3BsGVMbpnkGyBgcJC-HKd_VafAxSYaG1xICxgDGPWc5PiMIq7sQSFbX4wZAnBIozFG8IBtzgxrFhSdaJS_MJROm5gYZf5mRezAJf-QRovX-e2xcfkQ

 

使用輸出的 token 登錄 Dashboard。

 

5.2.8.    創建使用 token 的 KubeConfig 文件
cd /opt/k8s/work
source /opt/k8s/bin/environment.sh
# 設置集群參數
kubectl config set-cluster kubernetes \
  --certificate-authority=/etc/kubernetes/cert/ca.pem \
  --embed-certs=true \
  --server=${KUBE_APISERVER} \
  --kubeconfig=dashboard.kubeconfig
 
# 設置客戶端認證參數,使用上面創建的 Token
kubectl config set-credentials dashboard_user \
  --token=${DASHBOARD_LOGIN_TOKEN} \
  --kubeconfig=dashboard.kubeconfig
 
# 設置上下文參數
kubectl config set-context default \
  --cluster=kubernetes \
  --user=dashboard_user \
  --kubeconfig=dashboard.kubeconfig
 
# 設置默認上下文
kubectl config use-context default --kubeconfig=dashboard.kubeconfig

用生成的 dashboard.kubeconfig 登錄 Dashboard。

 

 

由於缺少 Heapster 插件,當前 dashboard 不能展示 Pod、Nodes 的 CPU、內存等統計數據和圖表;

 

5.3  heapster 插件

特別重要:

source /opt/k8s/bin/environment.sh
for node_ip in ${NODE_IPS[@]}
  do
    echo ">>> ${node_ip}"
    ssh ${node_ip} "docker pull registry.cn-hangzhou.aliyuncs.com/google_containers/heapster-grafana-amd64:v4.4.3 && docker tag registry.cn-hangzhou.aliyuncs.com/google_containers/heapster-grafana-amd64:v4.4.3 gcr.io/google_containers/heapster-grafana-amd64:v4.4.3"
    ssh ${node_ip} "docker pull registry.cn-hangzhou.aliyuncs.com/google_containers/heapster-amd64:v1.5.3 && docker tag registry.cn-hangzhou.aliyuncs.com/google_containers/heapster-amd64:v1.5.3 gcr.io/google_containers/heapster-amd64:v1.5.3"
    ssh ${node_ip} "docker pull registry.cn-hangzhou.aliyuncs.com/google_containers/heapster-influxdb-amd64:v1.3.3 && docker tag registry.cn-hangzhou.aliyuncs.com/google_containers/heapster-influxdb-amd64:v1.3.3 gcr.io/google_containers/heapster-influxdb-amd64:v1.3.3"
  done

Heapster是一個收集者,將每個Node上的cAdvisor的數據進行匯總,然后導到第三方工具(如InfluxDB)。

 

Heapster 是通過調用 kubelet 的 http API 來獲取 cAdvisor 的 metrics 數據的。

 

由於 kublet 只在 10250 端口接收 https 請求,故需要修改 heapster 的 deployment 配置。同時,需要賦予 kube-system:heapster ServiceAccount 調用 kubelet API 的權限。

 

注意:如果沒有特殊指明,本文檔的所有操作均在 master 節點上執行。

 

5.3.1.    下載 heapster 文件

heapster release 頁面 下載最新版本的 heapster

cd /opt/k8s/work
wget https://github.com/kubernetes/heapster/archive/v1.5.4.tar.gz
tar -xzvf v1.5.4.tar.gz
mv v1.5.4.tar.gz heapster-1.5.4.tar.gz

官方文件目錄: heapster-1.5.4/deploy/kube-config/influxdb

 

5.3.2.    修改配置
cd heapster-1.5.4/deploy/kube-config/influxdb
cp grafana.yaml{,.orig}
 
diff grafana.yaml.orig grafana.yaml

67c67

<   # type: NodePort

---

>   type: NodePort

l  開啟 NodePort;

 

cp heapster.yaml{,.orig}
diff heapster.yaml.orig heapster.yaml

<         - --source=kubernetes:https://kubernetes.default

---

>         - --source=kubernetes:https://kubernetes.default?kubeletHttps=true&kubeletPort=10250

l  由於 kubelet 只在 10250 監聽 https 請求,故添加相關參數;

 

5.3.3.    執行所有定義文件
$ cd  /opt/k8s/work/heapster-1.5.4/deploy/kube-config/influxdb
$ ls *.yaml
grafana.yaml  heapster.yaml  influxdb.yaml
$ kubectl create -f  .
 
$ cd ../rbac/
$ cp heapster-rbac.yaml{,.orig}
$ diff heapster-rbac.yaml.orig heapster-rbac.yaml
12a13,26
> ---
> kind: ClusterRoleBinding
> apiVersion: rbac.authorization.k8s.io/v1beta1
> metadata:
>   name: heapster-kubelet-api
> roleRef:
>   apiGroup: rbac.authorization.k8s.io
>   kind: ClusterRole
>   name: system:kubelet-api-admin
> subjects:
> - kind: ServiceAccount
>   name: heapster
>   namespace: kube-system
 
$ kubectl create -f heapster-rbac.yaml

l  將 serviceAccount kube-system:heapster 與 ClusterRole system:kubelet-api-admin 綁定,授予它調用 kubelet API 的權限;

 

如果不修改,默認的 ClusterRole system:heapster 權限不足:

E1128 10:00:05.010716 1 manager.go:101] Error in scraping containers from kubelet:192.168.100.246:10250: failed to get all container stats from Kubelet URL "https://192.168.100.246:10250/stats/container/": request failed - "403 Forbidden", response: "Forbidden (user=system:serviceaccount:kube-system:heapster, verb=create, resource=nodes, subresource=stats)" E1128 10:00:05.018556 1 manager.go:101] Error in scraping containers from kubelet:172.27.128.149:10250: failed to get all container stats from Kubelet URL "https:// 192.168.100.247:10250/stats/container/": request failed - "403 Forbidden", response: "Forbidden (user=system:serviceaccount:kube-system:heapster, verb=create, resource=nodes, subresource=stats)" E1128 10:00:05.022664 1 manager.go:101] Error in scraping containers from kubelet:172.27.128.148:10250: failed to get all container stats from Kubelet URL "https:// 192.168.100.248:10250/stats/container/": request failed - "403 Forbidden", response: "Forbidden (user=system:serviceaccount:kube-system:heapster, verb=create, resource=nodes, subresource=stats)" W1128 10:00:25.000467 1 manager.go:152] Failed to get all responses in time (got 0/3)

 

5.3.4.    檢查執行結果
$ kubectl get pods -n kube-system | grep -E 'heapster|monitoring'
heapster-56c9dc749-j7hvz                1/1       Running   0          1m
monitoring-grafana-c797777db-lnwnc      1/1       Running   0          1m
monitoring-influxdb-cf9d95766-5wd28     1/1       Running   0          1m

 

檢查 kubernets dashboard 界面,可以正確顯示各 Nodes、Pods 的 CPU、內存、負載等統計數據和圖表:

 

 

5.3.5.    訪問 grafana
  1. 通過 kube-apiserver 訪問:

獲取 monitoring-grafana 服務 URL:

kubectl cluster-info

Kubernetes master is running at https://192.168.100.246:8443

Heapster is running at https://192.168.100.246:8443/api/v1/namespaces/kube-system/services/heapster/proxy

CoreDNS is running at https://192.168.100.246:8443/api/v1/namespaces/kube-system/services/kube-dns:dns/proxy

kubernetes-dashboard is running at https://192.168.100.246:8443/api/v1/namespaces/kube-system/services/https:kubernetes-dashboard:/proxy

monitoring-grafana is running at https://192.168.100.246:8443/api/v1/namespaces/kube-system/services/monitoring-grafana/proxy

monitoring-influxdb is running at https://192.168.100.246:8443/api/v1/namespaces/kube-system/services/monitoring-influxdb/proxy

 

To further debug and diagnose cluster problems, use 'kubectl cluster-info dump'.

 

瀏覽器訪問 URL:

https://192.168.100.246:8443/api/v1/namespaces/kube-system/services/monitoring-grafana/proxy

對於 virtuabox 做了端口映射:

http://127.0.0.1:8080/api/v1/namespaces/kube-system/services/monitoring-grafana/proxy

 

  1. 通過 kubectl proxy 訪問:

創建代理

kubectl proxy --address='192.168.100.246' --port=8086 --accept-hosts='^*$'

Starting to serve on 172.27.129.150:8086

 

瀏覽器訪問 URL:

http://192.168.100.246:8086/api/v1/namespaces/kube-system/services/monitoring-grafana/proxy/?orgId=1

對於 virtuabox 做了端口映射:

http://127.0.0.1:8086/api/v1/namespaces/kube-system/services/monitoring-grafana/proxy/?orgId=1

 

  1. 通過 NodePort 訪問:
kubectl get svc -n kube-system|grep -E 'monitoring|heapster'

heapster               ClusterIP   10.254.199.65    <none>        80/TCP          3m

monitoring-grafana     NodePort    10.254.116.161   <none>        80:31470/TCP    3m

monitoring-influxdb    ClusterIP   10.254.250.185   <none>        8086/TCP        3m

l  grafana 監聽 NodePort 31470;

 

瀏覽器訪問 URL:http://192.168.100.246:31470/?orgId=1

 

 

5.3.6.    參考
  1. 配置 heapster:https://github.com/kubernetes/heapster/blob/master/docs/source-configuration.md

 

 

5.4  metrics-server 插件

注意:如果沒有特殊指明,本文檔的所有操作均在 master 節點上執行。

 

5.4.1.    創建 metrics-server 使用的證書
cd /opt/k8s/work/cert
cat > metrics-server-csr.json <<EOF
{
  "CN": "aggregator",
  "hosts": [],
  "key": {
    "algo": "rsa",
    "size": 2048
  },
  "names": [
    {
      "C": "CN",
      "ST": "BeiJing",
      "L": "BeiJing",
      "O": "k8s",
      "OU": "study163"
    }
  ]
}
EOF

 

l  注意: CN 名稱為 aggregator,需要與 kube-apiserver 的 --requestheader-allowed-names 參數配置一致;

 

生成 metrics-server 證書和私鑰:

cfssl gencert -ca=/etc/kubernetes/cert/ca.pem \
  -ca-key=/etc/kubernetes/cert/ca-key.pem  \
  -config=/etc/kubernetes/cert/ca-config.json  \
  -profile=kubernetes metrics-server-csr.json | cfssljson -bare metrics-server
 

將生成的證書和私鑰文件拷貝到 kube-apiserver 節點:

source /opt/k8s/bin/environment.sh
for node_ip in ${NODE_IPS[@]}
  do
    echo ">>> ${node_ip}"
    scp metrics-server*.pem root@${node_ip}:/etc/kubernetes/cert/
  done
 
5.4.2.    修改 kubernetes 控制平面組件的配置以支持 metrics-server
5.4.2.1.  kube-apiserver

添加如下配置參數:

--requestheader-client-ca-file=/etc/kubernetes/cert/ca.pem

--requestheader-allowed-names=""

--requestheader-extra-headers-prefix="X-Remote-Extra-"

--requestheader-group-headers=X-Remote-Group

--requestheader-username-headers=X-Remote-User

--proxy-client-cert-file=/etc/kubernetes/cert/metrics-server.pem

--proxy-client-key-file=/etc/kubernetes/cert/metrics-server-key.pem

--runtime-config=api/all=true

l  --requestheader-XXX、--proxy-client-XXX 是 kube-apiserver 的 aggregator layer 相關的配置參數,metrics-server & HPA 需要使用;

l  --requestheader-client-ca-file:用於簽名 --proxy-client-cert-file 和 --proxy-client-key-file 指定的證書;在啟用了 metric aggregator 時使用;

l  如果 --requestheader-allowed-names 不為空,則--proxy-client-cert-file 證書的 CN 必須位於 allowed-names 中,默認為 aggregator;

 

如果 kube-apiserver 機器沒有運行 kube-proxy,則還需要添加 --enable-aggregator-routing=true 參數;

 

關於 --requestheader-XXX 相關參數,參考:

https://github.com/kubernetes-incubator/apiserver-builder/blob/master/docs/concepts/auth.md

https://docs.bitnami.com/kubernetes/how-to/configure-autoscaling-custom-metrics/

 

注意:requestheader-client-ca-file 指定的 CA 證書,必須具有 client auth and server auth;

 

5.4.2.2.  kube-controllr-manager

添加如下配置參數(從 v1.12 開始,該選項默認為 true,不需要再添加):

--horizontal-pod-autoscaler-use-rest-clients=true

用於配置 HPA 控制器使用 REST 客戶端獲取 metrics 數據。

 

5.4.3.    整體架構

暫缺

 

5.4.4.    修改插件配置文件配置文件

metrics-server 插件位於 kubernetes 的 cluster/addons/metrics-server/ 目錄下。

 

修改 metrics-server-deployment 文件:

$ cp metrics-server-deployment.yaml{,.orig}
$ diff metrics-server-deployment.yaml.orig metrics-server-deployment.yaml

51c51

<         image: mirrorgooglecontainers/metrics-server-amd64:v0.2.1

---

>         image: k8s.gcr.io/metrics-server-amd64:v0.2.1

54c54

<         - --source=kubernetes.summary_api:''

---

>         - --source=kubernetes.summary_api:https://kubernetes.default?kubeletHttps=true&kubeletPort=10250

60c60

<         image: siriuszg/addon-resizer:1.8.1

---

>         image: k8s.gcr.io/addon-resizer:1.8.1

l  metrics-server 的參數格式與 heapster 類似。由於 kubelet 只在 10250 監聽 https 請求,故添加相關參數;

 

授予 kube-system:metrics-server ServiceAccount 訪問 kubelet API 的權限:

$ cat auth-kubelet.yaml

apiVersion: rbac.authorization.k8s.io/v1

kind: ClusterRoleBinding

metadata:

  name: metrics-server:system:kubelet-api-admin

  labels:

    kubernetes.io/cluster-service: "true"

    addonmanager.kubernetes.io/mode: Reconcile

roleRef:

  apiGroup: rbac.authorization.k8s.io

  kind: ClusterRole

  name: system:kubelet-api-admin

subjects:

- kind: ServiceAccount

  name: metrics-server

  namespace: kube-system

l  新建一個 ClusterRoleBindings 定義文件,授予相關權限;

 

5.4.5.    創建 metrics-server
$ cd /opt/k8s/kubernetes/cluster/addons/metrics-server
$ ls -l *.yaml

-rw-rw-r-- 1 k8s k8s  398 Jun  5 07:17 auth-delegator.yaml

-rw-rw-r-- 1 k8s k8s  404 Jun 16 18:02 auth-kubelet.yaml

-rw-rw-r-- 1 k8s k8s  419 Jun  5 07:17 auth-reader.yaml

-rw-rw-r-- 1 k8s k8s  393 Jun  5 07:17 metrics-apiservice.yaml

-rw-rw-r-- 1 k8s k8s 2640 Jun 16 17:54 metrics-server-deployment.yaml

-rw-rw-r-- 1 k8s k8s  336 Jun  5 07:17 metrics-server-service.yaml

-rw-rw-r-- 1 k8s k8s  801 Jun  5 07:17 resource-reader.yaml

 

$ kubectl create -f .

 

5.4.6.    查看運行情況
$ kubectl get pods -n kube-system |grep metrics-server
metrics-server-v0.2.1-7486f5bd67-v95q2   2/2       Running   0          45s
 
$ kubectl get svc -n kube-system|grep metrics-server
metrics-server         ClusterIP   10.254.115.120   <none>        443/TCP         1m

 

5.4.7.    查看 metrcs-server 輸出的 metrics

metrics-server 輸出的 APIs:

https://github.com/kubernetes/community/blob/master/contributors/design-proposals/instrumentation/resource-metrics-api.md

 

  1. 通過 kube-apiserver 或 kubectl proxy 訪問:

https://192.168.100.246:6443/apis/metrics.k8s.io/v1beta1/nodes https://192.168.100.246:6443/apis/metrics.k8s.io/v1beta1/nodes/ https://192.168.100.246:6443/apis/metrics.k8s.io/v1beta1/pods https://192.168.100.246:6443/apis/metrics.k8s.io/v1beta1/namespace//pods/

 

  1. 直接使用 kubectl 命令訪問:

 

kubectl get --raw apis/metrics.k8s.io/v1beta1/nodes kubectl get --raw apis/metrics.k8s.io/v1beta1/pods kubectl get --raw apis/metrics.k8s.io/v1beta1/nodes/ kubectl get --raw apis/metrics.k8s.io/v1beta1/namespace//pods/

 

$ kubectl get --raw "/apis/metrics.k8s.io/v1beta1" | jq .

{

  "kind": "APIResourceList",

  "apiVersion": "v1",

  "groupVersion": "metrics.k8s.io/v1beta1",

  "resources": [

    {

      "name": "nodes",

      "singularName": "",

      "namespaced": false,

      "kind": "NodeMetrics",

      "verbs": [

        "get",

        "list"

      ]

    },

    {

      "name": "pods",

      "singularName": "",

      "namespaced": true,

      "kind": "PodMetrics",

      "verbs": [

        "get",

        "list"

      ]

    }

  ]

}

 

$ kubectl get --raw "/apis/metrics.k8s.io/v1beta1/nodes" | jq .

{

  "kind": "NodeMetricsList",

  "apiVersion": "metrics.k8s.io/v1beta1",

  "metadata": {

    "selfLink": "/apis/metrics.k8s.io/v1beta1/nodes"

  },

  "items": [

    {

      "metadata": {

        "name": "node2",

        "selfLink": "/apis/metrics.k8s.io/v1beta1/nodes/node2",

        "creationTimestamp": "2018-06-16T10:24:03Z"

      },

      "timestamp": "2018-06-16T10:23:00Z",

      "window": "1m0s",

      "usage": {

        "cpu": "133m",

        "memory": "1115728Ki"

      }

    },

    {

      "metadata": {

        "name": "master",

        "selfLink": "/apis/metrics.k8s.io/v1beta1/nodes/master",

        "creationTimestamp": "2018-06-16T10:24:03Z"

      },

      "timestamp": "2018-06-16T10:23:00Z",

      "window": "1m0s",

      "usage": {

        "cpu": "221m",

        "memory": "6799908Ki"

      }

    },

    {

      "metadata": {

        "name": "node1",

        "selfLink": "/apis/metrics.k8s.io/v1beta1/nodes/node1",

        "creationTimestamp": "2018-06-16T10:24:03Z"

      },

      "timestamp": "2018-06-16T10:23:00Z",

      "window": "1m0s",

      "usage": {

        "cpu": "76m",

        "memory": "1130180Ki"

      }

    }

  ]

}

 

l  /apis/metrics.k8s.io/v1beta1/nodes 和 /apis/metrics.k8s.io/v1beta1/pods 返回的 usage 包含 CPU 和 Memory;

 

5. 5  EFK 插件

EFK 對應的目錄:kubernetes/cluster/addons/fluentd-elasticsearch

$ cd /opt/k8s/work/kubernetes/cluster/addons/fluentd-elasticsearch
$ ls *.yaml
es-service.yaml  es-statefulset.yaml  fluentd-es-configmap.yaml  fluentd-es-ds.yaml  kibana-deployment.yaml  kibana-service.yaml
 

注意:如果沒有特殊指明,本文檔的所有操作均在 master 節點上執行。

 

5.5.1.    拉取鏡像

注意:因為elk插件使用的是谷歌鏡像,由於眾所周知的原因我們無法使用,只能通過先拉去對於的其他公開鏡像然后改名。或者直接修改yml文件中定義的谷歌鏡像名(推薦使用第一種)。

source /opt/k8s/bin/environment.sh
for node_ip in ${NODE_IPS[@]};   
  do     
    echo ">>> ${node_ip}";     
    ssh ${node_ip} "docker pull xiaochunping/elasticsearch:v6.2.5 && docker tag xiaochunping/elasticsearch:v6.2.5 k8s.gcr.io/elasticsearch:v6.2.5"; 
    ssh ${node_ip} "docker pull xiaochunping/fluentd-elasticsearch:v2.2.0 && docker tag xiaochunping/fluentd-elasticsearch:v2.2.0 k8s.gcr.io/fluentd-elasticsearch:v2.2.0";   
  done

命令只需要在master節點上執行即可。

 

5.5.2.          給 Node 設置標簽

DaemonSet fluentd-es 只會調度到設置了標簽 beta.kubernetes.io/fluentd-ds-ready=true 的 Node,需要在期望運行 fluentd 的 Node 上設置該標簽;

$ kubectl get nodes

NAME         STATUS    ROLES     AGE       VERSION

master   Ready     <none>    3d        v1.10.4

node1   Ready     <none>    3d        v1.10.4

node2   Ready     <none>    3d        v1.10.4

 

$ kubectl label nodes node2 beta.kubernetes.io/fluentd-ds-ready=true

node "node2" labeled

 

5.5.3.          執行定義文件
$ cd /opt/k8s/kubernetes/cluster/addons/fluentd-elasticsearch
 
$ ls *.yaml
es-service.yaml  es-statefulset.yaml  fluentd-es-configmap.yaml  fluentd-es-ds.yaml  kibana-deployment.yaml  kibana-service.yaml
 
$ kubectl create -f .

 

5.5.4.    檢查執行結果
$ kubectl get pods -n kube-system -o wide|grep -E 'elasticsearch|fluentd|kibana'

elasticsearch-logging-0                  1/1       Running   0          5m        172.30.81.7   master

elasticsearch-logging-1                  1/1       Running   0          2m        172.30.39.8   node2

fluentd-es-v2.0.4-hntfp                  1/1       Running   0          5m        172.30.39.6   node2

kibana-logging-7445dc9757-pvpcv          1/1       Running   0          5m        172.30.39.7   node2

 

$ kubectl get service  -n kube-system|grep -E 'elasticsearch|kibana'

elasticsearch-logging   ClusterIP   10.254.50.198    <none>        9200/TCP        5m

kibana-logging         ClusterIP   10.254.255.190   <none>        5601/TCP        5m

 

kibana Pod 第一次啟動時會用**較長時間(0-20分鍾)**來優化和 Cache 狀態頁面,可以 tailf 該 Pod 的日志觀察進度:

$ kubectl logs kibana-logging-7445dc9757-pvpcv -n kube-system -f

{"type":"log","@timestamp":"2018-06-16T11:36:18Z","tags":["info","optimize"],"pid":1,"message":"Optimizing and caching bundles for graph, ml, kibana, stateSessionStorageRedirect, timelion and status_page. This may take a few minutes"}

{"type":"log","@timestamp":"2018-06-16T11:40:03Z","tags":["info","optimize"],"pid":1,"message":"Optimization of bundles for graph, ml, kibana, stateSessionStorageRedirect, timelion and status_page complete in 224.57 seconds"}

 

注意:只有當的 Kibana pod 啟動完成后,才能查看 kibana dashboard,否則會提示 refuse。

 

5.5.5.    訪問 kibana
  1. 通過 kube-apiserver 訪問:
$ kubectl cluster-info|grep -E 'Elasticsearch|Kibana'

Elasticsearch is running at https://192.168.100.246:6443/api/v1/namespaces/kube-system/services/elasticsearch-logging/proxy

Kibana is running at https://192.168.100.246:6443/api/v1/namespaces/kube-system/services/kibana-logging/proxy

 

瀏覽器訪問 URL:

https://192.168.100.246:6443/api/v1/namespaces/kube-system/services/kibana-logging/proxy

對於 virtuabox 做了端口映射:

http://127.0.0.1:8080/api/v1/namespaces/kube-system/services/kibana-logging/proxy

 

  1. 通過 kubectl proxy 訪問:

創建代理

$ kubectl proxy --address='192.168.100.246' --port=8086 --accept-hosts='^*$'
Starting to serve on 172.27.129.150:8086

 

瀏覽器訪問 URL:

http://192.168.100.246:8086/api/v1/namespaces/kube-system/services/kibana-logging/proxy 

對於 virtuabox 做了端口映射:

http://127.0.0.1:8086/api/v1/namespaces/kube-system/services/kibana-logging/proxy

 

在 Settings -> Indices 頁面創建一個 index(相當於 mysql 中的一個 database),選中 Index contains time-based events,使用默認的 logstash-* pattern,點擊 Create ;

 

 

創建 Index 后,稍等幾分鍾就可以在 Discover 菜單下看到 ElasticSearch logging 中匯聚的日志;

 

 

 

 

 

六、結合k8s的系統整體監控方案、業務部屬系統

 

 

七、xx公司的探索和實踐

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM