k8s基本原理

kinnylee發表於2019-07-30

分享的內容包括

  • k8s demo部署示例
  • k8s基本架構和原理
  • k8s資源物件
  • k8s網路模型
  • 總結

k8s就像圖中的貨船,管理各種集裝箱(容器)

裝滿集裝箱的船

一. k8s demo部署示例

說明

  • 先通過一個hello world程式直觀感受一下k8s
  • 程式部署在宿主機,容器和k8s三種環境,對比他們的差異
  • 程式碼大致是這個樣子
    @RestController
    public class K8sDemoController {
    
        @GetMapping("/hello")
        public String hello(){
            return "hello k8s demo.";
        }
    }
    複製程式碼

1. 宿主機上如何執行

  1. mvn編譯程式碼打成jar包
  2. 執行java -jar k8s-demo.jar &
  3. 瀏覽器中輸入 http://10.1.69.101:8080/hello 地址訪問服務

2. Docker容器上如何執行

  1. mvn編譯程式碼打成jar包
  2. 將jar包打成docker映象
  3. 執行docker run --name k8s-demo -d -p 8080:8080 k8s-demo:0.0.1-SNAPSHOT
  4. 瀏覽器中輸入 http://10.1.69.101:8080/hello 地址訪問服務

3. 在k8s中如何執行

這一步大致感受一下yaml的樣子,不需要關心指令碼的細節,後面介紹資源時會細說。只需要有個大體的印象,部署一個k8s服務的基本流程。

  1. mvn編譯程式碼打成jar包
  2. 將jar包打成docker映象
  3. 構建一個執行服務的yaml檔案
  4. 執行kubectl apply -f k8s-demo.yaml
  5. 瀏覽器中輸入 www.k8s-demo.com/hello 地址訪問服務
  • yaml檔案內容
# 檔名為k8s-demo.yaml
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  name: k8s-demo
  namespace: spring-test
spec:
  replicas: 3
  template:
    metadata:
      labels:
        app: k8s-demo
    spec:
      containers:
      - name: k8s-demo
        image: k8s-demo:0.0.1-SNAPSHOT
        ports:
          - containerPort: 8080

---
apiVersion: v1
kind: Service
metadata:
  name: k8s-demo
  namespace: spring-test
spec:
  type: NodePort
  selector:
    app: k8s-demo
  ports:
   - protocol: TCP
     port: 8888
     targetPort: 8080
     nodePort: 30003

---
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: k8s-demo
  namespace: spring-test
spec:
  rules:
  - host: www.k8s-demo.com
    http:
      paths:
      - path: /hello
        backend:
          serviceName: k8s-demo
          servicePort: 8888
複製程式碼

4. 總結三種部署方式

為了減少部署複雜度,程式碼並沒有使用redis,只是例項圖增加了redis

k8s基本原理

5. 流程越來越複雜,為什麼不直接部署在宿主機?

5.1 容器比宿主機優勢在哪?

  • 可移植性:容器提供了執行應用程式的基本包裝,可以在任何支援容器的雲上部署
  • 高效率:啟動一個容器只需一個映象,且啟動時間非常短
  • 隔離性:宿主機上往往安裝很多服務,且各自依賴不一樣。而一個容器只跑一個服務
  • 版本控制:方便追溯不同版本差異,方便快速回滾,只需替換映象版本,無需宿主機上一套複雜的流程
  • 低成本:小巧輕便,不需要像宿主機或虛擬機器一樣佔用很多資源

5.2 k8s的出現又解決了容器的什麼問題?

  • 自動編排排程:大量容器劇增後,如何管理、如何排程的問題
  • 分散式解決方案:節點可水平擴充套件,容器可方便擴縮容
  • 自愈能力:故障自動發現,並進行自我修復

我們說容器實現了單個應用程式的基本包裝實現可移植。上圖中,宿主機部署的方式如果加上一個nginx做反向代理,就和k8s中ingress的部署方式是一樣的。也就是k8s實現了整套分散式應用的可移植

二. 基本架構和原理

k8s基本原理

k8s架構圖

1. Master節點的元件

apiServer

  • 提供資源操作的唯一入口,提供api註冊、發現、認證、訪問控制等功能

etcd

  • 一個key-value資料庫
  • 儲存整個機器的狀態

controller-manager

  • 負責維護機器狀態,比如:自動擴容、故障檢查、滾動更新
  • 實現叢集自動化的關鍵元件

scheduler

  • 負責資源排程
  • 將未分配節點的pod排程到合適的節點上

2. Node節點的元件

kubelet

  • 負責容器生命週期管理,比如:建立、刪除
  • 同時負責Volume,網路的管理

kube-proxy

  • 負責為Service提供負載均衡、服務發現

Container Runtime

  • 容器執行環境
  • 預設是Docker,同時還支援其他容器引擎

三. 資源物件

概述

  • k8s中大部分概念,如Node,Pod,Service都可以看做一種資源物件
  • 資源的描述:yaml檔案或json檔案
  • 資源的操作:物件可以通過kubectl(或者api)執行增、刪、改、查
  • 資源的儲存:資訊在etcd中持久化

k8s通過對比資源的“實際狀態”和etcd中的“期望狀態”,實現自動化控制

k8s基本原理

1. Pod

  • Pod是k8s中最重要最基本的資源
  • pod是在容器之外又封裝的一層概念
  • pod是容器排程的基本單元(不是docker容器)
  • 每個pod包含一個特殊的根容器:Pause容器,和一個或多個業務容器
  • 每個pod有唯一的ip,pod內的容器可通過localhost通訊

為什麼要新增pod這個概念?

  1. 一組容器作為一個單元,很難判斷整體狀態,以及對整體進行管控。新增業務無關的pause容器,用於管控整體
  2. 簡化了關聯容器通訊和共享的問題

2. Deployment

  • 實現Pod自動編排:建立、刪除、擴容、縮容
  • 通過replicas控制pod數量,template控制要建立的pod的模板
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  name: k8s-demo
  namespace: spring-test
spec:
  replicas: 3
  template:
    metadata:
      labels:
        app: k8s-demo
    spec:
      containers:
      - name: k8s-demo
        image: k8s-demo:0.0.1-SNAPSHOT
        ports:
          - containerPort: 8080
複製程式碼

3. Service

  • pod異常時,可能會被排程到另一臺機器,導致pod的ip改變,使用ip訪問服務不可靠

3.1概述

  • k8s裡最核心的資源之一,類似微服務架構中的“微服務”
  • 前端應用通過入口地址訪問服務,服務通過label對接到後端的pod,即使pod的ip變了
  • kube-proxy負責把service請求轉發到後端,並做負載均衡
  • service整個生命週期內,ClusterIp不會變,對外提供的服務地址也就不會變
apiVersion: v1
kind: Service
metadata:
  name: k8s-demo
  namespace: spring-test
spec:
  type: NodePort
  selector:
    app: k8s-demo
  ports:
   - protocol: TCP
     port: 8888
     targetPort: 8080
     nodePort: 30003
複製程式碼

4. Ingress

service提供了ip:port的訪問方式,即工作在tcp/ip層,而http服務需要將不同的url對應到不同的後端服務,service是無法實現這一功能的。

  • Ingress提供http層的負載分發功能
  • Ingress可以實現不同的請求,分發到不同的後端服務
  • Ingress定義後,需要結合Ingress Controller,才能形成完整的功能
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: k8s-demo
  namespace: spring-test
spec:
  rules:
  - host: www.k8s-demo.com
    http:
      paths:
      - path: /hello
        backend:
          serviceName: k8s-demo
          servicePort: 8888
複製程式碼

4.1 Ingress Controller定義

  • 可以使用公有云提供的Ingress Controller
  • 也可以使用google提供的Ingress Controller,以pod形式執行,功能如下:
    • 監聽apiserver,獲取ingress的定義
    • 基於ingress定義,生成nginx的配置檔案的內容
    • 執行nginx -s reload,重新載入配置

4.2 Ingress定義

  • 建立型別為Ingress的yaml檔案
  • 配置spec.rules,指定hostname中url和service的對應關係

四. k8s網路模型

前面hello world程式中,對於如何訪問到服務,有必要了解一下k8s的網路模型,在這之前先介紹docker的網路模型

1. Docker網路模型

docker網路模型

k8s基本原理

  • docker第一次啟動時,會建立虛擬網橋docker0
  • 為docker0分配一個子網
  • docker建立每個容器時,會建立veth裝置對,一端關聯到網橋上,另一端使用linux的網路名稱空間技術連線到容器內,並給容器內eth0裝置分配一個ip地址

2. Docker網路的侷限性

  • Docker網路模型沒有考慮到多主機互聯的網路解決方案,崇尚簡單為美
  • 同一機器內的容器之間可以直接通訊,但是不同機器之間的容器無法通訊
  • 為了跨節點通訊,必須在主機的地址上分配埠,通過埠路由或代理到容器
  • 分配和管理容器特別困難,特別是水平擴充套件時

3. k8s網路模型概述

3.1 k8s網路模型的原則:

  • 每個pod都擁有唯一個獨立的ip地址,稱IP-Per-Pod模型
  • 所有pod都在一個可連通的網路環境中
  • 不管是否在同一個node,都可以通過ip直接通訊
  • pod被看作一臺獨立的物理機或虛擬機器

目前原生docker和kubernetes還不能打通多節點容器與容器的通訊,要支援該模型,必須依靠第三方網路外掛實現,比如:flannel

3.2 設計這個原則的原因:

  • 使用者不需要額外考慮如何建立pod之間的連線
  • 使用者不需要考慮將容器埠對映到主機埠的問題
  • 可以相容過去跑在宿主機和KVM的應用

3.3 IP-Per-Pod與Docker埠對映的區別

  • docker埠對映到宿主機會引入埠管理的複雜性
  • docker最終被訪問的ip和埠,與提供的不一致,引起配置的複雜性

4. k8s網路模型詳解

k8s網路實現

k8s基本原理

4.1 容器與容器的通訊

  • 同一個容器的pod直接共享同一個linux協議棧
  • 就像在同一臺機器上,可通過localhost訪問
  • 可類比一個物理機上不同應用程式的情況

4.2 pod與pod的通訊

同一Node內的pod之間通訊
  • 同一Node內的pod都是通過veth連線在同一個docker0網橋上,地址段相同,所以可以直接通訊
不同Node的pod之間通訊
  • docker0網段與宿主機不在同一個網段,所以不同pod之間的pod不能直接通訊
  • 不同node之間通訊只能通過宿主機物理網路卡
  • 前面說過k8s網路模型需要不同的pod之間能通訊,所以ip不能重複,這就要求k8s部署時要規劃好docker0的網段
  • 同時,要記錄每個pod的ip地址掛在哪個具體的node上
  • 為了達到這個目的,有很多開源軟體增強了docker和k8s的網路

4. 開源網路元件Flannel

4.1 實現的功能

  • 協助k8s給每個Node上的docker容器分配互不衝突的ip地址
  • 能在這些ip地址之間建立覆蓋網路(Overlay Network),將資料傳遞到目標容器

4.2 底層原理

  • Flannel建立名為flannel0的網橋
  • flannel0網橋一端連線docker0網橋,另一端連線flanneld程式
  • flanneld程式一端連線etcd,利用etcd管理分配的ip地址資源,同時監控pod地址,建立pod節點路由表
  • flanneld程式一端連線docker0和物理網路,配合路由表,完成資料包投遞,完成pod之間通訊

4.3 缺點

  • 引入多個網路元件,帶來網路時延和損耗
  • 預設使用udp作為底層傳輸協議,具有不可靠性

五. 總結

  • 本文先通過一個demo,部署在不同的環境中,直觀感受了如何使用k8s。這個過程我們需要思考k8s誕生解決了什麼問題?核心的提供了一個平臺,主要負責容器的自動排程和編排
  • 對k8s有直觀感受後,介紹了下k8s的基本架構。各個元件是如何互動的,在使用k8s過程中不斷回想架構圖,能加深對k8s的瞭解
  • 掌握了基本架構後,想要將服務部署到k8s中,需要對常用的資源物件有一定了解,因此接著介紹了主要的資源物件。k8s中其他的資源物件可類比學習
  • 當你把一個服務部署到k8s之後,如何做驗證呢,如何暴露你的服務呢?需要對k8s的網路模型有一定了解,才能真正掌握它暴露服務的方式。因此最後部分著重介紹了k8s的網路模型

參考

  • 《kubernetes權威指南》