k8s的pod資源管理與配置使用憑證的harbor倉庫
k8s 裡的pod 資源
目錄一: Pod 的基礎概念
1.1 pod 是什麼
Pod是kubernetes中最小的資源管理元件,Pod也是最小化執行容器化應用的資源物件。
一個Pod代表著叢集中執行的一個程序。
kubernetes中其他大多陣列件都是圍繞著Pod來進行支撐和擴充套件Pod功能的,例如,用於管理Pod執行的StatefulSet和Deployment等控制器物件,用於暴露Pod應用的Service和Ingress物件,為Pod提供儲存的PersistentVolume儲存資源物件等。
1.2 pod 的兩種使用(執行方式)
-
一個Pod中執行一個容器。
- 每個Pod中一個容器”的模式是最常見的用法;
- 在這種使用方式中,你可以把Pod想象成是單個容器的封裝,kuberentes管理的是Pod而不是直接管理容器。
-
在一個Pod中同時執行多個容器。
- 一個Pod中也可以同時封裝幾個需要緊密耦合互相協作的容器,它們之間共享資源。
- 這些在同一個Pod中的容器可以互相協作成為一個service單位,比如一個容器共享檔案,另一個“sidecar”容器來更新這些檔案。Pod將這些容器的儲存資源作為一個實體來管理。
1.3 工作方式
一個Pod下的容器必須運行於同一節點上。現代容器技術建議一個容器只執行一個程序,該程序在容器中PID命令空間中的程序號為1,可直接接收並處理訊號,程序終止時容器生命週期也就結束了。
若想在容器內執行多個程序,需要有一個類似Linux作業系統init程序的管控類程序,以樹狀結構完成多程序的生命週期管理。
運行於各自容器內的程序無法直接完成網路通訊,這是由於容器間的隔離機制導致,k8s中的Pod資源抽象正是解決此類問題,Pod物件是一組容器的集合,這些容器共享Network、UTS及IPC命令空間,因此具有相同的域名、主機名和網路介面,並可通過IPC直接通訊。
1.4 pause 容器的功能
1.4.1 提供pid名稱空間,作為pid等於1的init程序
Pod資源中針對各容器提供網路命令空間等共享機制的是底層基礎容器pause,基礎容器(也可稱為父容器)pause就是為了管理Pod容器間的共享操作,這個父容器需要能夠準確地知道如何去建立共享執行環境的容器,還能管理這些容器的生命週期。為了實現這個父容器的構想,kubernetes中,用pause容器來作為一個Pod中所有容器的父容器。
pause容器有兩個核心的功能,一是它提供整個Pod的Linux名稱空間的基礎。二來啟用PID名稱空間,它在每個Pod中都作為PID為1程序(init程序),並回收殭屍程序。
1.4.2pause容器使得Pod中的所有容器可以共享 網路和儲存資源。
-
網路
- 每個Pod都會被分配一個唯一的IP地址。
- Pod中的所有容器共享網路空間,包括IP地址和埠。Pod內部的容器可以使用localhost互相通訊。Pod中的容器與外界通訊時,必須分配共享網路資源(例如使用宿主機的埠對映)。
-
儲存:
- 可以Pod指定多個共享的Volume。Pod中的所有容器都可以訪問共享的Volume。
- Volume也可以用來持久化Pod中的儲存資源,以防容器重啟後文件丟失
1.5 Kubernetes設計這樣的Pod概念和特殊組成結構有什麼用意
原因一:在一組容器作為一個單元的情況下,難以對整體的容器簡單地進行判斷及有效地進行行動。比如,一個容器死亡了,此時是算整體掛了麼?那麼引入與業務無關的Pause容器作為Pod的基礎容器,以它的狀態代表著整個容器組的狀態,這樣就可以解決該問題。
原因二:Pod裡的多個應用容器共享Pause容器的IP,共享Pause容器掛載的Volume,這樣簡化了應用容器之間的通訊問題,也解決了容器之間的檔案共享問題。
1.6 pod 的分類
-
自主式Pod
這種Pod本身是不能自我修復的,當Pod被建立後(不論是由你直接建立還是被其他Controller),都會被Kuberentes排程到叢集的Node上。直到Pod的程序終止、被刪掉、因為缺少資源而被驅逐、或者Node故障之前這個Pod都會一直保持在那個Node上。Pod不會自愈。如果Pod執行的Node故障,或者是排程器本身故障,這個Pod就會被刪除。同樣的,如果Pod所在Node缺少資源或者Pod處於維護狀態,Pod也會被驅逐。 -
控制器管理的Pod
Kubernetes使用更高階的稱為Controller的抽象層,來管理Pod例項。Controller可以建立和管理多個Pod,提供副本管理、滾動升級和叢集級別的自愈能力。例如,如果一個Node故障,Controller就能自動將該節點上的Pod排程到其他健康的Node上。雖然可以直接使用Pod,但是在Kubernetes中通常是使用Controller來管理Pod的。
二: Pod容器分類
2.1 基礎容器(infrastructure container)
維護整個 Pod 網路和儲存空間
啟動一個容器時,k8s會自動啟動一個基礎容器
每次建立 Pod 時候就會建立,執行的每一個容器都有一個 pause-amd64 的基礎容器自動會執行,對於使用者是透明的
#在mster上建立pod
[root@master ~]# kubectl create deployment nginx-demo1 --image=nginx:1.14
#檢視pod 被排程在哪個node節點上
[root@master ~]# kubectl get pod nginx-demo1-7bf84576d8-nhv9n -o wide
#在node01節點上,檢視容器,發現自動建立了pause容器
[root@node01 ~]# docker ps | grep nginx-demo1
2.2 初始化容器(init 容器)initcontainers
Init容器必須在應用程式容器啟動之前執行完成,而應用程式容器是並行執行的,所以Init容器能夠提供了一種簡單的阻塞或延遲應用容器的啟動的方法。
2.2.1 init 容器與普通容器的區別
Init 容器與普通的容器非常像,除了以下兩點:
- Init 容器總是執行到成功完成為止
- 每個 Init 容器都必須在下一個 Init 容器啟動之前成功完成啟動和退出
如果 Pod 的 Init 容器失敗,k8s 會不斷地重啟該 Pod,直到 Init 容器成功為止。然而,如果 Pod 對應的重啟策略(restartPolicy)為 Never,它不會重新啟動。
2.2.2Init 容器的作用
因為init容器具有與應用容器分離的單獨映象,其啟動相關程式碼具有如下優勢:
- Init 容器可以包含一些安裝過程中應用容器中不存在的實用工具或個性化程式碼。例如,沒有必要僅為了在安裝過程中使用類似 sed、 awk、 python 或 dig 這樣的工具而去FROM 一個映象來生成一個新的映象。
- Init 容器可以安全地執行這些工具,避免這些工具導致應用映象的安全性降低。
- 應用映象的建立者和部署者可以各自獨立工作,而沒有必要聯合構建一個單獨的應用映象。
- Init 容器能以不同於Pod內應用容器的檔案系統檢視執行。因此,Init容器可具有訪問 Secrets 的許可權,而應用容器不能夠訪問。
- 由於 Init 容器必須在應用容器啟動之前執行完成,因此 Init 容器提供了一種機制來阻塞或延遲應用容器的啟動,直到滿足了一組先決條件。一旦前置條件滿足,Pod內的所有的應用容器會並行啟動。
2.3 應用容器(業務容器你)(Maincontainer)
平時最常使用的容器
並行啟動
2.4 示例
官網示例:https://kubernetes.io/docs/concepts/workloads/pods/init-containers/
2.4.1 宣告式啟動應用容器
這個例子是定義了一個具有 2 個 Init 容器的簡單 Pod。 第一個等待 myservice 啟動, 第二個等待 mydb 啟動。 一旦這兩個 Init容器都啟動完成,Pod 將啟動 spec 中的應用容器。
[root@master ~]# vim demo1.yaml
apiVersion: v1
kind: Pod
metadata:
name: myapp-pod
labels:
app: myapp
spec:
containers:
- name: myapp-container
image: busybox:1.28
command: ['sh', '-c', 'echo The app is running! && sleep 3600']
initContainers:
- name: init-myservice
image: busybox:1.28
command: ['sh', '-c', 'until nslookup myservice; do echo waiting for myservice; sleep 2; done;']
- name: init-mydb
image: busybox:1.28
command: ['sh', '-c', 'until nslookup mydb; do echo waiting for mydb; sleep 2; done;']
#宣告式啟動
kubectl create -f demo1.yaml
2.4.2 檢視資訊
kubectl get all
#檢視容器的詳細資訊
kubectl describe pod myapp-pod
#檢視日誌
kubectl logs myapp-pod -c init-myservice
2.4.3 建立啟動myservice,檢視日誌
[root@master ~]#vim myservice.yaml
apiVersion: v1
kind: Service
metadata:
#注意,name定義的名字需要是myservice
name: myservice
spec:
ports:
- protocol: TCP
port: 80
targetPort: 9376
kubectl create -f myservice.yaml
[root@master ~]# kubectl get svc
1NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
myservice ClusterIP 10.1.49.69 <none> 80/TCP 4s
[root@master ~]# kubectl get pods
NAME READY STATUS RESTARTS AGE
myapp-pod 0/1 Init:1/2 0 15m
2.4.4檢視容器mydb日誌
#檢視容器init-mydb日誌
kubectl logs myapp-pod -c init-mydb
2.4.5 建立啟動容器mydb,檢視應用容器的狀態
[root@master ~]# vim mydb.yaml
apiVersion: v1
kind: Service
metadata:
#name欄位,值需要是mydb
name: mydb
spec:
ports:
- protocol: TCP
port: 80
targetPort: 9377
[root@master ~]#kubectl create -f mydb.yaml
[root@master ~]# kubectl get pods
NAME READY STATUS RESTARTS AGE
myapp-pod 1/1 Running 0 23m
2.5 特別說明
- 在Pod啟動過程中,Init容器會按順序在網路和資料卷初始化之後啟動。每個容器必須在下一個容器啟動之前成功退出。
- 如果由於執行時或失敗退出,將導致容器啟動失敗,它會根據Pod的restartPolicy指定的策略進行重試。然而,如果Pod的restartPolicy設定為Always,Init容器失敗時會使用RestartPolicy策略。
- 在所有的Init容器沒有成功之前,Pod將不會變成Ready狀態。Init容器的埠將不會在Service中進行聚集。正在初始化中的Pod處於Pending狀態,但應該會將Initializing狀態設定為true。
- 如果Pod重啟,所有Init容器必須重新執行。
- 對Init容器spec的修改被限制在容器image欄位,修改其他欄位都不會生效。更改Init容器的image欄位,等價於重啟該Pod。
- Init容器具有應用容器的所有欄位。除了readinessProbe,因為Init容器無法定義不同於完成(completion)的就緒(readiness)之外的其他狀態。這會在驗證過程中強制執行。
- 在Pod中的每個app和Init容器的名稱必須唯一;與任何其它容器共享同一個名稱,會在驗證時丟擲錯誤。
三:映象拉取策略(image PullPolicy)
3.1 映象拉取策略
Pod 的核心是執行容器,必須指定容器引擎,比如 Docker,啟動容器時,需要拉取映象,k8s 的映象拉取策略可以由使用者指定:
- IfNotPresent:在映象已經存在的情況下,kubelet 將不再去拉取映象,僅當本地缺失時才從倉庫中拉取,預設的映象拉取策略
- Always:每次建立 Pod 都會重新拉取一次映象;
- Never:Pod 不會主動拉取這個映象,僅使用本地映象
注意:對於標籤為“:latest”的映象檔案,或者無標籤的映象檔案,其預設的映象獲取策略即為“Always”;而對於其他標籤的映象,其預設策略則為“IfNotPresent”。
3.2 示例
官方示例:
https://kubernetes.io/docs/concepts/containers/images
3.2.1 建立測試案例
[root@master ~]# vim pod1.yaml
#當kind: 的值為Pod,則表示建立自主式pod
apiVersion: v1
kind: Pod
metadata:
name: pod-test1
spec:
containers:
- name: nginx
image: nginx
imagePullPolicy: Always
#command欄位可以定義容器啟動後的第一個命令
command: [ "echo", "SUCCESS" ]
kubectl create -f pod1.yaml
kubectl get pods -o wide
pod-test1 0/1 CrashLoopBackOff 2 2m17s
#此時 Pod 的狀態異常,原因是 echo 執行完程序終止,容器生命週期也就結束了
3.2.2 更新資源
#修改pod1.yaml檔案
[root@master ~]#vim pod1.yaml
apiVersion: v1
kind: Pod
metadata:
name: pod-test1
spec:
containers:
- name: nginx
#修改 nginx 映象版本,指定標籤
image: nginx:1.14
#註釋映象拉取策略
#imagePullPolicy: Always
#command: [ "echo", "SUCCESS" ] #刪除
#刪除原有的資源
kubectl delete -f pod1.yaml
#更新資源
kubectl apply -f pod1.yaml
[root@master ~]# kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
myapp-pod 1/1 Running 0 61m 10.244.2.47 node02 <none> <none>
nginx-demo1-7bf84576d8-nhv9n 1/1 Running 0 96m 10.244.1.61 node01 <none> <none>
pod-test1 1/1 Running 0 35s 10.244.1.65 node01 <none> <none>
#使用edit 線上修改,檢視資源配置
[root@master ~]# kubectl edit pod pod-test1
四 Pod的重啟策略
4.1 pod 的重啟策略
重啟策略(restartPolicy) : Pod在遇到故障之後重啟的動作
- Always:當容器終止退出後,總是重啟容器,預設策略
- OnFailure:當容器異常退出(退出狀態碼非0)時,重啟容器;正常退出則不重啟容器
- Never:當容器終止退出,從不重啟容器。
注意: K8s中不支援重啟Pod資源,只有刪除重建
4.2 示例
4.2.1 建立啟動一個pod,檢視狀態
[root@master ~]# vim pod3.yaml
apiVersion: v1
kind: Pod
metadata:
name: foo
spec:
containers:
- name: busybox
image: busybox
args:
- /bin/sh
- -c
- sleep 20; exit 3
#建立pod
kubectl apply -f pod3.yaml
#檢視pod狀態
kubectl get pods
4.2.2 修改yaml 檔案,設定重啟策略為Never
[root@master ~]# vim pod3.yaml
apiVersion: v1
kind: Pod
metadata:
name: foo
spec:
containers:
- name: busybox
image: busybox
args:
- /bin/sh
- -c
- sleep 20; exit 3
#設定重啟策略為從不
restartPolicy: Never
[root@master ~]# kubectl delete -f pod3.yaml
[root@master ~]# kubectl apply -f pod3.yaml
#在74s後,即使過了 20s 也沒有新的狀態出現.因為重啟策略是Never,所以,不會重啟
[root@master ~]# kubectl get pods foo -w
NAME READY STATUS RESTARTS AGE
foo 0/1 ContainerCreating 0 40s
foo 1/1 Running 0 54s
foo 0/1 Error 0 74s
#新開一個終端檢視狀態
[root@master ~]# kubectl get pods foo
NAME READY STATUS RESTARTS AGE
foo 0/1 Error 0 103s
總結
- pod 的執行方式有兩種:
- 自主式pod:沒有自愈能力
- 控制器管理pod: 有自愈能力(Pod被刪除後會重新拉起新pod)
- pod 中有 3 種容器:
-
基礎容器(pause):
-
- 初始化容器環境,開啟pid=1的init程序來管理其他容器的生命週期
- 提供網路和儲存空間的共享環境基礎
-
init 容器
-
- 是在基礎容器之後,應用容器之前執行的容器
- 多個容器是序列執行
- init 容器必須在上一init容器執行成功且退出後才會執行
-
應用容器(main c)
-
- 執行業務的容器
- 在init容器都成功執行和退出後執行的
- 多個應用容器是並行執行的
-
在 一個pod 中,init 容器和應用容器的名稱都是唯一的
-
pod 的映象拉取策略 imagePullPolicy,配置在Containers欄位的下面,是它的子欄位
-
IfNotPresent
-
- 是帶有指定標籤的映象的預設拉取測試。
- 本地有,則用本地映象。本地沒有則從倉庫中拉取映象
-
Always
-
- 是沒有標籤的映象或者使用哦latest標籤的映象拉取策略
- 建立pod總是從倉庫拉取映象
-
Never
-
- 不從倉庫拉取映象,僅使用本地映象
- pod 重啟策略 restartPolicy ,配置在containers欄位同一層,和containers同屬 spec的子欄位
-
Always
-
- 預設的重啟策略。
- 容器退出時總是重啟容器
-
Never
-
- 容器退出,從不重啟容器
-
OnFailure
-
- 只有容器異常退出(非0狀態碼退出),才會重啟容器
五: 部署harbor 建立私有專案,使用憑證登入
5.1 在docker harbor 上(192.168.23.10)上環境準備
systemctl stop firewalld.service
systemctl disable firewalld.service
setenforce 0
yum install -y yum-utils device-mapper-persistent-data lvm2
yum-config-manager --add-repo https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
yum install -y docker-ce
systemctl start docker.service
systemctl enable docker.service
docker version
5.2 部署harbor
#上傳 docker-compose 和 harbor-offline-installer-v1.2.2.tgz 到 /opt 目錄中
cd /opt
chmod +x docker-compose
mv docker-compose /usr/local/bin/
#部署 Harbor 服務
tar zxvf harbor-offline-installer-v1.2.2.tgz -C /usr/local/
vim +5 /usr/local/harbor/harbor.cfg
--5行--修改,設定為Harbor伺服器的IP地址或者域名
hostname = 192.168.23.10
cd /usr/local/harbor/
./install.sh
5.3 登入harbor,建立專案
/#在 Harbor 中建立一個新專案
(1)瀏覽器訪問:http://192.168.23.10 登入 Harbor WEB UI 介面,預設的管理員使用者名稱和密碼是 admin/Harbor12345
(2)輸入使用者名稱和密碼登入介面後可以建立一個新專案。點選“+專案”按鈕
(3)填寫專案名稱為“kgc-project”,點選“確定”按鈕,建立新專案
5.4 每個node節點登入harbor ,上傳映象
#在每個 node 節點配置連線私有倉庫(注意每行後面的逗號要新增)
cat > /etc/docker/daemon.json <<EOF
{
"registry-mirrors": ["https://6ijb8ubo.mirror.aliyuncs.com"],
"insecure-registries":["192.168.23.10"]
}
EOF
systemctl daemon-reload
systemctl restart docker
#在每個 node 節點登入 harbor 私有倉庫
docker login -u admin -p harbor12345 http://192.168.23.10
#在一個 node 節點下載 Tomcat 映象進行推送
docker pull tomcat:8.0.52
docker images
docker tag tomcat:8.0.52 192.168.23.10/kgc-project/tomcat:v1
docker images
docker push 192.168.23.10/kgc-project/tomcat:v1
5.5 配置憑據
#檢視登陸憑據
#base64 -w 0:進行 base64 加密並禁止自動換行
cat /root/.docker/config.json | base64 -w 0
ewoJImF1dGhzIjogewoJCSIxOTIuMTY4LjIzLjEwIjogewoJCQkiYXV0aCI6ICJZV1J0YVc0NlNHRnlZbTl5TVRJek5EVT0iCgkJfSwKCQkiaHViLmNvbSI6IHsKCQkJImF1dGgiOiAiWVdSdGFXNDZTR0Z5WW05eU1USXpORFU9IgoJCX0KCX0KfQ==
#master 節點上 建立 harbor 登入憑據資源清單
vim harbor-pull-secret.yaml
apiVersion: v1
kind: Secret
metadata:
name: harbor-pull-secret
data:
.dockerconfigjson: ewoJImF1dGhzIjogewoJCSIxOTIuMTY4LjIzLjEwIjogewoJCQkiYXV0aCI6ICJZV1J0YVc0NlNHRnlZbTl5TVRJek5EVT0iCgkJfSwKCQkiaHViLmNvbSI6IHsKCQkJImF1dGgiOiAiWVdSdGFXNDZTR0Z5WW05eU1USXpORFU9IgoJCX0KCX0KfQ== #複製貼上上述檢視的登陸憑據
type: kubernetes.io/dockerconfigjson
#建立 secret 資源
kubectl create -f harbor-pull-secret.yaml
#檢視 secret 資源
kubectl get secret
#建立資源從 harbor 中下載映象
cd /opt/demo
vim tomcat-deployment.yaml
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: my-tomcat
spec:
replicas: 2
template:
metadata:
labels:
app: my-tomcat
spec:
imagePullSecrets: #新增拉取 secret 資源選項
- name: harbor-pull-secret #指定 secret 資源名稱
containers:
- name: my-tomcat
image: 192.168.80.30/kgc-project/tomcat:v1 #指定 harbor 中的映象名
ports:
- containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
name: my-tomcat
spec:
type: NodePort
ports:
- port: 8080
targetPort: 8080
nodePort: 31111
selector:
app: my-tomcat
#node節點刪除之前在 node 節點下載的 Tomcat 映象
docker rmi tomcat:8.0.52
docker rmi 192.168.23.10/kgc-project/tomcat:v1
docker images
#master 節點建立資源
kubectl create -f tomcat-deployment.yaml
kubectl get pods
#檢視 Pod 的描述資訊,可以發現映象時從 harbor 下載的
kubectl describe pod my-tomcat-5487585446-d8j2h
#重新整理 harbor 頁面,可以看到映象的下載次數增加了