K8S | 容器和Pod元件

2023-07-03 21:00:15

對比軟體安裝和執行;

一、場景

作為研發人員,通常自己電腦的系統環境都是非常複雜,在個人的習慣上,是按照下圖的模組管理電腦的系統環境;

對於「基礎設施」、「主機作業系統」、「系統軟體」來說,通常只做設定修改;

對於自行安裝的軟體環境來說,個人通常這樣分類:「應用軟體」、「研發軟體」、「持續整合」、「虛擬機器器環境」;

  • 應用軟體:主要指常用的辦公軟體,比如檔案編寫,畫圖設計,通訊產品等;
  • 研發軟體:比如基礎開發環境,各種中介軟體環境,資料儲存查詢等;
  • 持續整合:主流的就是Jenkins、Docker、Kubernetes等元件,整體比較複雜,不好管理;
  • 虛擬機器器環境:研發必備的Linux作業系統,用來部署一些標準的元件叢集;

不論是這些軟體環境還是虛擬機器器系統的搭建,基本都是通過下載軟體安裝包,然後在本地部署和定期更新以及執行,基於這個場景再去理解容器和Pod元件,會輕鬆許多;

二、容器

1、容器映象

參考上面系統環境的管理,軟體包和安裝部署的原理;

Docker容器映象是一個輕量級的、獨立的、可執行的軟體包,它包含了執行應用程式所需的一切:程式碼、執行時、系統工具、系統庫和設定,帶有建立Docker容器的說明;

可以通過Dockerfile指令碼自定義映象,也可以使用雲端倉庫中其他人公開發布的,生產環境通常採用私有倉庫管理映象;

容器映象所承載的是封裝了應用程式及其所有軟體依賴的二進位制資料,容器映象是可執行的軟體包,可以單獨執行;通常會建立應用的容器映象並將其推播到某倉庫,然後在Pod中參照它;

2、容器

容器將應用程式從底層的主機設施中解耦,這使得在不同的雲或OS環境中部署更加容易;

容器的本質就是一個檢視隔離、可限制資源、獨立檔案系統的程序集合;

以常見的Linux研發環境來分析,可以限制容器的資源分配,比如記憶體大小、CPU使用,隔離程序之間的通訊,設定獨立的檔案系統等;

Kubernetes叢集中的每個節點都會執行容器,這些容器構成分配給該節點的Pod,單個Pod中的容器會在共同排程下,於同一位置執行在相同的節點上;

從整體上可以把K8S理解為「作業系統」,映象理解為「軟體安裝包」,容器理解為「應用程序」;

3、實踐案例

製作映象,首先將程式碼工程auto-clientauto-serve打包,然後構建映象檔案,放在本地環境中;

  • 製作【auto-client】映象

構建命令

docker build -t auto-client:latest .

Dockerfile指令碼

# 基礎映象
FROM openjdk:8

# 維護者
MAINTAINER cicadasmile

# 持久化目錄
VOLUME /data/docker/logs

# 新增應用服務JAR包
ADD auto-client.jar application.jar

# 設定引數
ENTRYPOINT ["java","-Dspring.profiles.active=dev","-Djava.security.egd=file:/dev/./urandom","-jar","/application.jar"]
  • 製作【auto-serve】映象

構建命令

docker build -t auto-serve:latest .

Dockerfile指令碼

# 基礎映象
FROM openjdk:8

# 維護者
MAINTAINER cicadasmile

# 持久化目錄
VOLUME /data/docker/logs

# 新增應用服務JAR包
ADD auto-serve.jar application.jar

# 設定引數
ENTRYPOINT ["java","-Dspring.profiles.active=dev","-Djava.security.egd=file:/dev/./urandom","-jar","/application.jar"]

三、Pod元件

1、基本概念

Pod是可以在K8S中建立和管理的、最小的可部署的計算單元;

Pod是一組(一個或多個)容器,這些容器共用儲存、網路、以及怎樣執行這些容器的宣告,Pod中的內容總是並置的並且一同排程,在共用的上下文中執行;

2、Pod管理

【Pod建立】

通常不會直接建立Pod,而是使用諸如Deployment或Job這類工作負載資源來建立Pod;是相對臨時性的、用後即拋的一次性實體;

【單容器Pod】

每個Pod都意在執行給定應用程式的單個範例,可以使用多個Pod對應用程式橫向擴充套件,即一個範例一個Pod對應,Pod看作單個容器的包裝器由K8S直接管理,是常見的部署方式;

【多容器Pod】

分散式系統中可能存在由多個緊密耦合且需要共用資源的共處容器組成的應用程式,比較典型的是「生產消費」場景,Pod將這些容器和儲存資源打包為一個可管理的實體;

Pod中的容器被自動安排到叢集中的同一物理機或虛擬機器器上,並可以一起進行排程,容器之間可以共用網路和儲存資源和依賴、彼此通訊、協調何時以及何種方式終止自身;

容器之間原本是被隔離開的,而Pod在設計上可以突破這種隔離,進而實現資源共用;

  • 儲存共用

在Pod層面設定共用的Volume,該Pod中所有容器都可以存取該共用Volume,這也是Pod元件的儲存方式,Volume還允許Pod中持久資料保留下來,即使其中的容器需要重新啟動;

  • 網路共用

同一個Pod內,所有容器共用一個IP地址和埠空間,並且可以通過localhost發現對方;

3、實踐案例

3.1 Pod指令碼

在此前的案例中,都是單容器Pod,這裡演示多容器Pod,將【auto-client】和【auto-serve】放在同一個「auto-pod」中執行;

並且這裡為兩個容器分配CPU和記憶體資源,requests是要為容器指定資源需求,limits是要為容器指定資源限制;

apiVersion: v1
kind: Pod
metadata:
  name: auto-pod
spec:
  containers:
    - name: auto-client
      image: auto-client
      imagePullPolicy: Never
      ports:
        - containerPort: 8079
      resources:
        requests:
          cpu: "250m"
          memory: "64Mi"
        limits:
          cpu: "500m"
          memory: "128Mi"
    - name: auto-serve
      image: auto-serve
      imagePullPolicy: Never
      ports:
        - containerPort: 8082
      resources:
        requests:
          cpu: "250m"
          memory: "64Mi"
        limits:
          cpu: "500m"
          memory: "128Mi"

3.2 Pod命令

  • 建立Pod
kubectl create -f pod.yaml
  • 檢視指定Pod
kubectl get pod/auto-pod -o wide
NAME       READY   STATUS    RESTARTS   AGE    IP           NODE             NOMINATED NODE   READINESS GATES
auto-pod   2/2     Running   0          9m2s   10.1.0.123   docker-desktop   <none>           <none>
  • 檢視指定Pod描述
kubectl describe pod/auto-pod

# 此處只展示部分資訊
Name:         auto-pod
Namespace:    default
Node:         docker-desktop/192.168.65.11
Status:       Running
IP:           10.1.0.123
Containers:
  auto-client:
    Container ID:   docker://Container-ID
    Image:          auto-client
    Image ID:       docker://sha256:Image-ID
    Port:           8079/TCP
    Limits:
      cpu:     500m
      memory:  128Mi
    Requests:
      cpu:        250m
      memory:     64Mi
  auto-serve:
    Container ID:   docker://Container-ID
    Image:          auto-serve
    Image ID:       docker://sha256:Image-ID
    Port:           8082/TCP
    Limits:
      cpu:     500m
      memory:  128Mi
    Requests:
      cpu:        250m
      memory:     64Mi
Events:
  Type    Reason     Age   From               Message
  ----    ------     ----  ----               -------
  Normal  Scheduled  38s   default-scheduler  Successfully assigned default/auto-pod to docker-desktop
  Normal  Pulled     37s   kubelet            Container image "auto-client" already present on machine
  Normal  Created    37s   kubelet            Created container auto-client
  Normal  Started    37s   kubelet            Started container auto-client
  Normal  Pulled     37s   kubelet            Container image "auto-serve" already present on machine
  Normal  Created    37s   kubelet            Created container auto-serve
  Normal  Started    37s   kubelet            Started container auto-serve
  • 刪除Pod
kubectl delete -f pod.yaml

3.3 服務紀錄檔

在「auto-client」服務中,提供一個簡單的定時任務,每10秒存取一次「auto-serve」的介面,列印請求的響應結果;

@Component
public class HttpJob {

    private static final Logger LOG = LoggerFactory.getLogger(HttpJob.class.getName()) ;

    private static final String SERVER_URL = "http://localhost:8082/serve";

    /**
     * 每10秒執行一次
     */
    @Scheduled(fixedDelay = 10000)
    public void systemDate (){
        try{
            SimpleClientHttpRequestFactory factory = new SimpleClientHttpRequestFactory();
            factory.setReadTimeout(3000);
            factory.setConnectTimeout(6000);
            RestTemplate restTemplate = new RestTemplate(factory);
            Map<String,String> paramMap = new HashMap<>() ;
            String result = restTemplate.getForObject(SERVER_URL,String.class,paramMap);
            LOG.info("server-resp::::"+result);
        } catch (Exception e){
            e.printStackTrace();
        }
    }
}

在「auto-serve」服務中,提供一個簡單的Get請求介面;

@RestController
public class ServeWeb {
    private static final Logger logger = LoggerFactory.getLogger(ServeWeb.class) ;

    @Value("${server.port:}")
    private Integer servePort ;

    @GetMapping("/serve")
    public String serve (){
        logger.info("serve:{}",servePort);
        return "serve:"+servePort ;
    }
}

檢視兩個容器的執行紀錄檔,發現「auto-client」和「auto-serve」可以正常通訊,以此來驗證同一個Pod內網路共用;

4、狀態與重啟

4.1 重啟策略

可以在Pod中通過restartPolicy屬性設定重啟策略,常用的取值是Always以降低應用的中斷時間,適用於Pod中的所有容器;

  • Always:預設值,容器失效時,kubelet自動重啟該容器。
  • OnFailure:容器停止執行且退出碼不為0時,kubelet自動重啟該容器。
  • Never:不論容器是什麼狀態,kubelet都不重啟該容器。

4.2 生命週期

  • Pending:Pod被Kubernetes系統接受,但有一個或者多個容器未建立,此階段包括等待Pod被排程的時間和通過網路下載映象的時間。
  • Running:Pod已經繫結到了某個節點,Pod中所有的容器都已被建立,至少有一個容器在執行,或者正處於啟動或重啟狀態。
  • Succeeded:Pod中的所有容器都已成功終止,並且不會再重啟。
  • Failed:Pod中的所有容器都已終止,並且至少有一個容器是因為失敗被終止。
  • Unknown:因為某些原因無法取得Pod的狀態,通常是因為與Pod所在主機通訊失敗。

Pod遵循預定義的生命週期,起始於Pending階段,如果至少其中有一個主要容器正常啟動,則進入Running階段,之後取決於Pod中是否有容器以失敗狀態結束而進入Succeeded或者Failed階段。

四、參考原始碼

檔案倉庫:
https://gitee.com/cicadasmile/butte-java-note

指令碼倉庫:
https://gitee.com/cicadasmile/butte-auto-parent