# KK 讀書會 ## 下周導讀: 經喬 會議記錄: 耀銘 ### 導讀讀書紀錄-耀銘 <<筆記>> <<問關貿事項>> ETCD問題處理(如備份,災後復原..等等) 安裝參考文件 install遇到的異常 命名規劃,如lables多時 平常監控哪些指標 資源告警機制、巡檢? k8s程式管控版本(集群配置文件,正/測),operator等。。 還有哪些集群需區分 <<討論事項>> <<ToDo>> - 試 token list 的指令? - Webhook配置文件需mount 進 Pod ? - Role 和 ClusterRole 的 roles 的[Resources設定細節(如pods, secrets) ]? - Role binding中設定roleRef的原因, 是有提到(引用ClusterRole)? - 了解群組授權中的 name ? - p29頁 透過 ssh進去到master , 通過inscure port訪問是否可關閉?(例如8080) - 細部了解 準入控制 ? ### 導讀讀書紀錄-經喬 <<筆記>> 1. ![](https://hackmd.io/_uploads/By8foeZxa.png) 2. 控制面:管理組件 數據面:應用 > 終端用戶 認證:是誰 鑒權:操作權限 准入: Mutating:變形 Validating:校驗 Admission: 限流: 3. webhook:編寫如何變形的邏輯 max-in-flight:請求上限 4. RBAC老圖 ![](https://hackmd.io/_uploads/H1Skxm-ga.png) 每個角色至少具備一個權限,每個使用者至少扮演一個角色;可以對兩個完全不同的角色分配完全相同的存取權限;會話由使用者控制,一個使用者可以創建會話並啟動多個使用者角色,從而獲取 相應的存取權限,使用者可以在會話中更改啟動角色,並且使用者可以主動結束一個會話。 使用者和角色是多對多的關係,表示一個使用者在不同的場景下可以有不同的角色。 例如專案經理也可以是專案架構師等;當然了一個角色可以給多個用戶,例如一個專案中有多個組長,多個組員等。 ------------- <<問關貿事項>> ### 0926關貿分享 - 由永成分享先(Rex) - 有分享rancher拍照(\\ec-nas\share_emp\技術分享\訓練\99_分享_極客雲原生\關貿分享) - CI的部分之後待建置,佈署時再安排分享 - Rancher不錯之處(要自已維持3個版本內就ok..很重要) - k8s只保證三版內. - 用opensuse 是因為有support(有enterprise) - 170那台有rancher.sh可以安裝rancher(有圖) - 手動有建,但ubuntu 20.04 OS 升級時=>22.4, k8s掛了。 - 因為os 和 k8s有些底層有連結(但k8s可能沒接上),就掛了 - 但rancher這部分都有自動cover到, 所以直接用rancher就沒問題. - 建議使用Rancher ,不要使用手動踩坑。(也可用kubespray) - 會提供kubeadm安裝的md,但只有裝ubuntu 22.04 ok - 裝 Opesuse leap 15.5 (kubernetes只到 1.24 ) 所以, 那段未試完成!!!僅供參考(InstallK8sByKubeadm.pdf) - 由我們自已測看看 ubuntu 安裝.. - 文件分享: 1. \\\ec-nas\share_emp\技術分享\訓練\99_分享_極客雲原生\關貿分享\InstallK8sByKubeadm.pdf 2. \\\ec-nas\share_emp\技術分享\訓練\99_分享_極客雲原生\關貿分享\WSL2-RancherDesktop.pdf ![](https://hackmd.io/_uploads/BkFeZ-bgp.png) https://rancher.com/docs/rancher/latest/zh/ <<討論事項>> ### 導讀讀書紀錄-佑安 <<筆記>> <<問關貿事項>> 1. 架設K8S遇到什麼問題? 2. 運行時有遇到什麼問題?怎麼解決? 1) 頻繁的leader election 2) etcd分裂 3) etcd沒反應 4) 與apiserver之間阻塞 5) 磁碟暴漲 => etcd硬碟空間要設定多大?多久備份一次? 3. 每個服務使用多少POD?有無建議的準則或公式? 4. CPU、記憶體、硬碟、頻寬分別使用什麼?運行時使用量多少?有無特定變化需要注意? 5. 資料夾權限設定? 6. 程式派送上線有遇到什麼困難?怎麼解決? 7. 有無限定每個用戶使用的資源量?怎麼做到的? 8. 使用什麼UI進行控管? <<討論事項>> # 導讀紀錄 ## ◼ 2023-10-11 調度器和控制器 ### 筆記 ### 讀書紀錄-佑安 #### kube-scheduler 是K8S中負責集群中的工作附載運行調度,會根據各種因素,將POD分配給集群中的節點。 監聽kube-apiserver,查詢還未分配NODE的POD,依據調度策略分配節點(更新POD的NODENAME字段)。 ##### 考量因素: 1.公平調度 (節點資源使用情況,避免資源過度集中或分散) 2.資源高校利用 3.QoS(Quality of Service,服務質量,一種衡量網絡性能的標準,其目的是為了保證在網絡中傳輸的數據能夠得到一定的性能保證。) 3.親和性和反親和性規則 4.資料位置 => 本地化 5.工作附載間的依賴關係 => 內部附載干擾 6.deadlines ##### 工作原理: 通過分析集群的當前狀態,包括各節點的資源使用情況(如CPU、記憶體和存儲),以及其他因素(如節點故障、網絡拓撲和Pod的資源需求)來做出決策。kube-scheduler會根據預定義的排程策略和算法,以及任何自定義的排程策略,來確定最佳的節點選擇。 此外,支持多種可擴展的排程功能,允許開發人員和操作人員根據特定的需求和政策定制Pod的排程行為。 分為兩個階段: 1.predicat:過濾不符合條件的節點 2.priority:優先級排序,選擇優先級最高的節點 ##### predicat策略: PodFitsHostPorts:檢查是否有Host Ports衝突。 PodFitsPorts:同PodFitsHostPorts。 PodFitsResources:檢查Node的資源是否充足,包括允許的Pod數量、CPU、記憶體、GPU個數、其他的OpaqueIntResources。 HostName:檢查pod.Spec.NodeName是否與候選點一致 MatchNodeSelector:檢查候選節點的pod.Spec.NodeSelector是否匹配 NoVolumeZoneConflict:檢查Volume zone是否衝突 MatchInterPodAffinity:檢查是否匹配POD的親和性要求。 NoDiskConflict:檢查是否存在Volume衝突,僅限於GCE PD、AWS EBS、Ceph RBD以及 iSCSI PodToleratesNodeTaints:檢查POD是否容忍Node Taints。 CheckNodeMemoryPressure:檢查POD是否可調度到MemoryPressure的節點上。 CheckNodeDiskPressure:檢查POD是否可調度到DiskPressure的節點上。 NoVolumeNodeConflict:檢查節點是否滿足POD所引用的Volume條件。 其他很多策略,可自己編寫 ##### predicat plugin工作原理: 當一個插件進來,會先將所有節點全部列出,然後用上述的策略一個一個進行過濾,到最後剩下的就是可選擇的節點 ##### priorities策略 SelectorSpreadPriority:(盡量分散)優先減少節點上屬於同一個Service或Replication Controlller的Pod數量。 InterPodAffinityPriority:優先將Pod調度到相同的拓樸上 LeastRequestedPriority:優先調度到請求資源減少的節點 BalancedResourceAllocation:優先平衡各節點的資源使用 NodePreferAvoidPodsPriority:alpha.kubernetes.io/preferAvoidPods 判斷,權重為10000,避免其他優先級策略的影響。 NodeAffinityPriority:優先調度到匹配NodeAffinity的節點上 TaintTolerationPriority:優先調度到匹配TaintToleration的節點上 ServiceSpreadingPriority:盡量將同一個service的pod分布到不同節點上,已被SelectorSpreadPriority替代(預設不使用) EqualPriority:將所有節點的優先權設置為1(預設不使用) ImageLocalityPriority:盡量將使用大鏡像的容器調度到已抓取該鏡像的節點上(預設不使用) NodeRequestedPriority:盡量調度到已使用過的Node上,特別適用於cluster-autoscaler(預設不使用) ##### priorities plugin工作原理: 當一個插件進來都會打分,打分方式針對每個優先權策略進行分數評估,打完的分數乘上此策略的權重,全部相加之後得到的一個優先分數,越高的越優先執行。 ##### QoS (Quality of Service,服務質量)是一種衡量網絡性能的標準,其目的是為了保證在網絡中傳輸的數據能夠得到一定的性能保證。 1.帶寬保證:通過保證一定的網絡帶寬,以確保數據傳輸的速度和效率。 2.延遲:控制和減少數據傳輸的延遲,確保數據能夠及時到達目的地。 3.抖動(Jitter):減少網絡抖動,即減少延遲的變化,以提供更加穩定的網絡性能。 4.丟包率:通過控制丟包率,以減少需要重新傳輸的數據包,從而提高網絡效率。 5.錯誤率:減少網絡中的錯誤率,以確保數據的準確性和完整性。 6.優先級和策略:為不同類型的流量設定不同的優先級和策略,以確保關鍵應用和服務能夠得到優先的網絡資源。 ##### affinity和anti-affinity Affinity(親和性)和 Anti-affinity(反親和性)是在集群環境中,特別是在 Kubernetes(K8s)這類的容器編排系統中,用來指導 Pod 如何被排程到節點(Node)上的一組規則。 Affinity(親和性): 親和性規則用於將某些 Pods 吸引到一組特定的節點上。這意味著,當符合親和性規則時,這些 Pods 會被優先排程到這些節點上。例如,如果有兩個相互依賴的 Pods,親和性規則可以幫助將它們排程到同一節點或相鄰節點上,以減少網絡延遲並提高效率。 Anti-affinity(反親和性): 反親和性規則則是用於將某些 Pods 排除在一組特定的節點之外。這意味著,當符合反親和性規則時,這些 Pods 會被排程到遠離這些節點的其他節點上。例如,為了提高服務的可用性和容錯性,反親和性規則可以幫助確保相同應用的多個實例不會被排程到同一節點上。 ##### 硬碟資源需求 容器的臨時儲存,可通過定義pod spec中limit.ephemeral-storage(限制)和request.ephemeral-storage(需求)來申請 Pod調度完成後,計算節點臨時儲存的限制不是基於CGroup,而是透過Kubelet定時取得容器日誌與可寫層的硬碟使用狀況,若超過限制,則會驅除Pod ##### Init Container的資源需求 調度帶有多個init容器的Pod時,只計算cpu.request最多的init容器 多個init容器按照順序執行,執行完畢立即退出 => 針對申請最多資源的init容器申請所需資源即可滿足所有init容器需求。 計算該節點被占用的的資源時,即使init容器已經被退出了,init容器資源依然被納入計算,因為init在特定情況下會被再次執行。 ##### 把Pod調度到指定Node上 可透過nodeSelector、nodeAffinity、podAffinity、Taints、tolerations設定 還可以通過設定nodeName來將Pod調度到指定Node上。 ##### 多調度器 預設的調度器無法滿足需求時,可以佈署自定義的調度器。且整個集群可同時使用多個調度器,通過podSpec.schedulerName來選擇使用哪個調度器(預設使用內建的調度器)。 ##### 來自工作的經驗 用戶會忘記打tolerance,導致pod無法調度 新員工常犯的錯誤,可透過聊天機器人的Q&A解決 小集群:100個node開發創建到8000個pod的最大調度消耗大約2分鐘,發生過刪除node後schedult cache還有資料的情況下會導致Pod調度失敗。 放大效應:當node出現問題所以load較小時,通常用戶的pod都會優先調度到此node上,導致失敗。 應用炸彈:存在危險有問題的用戶Pod,在調度到某個node上之後,會導致node當機,此pod會被驅逐到其他node上,導致其他node也掛掉,最後所有node都不能用了。 #### Controller Manager 其實是一堆Controller組合在一起。 ##### Cloud Controller Manager 使得k8s能夠在各種雲平台(如AWS、Azure和GCP)上運行,並利用雲提供商提供的基礎設施服務。 通常需要:授權認證、在K8S中有正確的RBAC設定,才能取得操作權限、要通過leader election確保其高可用。 ##### Cloud Controller Manager 設定 從老版本的APIServer分離出來的, 為了確保執行的Controller Manager是採用雲端的,相關設定必須注意,否則就會去自動下載安裝在本地。 主要支持:node controller、Service controller、Route controller、...自定義cloud controller ##### 需要訂製的cloud controller ingress controller service controller 自製controller,如RBAC、Account ##### 來自工作的經驗 保護好Controller Manager的kubeconfig:此文件擁有所有資源的操作權限,防止普通用戶通過kubectl exec kube-controller-manager cat去取得此文件。用戶可能做出很特殊的操作出現問題後找你支援。 pod evict後ip改變了,但endpoint中的address更新失敗:分析stacktrace發現endpoint更新LoadBalancer時調用gophercloud連接發生hang住,導致endpoint worker線程全部卡死。 ##### Leader Election 取得key後將自己的身分、取得key的時間、更新時間寫進去, 當有競爭者出現時,會先判斷key的租期是否到了(acquireTime + leaseDurationSeconds 是否超過 renewTime),租期未到就不能更新key,也就不能替換leader 如果租期已到,則開始競選leader 如此確保每次只有一個leader #### kubelet ProbeManager:用来监测集群中 Pod 的健康状态。 1.把節點狀態放上去(每個節點都有kubelet) 2.接收API指令去控制POD的生命週期 3.看看還活著沒 指針種類: 1)Liveness Probe:此探针检测应用程序是否健康。如果应用程序不健康,Kubernetes 会删除 Pod 并启动一个新的替换它,从而实现自我修复。 2)Readiness Probe:告诉 Kubernetes 何时可以将容器加入到 Service 负载均衡中,对外提供服务。 3)从 1.16 版本开始支持的,主要用于检测慢启动容器的状态 OOMWatcher: 用於監控和記錄系統的Out Of Memory (OOM)事件。如果檢測到系統OOM事件,則會記錄一個event事件。對於容器的OOM狀態,Kubernetes使用Docker的狀態State.OOMKilled來判斷是否經歷了OOM事件。 kubelet啟動時OOMWatcher會創建兩個goroutine,一個作為OOM事件的生產者,另一個作為OOM事件的消費者。這兩個goroutine通過channel進行數據傳輸,OOMWatcher負責記錄系統OOM並將這些記錄到節點的event。 及時捕捉和處理系統和容器的記憶體不足問題,並通過記錄和報告OOM事件,協助系統管理員和開發人員更好地理解和解決記憶體相關的問題。 GPUMAnager:GPU管理器 cAdvisor:提供容器使用者和性能特性的分析和監視。 DiskSpaceManager:查看儲存空間夠不夠 StatusManager:查看節點狀態 EvictionManager:環境資源不足時要驅逐POD,用什麼行為驅逐 VolumeManager: Image GC:清理不再需要的容器image Container GC:清理不再需要的容器 ImageManager: CertificateManager: CRI gRPC Server:起POD時通過CRI執行 CRI有兩套: 1)docker shim:使K8S可以通過標準接口與Docker進行交互 2)remote Container Runtime:輕量級的控制器 Container Network Plugin: ##### 管理POD的核心流程 每個節點的POD是有設定上限的 ##### kubelet ##### POD啟動流程 POD是一組容器的組合,會共享一些系統層面的資源 先啟一個沙盒叫pause再啟容器,永遠睡眠的thread,因此不消耗資源,image很小,不消耗記憶體CPU,極度穩定的進程 此為一個底座,理想運行下不會出錯,所有網路配置會在這裡,以此達到極度穩定。 nginx是有邏輯有開銷,執行時都會消耗資源,因此有問題的機率較高。 在主容器啟動時需要有網路就緒,因此需要這個沙盒。 ##### CRI (Container Runtime Interface,容器運行時接口) 容器運行時每個集群傑點中負責容器整個生命週期。 在kubernetes 1.5時推出用於支持更多容器運行。 為gRPC服務 高層級及時運行:當Dockershim/containerd/CRI-O都遵循CRI運行時 ##### OCI(Open Container Initiative,開放容器倡議) 定義容器格式和執行時的開源行業標準,包括鏡像與及時的規範 鏡像規範(Image Specification):執行:將下載的OCI鏡像解壓成filesystem bundle 及時規範(Runtime Specification):上下連接 ##### CNI(Container Network Interface,容器網路接口) 是一個由CNCF(Cloud Native Computing Foundation,雲原生計算基金會)主導的項目,旨在提供一個通用的、標準化的插件接口,以允許不同的容器運行時技術與各種網路解決方案進行交互。 POD不用通過NAT就可相互訪問 節點能不通過NAT就可相互訪問 容器內看見的IP與外部組件看到的容器IP相同 ##### CNI插件運行機制 # 導讀紀錄 ## ◼ 2023-10-11 ### 筆記 ### 讀書紀錄-耀銘 ### [CNI插件分類與常見插件] - ip分配:ipam 分配 - 3個網路問題:容器/主機, 同一主機內容器/容器, 跨主機 - 主插件:網卡。bridge(主機port,容器port 加入網橋)=>容器加ipvlan網口=>設loopback網口 - meta:附加功能:portmap(如設snam=true,portmappings:true), bandwidth(限流,linux traffic contrl),firewall(iptables或firewall) - ### CNI 插件運行機制 - 例子: - 每台主機都有/etc/cni/net.d/ <=CNI插件 - cni-conf-dir =>看10-calico.conlist=>只顯示配置 - 有cniVersion, plugins (type, ipam=>calico-ipam,ipv4, bandwith:true),portmap - cni-bin-di =>實際定義的內容=>看/opt/cni/bin (有 calico, calico-ipam, bandth) - 實際是運行上方的可執行文件. - 插件實作:建網路/刪網路 - cni-conf-dir , cni-bin-dir 要配置 - 特殊: 即kubelet內置docker運行時. 是由kubelet查找CNI,所以這二個參數在Kubelet那兒. ### CNI 設計考量 - 插件前要先建一個網路命名空間(sandbox) <==看module 3 - 讀配置文件. - 按順序執行 - ADD , DEL(tear down) 操作 - [不是透過參數]如calico ADD =>帶屬於那個pod, 容器sandbox 網路的NS,ADDorDEL =>透過[環境變量] - 所以, 先全設[環境變量] =>插件再調用 - ADD 只能一個 , del 可多次 ### 打通主機網路 - 除CNI插件外, 還有[標準的cni插件Io,最低為0.2.0版) - 機制: 2個簡單port => runtime告訢CNI插件(target , operation)=>CNI進行工作配置. - 就如:module3 起pod時 - runtime 調CNI=>調ipam(分到一個ip)=>主插件(將ip配給該容器的NS)=>network bandwidth插件會限制頻=>回報runtime=>runtime將配置帶回kubelet=>kubelet上報api server=>api server 更新 ETCD 內pod 狀態(更新ip)===>就get得到Ip 了. ### CNI plugin - calico - cilium , 看好它, 但規模不如calico大==>對內核, 走TC , SDP ,更輕量; 一籃解決 ### Fannel:coreOS - 用VxLAN(每個設備會有 tunnel device ,包進出時會加/解) - 經過tunnel做的 - 10%網路開銷=>網路效率注重的不用這個 - 只作插件, 沒有整個生態(如network policy沒做....) - - # Calico - 1.如何加載 2. 網路如何設置好的. - 模式:支持模式多 - ip 統一規劃亦可, 都配好路由=> 效率高(但Ip資源寶貴,會有浪費) - L2網路, ip可以票的. - pod ip 底層設不得 =>封包/ 解包(如原始的資訊加上.ip包再加udp) - 透過動態路由 - # Calico 組件 - 三種模式 - 1. IPinIP, - 每個節點跑好幾個agent(felix ,BIRD[邊界網關協議],confd) - pods subnets - NODE 間透過tunnel IPinIP - 路由模式, ### Calico 初始化 - k get po -A ==>calico-sysem[NS ] - k get po calico-node-xk4n -n calico-system -oyaml - setup , 怎麼流轉 - 有initContainers: ==>拷貝至目錄..(***) - command: /opt/cni/bin/install - value: 10-calico.conflist - 配了cni_net_dir =>/etc/cni/net.d - 將 10-calico.conflist, IPAM 拷貝過去目錄 - 即volumnMounts設cni-net-dir - hostPath 主機上的 /opt/cni/bin ==>啟動時將容器內的配置copy至主機目錄==>就打通了. - 要containerd 要執行主機的netd ### Calico VXLan:看數據面 - pod1<-->pod2 - 透過vxlan-calico (10.0.1.1) ==>用ip a 看. - 實際看 k get crd - 有ipamconfigs.crd.XXXX - 有ipamhandles.crd.XXXX <==哪些分出去, 哪些pod用了. - 有handle_id (含node1, pod : coredns-4525kgwgr 配置資訊) - 有ipamblocks.crd.projectcalico.org <==每個節點都有的對象 - 用k get ippools.crd.projectcalico.org -oyaml 來看 - 有定義 cidr: 192.168.0.0/16 - 有定ipipMode: Never <==沒開啟 - nodeSelector: all() - blockSize: 26 <==主機上的Ip段 - k get ipamblocks.crd.projectcalico.org ==>192-168-166-26 - -oyaml會列一堆 unlocated - cidr: 192.168.166.128/26 ==> 有24個ip - 用 k get po -w -owide 看 - 用 k get ipamblocks.crd.projectcalico.org 可看到一堆k8s-pod-network-trgrwgxxx - 用 k get k get ipamblocks.crd.projectcalico.org k8s-pod-network-trgrwgxxx -oyaml - 接下來看鏈路... ### ## ◼ 2023-09-27 API Server ### 筆記 ### 讀書紀錄-耀銘 - 控制面:k8s組件 - 數據面:應用、業務服務 -- -------- API Server: - 是集群管理的REST API接口 - 模塊間數據通信/數據交互的樞紐 - 任何人可訪問? 某個操作? 準入(屬性不照規範)? - 認證、鑑權、準入(Mutating,Validating,Admission, 即數據校驗) -- (A) - 集群狀態變更[?????] -- (B) - 會不會量太大掛掉(如程式寫不好, 或用list用太多)? - 限流(如, 支持最大併發請求量?? ) - API對象的實現??[?????] - 一.訪問控制概說 - API HTTP handler - 如,存取ETCD時要求路徑 /XX/XX/namespace/id - 每個請求經過多階段的[訪問控制]才會被接受 <== (A) - (1)認證+授權 - (2)可加[Mutating admission] - ==>可call [webhook] - 是可修改對象值[?????] - (3)轉回來 [object Schema Validation] - (4)經Validating admission - ==>可call [webhook] - 不可改修改對象值[?????] - (4)最後保存至 [Persisted to ETCD] - 二、訪問控制細節簡說, [DATA FLOW]如下: - (1)handler chain - 1.開始[request timout],[authentication] - 2.然後[audit,日誌記錄對象的CRUD] - 3.也可以用[impersonation]於header中模擬成其他用戶 - 4.再用[max-in-flight]限流,即有多少請求發至API Server,但還沒返回的上限! - 5.最後再鑑權[authorization] - 6.若想由別的API Server處理, 可由[kube aggregator & CRDs]導流至其他外部的[aggregated apiservers] - (2)[MUX] - (3)[resource handler] - [decoding解碼] ==>[request conversion & defaulting] - 這二步會與[api server]的核心互動,即向[schema]內的[core/v1 Pod]採[call back] 溝通!!{*****} - [admission準入]==> [REST logic校驗] - 這二步也會與[api server]的核心互動,即向[API Group "core"] 中的[Pod Storage]的[Generic Registry]互動。{*****} - 目的應是要找出各種資源對象的存儲邏輯[?????]{*****} - 應是kubernetes/pkg/registry內的程式源碼在實作[?????]{*****} - kubernetes/pkg/registry负责k8s内置的资源对象存储逻辑实现 - 通過後會存入[ETCD]!!{*****}} - 三、認證 - 所有請求都需先認證 - 可同時開啟多項認證(一個通過即可) - 認證後[username]會傳入[授權模塊]驗證,失敗則傳回[http 401] - 四、認證插件 - X509客戶端證書: API Server 啟動時配置 --client-ca-file - 靜態token文件: API Server 啟動時配置 --token-auth-file - csv格式,每行至少3列(token,username,userid),如: - [示例1]2023-09-24_200132 ```sh cat ~/.kube/config ``` ```yaml - cluster: certificate-authority-data: 一堆亂碼 server: https://192.168.34.2:6443 name: kubernetes contexts: - context: cluster: kubernetes user: kubernetes-admin name: kubernetes-admin@kubernetes current-context: kubernetes-admin@kubernetes kind: Config ``` ```yaml users: - name: kubernetes-admin user: client-certificate-data: 一堆亂碼 client-key-data: 一堆亂碼 ``` - DONNY 另找: - SSL certificate 的開通: - 如何建立 [certificate request] - 如何讓 CA 幫你簽 - 如何在你的網站或是 server 上安裝憑證, 讓其可透過 HTTPS 給外界存取 - CA實作參考 - https://medium.com/@clu1022/%E9%82%A3%E4%BA%9B%E9%97%9C%E6%96%BCssl-tls%E7%9A%84%E4%BA%8C%E4%B8%89%E4%BA%8B-%E5%8D%81%E4%B8%80-%E6%86%91%E8%AD%89%E7%94%B3%E8%AB%8B%E5%AF%A6%E4%BD%9C%E7%AF%87-903834f1ac5f - Certificate request and signing, 第一步驟, 網站的擁有者要先建立屬於自己的 private key. 這部分可以使用 openssl command 來完成 - 會建立一個 .pem 格式, 4096 bit 的 RSA 金鑰 ```ssh $ openssl genrsa -out [name_of_your_key].key 4096 ``` - 建立一個 certificate signing request (csr), 也是透過 openssl command 來完成 ```ssh $ openssl req -new -key [name_of_your_key].key -out [name_of_your_csr].csr ``` - 一旦你準備好了 CSR 檔案, 就可以來選擇 CA 了. 市場上的 CA 有很多, 通常會根據 CA 的名聲與價格等因素來選擇. 常見的有GoDaddy, GeoTrust, DigiCert等等. 當你決定好要找哪個 CA 後, 就到他們的網站並且把你的 CSR 傳上去即可 - 收到 CSR 後, CA 會根據你的 domain 開始實行一系列的背景審核, 確認你是否是正確/合法的憑證擁有者. 當然, 前面也提到過, 這階段也會根據你所選擇的憑證等級而有不同的作業時間. 如 EV (Extended validation certificate) 可能就要花上10個工作天 - 當 CA 完成了審核過程後, 就會簽核你的 CSR 然後把簽過的憑證寄還給你, 通常是一個 .crt 檔案 - 詳細一點的說, CA 會根據憑證的資料區段來計算出 checksum, 並且以其 private key 對這段 checksum 進行加密, 然後把這段加密後的密文 (signature) 附加在原本的憑證後並且寄還給你. 這就是你要用來安裝在你的網站或是 load balancer/webserver 上的東西了 - 自簽實作參考: - 如果你不想要讓 CA 幫你簽呢? 譬如說你想要自己簽 (self signing). 對自簽來說, 最大的問題就是市場上的瀏覽器沒辦法驗證這些憑證除非你手動將自己的 public key 加到這些瀏覽器的 cert store 裡面. 不過自簽這種事通常也只會用在內部網路裡, 所以通常就是幫內部網路的客戶端安裝 public key 即可 - Step1: ```ssh $ openssl req -x509 -newkey rsa:4096 -keyout [name_of_your_key].key -out [name_of_your_crt].crt -days 365 ``` - 部署你的憑證: - 安裝在 load balancer 或著是直接安裝在 web server - Apache 跟 Nginx 的設定方法不同 - Apache 是在VirtualHost內設 - SSLCertificateFile (domain.crt) - SSLCertificateKeyFile (your_private.key) - SSLCertificateChainFile (DigiCertCA.crt) - [示例2]靜態token文件,見[1.basic-auth.MD] - 會用到 [kube-apiserver.yaml] - 可實作成多用戶的token,各自獨立!![*****] - 裏面有一行 --token-auth-file=/etc/kubernetes/auth/static-token - hostPath: 指向 host的/etc/kubernetes/auth - 記得要用volume MOUNT 掛載到API! - cp ./kube-apiserver.yaml /etc/kubernetes/manifests/kube-apiserver.yaml會讓API Server 自動重起! - k get po -A 可看 [kube-apiserver-cadmin] - 雖重起後看不到USER, 所以要加一個用戶在CONFIG ```sh cat ~/.kube/config ``` - k get ns default -v 9 - 可拿到curl命令[圖1:2023-09-24_205746] - 因為kubectl的命令都是透過curl來進行, 所以可以組裝curl指令,指定某人的token 來訪問。 - 出錯1:沒有sign - 加 -k - 出錯2:Error 403 - 拚錯字authorization - ok 時雖然還是403 , 但message 有出現User \"cncamp" 資訊, 表示API server有認得。 - 只是因為沒授權無法訪問成功! - 建議仍至kube config加user ```yaml - name: cncamp user: token: cncamp-token ``` - 用 ```sh k get ns --user=cncamp ``` ## Static token ### Put static-token to target folder ```sh mkdir -p /etc/kubernetes/auth cp static-token /etc/kubernetes/auth ``` ### Backup your orginal apiserver ```sh cp /etc/kubernetes/manifests/kube-apiserver.yaml ~/kube-apiserver.yaml ``` ### Override your kube-apiserver with the one with static-token config ```sh cp ./kube-apiserver.yaml /etc/kubernetes/manifests/kube-apiserver.yaml ``` ### Get kubernetes object with static token ```sh curl https://192.168.34.2:6443/api/v1/namespaces/default -H "Authorization: Bearer cncamp-token" -k ``` - ServiceAccount - k8s自動生成的 - 可測試建立 ```sh k create sa demo k get sa demo -oyaml ``` - 即可看到 ```yaml secrets: - name: demo-token-pnzbx ``` - 會自動掛戴到/run/secrets/kubernetes.io/serviceaccount目錄中 ```sh ks get po ks get go coredns-XXDF -oyaml ``` ```yaml - mountPath: /run/secrets/kubernetes.io/serviceaccount name: kube-api-access-f5x9m readOnly: true ``` - k get sa 可看到 - namespace controller 會自動創建default 的 ServiceAccount ```sh k get serviceaccount default -oyaml ``` - 會有secrets ```yaml secrets - name: default-token-9m8fs ``` ```sh k get secret default-token-9m8fs -oyaml ``` - 內含ca.crt、namespace、token(均為亂碼!) ```sh echo 亂碼|base64 -d ``` - 可看出是標準的JWT token (分三段, 用.隔開) - 參考 https://medium.com/%E9%BA%A5%E5%85%8B%E7%9A%84%E5%8D%8A%E8%B7%AF%E5%87%BA%E5%AE%B6%E7%AD%86%E8%A8%98/%E7%AD%86%E8%A8%98-%E9%80%8F%E9%81%8E-jwt-%E5%AF%A6%E4%BD%9C%E9%A9%97%E8%AD%89%E6%A9%9F%E5%88%B6-2e64d72594f8 - 即代表token是來自於default namespace的default ServiceAccount - OpenID - WebHook - LDAP - -- authentication-token-webhook-config-file 指向配置文件 - -- authentication-token-webhook-cache-ttl 設定 身份認證決定的緩存時間(default 2 mins) - 依k8s規範,認證tokenreview request - URL: https://auth.example.com/authenticate - POST - Input: - apiVersion: authenticatio.k8s.io/v1beta1 - kind: TokenReview - spec: {token: "(BEARERTOKEN)"} - Output: - apiVersion: authenticatio.k8s.io/v1beta1 - kind: TokenReview - status: - authenticated: true - user: - username: donny@fpg.com - uid: 1234 - groups: ["develops","qa"] - 解釋github\101-master\module6\authn-webhook\main.go - 略過............. - 解釋config-file配置文件, 見[webhook-config.json] - 認證在主機上, 服務在容器內. - 配置文件需mount 至Pod - 配置文件服務器指向authService - 跟k8s的cluster的配置一樣, 裏面配了 - cluster: {"server":"http://192.168.34.2:3000/authenticate"} - 步驟見[\module6\authn-webhook\readme.MD] - 先建webhook ```sh cat Makefile make build ./bin/amd64/authn-webhook netstat -na|grep 3000 curl http://192.168.34.2:3000/authenticate - 配置webhook - 1.先mount - 看[\module6\authn-webhook\specs\kube-apiserver.yaml] - 有[webhook-config] 設定mountPath: /etc/config , 是hostPath - 2.改API server 啟動參數(換檔,有含config file) ``` ```sh cp specs/kube-apiserver.yaml /etc/kubernetes/manifests/kube-apiserver.yaml ``` - [圖2023-09-24_231539]示範github[personal access tokens], 拿到token xXXX ```sh vi ~/.kube/config ``` - 換掉token: xXXX ```sh k get po --user mfanjie ``` - [圖2023-09-24_231947]使用get po, 同步看webhook反應 - github 有返回ok ,所以webhook 呈現[success]login as mfanjie - [示例3]x509.MD - 知識: k8s是CAA, 啟動時會產生ca.key,ca.crt(root ca )..等, 在 /etc/kubernetes/pki - ### Create private key and csr ```sh openssl genrsa -out myuser.key 2048 openssl req -new -key myuser.key -out myuser.csr # openssl req -new -x509 -days 10000 -key .key -out <CA_public>.crt ``` - ### Encode csr ```sh cat myuser.csr | base64 | tr -d "\n" ``` - ### Replace request and create csr ```sh cat <<EOF | kubectl apply -f - apiVersion: certificates.k8s.io/v1 kind: CertificateSigningRequest metadata: name: myuser spec: request: 亂碼== signerName: kubernetes.io/kube-apiserver-client expirationSeconds: 86400 # one day usages: - client auth EOF ``` - ### Approve csr ```sh kubectl certificate approve myuser ``` - ### Check csr ```sh kubectl get csr/myuser -o yaml ``` - ### Extract crt ```sh kubectl get csr myuser -o jsonpath='{.status.certificate}'| base64 -d > myuser.crt ``` - ### Set credential ```sh kubectl config set-credentials myuser --client-key=myuser.key --client-certificate=myuser.crt --embed-certs=true ``` - ### Grant permission ```sh kubectl create role developer --verb=create --verb=get --verb=list --verb=update --verb=delete --resource=pods kubectl create rolebinding developer-binding-myuser --role=developer --user=myuser ``` - ### Get pod - try ```sh k get ns --user myuser K get rolebinding - oyaml k get po --user myuser #出錯 k edit rolebinding # 雖然name是myuser ,但實際是簽給cncamp,所以要改user: myuser成cncamp ``` - impersonation說明 - 集群聯邦 (似混合雲,多個集群的集合) - user account (外部平台的帳戶)和 service account(組件的帳號) - user account 用webhook token 來訪問 - [圖2023-09-24_232317]生產系統遇到的陷阱 - gophercloud去 keystone ,在客戶端緩存 - 但剛好reAuth時掛掉, 又再去reAuth - 一堆期限失效, 狂發keystone - api server過期, - 解決: 修復keystone back off - gophercloud在客戶端Circuit break - keystone 加rate limit - 六、授權[圖2023-09-24_234306] - ABAC[寫死靜態文件], RBAC[role的],WebHook, Node - ABAC 麻煩, 有改要重起API Server - RBAC滿足大部分(因為在k8s內部) - Node的是指不同node的隔離用 - RBAC老圖[圖2023-09-24_234640] - RBAC新解[圖2023-09-24_234730] - RoleBindings ---- - Namespace - Role - Verbs - APIGroups + Resources + SubResources - ClusterRoleBindings---- - All Namespaces - ClusterRole - Verbs - APIGroups + Resources + SubResources - Subject---- - RoleBindings - ClusterRoleBindings - 包含 - User - Subject: ServiceAccount - Role與ClusterRole[圖2023-09-24_235507] - Role:只在某個Namespace看得到 - metadata:有Namespace - ClusterRole:對多Namespaces和集群群級的資源, 或是非資源類的API(如/healthz) - metadata:沒有Namespace - binding[圖2023-09-24_235908] - 是可傳下去的.. - 以RoleBinding示例(有引用ClusterRole) ```yaml roleRef: kind: ClusterRole name: secret-reader apiGroup: rbac.authorization.k8s.io ``` - 帳戶/組的管理[圖2023-09-25_000344] - 組的概念 - 與外部認證相接時,UserInfo可包含Group訊息,故授權可針對用戶的Group - 當對ServiceAccount授權時,Group代表[某個Namespace]下的所有[ServiceAccount] - 針對群組授權[圖2023-09-25_000944] - 規劃系統角色[圖2023-09-25_001056] - 問題: - rancher 的帳號是user account嗎? - default service account 是默認無權限訪問API Server的哦! - 連 get 都不行(還是要授權). - system:serviceaccount前綴是固定的 ### 讀書紀錄-佑安 kube-apiserver 是 Kubernetes 集群的主要控制組件之一,它是 Kubernetes API 的主要入口點。功能和特點: 1. API 伺服器:kube-apiserver 是 Kubernetes API 的伺服器,它提供了 HTTP/HTTPS 的端點,用戶和 Kubernetes 內部組件可以使用這些端點與 API 進行通信。 2. 擴展性:kube-apiserver 設計為可擴展的,這意味著它可以運行在多個實例上,以支持大型集群。 3. 驗證和授權:kube-apiserver 負責驗證請求的身份和授權請求。它支持多種驗證方法,如憑證、Bearer tokens、OAuth 等。一旦用戶被驗證,kube-apiserver 還會檢查他們是否有權執行特定的操作。 4. 資料存儲:雖然 kube-apiserver 是與用戶和其他組件互動的主要端點,但它不直接存儲任何數據。相反,它與 etcd(Kubernetes 的一致性數據存儲)通信,將所有集群數據存儲在那裡。 5. 版本控制:Kubernetes API 有多個版本(例如 v1、v1beta1 等),kube-apiserver 能夠同時支持多個 API 版本。 6. 其他功能:kube-apiserver 還提供了許多其他功能,如限流、請求日誌、API 文檔等。 #### Mutating Admission Webhooks 1. 動態修改:Mutating Admission Webhooks 允許外部來源在一個 API 對象被接受並存儲到 etcd 之前動態地修改它。 2. Webhooks:這些是由用戶提供的 HTTP 回調,它們由 Kubernetes API 伺服器在執行某些操作(例如創建、修改或刪除)之前調用。 3. 配置:要使用 Mutating Admission Webhooks,用戶需要創建一個 MutatingWebhookConfiguration 資源,其中定義了 webhook 的詳細信息,例如其 URL、所支持的操作和對象類型等。 4. 安全性:由於 webhooks 可能會修改 Kubernetes 對象,因此它們需要正確和安全地配置。例如,它們應該使用 HTTPS 並提供有效的憑證。 5. 用途:Mutating Admission Webhooks 可用於多種用途,例如設置對象的預設值、正規化對象數據或實施特定的策略。 6. 與 Validating Webhooks 的區別:除了 Mutating Admission Webhooks 外,還有 Validating Admission Webhooks。兩者的主要區別在於,Mutating Webhooks 旨在修改對象,而 Validating Webhooks 則用於驗證對象是否符合特定的標準或策略,但不修改對象本身。 #### CRDs CRD(Custom Resource Definition),允許用戶定義自己的資源類型,而無需修改 Kubernetes 核心代碼。 CRD 提供了一種【擴展】 Kubernetes API 的方法,使開發人員能夠創建自定義的資源,這些資源與內置的 Kubernetes 資源(如 Pod、Service 和 Deployment)在使用上非常相似。 #### RBAC (Role-Based Access Control)是一種基於角色的訪問控制策略,它根據用戶的角色來決定他們可以訪問的資源和執行的操作。在 RBAC 中,訪問權限不是直接分配給單個用戶,而是分配給特定的角色,然後用戶被分配到這些角色。 #### ABAC (Attribute-Based Access Control)是一種訪問控制方法,它基於屬性(attributes)來決定誰可以訪問什麼。 ABAC 不僅考慮用戶的角色,還考慮其他屬性,如用戶屬性、資源屬性和環境屬性。 儘管 Kubernetes 最初支持 ABAC,但由於其複雜性和難以管理,Kubernetes 社區已經轉向使用 RBAC 作為主要的授權方法。 #### RBAC 和 ABAC 的差異 RBAC:相對固定。一旦角色和其權限被定義,它們通常不會頻繁地改變。 通常較為簡單,因為它主要基於預定義的角色。 管理相對簡單。當用戶的角色改變時,只需更改其角色分配。 ==> 動態配置文件 ABAC:更加靈活。可以基於多種屬性組合創建細粒度的訪問控制策略。 可能更加複雜,因為它考慮了多種屬性和它們之間的關係。 可能需要更多的管理工作,特別是當涉及到多種屬性和策略時。 ==> 靜態配置文件 #### Role與ClusterRole 可以多種resources #### 针对群租授权 可自定義不同群組 mager 是外面自定義 server 是系統預設 #### 規劃系統腳色 管理員是否有所有權限??個人的密碼不應該可以被讀取,要去關閉此權限。 普通用戶對自己創建namespace下的所有object操作權限?部分狀況也不該有 對其他用戶的namespace #### 与权限相关的其他最佳实践 SSH到master节点通过insecure port访问apiserver可绕过鉴权,当需要做管理操作又没 有权限时可以使用(不推荐) API Server 作为 K8s 集群的管理入口,在集群中被用于提供API来控制集群内部。默认情况下使用 8080 (insecure-port,非安全端口)和 6443 (secure-port,安全端口)端口,其中 8080 端口无需认证,6443端口需要认证且有 TLS 保护。如果其在生产环境中Insecure-port 被暴露出来,便利用此端口进行对集群的攻击。 # 導讀紀錄 ## ◼ 2023-09-21 etcd ### 讀書紀錄-耀銘 ETC安裝-參考外部(Docker那段)=>請必試(或用killer亦可) - https://github.com/etcd-io/etcd/releases ``` rm -rf /tmp/etcd-data.tmp && mkdir -p /tmp/etcd-data.tmp && \ docker rmi gcr.io/etcd-development/etcd:v3.4.27 || true && \ docker run \ -p 2379:2379 \ -p 2380:2380 \ --mount type=bind,source=/tmp/etcd-data.tmp,destination=/etcd-data \ --name etcd-gcr-v3.4.27 \ gcr.io/etcd-development/etcd:v3.4.27 \ /usr/local/bin/etcd \ --name s1 \ --data-dir /etcd-data \ --listen-client-urls http://0.0.0.0:2379 \ --advertise-client-urls http://0.0.0.0:2379 \ --listen-peer-urls http://0.0.0.0:2380 \ --initial-advertise-peer-urls http://0.0.0.0:2380 \ --initial-cluster s1=http://0.0.0.0:2380 \ --initial-cluster-token tkn \ --initial-cluster-state new \ --log-level info \ --logger zap \ --log-outputs stderr ``` - 列出ETCD情境 問題(如復原、容量告警) - 操作ETCD指令過, 如情境 (如復原) ##### 以下為筆記內容 RAFT協議(多數投票機), 運用二方面 - 選主 - 數據寫入 存儲機制=>數據寫入/保存細節 -任一key的修改都會有新版本 - 可回看 - 可監控某版本(也可指定哪個版本開始監控!),所以ETCD在推事件時就會從指定的版本之後開始推送 - reversion 分二種(main rev, sub rev) - main :每次事務+! ; sub:同一事務中的每次操作+1 - 因為版本很多, 所以ETCD 可以compact(壓縮) - [圖2 ]etcdctl get -wjson <= revision:全局 ;解釋不同vision /version - [囻1] - 提到k8s 沒用etcd內的用戶、權限管理?? - ETCD request包 有限制1.5 兆! (why???) - (1)預檢查? - (2)KVServer=>用propose(input y=9)發到一致性模塊(選主,日志copy) - 一致性(raftlog)會先存在<unstable> ,再返回output:ready - (3)接下來 有二個同時操作 - a.用RPC發至follower (也會有I/O) - 如果是follower先收, 也會轉發至leader - b 寫入日誌模塊: WAL日誌(MSG序列化成二進制....) - 日志模塊有硬盤空間, 會透過fsync將wal 寫入<持久化> - WAL log 平常都讀不到/ - (4)KVServer<收到follower Response>, 判是否<過半數>! - 若是, 則更新MatchIndex - [??] MaInux應該指的是多數人確認的index. - 此時get 還抓不到.,只是在寫log階段,數據尚未實際寫入! - (5)操作MVCC模塊<MultiVersionConcurrentControl> - MVCC目的:在不加鎖的前堤下達多版本數據存儲 - APPLY <raftlog內MSG移到committed>,會寫入二塊: - (1)TreeINdex=>key=y, modified:<4,0>, generations[ver:1,<3.0>,<4.0> ] - (2)BoltDB:是B+Tree的結構, key 是版本號<4,0>, value是各種version<x,0> 及其value(如y的值)構成 - 同個key如果創建/刪除、創建/刪除=>資料會在generations內. - - - 多讀少寫(key 先在treeindex找revision ,再用revision去boltDB找) - 不直接寫MVCC(要多數同意), 所以,是放mem, 再透過日誌持久化有了後, 多數同意才寫入<狀態模塊> -說明:resourceVersion:338 ==>樂觀鎖 - 查找: ks get po kube-controller-manager-cadmin中的metaData - 目的:多的控制器要去改對象時, 不能版本衝突 - 來源:MVCC->treeIndex->modified:<4,0> - ex : 修改時如果和revision:388相等, 所以, 通過修改(集群的revision+1=399)==>對象的modified revision 也變為399 - 返回409(拒絶): 如果另個控制器帶388來修改時。 - ETCD的數據一致性(用1L2F為例) - 寫入多次(a,b,c,d,e,f,g,h)來說明 committed log - 遇有跟不上數據寫入的follower, 如果還是有半數同意, 仍會commit(如a~g) - 如果不到半數的數據就不會commit (如h) - etcdctl --endpoints=http://xx get b --rev=19c - Watch 2種: key watcher & range watcher - 每個watchableStore 包含二種WatcherGroup(synced, unsynced) - synced:該group的數據都已同步完,等待新的變更 - unsynced:該group的數據落後於當前最新變更, 還在追趕 - ETCD收到客戶端Watch請求, 如果請求有帶revision - 比較store當前的revision =>若大則放入synced(直接把當前數據發給),否則放入unsynced(需讀歷史數據)==>同時後台會啟動goroutine持續同步unsynced的watcher, 然後將其移到synced組。 - 所以, 此機制使etcd v3支持由任意版本開始watch (原本v2有1000條的限制) - 安裝: https://github.com/etcd-io/etcd/releases - 48:39=>回答問題(重講圖一) - leader, follow都有etcd 的3模塊 - ETCD成員重要參數 - ==>會定期備份,目錄(snap, wal) - peer-url , client-url - 集群相關參數: initial-cluster 開頭 - 安全相關 : client , peer 各配一套含(crl , ca, cert ,key ..等) - - 災備備做法 - 做snapshot =>指定一些安全參數 - 如 etcdctl --endpoints xxxx --cert xxxx..... snapshot save snapshot.db - 恢復數據 =>指定一些initial , data-dir,name參數 - 如etcdctl snapshot restore snapshot.db \ - - 容量管理 - 單個對象不超過1.5M <==心跳會...帶很大資訊.. - 默認容量2G - 不建議超過8G(與boltDB相關, 內存有關) - Alarm & Disarm Alarm (ETCD是會爆的...) - 見 4.alarm.MD - 設ETCD存儲大小 - etcd --quota-backend-bytes=$((16*1024*1024)) - - 寫爆disk: 只可讀不可寫 - 看狀態:ETCDCTL_API=3 etcdctl --write-out=table endpoint status - ERRORS會出現alarm:NOSPACE - 查看 alarm=> etcdctl alarm list - ETCDCTL_API=3 etcdctl defrag (也可用compact ) - ETCDCTL_API=3 etcdctl alarm disarm - Compact up to revision 3=> etcdctl compact 3 - 現在ETCD會有日AUTO compact - <高可用ETCD集群之建置> - 見etcd-ha-demo (install-ha-etcd.md) - start-all.sh - backup.sh - 開始破壞集群(見install-ha-etcd.md) - 停集群=>ps -ef|grep "/tmp/etcd/infra"|grep -v grep |awk '{print $2}'|xargs kill - 刪目錄=> rm -rf /tmp/etcd - restore.sh <==一份snapshot檔可恢復多個實例 - restart-all.sh - 查看是否有3個實例=>ps -ef | grep etcd - 查看log(是否restore正常)=>tail -f /var/log/infra0.log - member list 一下=> etcdctl --endpoints https://127.0.0.1:3379 --cert /tmp/etcd-certs/certs/127.0.0.1.pem --key /tmp/etcd-certs/certs/127.0.0.1-key.pem --cacert /tmp/etcd-certs/certs/ca.pem member list - 自動化<高可用ETCD集群之建置> - etcd-operator - bitnami.com - bitnami範例=> (6.statefulset-etcd.MD) - (未來學習)說明一下<helm> ==>時點1:48:49 - 回答問題 時點 1:49:56 - 使用 1.etcd-member-list.MD - 沒有安全參數(cert..等...) - URL都是用http - 不適用於production - 生產環境部署時要配在不同的server (install-ha-etcd.md內的是用3個port 分開...) - 集群3個實例建立時都是initial-cluster-state new - - 開講ETCD-operator - 成員有 - etcdCluster(是CRD), etcd-operator(watch前者,create/restore etcd Pod , watch 後者), etcd Pod,etcdRestoreResource(數據恢復用., 會reference Remote volume) - etcd Pod 有2個container - etcd => local voulumn - backup =>snapshot 至Remote volume - (暫時轉)查看meta yaml - volumeMounts - mountPath: /var/lib/etcd - name: etcd-data - mountPath: /etc/k8s/pki/etcd - name: etcd-certs - 上述mount來源是host主機的(相當於是外部存儲), 如下: - volumes: - hostPath: - path: /var/lib/etcd - type:DirectoryOrCreate - name: etcd-data - 跳講<etcd-operator >:講go,所以跳過.. - 見 https://github.com/coreos/etcd-operator/blob/master/cmd/operator/main.go 開始 - 重要: <kubernetes如何使用ETCD> - ETCD是k8s後端儲存 - 每個k8s object 都有對應的storage.go負責對象的存儲操作 - pkg/registry/core/pod/storage/storage.go - API腳本中指定ETCD SERVERS集群(見其spec), 以下查看: - ks get po kube-apiserver-cadmin -oyaml - 也可以看到livenessProbe(或其他探針) - API Server現在已是用ETCD API CALL 強化check - - <k8s對象在ETCD中的存儲路徑> - ks exec -it etcd-cadmin sh - alias etcl ='etcdctl ..endpoint+安全參數....' - etcl get --prefix --keys-only <==列出 (/registry/xxxxx) - 查spec: ks get role system:controller:token-cleaner -oyaml -v 9 - 刪除: etcdctl del --prefix /registry/roles/ - <ETCD在集群中的位置> - 在管理節點內才有 - API啟動腳本還可取代導向 --etcd-servers-overrides=/events#http://localhost:4002 - <ETCD集群高可用拓扑>堆疊 - 同主機(API+etcd) - 適合機容大的 - 主機少.. - 外部集<ETCD集群>高可用拓扑> - API 連外call ETCD - 適合機容小要將ETCD拆出去的 - 主機數多 - 實踐:ETCD高可用 - 多少peer最適合? - 用3個的話=>需立馬處理( 如果連續壞2個, 就很嚴重了) - 用5個的話=>隔天再處理 - 需要動態flex up =>很少, 因為要證書.., 一次要加2台. - 實踐:保證api server 與etcd高效通訊 - 在同一節點 - 基於gRPC - stream共享(1條高速公路, 多個車道stream quota) - http2 協議 - 問題: 一個對象佔滿高速公路? (如10000pod, list 操作) - 其他對象過不去. - 節點心跳跟不上, 所有節點會下線!!! - 實踐:etcd 存儲規劃 - LOCAL SSD - 利用local volume 分配空間 - 空間:與集規模相關, (不超過8G) - 為什麼會有member的DB size 不一致(WAL log, MVCC) - 減少網路delay - RTT(國內約50ms,兩洲間400ms) - ETCD集群儘量同地佈署+ 數據備份 - 用流量管制工具(let ETCD先過) - - 實踐:k8s是會增加運維, 但主要目的是: - 自動部署和管理雲原生應用程式。 將應用程式工作負載分配至整個Kubernetes 叢集中,並將動態容器網路需求自動化 - ### 讀書紀錄-佑安 #### etcd 是一個開源的、高可用性的鍵值存儲系統,用於配置管理和服務發現。 在 Kubernetes 中作為其後端存儲,保存所有的集群數據。使得 Kubernetes 可以在節點之間保持配置的一致性,並提供服務發現功能。 核心功能和特點包括: 1. 分佈式:etcd 是一個分佈式的鍵值存儲系統,這意味著它可以在多個節點上運行,形成一個集群,以提供高可用性和故障轉移能力。 2. 一致性:etcd 使用 Raft 一致性算法來確保所有的節點在分佈式環境中都有相同的數據。 3. 事務性記錄:etcd 提供了一種方式來進行原子性的多步操作。 4. 觀察者模式:客戶端可以訂閱特定的鍵或目錄的更改,這使得它非常適合於服務發現和其他需要實時更新的應用。 5. 安全性:etcd 支持 SSL/TLS 以確保數據的安全性和完整性。 6. 簡單的 API:etcd 提供了一個 HTTP/JSON API,使得它可以很容易地與各種應用和工具集成。 7. 快速:每秒1000次寫,2000次以上讀。 8. 可靠:使用Raft算法保持一致。 #### TTL Time to Live(TTL),翻譯為「生存時間」。 是一種機制,用於確定數據或資訊在系統或網絡中的「生存時間」,以確保資訊的時效性和防止潛在的問題(如網絡循環)。 主要在以下幾個領域中有所應用: 1. 網絡和路由:在 IP 協議中,TTL 是一個字段,用於指定數據包在網絡中可以存在的最大跳數(hops)。每當數據包經過一個路由器,其 TTL 值就會減1。當 TTL 值降到 0 時,該數據包將被丟棄,並且會發送一個 ICMP「超時」消息給發送者。這可以防止因路由循環而導致的數據包在網絡中無限循環。 2. DNS:在域名系統 (DNS) 中,TTL 是一個值,用於指定 DNS 記錄在本地緩存中可以存儲的時間。當緩存的 DNS 記錄過期後,DNS 解析器必須再次查詢該記錄,以確保它獲得的是最新的資訊。 3. 數據庫和緩存系統:在某些數據庫和緩存系統(如 Redis)中,TTL 可用於指定某個鍵值對的過期時間。當該時間到達後,該鍵值對將自動從系統中刪除。 4. 應用程式和網頁內容:TTL 也可以用於指定應用程式或網頁內容的緩存時間,以確保用戶總是獲得最新的資訊。 #### CAS Atomic Compare-and-Swap(CAS) 是一種在多處理器和多線程環境中用於實現無鎖(lock-free)數據結構和算法的原子操作。CAS 用於確保數據的一致性,而不需要使用傳統的鎖或互斥體。 CAS 操作的基本概念是:比較當前的值與預期的值,如果當前的值與預期的值相匹配,則更新為新的值。這三個參數(當前值、預期值和新值)是 CAS 操作的典型參數。 CAS 的工作流程如下: 1. 讀取當前的值。 2. 進行某些計算以得到新的值。 3. 使用 CAS 來更新值:如果當前值仍然是步驟1中讀取的值,則更新為步驟2中計算的新值。 4. 如果在步驟3中當前值已經被其他處理器或線程更改,則 CAS 操作將失敗。當 CAS 失敗時,整個操作通常會重新開始,直到成功為止。 CAS 的優點: 1. 效率:在高競爭的環境中,CAS 可能比使用鎖更有效率。 2. 死鎖避免:由於不使用傳統的鎖,CAS 操作不會導致死鎖。 CAS 的缺點: 1. 自旋:如果 CAS 操作持續失敗,它可能會導致所謂的"自旋",其中線程不斷地重試操作,這可能會浪費 CPU 資源。 2. ABA 問題:如果一個值從 A 更改為 B,然後再更改回 A,CAS 可能無法檢測到這種更改。這稱為 ABA 問題,可能需要額外的機制(如版本號)來解決。 3. 儘管 CAS 有其挑戰和限制,但它仍然是許多無鎖數據結構和算法的基石。 #### Raft協議 Raft 協議是一種用於分散式系統的共識算法,它的目的是確保系統中的多個節點能夠在不可靠的網絡環境中達成一致性。Raft 協議是為了解決 Paxos 共識算法的複雜性而設計的,並且特別強調了易於理解和實現的特點。 Raft 協議在許多分散式存儲系統和服務中都有應用,例如 etcd、Consul 和 CockroachDB 等。 特點和概念: 1. 領導者選舉 (Leader Election): 在 Raft 中,節點可以是三種角色之一:領導者 (Leader)、跟隨者 (Follower) 或候選人 (Candidate)。在任何時候,集群中只能有一個領導者。當領導者失效或網絡分割時,會進行新的領導者選舉。 2. 日誌複製 (Log Replication): 領導者負責管理日誌的複製。當領導者接收到一個客戶端的請求時,它首先將該請求添加到其日誌中,然後嘗試將該日誌條目複製到其他節點。 3. 安全性: Raft 確保只要大多數節點從領導者那裡接收了一個日誌條目,該條目就不會被丟棄。這確保了系統的一致性和容錯性。 4. 簡單性: 與 Paxos 相比,Raft 的設計目標是簡單和直觀的。這使得它更容易實現和理解。 #### Raft協議中的Learner 在 Raft 協議的某些實現中,引入了一個稱為 "Learner" 的角色。Learner 是集群中的一個非核心角色,它可以接收日誌條目,但不參與領導者選舉和日誌複製的投票。它允許新節點加入和同步集群,而不會影響集群的共識決策。 特點和用途: 1. 只讀成員: Learner 可以被視為集群的只讀成員。它們可以接收和應用日誌條目,但不會影響集群的共識決策。 2. 無投票權: Learner 不參與領導者的選舉過程,也不參與日誌條目的投票。這意味著它們不會影響集群的選舉結果或日誌的一致性。 3. 用於觀察和學習: Learner 的主要用途是允許新節點加入集群並同步日誌,而不影響集群的運行。一旦 Learner 完全同步,它可以被提升為一個完整的跟隨者 (Follower)。 4. 增加容錯性: 由於 Learner 不參與投票,所以可以在不影響集群共識的情況下增加更多的節點,這有助於提高系統的可觀察性和容錯性。 5. 平滑擴展: 當需要將新節點添加到集群中時,首先將其作為 Learner 加入,這允許新節點平滑地同步數據並成為集群的一部分,而不會對集群的運行造成干擾。 #### WAL Write-Ahead Logging (WAL) 是一種日誌技術,主要用於數據庫和文件系統中,以確保數據的完整性和持久性。WAL 的主要思想是:在將任何更改(如更新、刪除或插入)寫入主數據存儲之前,先將這些更改記錄到日誌中。 主要特點和工作原理: 1. 持久性:當一個事務(transaction)或操作被提交時,系統首先將該事務的詳細信息寫入到 WAL 中。只有當這些日誌成功寫入並確認後,事務才被認為是提交的。 2. 恢復:如果系統突然崩潰(例如,由於電源故障或系統故障),WAL 可用於恢復數據庫到最後一個已知的一致狀態。在系統重新啟動後,它會讀取 WAL,重新播放(replay)日誌中的操作,以確保所有已提交的事務都被正確地應用到數據存儲中。 3. 性能優勢:WAL 可以提供性能上的優勢,因為寫入日誌通常是順序的,而不需要立即更新數據庫的多個位置。這意味著磁盤I/O操作可以更加高效。 4. 原子性:WAL 有助於確保事務的原子性。如果一個事務在其完成之前被中斷(例如,由於系統崩潰),那麼在恢復時,該事務的所有更改都可以從 WAL 中回滾,確保數據的一致性。 5. 隔離性:WAL 也有助於實現事務的隔離性,因為它可以確保在一個事務完成之前,其他事務不會看到其中間狀態的更改。 SQLite、PostgreSQL 和許多其他數據庫系統都使用了 Write-Ahead Logging 技術來確保數據的完整性和持久性。 #### etcd v3 的 watch機制 etcd v3 的 watch 機制是一個強大的功能,允許客戶端訂閱一個或多個鍵的更改。當這些鍵的值發生變化時,watch 會通知客戶端。這對於實時配置更新、服務發現和其他需要即時知道數據更改的應用非常有用。提供了一種高效、靈活和可靠的方式來實時監視鍵值存儲中的數據更改,並對這些更改做出反應。 主要特點和工作原理: 1. 長連接:客戶端使用 gRPC 長連接訂閱鍵的更改。這意味著一旦設置了 watch,連接將保持開放,直到客戶端取消訂閱或發生錯誤。 2. 範圍訂閱:除了訂閱單個鍵外,客戶端還可以訂閱鍵的範圍。這意味著可以監視一整個目錄或鍵的前綴。 3. 版本化的事件:當鍵的值發生變化時,watch 會返回一個包含更改詳情的事件。這些事件包括更改的類型(如 PUT 或 DELETE)、鍵、值以及相關的版本信息。 4. 從特定版本開始觀看:客戶端可以選擇從特定的修訂版本開始觀看。這允許客戶端獲得自某一版本以來的所有更改,這對於在客戶端斷開連接後重新同步非常有用。 5. 集成租約:watch 可以與 etcd 的租約機制結合使用。這意味著如果一個鍵與一個租約相關聯,並且該租約到期,則 watch 會收到一個刪除事件。 6. 效率:watch 機制是高效的,因為它只在鍵的值實際發生變化時才發送通知,而不是定期輪詢。 7. 多客戶端支持:多個客戶端可以同時訂閱同一個鍵或鍵的範圍的更改,並且每個客戶端都會收到相應的通知。 #### etcd v3 的 store機制 負責持久化和管理鍵值數據。提供了一個高效、可靠和一致的方式來管理分佈式鍵值數據。它包含了一系列先進的功能,使其成為分佈式系統和雲原生應用的理想選擇。 主要特點和說明: 1. 多版本並發控制 (MVCC):etcd v3 的存儲使用 MVCC 來支持並發操作。每次寫入都會產生一個新的版本,而舊版本的數據會被保留。這允許客戶端讀取過去的版本,並支持乐观锁策略。 2. 範圍查詢:etcd v3 支持範圍查詢,允許客戶端查詢一個鍵的範圍,而不僅僅是單個鍵。這對於查找目錄或鍵的前綴非常有用。 3. 租約機制:etcd v3 引入了租約概念,允許客戶端設定鍵的生存時間 (TTL)。當租約到期時,與其關聯的鍵會被自動刪除。 4. 事務操作:etcd v3 支持事務性操作,允許客戶端在一個原子操作中執行一組條件和請求。這確保了一系列操作的一致性。 5. boltdb 存儲引擎:etcd v3 使用 boltdb 作為其後端存儲引擎。boltdb 是一個 Go 語言寫的嵌入式鍵值數據庫,它提供了高效的磁盤I/O操作。 6. 緊湊和快照:為了回收不再需要的舊數據和保持存儲的效率,etcd v3 提供了緊湊和快照功能。緊湊操作會刪除舊的不再需要的版本,而快照則允許創建存儲的完整副本。 7. 持久化和一致性:etcd v3 使用 Raft 一致性算法來確保所有節點在集群中都有相同的數據。此外,所有的數據都會被持久化到磁盤,以確保在節點重啟後數據不會丟失。 8. 隔離性:由於 MVCC 的支持,etcd v3 可以同時處理多個讀和寫操作,而不會互相干擾,從而提供了高度的隔離性。 #### 容量管理 單個對象不建議超過1.5M => 為什麼? 默認容量2G 不建議超過8G => 為什麼? #### etcd集群高可用設定 1. 幾個peer: 3個peer:最少需要3個peer才能組成叢集,且效能也最佳 5個peer:效能不及3個peer,但若2個peer掛了時,系統還能承受,不至於要馬上處理。 2. 首要目標是保證高可用性 => 多一點peer 3. 所有寫操作都要經過leader 4. peer多了能提升集群並讀操作的開發能力? apiserver的配置只連本地etcd peer apiserver的配置指定所有etcd peer,但只有當前連接的etcd member異常時apiserver才會換目標 5. apiserver和etcd之間的通訊基於gRPC #### etcd儲存規則 1. 使用本地SSD 2. 利用local volume分配空間 #### 減少網路延遲 1. 盡可能將集群佈署在同一個地區(同樣網路速度的區域) 2. 在節點上使用流量控制工具提高etcd成員之間發送數據的優先權 #### 減少硬碟I/O延遲 1. 採用SSD,越快速越好 2. 將etcd的資料存在單獨硬碟中,或依照類型區分去儲存在不同集群中,這些集群最好也有單獨硬碟 3. 若etcd不可避免要與其他服務共享磁碟,則須通過下面ionice命令對etcd服務設定更高硬碟I/O優先權,盡可能避免受到其他服務的影響。 $ ionice -c2 -n0 -p 'pgrep etcd' #### 合理日誌大小 1. 固定周期快照保存系統當前狀態,並移除舊的日誌 2. 當修改超過一定數量時,etcd也會創建快照文件(默認10000,通過參數"--snapshot-count"指定) 3. 須避免太過頻繁的快照,也不可太少快照 太頻繁快照:快照時會將硬碟lock住,此時系統仍執行中,為了儲存日誌,系統會另外取得硬碟空間,造成硬碟使用量增加。如果太頻繁,則可能造成硬碟空間快速被吃光。 太少快照:日誌會不斷增長,太少快照一樣會導致硬碟空間被吃光的問題。 #### 合理的儲存配置 1. 建議不要超過8G => 為什麼? #### 自動壓縮歷史版本,避免空間用完導致無法寫入 "--auto-compaction" #### 定期消除碎片化,避免儲存空間無法利用 類似硬碟重整 ### 問關貿事項 1. 運行時有遇到什麼問題?怎麼解決? 1) 頻繁的leader election 2) etcd分裂 3) etcd沒反應 4) 與apiserver之間阻塞 5) 磁碟暴漲 => etcd硬碟空間要設定多大?多久備份一次? 2. 每個服務使用多少POD?有無建議的準則或公式?