Pod基礎概念:
Pod是kubernetes中最小的資源管理組件,Pod也是最小化運行容器化應用的資源對象。一個Pod代表着集群中運行的一個進程。kubernetes中其他大多數組件都是圍繞着Pod來進行支撐和擴展Pod功能的,例如,用於管理Pod運行的StatefulSet和Deployment等控制器對象,用於暴露Pod應用的Service和Ingress對象,為Pod提供存儲的PersistentVolume存儲資源對象等。
在Kubrenetes集群中Pod有如下兩種使用方式:
●一個Pod中運行一個容器。“每個Pod中一個容器”的模式是最常見的用法;在這種使用方式中,你可以把Pod想象成是單個容器的封裝,kuberentes管理的是Pod而不是直接管理容器。
●在一個Pod中同時運行多個容器。一個Pod中也可以同時封裝幾個需要緊密耦合互相協作的容器,它們之間共享資源。這些在同一個Pod中的容器可以互相協作成為一個service單位,比如一個容器共享文件,另一個“sidecar”容器來更新這些文件。Pod將這些容器的存儲資源作為一個實體來管理。
一個Pod下的容器必須運行於同一節點上。現代容器技術建議一個容器只運行一個進程,該進程在容器中PID命令空間中的進程號為1,可直接接收並處理信號,進程終止時容器生命周期也就結束了。若想在容器內運行多個進程,需要有一個類似Linux操作系統init進程的管控類進程,以樹狀結構完成多進程的生命周期管理。運行於各自容器內的進程無法直接完成網絡通信,這是由於容器間的隔離機制導致,k8s中的Pod資源抽象正是解決此類問題,Pod對象是一組容器的集合,這些容器共享Network、UTS及IPC命令空間,因此具有相同的域名、主機名和網絡接口,並可通過IPC直接通信。
Pod資源中針對各容器提供網絡命令空間等共享機制的是底層基礎容器pause,基礎容器(也可稱為父容器)pause就是為了管理Pod容器間的共享操作,這個父容器需要能夠准確地知道如何去創建共享運行環境的容器,還能管理這些容器的生命周期。為了實現這個父容器的構想,kubernetes中,用pause容器來作為一個Pod中所有容器的父容器。這個pause容器有兩個核心的功能,一是它提供整個Pod的Linux命名空間的基礎。二來啟用PID命名空間,它在每個Pod中都作為PID為1進程(init進程),並回收僵屍進程。
pause容器使得Pod中的所有容器可以共享兩種資源:網絡和存儲。
●網絡:
每個Pod都會被分配一個唯一的IP地址。Pod中的所有容器共享網絡空間,包括IP地址和端口。Pod內部的容器可以使用localhost互相通信。Pod中的容器與外界通信時,必須分配共享網絡資源(例如使用宿主機的端口映射)。
●存儲:
可以Pod指定多個共享的Volume。Pod中的所有容器都可以訪問共享的Volume。Volume也可以用來持久化Pod中的存儲資源,以防容器重啟后文件丟失。
總結:
每個Pod都有一個特殊的被稱為“基礎容器”的Pause容器。Pause容器對應的鏡像屬於Kubernetes平台的一部分,除了Pause容器,每個Pod還包含一個或者多個緊密相關的用戶應用容器。
kubernetes中的pause容器主要為每個容器提供以下功能:
●在pod中擔任Linux命名空間(如網絡命令空間)共享的基礎;
●啟用PID命名空間,開啟init進程。
Kubernetes為什么設計這樣的Pod概念和特殊組成結構
●原因一:在一組容器作為一個單元的情況下,難以對整體的容器簡單地進行判斷及有效地進行行動。比如,一個容器死亡了,此時是算整體掛了么?那么引入與業務無關的Pause容器作為Pod的基礎容器,以它的狀態代表着整個容器組的狀態,這樣就可以解決該問題。
●原因二:Pod里的多個應用容器共享Pause容器的IP,共享Pause容器掛載的Volume,這樣簡化了應用容器之間的通信問題,也解決了容器之間的文件共享問題。
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容器的分類:
1、基礎容器(infrastructure container)
//維護整個 Pod 網絡和存儲空間
//node 節點中操作
//啟動一個容器時,k8s會自動啟動一個基礎容器
cat /opt/kubernetes/cfg/kubelet
......
--pod-infra-container-image=registry.cn-hangzhou.aliyuncs.com/google-containers/pause-amd64:3.0"
//每次創建 Pod 時候就會創建,運行的每一個容器都有一個 pause-amd64 的基礎容器自動會運行,對於用戶是透明的
docker ps -a
registry.cn-hangzhou.aliyuncs.com/google-containers/pause-amd64:3.0 "/pause"
2、初始化容器(initcontainers)
//Init容器必須在應用程序容器啟動之前運行完成,而應用程序容器是並行運行的,所以Init容器能夠提供了一種簡單的阻塞或延遲應用容器的啟動的方法。
Init 容器與普通的容器非常像,除了以下兩點:
●Init 容器總是運行到成功完成為止
●每個 Init 容器都必須在下一個 Init 容器啟動之前成功完成啟動和退出
如果 Pod 的 Init 容器失敗,k8s 會不斷地重啟該 Pod,直到 Init 容器成功為止。然而,如果 Pod 對應的重啟策略(restartPolicy)為 Never,它不會重新啟動。
//Init 的容器作用
因為init容器具有與應用容器分離的單獨鏡像,其啟動相關代碼具有如下優勢:
●Init 容器可以包含一些安裝過程中應用容器中不存在的實用工具或個性化代碼。例如,沒有必要僅為了在安裝過程中使用類似 sed、 awk、 python 或 dig 這樣的工具而去FROM 一個鏡像來生成一個新的鏡像。
●Init 容器可以安全地運行這些工具,避免這些工具導致應用鏡像的安全性降低。
●應用鏡像的創建者和部署者可以各自獨立工作,而沒有必要聯合構建一個單獨的應用鏡像。
●Init 容器能以不同於Pod內應用容器的文件系統視圖運行。因此,Init容器可具有訪問 Secrets 的權限,而應用容器不能夠訪問。
●由於 Init 容器必須在應用容器啟動之前運行完成,因此 Init 容器提供了一種機制來阻塞或延遲應用容器的啟動,
直到滿足了一組先決條件。一旦前置條件滿足,Pod內的所有的應用容器會並行啟動。
3、應用容器(Maincontainer)
//並行啟動
官網示例:
https://kubernetes.io/docs/concepts/workloads/pods/init-containers/
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.$(cat /var/run/secrets/kubernetes.io/serviceaccount/namespace).svc.cluster.local; do echo waiting for myservice; sleep 2; done"]
- name: init-mydb
image: busybox:1.28
command: ['sh', '-c', "until nslookup mydb.$(cat /var/run/secrets/kubernetes.io/serviceaccount/namespace).svc.cluster.local; do echo waiting for mydb; sleep 2; done"]
這個例子是定義了一個具有 2 個 Init 容器的簡單 Pod。 第一個等待 myservice 啟動, 第二個等待 mydb 啟動。 一旦這兩個 Init容器都啟動完成,Pod 將啟動 spec 中的應用容器。
kubectl describe pod myapp-pod
kubectl logs myapp-pod -c init-myservice
vim myservice.yaml
apiVersion: v1
kind: Service
metadata:
name: myservice
spec:
ports:
- protocol: TCP
port: 80
targetPort: 9376
kubectl create -f myservice.yaml
kubectl get svc
kubectl get pods -n kube-system
kubectl get pods
vim mydb.yaml
apiVersion: v1
kind: Service
metadata:
name: mydb
spec:
ports:
- protocol: TCP
port: 80
targetPort: 9377
kubectl create -f mydb.yaml
kubectl get pods
//特別說明:
●在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):
Pod 的核心是運行容器,必須指定容器引擎,比如 Docker,啟動容器時,需要拉取鏡像,k8s 的鏡像拉取策略可以由用戶指定:
1、IfNotPresent:在鏡像已經存在的情況下,kubelet 將不再去拉取鏡像,僅當本地缺失時才從倉庫中拉取,默認的鏡像拉取策略
2、Always:每次創建 Pod 都會重新拉取一次鏡像;
3、Never:Pod 不會主動拉取這個鏡像,僅使用本地鏡像。
注意:對於標簽為“:latest”的鏡像文件,其默認的鏡像獲取策略即為“Always”;而對於其他標簽的鏡像,其默認策略則為“IfNotPresent”。
官方示例:
https://kubernetes.io/docs/concepts/containers/images
kubectl apply -f - <<EOF
apiVersion: v1
kind: Pod
metadata:
name: private-image-test-1
spec:
containers:
- name: uses-private-image
image: $PRIVATE_IMAGE_NAME
imagePullPolicy: Always
command: [ "echo", "SUCCESS" ]
EOF
master01 上操作
kubectl edit deployment/nginx-deployment
......
template:
metadata:
creationTimestamp: null
labels:
app: nginx
spec:
containers:
- image: nginx:1.15.4
imagePullPolicy: IfNotPresent #鏡像拉取策略為 IfNotPresent
name: nginx
ports:
- containerPort: 80
protocol: TCP
resources: {}
terminationMessagePath: /dev/termination-log
terminationMessagePolicy: File
dnsPolicy: ClusterFirst
restartPolicy: Always #Pod的重啟策略為 Always,默認值
schedulerName: default-scheduler
securityContext: {}
terminationGracePeriodSeconds: 30
......
創建測試案例
mkdir /opt/demo
cd /opt/demo
vim pod1.yaml
apiVersion: v1
kind: Pod
metadata:
name: pod-test1
spec:
containers:
- name: nginx
image: nginx
imagePullPolicy: Always
command: [ "echo", "SUCCESS" ]
kubectl create -f pod1.yaml
kubectl get pods -o wide
//此時 Pod 會狀態異常,原因是 echo 執行完進程終止,容器生命周期也就結束了
kubectl describe pod pod-test1
//可以發現 Pod 中的容器在生命周期結束后,由於 Pod 的重啟策略為 Always,容器再次重啟了,並且又重新開始拉取鏡像
//修改 pod1.yaml 文件
cd /opt/demo
vim pod1.yaml
apiVersion: v1
kind: Pod
metadata:
name: pod-test1
spec:
containers:
- name: nginx
image: nginx:1.14 #修改 nginx 鏡像版本
imagePullPolicy: Always
#command: [ "echo", "SUCCESS" ] #刪除
//刪除原有的資源
kubectl delete -f pod1.yaml
//更新資源
kubectl apply -f pod1.yaml
//查看 Pod 狀態
kubectl get pods -o wide
//在任意 node 節點上使用 curl 查看頭部信息
部署 harbor 創建私有項目
在 Docker harbor 節點(192.168.73.40)上操作
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
上傳 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 /usr/local/harbor/harbor.cfg
--5行--修改,設置為Harbor服務器的IP地址或者域名
hostname = 192.168.73.40
cd /usr/local/harbor/
./install.sh
在 Harbor 中創建一個新項目
(1)瀏覽器訪問:http://192.168.80.10 登錄 Harbor WEB UI 界面,默認的管理員用戶名和密碼是 admin/Harbor12345
(2)輸入用戶名和密碼登錄界面后可以創建一個新項目。點擊“+項目”按鈕
(3)填寫項目名稱為“kgc-project”,點擊“確定”按鈕,創建新項目
在每個 node 節點配置連接私有倉庫
cat > /etc/docker/daemon.json <<EOF
{
"registry-mirrors": ["https://6ijb8ubo.mirror.aliyuncs.com"],
"insecure-registries":["192.168.73.40"]
}
EOF
systemctl daemon-reload
systemctl restart docker
在每個 node 節點登錄 harbor 私有倉庫
docker login -u admin -p harbor12345 http://192.168.73.40
在一個 node 節點下載 Tomcat 鏡像進行推送
docker pull tomcat:8.0.52
docker images
docker tag tomcat:8.0.52 192.168.73.40/dft-project/tomcat:v1
docker images
docker push 192.168.73.40/dft-project/tomcat:v1
查看登陸憑據
cat /root/.docker/config.json | base64 -w 0 #base64 -w 0 #進行 base64 加密並禁止自動換行
cat /root/.docker/config.json | base64 -w 0 #base64 -w 0
ewoJImF1dGhzIjogewoJCSIxOTIuMTY4LjczLjQwIjogewoJCQkiYXV0aCI6ICJZV1J0YVc0NlNHRnlZbTl5TVRJek5EVT0iCgkJfQoJfQp9
在master節點上創建 harbor 登錄憑據資源清單
vim harbor-pull-secret.yaml
apiVersion: v1
kind: Secret
metadata:
name: harbor-pull-secret
data:
.dockerconfigjson: ewoJImF1dGhzIjogewoJCSIxOTIuMTY4LjczLjQwIjogewoJCQkiYXV0aCI6ICJZV1J0YVc0NlNHRnlZbTl5TVRJek5EVT0iCgkJfQoJfQp9
#復制粘貼上述查看的登陸憑據
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.73.40/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 節點下載的 Tomcat 鏡像
docker rmi tomcat:8.0.52
docker rmi 192.168.73.40/dft-project/tomcat:v1
docker images
//創建資源
kubectl create -f tomcat-deployment.yaml
kubectl get pods