二、Kubernetes快速入門
(1)Kubernetes集群的部署方法及部署要點
(2)部署Kubernetes分布式集群
(3)kubectl使用基礎
1、簡介
kubectl就是API service的客戶端程序,通過連接master節點上的API service實現k8s對象、資源的增刪改查操作。
對象:node、pod、service、controller(replicaset,deployment,statefulet,daemonset,job,cronjob)
2、子命令
分類
#基本命令
Basic Commands (Beginner:初級):
create :Create a resource from a file or from stdin.
expose :Take a replication controller, service, deployment or pod and expose it as a new Kubernetes Service
run :Run a particular image on the cluster
set :Set specific features on objects
Basic Commands (Intermediate:中級):
explain :Documentation of resources
get :Display one or many resources
edit :Edit a resource on the server
delete :Delete resources by filenames, stdin, resources and names, or by resources and label selector
Deploy Commands(部署命令):
rollout :Manage the rollout of a resource #回滾
scale :Set a new size for a Deployment, ReplicaSet, Replication Controller, or Job #手動改變應用程序的規模
autoscale :Auto-scale a Deployment, ReplicaSet, or ReplicationController #自動改變
Cluster Management Commands(集群管理命令):
certificate :Modify certificate resources. #證書
cluster-info :Display cluster info #集群信息
top :Display Resource (CPU/Memory/Storage) usage.
cordon :Mark node as unschedulable #標記節點不可被調用
uncordon :Mark node as schedulable
drain :Drain node in preparation for maintenance #排干節點
taint :Update the taints on one or more nodes #給節點增加污點
Troubleshooting and Debugging Commands(故障排除和調試命令):
describe :Show details of a specific resource or group of resources #描述資源的詳細信息
logs :Print the logs for a container in a pod
attach :Attach to a running container
exec :Execute a command in a container
port-forward :Forward one or more local ports to a pod #端口轉發
proxy :Run a proxy to the Kubernetes API server
cp :Copy files and directories to and from containers.
auth :Inspect authorization
Advanced Commands(高級命令):
apply :Apply a configuration to a resource by filename or stdin
patch :Update field(s) of a resource using strategic merge patch
replace :Replace a resource by filename or stdin
wait :Experimental: Wait for a specific condition on one or many resources.
convert :Convert config files between different API versions
Settings Commands(設置命令):
label :Update the labels on a resource #標簽,有長度限制
annotate :Update the annotations on a resource #注解
completion :Output shell completion code for the specified shell (bash or zsh) #命令補全
Other Commands:
alpha :Commands for features in alpha
api-resources :Print the supported API resources on the server
api-versions :Print the supported API versions on the server, in the form of "group/version"
config :Modify kubeconfig files
plugin :Provides utilities for interacting with plugins.
version :Print the client and server version information
Usage:
kubectl [flags] [options]
3、創建Pod
創建一個控制器名為nginx-deploy,鏡像版本為nginx:1.14-alpine的Pod,暴露端口80,副本為1
[root@master ~]# kubectl run nginx-deploy --image=nginx:1.14-alpine --port=80 --replicas=1
如下圖,此時可以看出創建成功了,而且在node02節點上,網段是10.244.2.0/24,而node01節點的網段是10.244.1.0/24。
可通過node01節點進行訪問試試,而10.244.2.2是pod地址,只能在k8s集群中內部才能訪問。
Pod的客戶端有兩類:其他Pod和集群外的客戶端。
現在我們把nginx-deploy-5b595999-2q6j5刪除,然后控制器會自動創建一個新的Pod,如下圖:
而此時Pod的ip為10.244.1.2,因此需要給Pod一個固定端點來進行訪問,而這個固定端點是有servcie創建的
service的類型有:ClusterIP、NodePort、LoadBalancer、ExternalName。默認是ClusterIP,意思是這個service只有一個service IP,只能在集群內被各Pod客戶端訪問,而不能被集群外部的客戶端訪問。
創建service命令:kubectl expose deployment(控制器類型)nginx-deploy(控制器名稱) --name 服務名 --port=service端口 --target-port=Pod的端口(即容器端口)
這樣就可以通過固定的service的IP(10.98.39.54)來訪問nginx了
不僅可以通過訪問service的ip來訪問Pod,也可以通過service的服務名來訪問,前提是Pod客戶端需要能解析這個服務名,解析時需要依賴Core-dns服務。而物理機上的解析文件/etc/resolv.conf中的解析的IP不是Core-dns,可以通過master節點查看,命令為:kubectl get pods -n kube-system -o wide。如下圖:
而coredns也有服務名,叫kube-dns,如下圖:
如果從master節點上創建一個Pod客戶端來訪問其他Pod,它的dns服務直接指定到kube-dns的IP上。
因此在各個Pod客戶端之外解析的時候要加上搜索域,例如,在clinet這個Pod之外的master節點上解析就需要加上搜索域:
此時可以將這個nginx的Pod刪除,當控制器再次自動創建時,Pod的ip已經變為10.244.1.3,然后再次訪問servic的ip和服務名都可以訪問得到。
通過service的ip和服務名訪問Pod,不管Pod是如何變化,它都是根據service的標簽選擇器來判斷的
如何驗證,我們可以在master節點查看各Pod的標簽選擇器
同理,service的ip也動態生成的,當你刪除service,再創建相同的service的話,ip已經是另外一個。
同理,Pod是根據標簽選擇器歸為一類,而控制器,例如deployment也是根據標簽選擇器歸為一類。
4、集群外部訪問Pod
修改service中spec的type即可,將其改為NodePort
此時就可以在集群外部,通過節點ip:30020來訪問Pod了。
(4)命令式應用部署、擴縮容、服務暴露
1、擴、縮容Pod
創建一類名為myapp的Pod,副本為2個,可以kubectl get deployment -w進行實時監控創建情況
同時也創建一個service,服務名為myapp
通過Pod客戶端來訪問進行驗證,訪問服務名myapp是可以看到Hell MyApp,然后也可以訪問hostname.html查看Pod名稱
通過循環語句來驗證是隨機訪問這兩個Pod的
在副本為2的基礎上,進行擴容為5個
2、升級Pod
kubectl set image 控制器名稱 Pod名 容器名=鏡像:版本
注:容器名可以指多個,是指Pod內中的各層容器
將myapp版本更新為v2
kubectl set image deployment myapp myapp=ikubernetes/myapp:v2
通過rollout進行查看更新狀態
3、回滾
三、資源配置清單及Pod資源
(1)Kubernetes API中的資源配置格式
Restful定義:representational state transfer(表象性狀態轉變)或者表述性狀態轉移,詳解見:https://blog.csdn.net/hzy38324/article/details/78360525?utm_source=gold_browser_extension
Restful中的狀態get、put、delete、post通過kubectl run,get,edit等命令展現出來
(2)資源類型、API群組及其版本介紹
1、資源類型
k8s中所有內容抽象為資源,資源實例化后稱為對象。
workload(工作負載):Pod,ReplicaSet,Deployment,StatefulSet,DaemonSet,Job,Cronjob等
服務發現及均衡:Service,Ingress等
配置與存儲:Volume,CSI等
ConfigMap,Secret
DownwardAPI
集群級資源:Namespace,Node,Role,ClusterRole,RoleBinding,ClusterRoleBinding
元數據型資源:HPA,PodTemplate,LimitRange
(3)Pod資源及其配置格式
1、yaml格式
# yaml格式的pod定義文件完整內容:
apiVersion: v1 #必選,api版本號(或者組名+版本號:group/version。而group省略,則表示core(核心組)的意思),例如v1就是核心組
kind: Pod #必選,資源類別,例如:Pod
metadata: #必選,元數據(內部需要嵌套二級、三級字段)
name: string #必選,Pod名稱
namespace: string #必選,Pod所屬的命名空間
labels: #自定義標簽
- name: string #自定義標簽名字
annotations: #自定義注釋列表
- name: string
spec: #必選,規格即定義創建的資源對象應該要滿足什么樣的規范。Pod中容器的詳細定義
containers: #必選,Pod中容器列表
- name: string #必選,容器名稱
image: string #必選,容器的鏡像名稱
imagePullPolicy: [Always | Never | IfNotPresent] #獲取鏡像的策略 Alawys表示下載鏡像 IfnotPresent表示優先使用本地鏡像,否則下載鏡像,Nerver表示僅使用本地鏡像
command: [string] #容器的啟動命令列表,如不指定,使用打包時使用的啟動命令
args: [string] #容器的啟動命令參數列表
workingDir: string #容器的工作目錄
volumeMounts: #掛載到容器內部的存儲卷配置
- name: string #引用pod定義的共享存儲卷的名稱,需用volumes[]部分定義的的卷名
mountPath: string #存儲卷在容器內mount的絕對路徑,應少於512字符
readOnly: boolean #是否為只讀模式
ports: #需要暴露的端口庫號列表
- name: string #端口號名稱
containerPort: int #容器需要監聽的端口號
hostPort: int #容器所在主機需要監聽的端口號,默認與Container相同
protocol: string #端口協議,支持TCP和UDP,默認TCP
env: #容器運行前需設置的環境變量列表
- name: string #環境變量名稱
value: string #環境變量的值
resources: #資源限制和請求的設置
limits: #資源限制的設置
cpu: string #Cpu的限制,單位為core數,將用於docker run --cpu-shares參數
memory: string #內存限制,單位可以為Mib/Gib,將用於docker run --memory參數
requests: #資源請求的設置
cpu: string #Cpu請求,容器啟動的初始可用數量
memory: string #內存清楚,容器啟動的初始可用數量
livenessProbe: #對Pod內個容器健康檢查的設置,當探測無響應幾次后將自動重啟該容器,檢查方法有exec、httpGet和tcpSocket,對一個容器只需設置其中一種方法即可
exec: #對Pod容器內檢查方式設置為exec方式
command: [string] #exec方式需要制定的命令或腳本
httpGet: #對Pod內個容器健康檢查方法設置為HttpGet,需要制定Path、port
path: string
port: number
host: string
scheme: string
HttpHeaders:
- name: string
value: string
tcpSocket: #對Pod內個容器健康檢查方式設置為tcpSocket方式
port: number
initialDelaySeconds: 0 #容器啟動完成后首次探測的時間,單位為秒
timeoutSeconds: 0 #對容器健康檢查探測等待響應的超時時間,單位秒,默認1秒
periodSeconds: 0 #對容器監控檢查的定期探測時間設置,單位秒,默認10秒一次
successThreshold: 0
failureThreshold: 0
securityContext:
privileged: false
restartPolicy: [Always | Never | OnFailure] #Pod的重啟策略,Always表示一旦不管以何種方式終止運行,kubelet都將重啟,OnFailure表示只有Pod以非0退出碼退出才重啟,Nerver表示不再重啟該Pod
nodeSelector: obeject #設置NodeSelector表示將該Pod調度到包含這個label的node上,以key:value的格式指定
imagePullSecrets: #Pull鏡像時使用的secret名稱,以key:secretkey格式指定
- name: string
hostNetwork: false #是否使用主機網絡模式,默認為false,如果設置為true,表示使用宿主機網絡
volumes: #在該pod上定義共享存儲卷列表
- name: string #共享存儲卷名稱 (volumes類型有很多種)
emptyDir: {} #類型為emtyDir的存儲卷,與Pod同生命周期的一個臨時目錄。為空值
hostPath: string #類型為hostPath的存儲卷,表示掛載Pod所在宿主機的目錄
path: string #Pod所在宿主機的目錄,將被用於同期中mount的目錄
secret: #類型為secret的存儲卷,掛載集群與定義的secre對象到容器內部
scretname: string
items:
- key: string
path: string
configMap: #類型為configMap的存儲卷,掛載預定義的configMap對象到容器內部
name: string
items:
- key: string
path: string
(4)使用配置清單創建自主式Pod資源
創建資源的方法:
apiserver僅接收JSON格式的資源定義;
yaml格式提供配置清單,apiserver可自動將其轉為json格式,而后再提交;
命令:kubectl api-versions
可以查看所有API 群組/版本
其中Pod是最核心資源因此屬於核心組即v1,像控制器屬於應用程序管理核心資源因此他們是apps組,即apps/v1。
大部分資源的配置清單格式都由5個一級字段組成:
apiVersion:api版本號
kind:資源類別
metadata:元數據
name:同一類別下的name是唯一的 namespace:對應的對象屬於哪個名稱空間 labels:標簽,每一個資源都可以有標簽,標簽是一種鍵值數據 annotations:資源注解 每個的資源引用方式(selflink): /api/GROUP/VERSION/namespace/NAMESPACE/TYPE/NAME
spec:用戶定義一個資源對象應該所處的目標狀態,也叫期望狀態(可自定義)(disired state)
status:顯示資源的當前狀態(只讀),本字段由kubernetes進行維護(current state)
K8s存在內嵌的文檔格式說明,可以使用kubectl explain 進行查看,如查看Pod這個資源需要怎么定義:
[root@k8s-master ~]# kubectl explain pods KIND: Pod VERSION: v1 DESCRIPTION: Pod is a collection of containers that can run on a host. This resource is created by clients and scheduled onto hosts. FIELDS: apiVersion <string> APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#resources kind <string> Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#types-kinds metadata <Object> Standard object's metadata. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata spec <Object> Specification of the desired behavior of the pod. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#spec-and-status status <Object> Most recently observed status of the pod. This data may not be up to date. Populated by the system. Read-only. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#spec-and-status
從上面可以看到apiVersion,kind等定義的鍵值都是<string>,而metadata和spec看到是一個<Object>,當看到存在<Object>的提示,說明該字段可以存在多個二級字段,那么可以使用如下命令繼續查看二級字段的定義方式:
[root@k8s-master ~]# kubectl explain pods.metadata
[root@k8s-master ~]# kubectl explain pods.spec
二級字段下,每一種字段都有對應的鍵值類型,常用類型大致如下:
<[]string>:表示是一個字串列表,也就是字符串類型的數組
例如:command字段
<Object>:表示是可以嵌套的字段
例如:像上圖圖中的spec下嵌套containers字段
<map[string]string>:表示是一個由鍵值組成映射
<[]Object>:表示是一個對象列表
例如:上圖圖中的containers字段下的name列表,只是標明image這個鏡像名稱
-name:myapp(標明ikubernetes/myapp:v1簡稱為myapp)
-name:busybox
<[]Object> -required-:required表示該字段是一個必選的字段
使用配置清單創建自主式Pod資源
[root@k8s-master ~]# mkdir manifests
[root@k8s-master ~]# cd manifests
[root@k8s-master manifests]# vim pod-demo.yaml
apiVersion: v1
kind: Pod
metadata:
name: pod-demo
namespace: default
labels:
app: myapp
tier: frontend
spec:
containers:
- name: myapp
image: ikubernetes/myapp:v1
- name: busybox
image: busybox:latest
command:
- "/bin/sh"
- "-c"
- "sleep 3600"
[root@k8s-master manifests]# kubectl create -f pod-demo.yaml
[root@k8s-master manifests]# kubectl get pods
[root@k8s-master manifests]# kubectl describe pods pod-demo #獲取pod詳細信息
[root@k8s-master manifests]# kubectl logs pod-demo myapp #kubectl logs pod名稱 容器名稱 可以具體查看某個pod中某個容器的日志
[root@k8s-master manifests]# kubectl exec -it pod-demo -c myapp -- /bin/sh
[root@k8s-master manifests]# kubectl delete -f xxxxx.yaml #刪除這個yaml文件創建的資源
使用yaml清單創建資源,可以創建裸控制器Pod,無控制器管理,一刪除就沒有了。
事實上使用kubectl
命令管理資源有三種用法:
- 命令式用法;
- 命令式資源清單用法;
- 聲明式資源清單。使用聲明式資源清單,可以確保資源盡可能的向我們聲明的狀態改變,而且可以隨時改變聲明,並隨時應用。
Pod資源下spec的containers必需字段解析
自主式Pod資源(不受控制器控制)
[root@k8s-master ~]# kubectl explain pods.spec.containers name <string> -required- #containers 的名字 image <string> #鏡像地址 imagePullPolicy <string> #如果標簽是latest,默認就是Always(總是下載鏡像) IfNotPresent(先看本地是否有此鏡像,如果沒有就下載) Never (就是使用本地鏡像,如果沒有就從不下載) #這個字段是不允許被更改的 ports <[]Object> #是個對象列表;可以暴露多個端口;可以對每個端口的屬性定義 例如:(名稱(可后期調用)、端口號、協議、暴露在的地址上) 暴露端口只是提供額外信息的,不能限制系統是否真的暴露 - containerPort 容器端口 hostIP 節點地址(基本不會使用) hostPort 節點端口 name 名稱 protocol (默認是TCP) #修改鏡像中的默認應用 args <[]string> 傳遞參數給command 相當於docker中的CMD command <[]string> 相當於docker中的ENTRYPOINT;如果不提供命令,就運行鏡像中的ENTRYPOINT。
官方文檔對於command和args有個詳細的介紹:
https://kubernetes.io/docs/tasks/inject-data-application/define-command-argument-container/
Description | Docker field name | Kubernetes field name |
---|---|---|
The command run by the container | Entrypoint | command |
The arguments passed to the command | Cmd | args |
表示docker中的entrypoint、cmd分別相當於kubernetes中的command和args。
如果Pod不提供command
或args
使用Container,則使用Docker鏡像中的cmd或者ENTRYPOINT。
如果Pod提供command
但不提供args
,則僅使用提供 command
的。將忽略Docker鏡像中定義EntryPoint和Cmd。
如果Pod中僅提供args
,則args
將作為參數提供給Docker鏡像中EntryPoint。
如果提供了command
和args
,則Docker鏡像中的ENTRYPOINT和CMD都將不會生效,Pod中的args
將作為參數給command運行
。
(5)標簽及標簽選擇器
標簽既可以在對象創建時指定,也可以在創建之后使用命令來管理
1、標簽
key=value
- key:只能使用字母、數字 、_ 、- 、. (只能以字母數字開頭,不能超過63給字符)
- value: 可以為空,只能使用字母、數字開頭及結尾,中間可以使用字母、數字 、_ 、- 、.(不能超過63給字符)
[root@k8s-master manifests]# kubectl get pods --show-labels #查看所有資源的pod標簽
NAME READY STATUS RESTARTS AGE LABELS
pod-demo 2/2 Running 0 25s app=myapp,tier=frontend
[root@k8s-master manifests]# kubectl get pods -l app #只顯示包含app的標簽
NAME READY STATUS RESTARTS AGE
pod-demo 2/2 Running 0 1m
[root@k8s-master manifests]# kubectl get pods -L app #顯示app字段的標簽值的pod的資源
NAME READY STATUS RESTARTS AGE APP
pod-demo 2/2 Running 0 1m myapp
[root@k8s-master manifests]# kubectl label pods pod-demo release=canary #給pod-demo打上標簽
pod/pod-demo labeled
[root@k8s-master manifests]# kubectl get pods -l app --show-labels
NAME READY STATUS RESTARTS AGE LABELS
pod-demo 2/2 Running 0 1m app=myapp,release=canary,tier=frontend
[root@k8s-master manifests]# kubectl label pods pod-demo release=stable --overwrite #修改標簽
pod/pod-demo labeled
[root@k8s-master manifests]# kubectl get pods -l release
NAME READY STATUS RESTARTS AGE
pod-demo 2/2 Running 0 2m
[root@k8s-master manifests]# kubectl get pods -l release,app
NAME READY STATUS RESTARTS AGE
pod-demo 2/2 Running 0 2m
2、標簽選擇器類別
- 等值關系標簽選擇器:=, == , != (kubectl get pods -l app=test,app=dev)
- 集合關系標簽選擇器: KEY in (value1,value2,value3);KEY notin (value1,value2,value3); !KEY (例如:kubectl get pods -l "app in (test,dev)")
許多資源支持內嵌字段定義其使用的標簽選擇器
- matchLabels: 直接給定鍵值
- matchExpressions: 基於給定的表達式來定義使用標簽選擇器,{key:"KEY",operator:"OPERATOR",values:[V1,V2,....]}
- 操作符(即OPERATOR):in、notin(Values字段的值必須為非空列表)、Exists、NotExists(Values字段的值必須為空列表)
(6)Pod的節點選擇器
[root@k8s-master manifests]# kubectl get nodes --show-labels #查看node節點的標簽
如上圖beta.kubernetes.io是標簽前綴,標簽前綴必須是DNS名稱,DNS域名或者子域名,最長長度不能超過254個字符
[root@k8s-master manifests]# kubectl explain pod.spec
nodeName <string> #直接指定node節點名稱 NodeName is a request to schedule this pod onto a specific node. If it is non-empty, the scheduler simply schedules this pod onto that node, assuming that it fits resource requirements. nodeSelector <map[string]string> NodeSelector is a selector which must be true for the pod to fit on a node. Selector which must match a node's labels for the pod to be scheduled on that node. More info: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/
nodeSelector可以限定pod創建或者運行在哪個或哪類節點上,舉個例子,給節點k8s-node01打上標簽disktype=ssd,讓pod-demo指定創建在k8s-node01上
(1)給k8s-node01節點打標簽 [root@k8s-master manifests]# kubectl label nodes k8s-node01 disktype=ssd
node/k8s-node01 labeled [root@k8s-master manifests]# kubectl get nodes --show-labels
NAME STATUS ROLES AGE VERSION LABELS k8s-master Ready master 10d v1.11.2 beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/hostname=k8s-master,node-role.kubernetes.io/master= k8s-node01 Ready <none> 10d v1.11.2 beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,disktype=ssd,kubernetes.io/hostname=k8s-node01 k8s-node02 Ready <none> 9d v1.11.2 beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/hostname=k8s-node02 (2)修改yaml文件,增加標簽選擇器 [root@k8s-master manifests]# cat pod-demo.yaml
apiVersion: v1 kind: Pod metadata: name: pod-demo namespace: default labels: app: myapp tier: frontend spec: containers: - name: myapp image: ikubernetes/myapp:v1 - name: busybox image: busybox:latest command: - "/bin/sh" - "-c" - "sleep 3600" nodeSeletor: disktype: ssd (3)重新創建pod-demo,可以看到固定調度在k8s-node01節點上 [root@k8s-master manifests]# kubectl delete -f pod-demo.yaml
pod "pod-demo" deleted [root@k8s-master manifests]# kubectl create -f pod-demo.yaml
pod/pod-demo created [root@k8s-master mainfests]# kubectl get pods -o wide NAME READY STATUS RESTARTS AGE IP NODE pod-demo 2/2 Running 0 20s 10.244.1.13 k8s-node01 [root@k8s-master manifests]# kubectl describe pod pod-demo
...... Events: Type Reason Age From Message ---- ------ ---- ---- ------- Normal Scheduled 42s default-scheduler Successfully assigned default/pod-demo to k8s-node01 ......
annotations:
與label不同的地方在於,annotations不能用於挑選資源對象,僅用於為對象提供"元數據",沒有鍵值長度限制。在聲明式配置構建大型鏡像相關信息時,通常都會添加annotations,用來標記對應的資源對象的元數據或者屬性信息,同樣想查看annotations的信息可以使用kubectl describe pod pod-demo
(7)容器存活狀態探測及就緒狀態探測
1、Pod生命周期
在pod生命周期中需要經歷以下幾個階段。主容器(main container)在運行前需要做一些環境設定,因此在啟動之前可以運行另一個容器,為主容器做一些環境初始化,這類容器被稱為init容器(init container)。初始化容器可以有多個,他們是串行執行的,執行完成后就退出了。在主容器剛剛啟動之后,可以嵌入一個post start命令執行一些操作,在主容器結束前也可以指定一個 pre stop命令執行一些操作,作為開場的預設,結束時的清理。在整個主容器執行過程中,還可以做兩類對Pod的檢測 liveness probe 和 readness probe。如下圖:
Kubelet 可以選擇是否執行在容器上運行的兩種探針執行和做出反應:
livenessProbe
:存活狀態檢測。指容器是否正在運行。如果存活探測失敗,則 kubelet 會殺死容器,並且容器將受到其 重啟策略 的影響。如果容器不提供存活探針,則默認狀態為Success
。readinessProbe
:就緒狀態檢測。指容器是否准備好服務請求。如果就緒探測失敗,端點控制器將從與 Pod 匹配的所有 Service 的端點中刪除該 Pod 的 IP 地址。初始延遲之前的就緒狀態默認為Failure
。如果容器不提供就緒探針,則默認狀態為Success
。
2、常見的Pod狀態
Pod 的 status
在信息保存在 PodStatus 中定義,其中有一個 phase
字段。
Pod 的相位(phase)是 Pod 在其生命周期中的簡單宏觀概述。該階段並不是對容器或 Pod 的綜合匯總,也不是為了做為綜合狀態機。
Pod 相位的數量和含義是嚴格指定的。除了本文檔中列舉的狀態外,不應該再假定 Pod 有其他的 phase
值。
下面是 phase
可能的值:
- 掛起(Pending):Pod 已被 Kubernetes 系統接受,但有一個或者多個容器鏡像尚未創建。等待時間包括調度 Pod 的時間和通過網絡下載鏡像的時間,這可能需要花點時間。
- 運行中(Running):該 Pod 已經綁定到了一個節點上,Pod 中所有的容器都已被創建。至少有一個容器正在運行,或者正處於啟動或重啟狀態。
- 成功(Succeeded):Pod 中的所有容器都被成功終止,並且不會再重啟。
- 失敗(Failed):Pod 中的所有容器都已終止了,並且至少有一個容器是因為失敗終止。也就是說,容器以非0狀態退出或者被系統終止。
- 未知(Unknown):因為某些原因無法取得 Pod 的狀態,通常是因為與 Pod 所在主機通信失敗。
下圖是Pod的生命周期示意圖,從圖中可以看到Pod狀態的變化。
3、總結
Pod生命周期中的重要行為
1、初始化容器
2、容器探測:livenessProbe和
readinessProbe
livenessProbe
:存活狀態檢測(判定主容器是否處於運行狀態)
readinessProbe
:就緒狀態檢測(判定容器中的主進程,是否已經准備就緒並可以對外提供服務)
#kubernetes把容器探測分為這兩種形式,而docker只需探測第一種,如果容器不存活,這個docker就結束了;相對於kubernetes而言,一個Pod里可以存在多個容器。
容器探測的三種行為:
- ExecAction:在容器內執行指定命令。如果命令退出時返回碼為 0 則認為診斷成功。
- TCPSocketAction:對指定端口上的容器的 IP 地址進行 TCP 檢查。如果端口打開,則診斷被認為是成功的。
- HTTPGetAction:對指定的端口和路徑上的容器的 IP 地址執行 HTTP Get 請求。如果響應的狀態碼大於等於200 且小於 400,則診斷被認為是成功的。
容器重啟策略
[root@k8s-master manifests]# kubectl explain pod.spec
Spec 中有一個 restartPolicy
字段,可能的值為 Always、OnFailure 和 Never。默認為 Always。
Always:一旦Pod中的容器掛了,總是重啟
OnFailure:狀態錯誤時才重啟,正常關掉不重啟
Never: 狀態錯誤和正常關掉也從不重啟
其中默認值是Always,如果一直重啟對服務器是有壓力的,所以它重啟策略是,第一次為立即重啟;接下來第二次重啟則需要延時,比如延時10s在進行重啟;第三次延時20s;第四次延時40s;往下80s、160s、300s,300s是最長的延時時間(即5分鍾)。pod一旦綁定到一個節點,Pod 將永遠不會重新綁定到另一個節點,除非刪除Pod重新創建。
4、livenessProbe解析
[root@k8s-master ~]# kubectl explain pod.spec.containers.livenessProbe KIND: Pod VERSION: v1 RESOURCE: livenessProbe <Object> exec #command 的方式探測。例如:ps一個進程 failureThreshold #探測幾次失敗才算失敗,默認是連續三次 periodSeconds #每次多長時間探測一次,默認10s timeoutSeconds #探測超時的秒數 默認1s initialDelaySeconds #初始化延遲探測。第一次探測的時候延遲探測,因為主程序未必啟動完成 tcpSocket #檢測端口的探測 httpGet #http請求探測
舉個例子:定義一個liveness的pod資源類型,基礎鏡像為busybox,在busybox這個容器啟動后會執行創建/tmp/test的文件啊,並刪除,然后等待3600秒。隨后定義了存活性探測,方式是以exec的方式執行命令判斷/tmp/test是否存在,存在即表示存活,不存在則表示容器已經掛了。
[root@master manifests]# cat liveness.exec.ymal
apiVersion: v1
kind: Pod
metadata:
name: liveness-exec-pod
namespace: default
spec:
containers:
- name: liveness-exec-container
image: busybox:latest
imagePullPolicy: IfNotPresent #如果存在就不要下載了
command: ["/bin/sh","-c","touch /tmp/healthy;sleep 60;rm -f /tmp/healthy;sleep 3600"]
livenessProbe: #存活性探測
exec:
command: ["test","-e","/tmp/healthy"] #-e表示探測文件是否存在
initialDelaySeconds: 1 #表示容器啟動后多長時間開始探測
periodSeconds: 3 #表示每隔3s鍾探測一次
[root@master manifests]# kubectl create -f liveness.exec.ymal
pod/liveness-exec-pod created
[root@master manifests]# kubectl get pods -w
NAME READY STATUS RESTARTS AGE
liveness-exec-pod 1/1 Running 2 4m
[root@master manifests]# kubectl get pods -w
NAME READY STATUS RESTARTS AGE
liveness-exec-pod 1/1 Running 4 6m
[root@master manifests]# kubectl get pods -w
NAME READY STATUS RESTARTS AGE
client 1/1 Running 0 3d
liveness-exec-pod 1/1 Running 5 9m
[root@master manifests]# kubectl get pods -w
NAME READY STATUS RESTARTS AGE
client 1/1 Running 0 3d
liveness-exec-pod 1/1 Running 9 23m
可以看到restart此時在隨着時間增長。
上面的例子是用exec執行命令進行探測的。
下面我們看看基於tcp和httpget探測的選項。
[root@master manifests]kubectl explain pods.spec.containers.livenessProbe.tcpSocket
[root@master manifests]# kubectl explain pods.spec.containers.livenessProbe.httpGet
下面舉個例子
[root@master manifests]# cat liveness.httpget.yaml
apiVersion: v1
kind: Pod
metadata:
name: liveness-httpget-pod
namespace: default
spec:
containers:
- name: liveness-httpget-container
image: nginx:latest
imagePullPolicy: IfNotPresent #如果存在就不要下載了
ports:
- name: http
containerPort: 80
livenessProbe: #存活性探測
httpGet:
port: http
path: /index.html
initialDelaySeconds: 1
periodSeconds: 3 #表示每隔3s鍾探測一次
[root@master manifests]# kubectl create -f liveness.httpget.yaml
[root@master manifests]# kubectl get pods
NAME READY STATUS RESTARTS AGE
liveness-httpget-pod 1/1 Running 0 4m
[root@master manifests]# kubectl exec -it liveness-httpget-pod -- /bin/sh
# rm -rf /usr/share/nginx/html/index.html
[root@master manifests]# kubectl get pods
NAME READY STATUS RESTARTS AGE
liveness-httpget-pod 1/1 Running 1 27m
上面可以看到,當刪除pod里面的/usr/share/nginx/html/index.html,liveness監測到index.html文件被刪除了,所以restarts次數為1,但是只重啟一次,不會再重啟了。這是因為重啟一次后,nginx容器就重新初始化了,里面就會又生成index.html文件。所以里面就會有新的index.html文件了。
readlinessProbe(准備就緒型探針)
[root@master manifests]# cat readiness-httpget.ymal
apiVersion: v1
kind: Pod
metadata:
name: readdliness-httpget-pod
namespace: default
spec:
containers:
- name: readliness-httpget-container
image: nginx:latest
imagePullPolicy: IfNotPresent #如果存在就不要下載了
ports:
- name: http
containerPort: 80
readinessProbe: #准備型探針
httpGet:
port: http
path: /index.html
initialDelaySeconds: 1
periodSeconds: 3 #表示每隔3s鍾探測一次
[root@master manifests]# kubectl create -f readiness-httpget.ymal
pod/readdliness-httpget-pod created
[root@master ~]# kubectl get pods
NAME READY STATUS RESTARTS AGE
readdliness-httpget-pod 1/1 Running 0 16h
[root@master ~]# kubectl exec -it readdliness-httpget-pod -- /bin/sh
# rm -rf /usr/share/nginx/html/index.html
[root@master ~]# kubectl get pods
NAME READY STATUS RESTARTS AGE
readdliness-httpget-pod 0/1 Running 0 16h
上面可以看到,ready變成0/1了,但是status是runing的,這就是說nginx進程是在的,只是index.html不見了,可以判定nginx沒有就緒。
postStart(啟動后鈎子)
[root@master ~]# kubectl explain pods.spec.containers.lifecycle.postStart
postStart是指容器在啟動之后立即執行的操作,如果執行操作失敗了,容器將被終止並且重啟。而重啟與否是由重啟策略。
[root@master manifests]# cat poststart-pod.yaml
apiVersion: v1
kind: Pod
metadata:
name: poststart-pod
namespace: default
spec:
containers:
- name: busybox-httpd
image: busybox:latest
imagePullPolicy: IfNotPresent
lifecycle: #生命周期事件
postStart:
exec:
command: ["mkdir", "-p","/data/web/html"] #這個command是定義postStart后的需要執行的命令
command: ["/bin/sh","-c","sleep 3600"] #這是定義容器里面執行的命令,不過這個命令要先於postStart里面的command
#args: ["-f","-h /data/web/html"] #-f是前台,-h是家目錄
[root@master manifests]# kubectl create -f poststart-pod.yaml
pod/posttart-pod created
說明:刪除的方法
[root@master manifests]# kubectl delete -f poststart-pod.yaml
pod "posttart-pod" deleted
[root@master manifests]# kubectl get pods
NAME READY STATUS RESTARTS AGE
poststart-pod 1/1 Running 0 3m
[root@master manifests]# kubectl exec -it poststart-pod -- /bin/sh
/ # ls /data
web
/ # ls /data/web/html/
上面看到在容器啟動后,建立了/data/web/html目錄。這就是postStart的用法。
preStop(終止之前鈎子)
[root@master ~]# kubectl explain pods.spec.containers.lifecycle.preStop
preStop是指容器在終止前要立即執行的命令,等這些命令執行完了,容器才能終止。
容器的重啟策略-restartPolicy
一旦pod中的容器掛了,我們就把容器重啟。
策略包括如下:
Always:表示容器掛了總是重啟,這是默認策略
OnFailures:表容器狀態為錯誤時才重啟,也就是容器正常終止時才重啟
Never:表示容器掛了不予重啟
對於Always這種策略,容器只要掛了,就會立即重啟,這樣是很耗費資源的。所以Always重啟策略是這么做的:第一次容器掛了立即重啟,如果再掛了就要延時10s重啟,第三次掛了就等20s重啟...... 依次類推
容器的終止策略
k8s會給容器30s的時間進行終止,如果30s后還沒終止,就會強制終止。
總結
pod:
apiVersion
kind
metadata
spec
status(只讀)
spec:
containers
nodeSelector
nodeName
restartPolicy: Always,Never,OnFailure
containers:
name
image
imagePullPolicy: Always、Never、IfNotPresent
ports:
name
containerPort
livenessProbe
readinessProbe
liftcycle
ExecAction: exec
TCPSocketAction: tcpSocket
HTTPGetAction: httpGet
四、Pod控制器
(1)Pod控制器及其功用
(2)通過配置清單管理ReplicaSet控制器,包括擴縮容及更新機制
(3)Deployment控制器基礎應用及滾動更新:灰度部署、金絲雀部署、藍綠部署的實現;
(4)DaemonSet控制器基礎應用及使用案例
上一節,我們創建的pod,是通過資源配置清單定義的,如果手工把這樣的pod刪除后,不會自己重新創建,這樣創建的pod叫自主式Pod。
在生產中,我們很少使用自主式pod。
下面我們學習另外一種pod,叫控制器管理的Pod,控制器會按照定義的策略嚴格控制pod的數量,一旦發現pod數量少了,會立即自動建立出來新的pod;一旦發現pod多了,也會自動殺死多余的Pod。
pod控制器:ReplicaSet控制器、Deployment控制器(必須掌握)、DaenibSet控制器、Job控制器
ReplicaSet控制器 :替用戶創建指定數量Pod的副本,並保證pod副本滿足用戶期望的數量;而且更新自動擴縮容機制。
replicat主要由三個組件組成:1、用戶期望的pod副本數量;2、標簽選擇器(控制管理pod副本);3、pod資源模板(如果pod數量少於期望的,就根據pod模板來新建一定數量的pod)。
Deployment控制器 :Deployment通過控制replicaset來控制Pod。用於管理無狀態應用,目前來說最好的控制器。Deployment支持滾動更新和回滾,聲明式配置的功能。Deployment只關注群體,而不關注個體。
DaemonSet控制器 :用於確保集群中的每一個節點只運行一個特定的pod副本(畫外音,如果沒有DaemonSet,一個節點可以運行多個pod副本)。如果在集群中新加一個節點,那么這個新節點也會自動生成一個Pod副本。
特性:服務是無狀態的;服務必須是守護進程
Job控制器 :對於那些 只做一次,只要完成就正常退出,沒完成才重構pod ,叫job控制器。
Cronjob:周期性任務控制,不需要持續后台運行
StatefulSet控制器: 管理有狀態應用,每一個pod副本都是被單獨管理的。它擁有着自己獨有的標識。
K8s在1.2+至1.7開始,支持TPR(third party resources 第三方資源)。在k8s 1.8+以后,支持CDR(Custom Defined Reources,用戶自定義資源)。
Operator是CoreOS推出的旨在簡化復雜有狀態應用管理的框架,它是一個感知應用狀態的控制器,通過擴展Kubernetes API來自動創建、管理和配置應用實例。
ReplicaSet控制器
ReplicationController用來確保容器應用的副本數始終保持在用戶定義的副本數,即如果有容器異常退出,會自動創建新的Pod來替代;而如果異常多出來的容器也會自動回收。
在新版本的Kubernetes中建議使用ReplicaSet來取代ReplicationController。ReplicaSet跟ReplicationController沒有本質的不同,只是名字不一樣,並且ReplicaSet支持集合式的selector。
雖然ReplicaSet可以獨立使用,但一般還是建議使用 Deployment 來自動管理ReplicaSet,這樣就無需擔心跟其他機制的不兼容問題(比如ReplicaSet不支持rolling-update但Deployment支持)。
[root@master manifests]# kubectl explain replicaset
[root@master manifests]# kubectl explain rs (replicaset的簡寫)
[root@master manifests]# kubectl explain rs.spec.template
[root@master manifests]# kubectl get deploy
NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE
myapp 2 2 2 0 10d
mytomcat 3 3 3 3 10d
nginx-deploy 1 1 1 1 13d
[root@master manifests]# kubectl delete deploy myapp
deployment.extensions "myapp" deleted
[root@master manifests]# kubectl delete deploy nginx-deploy
deployment.extensions "nginx-deploy" deleted
[root@master manifests]# cat rs-demo.yaml
apiVersion: apps/v1
kind: ReplicaSet
metadata:
name: myapp
namespace: default
spec: #這是控制器的spec
replicas: 2 #幾個副本
selector: #查看幫助:,標簽選擇器。 kubectl explain rs.spec.selector
matchLabels:
app: myapp
release: canary
template: # 查看幫助:模板 kubectl explain rs.spec.template
metadata: # kubectl explain rs.spec.template.metadata
name: myapp-pod
labels: #必須符合上面定義的標簽選擇器selector里面的內容
app: myapp
release: canary
environment: qa
spec: #這是pod的spec
containers:
- name: myapp-container
image: ikubernetes/nginx:latest
ports:
- name: http
containerPort: 80
[root@master manifests]# kubectl create -f rs-demo.yaml
replicaset.apps/myapp created
[root@master manifests]# kubectl get rs
NAME DESIRED CURRENT READY AGE
myapp 2 2 2 3m
看到上面的ready是2,表示兩個replcatset控制器都在正常運行。
[root@master manifests]# kubectl get pods --show-labels
myapp-6kncv 1/1 Running 0 15m app=myapp,environment=qa,release=canary
myapp-rbqjz 1/1 Running 0 15m app=myapp,environment=qa,release=canary 5m
pod-demo 0/2 CrashLoopBackOff 2552 9d app=myapp,tier=frontend
[root@master manifests]# kubectl describe pods myapp-6kncv
IP: 10.244.2.44
[root@master manifests]# curl 10.244.2.44 Hello MyApp | Version: v1 | <a href="hostname.html">Pod Name</a>
編輯replicatset的配置文件(這個文件不是我們手工創建的,而是apiserver維護的)
[root@master manifests]# kubectl edit rs myapp
把里面的replicas改成5,保存后就立即生效。
[root@master manifests]# kubectl get pods --show-labels NAME READY STATUS RESTARTS AGE LABELS client 0/1 Error 0 11d run=client liveness-httpget-pod 1/1 Running 3 5d <none> myapp-6kncv 1/1 Running 0 31m app=myapp,environment=qa,release=canary myapp-c64mb 1/1 Running 0 3s app=myapp,environment=qa,release=canary myapp-fsrsg 1/1 Running 0 3s app=myapp,environment=qa,release=canary myapp-ljczj 0/1 ContainerCreating 0 3s app=myapp,environment=qa,release=canary myapp-rbqjz 1/1 Running 0 31m app=myapp,environment=qa,release=canary
同樣,也可以用命令kubectl edit rs myapp升級版本,改里面的image: ikubernetes/myapp:v2,這樣就變成v2版本了。
[root@master manifests]# kubectl get rs -o wide
NAME DESIRED CURRENT READY AGE CONTAINERS IMAGES SELECTOR
myapp 5 5 5 1h myapp-container ikubernetes/myapp:v2 app=myapp,release=canary
不過,只有pod重建后,比如增加、刪除Pod,才會更新成v2版本。
Deployment控制器
我們可以通過Deployment控制器來動態更新pod的版本。
我們先建立replicatset v2版本,然后一個一個的刪除replicatset v1版本中的Pod,這樣自動新創建的pod就會變成v2版本了。當pod全部變成v2版本后,replicatset v1並不會刪除,這樣一旦發現v2版本有問題,還可以回退到v1版本。
通常deployment默認保留10版本的replicatset。
[root@master manifests]# kubectl explain deploy
[root@master manifests]# kubectl explain deploy.spec
[root@master manifests]# kubectl explain deploy.spec.strategy (更新策略)
[root@master ~]# kubectl delete rs myapp
[root@master manifests]# cat deploy-demo.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: myapp-deploy
namespace: default
spec:
replicas: 2
selector: #標簽選擇器
matchLabels: #匹配的標簽為
app: myapp
release: canary
template:
metadata:
labels:
app: myapp #和上面的myapp要匹配
release: canary
spec:
containers:
- name: myapp
image: ikubernetes/myapp:v1
ports:
- name: http
containerPort: 80
[root@master manifests]# kubectl apply -f deploy-demo.yaml
deployment.apps/myapp-deploy created
apply表示是聲明式更新和創建。
[root@master manifests]# kubectl get deploy
NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE
myapp-deploy 2 2 2 2 1m
[root@master ~]# kubectl get rs
NAME DESIRED CURRENT READY AGE
myapp-deploy-69b47bc96d 2 2 2 17m
上面的rs式deployment自動創建的。
[root@master ~]# kubectl get pods
NAME READY STATUS RESTARTS AGE
myapp-deploy-69b47bc96d-7jnwx 1/1 Running 0 19m
myapp-deploy-69b47bc96d-btskk 1/1 Running 0 19m
修改配置文件deploy-demo.yaml,把replicas數字改成3,然后再執行kubectl apply -f deploy-demo.yaml 即可使配置文件里面的內容生效。
[root@master ~]# kubectl describe deploy myapp-deploy
[root@master ~]# kubectl get pods -l app=myapp -w
-l使標簽過濾
-w是動態監控
[root@master ~]# kubectl get rs -o wide
NAME DESIRED CURRENT READY AGE CONTAINERS IMAGES SELECTOR
myapp-deploy-69b47bc96d 2 2 2 1h myapp ikubernetes/myapp:v1 app=myapp,pod-template-hash=2560367528,release=canary
看滾動更新的歷史:
[root@master ~]# kubectl rollout history deployment myapp-deploy deployments "myapp-deploy" REVISION CHANGE-CAUSE 1 <none>
下面我們把deployment改成5個:我們可以使用vim deploy-demo.yaml方法,把里面的replicas改成5。當然,還可以使用另外一種方法,就patch方法,舉例如下。
[root@master manifests]# kubectl patch deployment myapp-deploy -p '{"spec":{"replicas":5}}'
deployment.extensions/myapp-deploy patched
[root@master manifests]# kubectl get deploy
NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE
myapp-deploy 5 5 5 5 2h
[root@master manifests]# kubectl get pods
NAME READY STATUS RESTARTS AGE
myapp-deploy-69b47bc96d-7jnwx 1/1 Running 0 2h
myapp-deploy-69b47bc96d-8gn7v 1/1 Running 0 59s
myapp-deploy-69b47bc96d-btskk 1/1 Running 0 2h
myapp-deploy-69b47bc96d-p5hpd 1/1 Running 0 59s
myapp-deploy-69b47bc96d-zjv4p 1/1 Running 0 59s
mytomcat-5f8c6fdcb-9krxn 1/1 Running 0 8h
下面修改策略:
[root@master manifests]# kubectl patch deployment myapp-deploy -p '{"spec":{"strategy":{"rollingUpdate":{"maxSurge":1,"maxUnavaliable":0}}}}'
deployment.extensions/myapp-deploy patched
strategy:表示策略
maxSurge:表示最多幾個控制器存在
maxUnavaliable:表示最多有幾個控制器不可用
[root@master manifests]# kubectl describe deployment myapp-deploy
RollingUpdateStrategy: 0 max unavailable, 1 max surge
下面我們用set image命令,將鏡像myapp升級為v3版本,並且將myapp-deploy控制器標記為暫停。被pause命令暫停的資源不會被控制器協調使用,可以使“kubectl rollout resume”命令恢復已暫停資源。
[root@master manifests]# kubectl set image deployment myapp-deploy myapp=ikubernetes/myapp:v3 &&
kubectl rollout pause deployment myapp-deploy
[root@master ~]# kubectl get pods -l app=myapp -w
停止暫停:
[root@master ~]# kubectl rollout resume deployment myapp-deploy
deployment.extensions/myapp-deploy resumed
看到繼續更新了(即刪一個更新一個,刪一個更新一個):
[root@master manifests]# kubectl rollout status deployment myapp-deploy
Waiting for deployment "myapp-deploy" rollout to finish: 2 out of 5 new replicas have been updated...
Waiting for deployment spec update to be observed...
Waiting for deployment spec update to be observed...
Waiting for deployment "myapp-deploy" rollout to finish: 2 out of 5 new replicas have been updated...
Waiting for deployment "myapp-deploy" rollout to finish: 3 out of 5 new replicas have been updated...
Waiting for deployment "myapp-deploy" rollout to finish: 3 out of 5 new replicas have been updated...
Waiting for deployment "myapp-deploy" rollout to finish: 4 out of 5 new replicas have been updated...
Waiting for deployment "myapp-deploy" rollout to finish: 4 out of 5 new replicas have been updated...
Waiting for deployment "myapp-deploy" rollout to finish: 4 out of 5 new replicas have been updated...
Waiting for deployment "myapp-deploy" rollout to finish: 1 old replicas are pending termination...
Waiting for deployment "myapp-deploy" rollout to finish: 1 old replicas are pending termination...
deployment "myapp-deploy" successfully rolled out
[root@master manifests]# kubectl get rs -o wide
NAME DESIRED CURRENT READY AGE CONTAINERS IMAGES SELECTOR
myapp-deploy-69b47bc96d 0 0 0 6h myapp ikubernetes/myapp:v1 app=myapp,pod-template-hash=2560367528,release=canary
myapp-deploy-6bdcd6755d 5 5 5 3h myapp ikubernetes/myapp:v3 app=myapp,pod-template-hash=2687823118,release=canary
mytomcat-5f8c6fdcb 3 3 3 12h mytomcat tomcat pod-template-hash=194729876,run=mytomcat
上面可以看到myapp有v1和v3兩個版本。
[root@master manifests]# kubectl rollout history deployment myapp-deploy deployments "myapp-deploy" REVISION CHANGE-CAUSE 1 <none> 2 <none>
上面可以看到有兩個歷史更新記錄。
下面我們把v3回退到上一個版本(不指定就是上一個版本)。
[root@master manifests]# kubectl rollout undo deployment myapp-deploy --to-revision=1
deployment.extensions/myapp-deploy
可以看到第一版還原成第3版了:
[root@master manifests]# kubectl rollout history deployment myapp-deploy deployments "myapp-deploy" REVISION CHANGE-CAUSE 2 <none> 3 <none>
可以看到正在工作的是v1版,即回退到了v1版。
[root@master manifests]# kubectl get rs -o wide
NAME DESIRED CURRENT READY AGE CONTAINERS IMAGES SELECTOR
myapp-deploy-69b47bc96d 5 5 5 6h myapp ikubernetes/myapp:v1 app=myapp,pod-template-hash=2560367528,release=canary
myapp-deploy-6bdcd6755d 0 0 0 3h myapp ikubernetes/myapp:v3 app=myapp,pod-template-hash=2687823118,release=canary
DaemonSet控制器
通過 https://hub.docker.com/r/ikubernetes/filebeat/tags/可以看到filebeat的版本有哪些:
[root@node1 manifests]# docker pull ikubernetes/filebeat:5.6.5-alpine
[root@node2 manifests]# docker pull ikubernetes/filebeat:5.6.5-alpine
node1和node2上都下載filebeat鏡像。
[root@node1 ~]# docker image inspect ikubernetes/filebeat:5.6.5-alpine
[root@master manifests]# kubectl explain pods.spec.containers.env
[root@master manifests]# cat ds-demo.yaml
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: myapp-ds
namespace: default
spec:
selector: #標簽選擇器
matchLabels: #匹配的標簽為
app: filebeat
release: stable
template:
metadata:
labels:
app: filebeat #和上面的myapp要匹配
release: stable
spec:
containers:
- name: myapp
image: ikubernetes/myapp:v1
env:
- name: REDIS_HOST
value: redis.default.svc.cluster.local #隨便取的名字
name: REDIS_LOG_LEVEL
value: info
[root@master manifests]# kubectl apply -f ds-demo.yaml
daemonset.apps/myapp-ds created
看到myapp-ds已經運行起來了,並且是兩個myapp-ds,這是因為我們有兩個Node節點。另外master節點上是不會運行myapp-ds控制器的,因為master有污點(除非你設置允許有污點,才可以在master上允許myapp-ds)
[root@master manifests]# kubectl get pods
NAME READY STATUS RESTARTS AGE
myapp-ds-5tmdd 1/1 Running 0 1m
myapp-ds-dkmjj 1/1 Running 0 1m
[root@master ~]# kubectl logs myapp-ds-dkmjj
[root@master manifests]# kubectl delete -f ds-demo.yaml
[root@master manifests]# cat ds-demo.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: redis
namespace: default
spec:
replicas: 1
selector:
matchLabels:
app: redis
role: logstor #日志存儲角色
template:
metadata:
labels:
app: redis
role: logstor
spec: #這個是容器的spec
containers:
- name: redis
image: redis:4.0-alpine
ports:
- name: redis
containerPort: 6379
#用減號隔離資源定義清單
---
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: filebeat-ds
namespace: default
spec:
selector: #標簽選擇器
matchLabels: #匹配的標簽為
app: filebeat
release: stable
template:
metadata:
labels:
app: filebeat #和上面的myapp要匹配
release: stable
spec:
containers:
- name: filebeat
image: ikubernetes/filebeat:5.6.6-alpine
env:
- name: REDIS_HOST #這是環境變量名,value是它的值
value: redis.default.svc.cluster.local #隨便取的名字
- name: REDIS_LOG_LEVEL
value: info
[root@master manifests]# kubectl create -f ds-demo.yaml
deployment.apps/redis created
daemonset.apps/filebeat-ds created
[root@master manifests]# kubectl expose deployment redis --port=6379 ##這是在用expose方式創建service,其實還有一種方式是根據清單創建service
service/redis exposed
[root@master manifests]# kubectl get svc #service的簡稱 NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE redis ClusterIP 10.106.138.181 <none> 6379/TCP 48s
[root@master manifests]# kubectl get pods
NAME READY STATUS RESTARTS AGE
filebeat-ds-hgbhr 1/1 Running 0 9h
filebeat-ds-xc7v7 1/1 Running 0 9h
redis-5b5d6fbbbd-khws2 1/1 Running 0 33m
[root@master manifests]# kubectl exec -it redis-5b5d6fbbbd-khws2 -- /bin/sh
/data # netstat -tnl
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address Foreign Address State
tcp 0 0 0.0.0.0:6379 0.0.0.0:* LISTEN
tcp 0 0 :::6379 :::* LISTEN
/data # nslookup redis.default.svc.cluster.local #看到DNS可以解析出來ip
nslookup: can't resolve '(null)': Name does not resolve
Name: redis.default.svc.cluster.local
Address 1: 10.106.138.181 redis.default.svc.cluster.local
/data # redis-cli -h redis.default.svc.cluster.local
redis.default.svc.cluster.local:6379> keys *
(empty list or set)
redis.default.svc.cluster.local:6379>
[root@master manifests]# kubectl exec -it filebeat-ds-pnk8b -- /bin/sh
/ # ps aux
PID USER TIME COMMAND
1 root 0:00 /usr/local/bin/filebeat -e -c /etc/filebeat/filebeat.yml
15 root 0:00 /bin/sh
22 root 0:00 ps aux
/ # cat /etc/filebeat/filebeat.yml
filebeat.registry_file: /var/log/containers/filebeat_registry
filebeat.idle_timeout: 5s
filebeat.spool_size: 2048
logging.level: info
filebeat.prospectors:
- input_type: log
paths:
- "/var/log/containers/*.log"
- "/var/log/docker/containers/*.log"
- "/var/log/startupscript.log"
- "/var/log/kubelet.log"
- "/var/log/kube-proxy.log"
- "/var/log/kube-apiserver.log"
- "/var/log/kube-controller-manager.log"
- "/var/log/kube-scheduler.log"
- "/var/log/rescheduler.log"
- "/var/log/glbc.log"
- "/var/log/cluster-autoscaler.log"
symlinks: true
json.message_key: log
json.keys_under_root: true
json.add_error_key: true
multiline.pattern: '^\s'
multiline.match: after
document_type: kube-logs
tail_files: true
fields_under_root: true
output.redis:
hosts: ${REDIS_HOST:?No Redis host configured. Use env var REDIS_HOST to set host.}
key: "filebeat"
/ # printenv
REDIS_HOST=redis.default.svc.cluster.local
/ # nslookup redis.default.svc.cluster.local
nslookup: can't resolve '(null)': Name does not resolve
Name: redis.default.svc.cluster.local
Address 1: 10.106.138.181 redis.default.svc.cluster.local
daemon-set也支持滾動更新。
[root@master manifests]# kubectl set image daemonsets filebeat-ds filebeat=ikubernetes/filebeat:5.5.7-alpine
說明: daemonsets filebeat-ds表示daemonsets名字叫filebeat-ds;
filebeat=ikubernetes/filebeat:5.5.7-alpine表示filebeat容器=ikubernetes/filebeat:5.5.7-alpine
五、Service資源對象
(1)Service及其實現模型
(2)Service的類型及其功用
(3)各Service類型的創建及應用方式
(4)Headless Service
(5)基於DNS的服務發現簡介
(6)Ingress類型及實現方式
Ingress:就是能利用 Nginx(不常用)、Haproxy(不常用)、Traefik(常用)、Envoy(常用) 啥的負載均衡器暴露集群內服務的工具。
Ingress為您提供七層負載均衡能力,您可以通過 Ingress 配置提供外部可訪問的 URL、負載均衡、SSL、基於名稱的虛擬主機等。作為集群流量接入層,Ingress 的高可靠性顯得尤為重要。
小知識:我們把k8s里面的pod服務發布到集群外部,可以用ingress,也可以用NodePort。
externalLB:外部的負載均衡器
service site:只是用來給pod分組歸類的。
1
|
[root@master manifests]# kubectl explain ingress
|
創建名稱空間:
1
2
3
4
5
6
7
8
|
[root@master manifests]# kubectl create namespace ingress-nginx
namespace/dev created
[root@master manifests]# kubectl get ns
NAME STATUS AGE
default
Active
17
d
ingress-nginx Active
8
s
kube-public Active
17
d
kube-system Active
17
d
|
訪問 https://github.com/kubernetes/ingress-nginx,進入deploy目錄,里面就有我們要用的yaml文件。
1
2
3
4
5
6
7
8
|
各文件的作用:
configmap.yaml:提供configmap可以在線更行nginx的配置
default-backend.yaml:提供一個缺省的后台錯誤頁面
404
namespace.yaml:創建一個獨立的命名空間 ingress-nginx
rbac.yaml:創建對應的role rolebinding 用於rbac
tcp-services-configmap.yaml:修改L
4
負載均衡配置的configmap
udp-services-configmap.yaml:修改L
4
負載均衡配置的configmap
with-rbac.yaml:有應用rbac的nginx-ingress-controller組件
|
訪問https://kubernetes.github.io/ingress-nginx/deploy/#generice-deployment,里面是ingress的部署文檔
1
2
|
[root@master ~]# mkdir ingress-nginx
[root@master ~]# cd ingress-nginx
|
部署ingress方法一(分步部署):
下載如下配置文件:
1
|
[root@master ingress-nginx]# for file in namespace.yaml configmap.yaml rbac.yaml tcp-services-configmap.yaml with-rbac.yaml udp-services-configmap.yaml; do wget https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/$file; done
|
1
2
|
[root@master ingress-nginx]# ls
configmap.yaml namespace.yaml rbac.yaml tcp-services-configmap.yaml udp-services-configmap.yaml with-rbac.yaml
|
1、創建名稱空間:
1
2
|
[root@master ingress-nginx]# kubectl apply -f namespace.yaml
namespace/ingress-nginx configured
|
2、把剩下的ymal文件全應用
1
2
3
4
5
6
7
8
9
10
11
|
[root@master ingress-nginx]# kubectl apply -f ./
configmap/nginx-configuration created
namespace/ingress-nginx configured
serviceaccount/nginx-ingress-serviceaccount created
clusterrole.rbac.authorization.k
8
s.io/nginx-ingress-clusterrole created
role.rbac.authorization.k
8
s.io/nginx-ingress-role created
rolebinding.rbac.authorization.k
8
s.io/nginx-ingress-role-nisa-binding created
clusterrolebinding.rbac.authorization.k
8
s.io/nginx-ingress-clusterrole-nisa-binding created
configmap/tcp-services created
configmap/udp-services created
deployment.extensions/nginx-ingress-controller created
|
1
2
3
4
|
[root@master ingress-nginx]# kubectl get pods -n ingress-nginx -w
NAME READY STATUS RESTARTS AGE
default-http-backend
-6586
bc
58
b
6
-qd
9
fk
0
/
1
running
0
4
m
nginx-ingress-controller
-6
bd
7
c
597
cb-zcbbz
0
/
1
running
0
1
m
|
可以看到ingress-nginx名稱空間里面有兩個pod都處於running狀態
部署ingress方法二(一鍵部署):
只下載mandatory.yaml文件,因為這個文件里面包含了上面所有yaml文件里面的內容。這是一鍵部署。
1
2
|
[root@master ingress-nginx]# wget
https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/mandatory.yaml
|
1
|
[root@master ingress-nginx]#kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/mandatory.yaml
|
1
2
3
4
|
[root@master ~]# kubectl get pods -n ingress-nginx -w -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE
default-http-backend
-6586
bc
58
b
6
-qd
9
fk
1
/
1
Running
0
11
h
10.244
.
1.95
node
1
<
none
>
nginx-ingress-controller
-6
bd
7
c
597
cb-jlqzp
1
/
1
Running
3
11
h
10.244
.
1.96
node
1
<
none
>
|
可以看到ingress-nginx名稱空間里面有兩個pod都處於running狀態
安裝service-nodeport
上面我們把ingress-nginx部署到了1號node上。接下來我們還需要部署一個service-nodeport服務,才能實現把集群外部流量接入到集群中來。
1
|
[root@master ingress]# wget https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/provider/baremetal/service-nodeport.yaml
|
我們為了不讓service nodeport自動分配端口,我們自己指定一下nodeport,修改文件中加兩個nodePort參數,最終如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
|
[root@master ingress]# cat service-nodeport.yaml
apiVersion: v
1
kind: Service
metadata:
name: ingress-nginx
namespace: ingress-nginx
labels:
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
spec:
type: NodePort
ports:
- name: http
port:
80
targetPort:
80
protocol: TCP
nodePort:
30080
- name: https
port:
443
targetPort:
443
protocol: TCP
nodePort:
30443
selector:
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
|
1
2
|
[root@master ingress]# kubectl apply -f service-nodeport.yaml
service/ingress-nginx created
|
1
2
3
4
|
[root@master ingress]# kubectl get svc -n ingress-nginx
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
default-http-backend ClusterIP
10.110
.
74.183
<
none
>
80
/TCP
12
h
ingress-nginx NodePort
10.102
.
78.188
<
none
>
80:
30080
/TCP,
443:
30443
/TCP
2
m
|
上面我看到80對應30080,,43對應30443
我們直接通過node1節點的ip就可以訪問到應用:
1
2
|
[root@master ingress]# curl http://
172.16
.
1.101:
30080
default
backend -
404
|
定義myapp service
1
|
[root@master manifests]# mkdir /root/manifests/ingress
|
1
|
[root@master ~]# kubectl explain service.spec.ports
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
|
[root@master ingress]# cat deploy-demo.yaml
apiVersion: v
1
kind: Service
#必須設置為無頭service
metadata:
name: myapp
namespace:
default
spec:
selector:
app: myapp
release: canary
ports:
- name: http
targetPort:
80
#這是容器port
port:
80
#這是service port
---
apiVersion: apps/v
1
kind: Deployment
metadata:
name: myapp-deploy
namespace:
default
spec:
replicas:
2
selector: #標簽選擇器
matchLabels: #匹配的標簽為
app: myapp
release: canary
template:
metadata:
labels:
app: myapp #和上面的myapp要匹配
release: canary
spec:
containers:
- name: myapp
image: ikubernetes/myapp:v
1
ports:
- name: http
containerPort:
80
|
1
2
3
|
[root@master ingress]# kubectl apply -f deploy-demo.yaml
service/myapp created
deployment.apps/myapp-deploy unchanged
|
1
2
3
4
|
[root@master ingress]# kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP
10.96
.
0.1
<
none
>
443
/TCP
17
d
myapp ClusterIP
10.108
.
177.62
<
none
>
80
/TCP
1
m
|
1
2
3
4
|
[root@master ingress]# kubectl get pods
NAME READY STATUS RESTARTS AGE
myapp-deploy
-69
b
47
bc
96
d
-79
fqh
1
/
1
Running
0
1
d
myapp-deploy
-69
b
47
bc
96
d-tc
54
k
1
/
1
Running
0
1
d
|
把myapp service通過ingress發布出去
下面我們再定義一個清單文件,把myapp應用通過Ingress(相當於nginx的反向代理功能)發布出去:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
[root@master ingress]# cat ingress-myapp.yaml
apiVersion: extensions/v
1
beta
1
kind: Ingress
metadata:
name: ingress-myapp
namespace:
default
#要和deployment和要發布的service處於同一個名稱空間
annotations: #這個注解說明我們要用到的ingress-controller是nginx,而不是traefic,enjoy
kubernetes.io/ingress.class:
"nginx"
spec:
rules:
- host: myapp.zhixin.com #表示訪問這個域名,就會轉發到后端myapp管理的pod上的服務:
http:
paths:
- path:
backend:
serviceName: myapp
servicePort:
80
|
1
2
|
[root@master ingress]# kubectl apply -f ingress-myapp.yaml
ingress.extensions/ingress-myapp created
|
1
2
3
|
[root@master ingress]# kubectl get ingress
NAME HOSTS ADDRESS PORTS AGE
ingress-myapp myapp.zhixin.com
80
8
m
|
1
|
[root@master ingress]# kubectl describe ingress
|
1
2
3
4
|
[root@master ingress]# kubectl get pods -n ingress-nginx
NAME READY STATUS RESTARTS AGE
default-http-backend
-6586
bc
58
b
6
-qd
9
fk
1
/
1
Running
0
12
h
nginx-ingress-controller
-6
bd
7
c
597
cb-jlqzp
1
/
1
Running
3
12
h
|
進入ingress-controller交互式命令行里面,可以清晰的看到nginx是怎么反向代理我們myapp.zhixin.com的:
1
2
3
4
5
6
7
8
9
10
11
12
13
|
[root@master ingress]# kubectl exec -n ingress-nginx -it nginx-ingress-controller
-6
bd
7
c
597
cb-jlqzp -- /bin/sh
$ cat nginx.conf
## start server myapp.zhixin.com
server {
server_name myapp.zhixin.com ;
listen
80
;
set $proxy_upstream_name
"-"
;
location / {
set $namespace
"default"
;
set $ingress_name
"ingress-myapp"
;
set $service_name
"myapp"
;
set $service_port
"80"
;
........
|
測試,下面我們把myapp.zhixin.com域名解析到node1 ip 172.16.1.101上。
1
2
|
[root@master ingress]# curl myapp.zhixin.com:
30080
Hello MyApp | Version: v
1
| <a href=
"hostname.html"
>Pod Name</a>
|
把tomcat service通過ingress發布出去(新例子)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
|
[root@master ingress]# cat tomcat-demo.yaml
apiVersion: v
1
kind: Service
#必須設置為無頭service
metadata:
name: tomcat
namespace:
default
spec:
selector:
app: tomcat
release: canary
ports:
- name: http
targetPort:
8080
#這是容器port
port:
8080
#這是service port
- name: ajp
targetPort:
8009
port:
8009
---
apiVersion: apps/v
1
kind: Deployment
metadata:
name: tomcat-deploy
namespace:
default
spec:
replicas:
2
selector: #標簽選擇器
matchLabels: #匹配的標簽為
app: tomcat
release: canary
template:
metadata:
labels:
app: tomcat #和上面的myapp要匹配
release: canary
spec:
containers:
- name: tomcat
image: tomcat:
8.5
.
34
-jre
8
-alpine #在https://hub.docker.com/r/library/tomcat/tags/上面找
ports:
- name: http
containerPort:
8080
- name: ajp
containerPort:
8009
|
1
2
3
|
[root@master ingress]# kubectl apply -f tomcat-demo.yaml
service/tomcat created
deployment.apps/tomcat-deploy created
|
1
2
3
4
|
[root@master ingress]# kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP
10.96
.
0.1
<
none
>
443
/TCP
17
d
tomcat ClusterIP
10.109
.
76.87
<
none
>
8080
/TCP,
8009
/TCP
1
m
|
1
2
3
4
|
[root@master ingress]# kubectl get pods
NAME READY STATUS RESTARTS AGE
tomcat-deploy
-64
c
4
d
54
df
4
-68
sk
8
1
/
1
Running
0
51
s
tomcat-deploy
-64
c
4
d
54
df
4
-7
b
58
g
1
/
1
Running
0
51
s
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
[root@master ingress]# cat ingress-tomcat.yaml
apiVersion: extensions/v
1
beta
1
kind: Ingress
metadata:
name: ingress-tomcat
namespace:
default
#要和deployment和要發布的service處於同一個名稱空間
annotations: #這個注解說明我們要用到的ingress-controller是nginx,而不是traefic,enjoy
kubernetes.io/ingress.class:
"nginx"
spec:
rules:
- host: tomcat.zhixin.com #表示訪問這個域名,就會轉發到后端myapp管理的pod上的服務:
http:
paths:
- path:
backend:
serviceName: tomcat
servicePort:
8080
|
1
2
|
[root@master ingress]# kubectl apply -f ingress-tomcat.yaml
ingress.extensions/ingress-myapp configured
|
1
2
3
|
[root@master ingress]# kubectl get ingress
NAME HOSTS ADDRESS PORTS AGE
ingress-tomcat tomcat.zhixin.com
80
11
s
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
[root@master ingress]# kubectl describe ingress ingress-tomcat
Name: ingress-tomcat
Namespace:
default
Address:
Default backend: default-http-backend:
80
(<
none
>)
Rules:
Host Path Backends
---- ---- --------
tomcat.zhixin.com
tomcat:
8080
(<
none
>)
Annotations:
kubernetes.io/ingress.class: nginx
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal CREATE
1
m nginx-ingress-controller Ingress
default
/ingress-tomcat
|
把tomcat.zhixin.com解析到node1上節點物理ip(我的是172.16.1.101)
測試,可以看到tomcat歡迎界面:
1
|
[root@master ingress]# curl tomcat.zhixin.com:
30080
|
使用https訪問(新例子)
1、先做個自簽的證書(我們這里不演示CA的例子)
1
|
[root@master ingress]# openssl genrsa -out tls.key
2048
|
1
|
[root@master ingress]# openssl req -new -x
509
-key tls.key -out tls.crt -subj /C=CN/ST=Beijing/O=DevOps/CN=tomcat.zhixin.com
|
2、通過secret把證書注入到pod中。
1
2
|
[root@master ingress]# kubectl create secret tls tomcat-infress-secret --cert=tls.crt --key=tls.key
secret/tomcat-infress-secret created
|
1
2
3
4
|
[root@master ingress]# kubectl get secret
NAME TYPE DATA AGE
default-token
-5
r
85
r kubernetes.io/service-account-token
3
17
d
tomcat-ingress-secret kubernetes.io/tls
2
41
s
|
1
2
3
4
5
6
7
8
9
10
|
[root@master ingress]# kubectl describe secret tomcat-ingress-secret
Name: tomcat-ingress-secret
Namespace:
default
Labels: <
none
>
Annotations: <
none
>
Type: kubernetes.io/tls
Data
====
tls.crt:
1245
bytes
tls.key:
1679
bytes
|
3、配置ingress為tls方式
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
[root@master ingress]# cat ingress-tomcat-tls.yaml
apiVersion: extensions/v
1
beta
1
kind: Ingress
metadata:
name: ingress-tomcat-tls
namespace:
default
#要和deployment和要發布的service處於同一個名稱空間
annotations: #這個注解說明我們要用到的ingress-controller是nginx,而不是traefic,enjoy
kubernetes.io/ingress.class:
"nginx"
spec:
tls:
- hosts:
- tomcat.zhixin.com
secretName: tomcat-ingress-secret #kubectl get secret命令查到的名字
rules:
- host: tomcat.zhixin.com #表示訪問這個域名,就會轉發到后端myapp管理的pod上的服務:
http:
paths:
- path:
backend:
serviceName: tomcat
servicePort:
8080
|
1
2
3
4
|
[root@master ingress]# kubectl get ingress
NAME HOSTS ADDRESS PORTS AGE
ingress-tomcat tomcat.zhixin.com 80 2h
ingress-tomcat-tls tomcat.zhixin.com 80, 443 3m
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
[root@master ingress]# kubectl describe ingress ingress-tomcat-tls
Name: ingress-tomcat-tls
Namespace:
default
Address:
Default backend: default-http-backend:
80
(<
none
>)
TLS:
tomcat-ingress-secret terminates tomcat.zhixin.com
Rules:
Host Path Backends
---- ---- --------
tomcat.zhixin.com
tomcat:
8080
(<
none
>)
Annotations:
kubectl.kubernetes.io/last-applied-configuration: {
"apiVersion"
:
"extensions/v1beta1"
,
"kind"
:
"Ingress"
,
"metadata"
:{
"annotations"
:{
"kubernetes.io/ingress.class"
:
"nginx"
},
"name"
:
"ingress-tomcat-tls"
,
"namespace"
:
"default"
},
"spec"
:{
"rules"
:[{
"host"
:
"tomcat.zhixin.com"
,
"http"
:{
"paths"
:[{
"backend"
:{
"serviceName"
:
"tomcat"
,
"servicePort"
:
8080
},
"path"
:null}]}}],
"tls"
:[{
"hosts"
:[
"tomcat.zhixin.com"
],
"secretName"
:
"tomcat-ingress-secret"
}]}}
kubernetes.io/ingress.class: nginx
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal CREATE
4
m nginx-ingress-controller Ingress
default
/ingress-tomcat-tls
|
4、連如ingress-controller查看nginx.conf的配置
1
2
3
4
|
[root@master ingress]# kubectl get pods -n ingress-nginx
NAME READY STATUS RESTARTS AGE
default-http-backend
-6586
bc
58
b
6
-qd
9
fk
1
/
1
Running
0
16
h
nginx-ingress-controller
-6
bd
7
c
597
cb-jlqzp
1
/
1
Running
3
16
h
|
1
2
3
4
5
6
7
8
9
10
11
|
[root@master ingress]# kubectl exec -n ingress-nginx -it nginx-ingress-controller
-6
bd
7
c
597
cb-jlqzp -- /bin/sh
$ $ cat nginx.conf
## start server tomcat.zhixin.com
server {
server_name tomcat.zhixin.com ;
listen
80
;
set $proxy_upstream_name
"-"
;
listen
443
ssl http
2
;
|
看到有listen 443了。
5、測試https
1
|
[root@master ingress]# curl https://tomcat.zhixin.com:
30443
|
部署方法三(利用ingress 的80端口)
前面兩種部署方法,是用node ip + 非80端口,訪問k8s集群內部的服務。可是,我們實際生產中更希望的是node ip + 80端口的方式,訪問k8s集群內的服務。我感覺這個方法最好,下面就就介紹這個方法。
這部分內容參考的是博文http://blog.51cto.com/devingeng/2149377
下載地址
https://github.com/kubernetes/ingress-nginx/archive/nginx-0.11.0.tar.gz
1
2
3
4
5
6
7
8
|
ingress-nginx文件位於deploy目錄下,各文件的作用:
configmap.yaml:提供configmap可以在線更行nginx的配置
default-backend.yaml:提供一個缺省的后台錯誤頁面
404
namespace.yaml:創建一個獨立的命名空間 ingress-nginx
rbac.yaml:創建對應的role rolebinding 用於rbac
tcp-services-configmap.yaml:修改L
4
負載均衡配置的configmap
udp-services-configmap.yaml:修改L
4
負載均衡配置的configmap
with-rbac.yaml:有應用rbac的nginx-ingress-controller組件
|
修改with-rbac.yaml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
|
apiVersion: extensions/v
1
beta
1
kind: Daemonset
metadata:
name: nginx-ingress-controller
namespace: ingress-nginx
spec:
selector:
matchLabels:
app: ingress-nginx
template:
metadata:
labels:
app: ingress-nginx
annotations:
prometheus.io/port:
'10254'
prometheus.io/scrape:
'true'
spec:
serviceAccountName: nginx-ingress-serviceaccount
hostNetwork: true
containers:
- name: nginx-ingress-controller
image: quay.io/kubernetes-ingress-controller/nginx-ingress-controller:
0.11
.
0
args:
- /nginx-ingress-controller
- --default-backend-service=$(POD_NAMESPACE)/default-http-backend
- --configmap=$(POD_NAMESPACE)/nginx-configuration
- --tcp-services-configmap=$(POD_NAMESPACE)/tcp-services
- --udp-services-configmap=$(POD_NAMESPACE)/udp-services
- --annotations-prefix=nginx.ingress.kubernetes.io
env:
- name: POD_NAME
valueFrom:
fieldRef:
fieldPath: metadata.name
- name: POD_NAMESPACE
valueFrom:
fieldRef:
fieldPath: metadata.namespace
ports:
- name: http
containerPort:
80
- name: https
containerPort:
443
livenessProbe:
failureThreshold:
3
httpGet:
path: /healthz
port:
10254
scheme: HTTP
initialDelaySeconds:
10
periodSeconds:
10
successThreshold:
1
timeoutSeconds:
1
readinessProbe:
failureThreshold:
3
httpGet:
path: /healthz
port:
10254
scheme: HTTP
periodSeconds:
10
successThreshold:
1
timeoutSeconds:
1
nodeSelector:
custom/ingress-controller-ready:
"true"
|
需要修改的地方:
kind: DaemonSet:官方原始文件使用的是deployment,replicate 為 1,這樣將會在某一台節點上啟動對應的nginx-ingress-controller pod。外部流量訪問至該節點,由該節點負載分擔至內部的service。測試環境考慮防止單點故障,改為DaemonSet然后刪掉replicate ,配合親和性部署在制定節點上啟動nginx-ingress-controller pod,確保有多個節點啟動nginx-ingress-controller pod,后續將這些節點加入到外部硬件負載均衡組實現高可用性。
hostNetwork: true:添加該字段,暴露nginx-ingress-controller pod的服務端口(80)
nodeSelector: 增加親和性部署,有custom/ingress-controller-ready 標簽的節點才會部署該DaemonSet
為需要部署nginx-ingress-controller的節點設置lable
1
2
3
|
kubectl label nodes vmnode
2
custom/ingress-controller-ready=true
kubectl label nodes vmnode
3
custom/ingress-controller-ready=true
kubectl label nodes vmnode
4
custom/ingress-controller-ready=true
|
加載yaml文件
1
2
3
4
5
6
7
|
kubectl apply -f namespace.yaml
kubectl apply -f default-backend.yaml
kubectl apply -f configmap.yaml
kubectl apply -f tcp-services-configmap.yaml
kubectl apply -f udp-services-configmap.yaml
kubectl apply -f rbac.yaml
kubectl apply -f with-rbac.yaml
|
查看pod是否正常創建
##下載鏡像可能會比較慢,等待一會所有pod都是Running狀態,按Ctrl + c 退出
1
2
3
4
5
6
|
[root@vmnode
1
deploy]# kubectl get pods --namespace=ingress-nginx --watch
NAME READY STATUS RESTARTS AGEdefault-
http-backend
-6
c
59748
b
9
b-hc
8
q
9
1
/
1
Running
0
6
m
nginx-ingress-controller
-7
fmlp
1
/
1
Running
1
13
d
nginx-ingress-controller-j
95
fb
1
/
1
Running
1
13
d
nginx-ingress-controller-ld
2
jw
1
/
1
Running
1
13
d
|
測試ingress
創建一個tomcat的Service
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
|
[root@k
8
s-master
1
test]# cat mytomcat.yaml
apiVersion: extensions/v
1
beta
1
kind: Deployment
metadata:
name: mytomcat
spec:
replicas:
2
template:
metadata:
labels:
run: mytomcat
spec:
containers:
- name: mytomcat
image: tomcat
ports:
- containerPort:
8080
---
apiVersion: v
1
kind: Service
metadata:
name: mytomcat
labels:
run: mytomcat
spec:
type: NodePort
ports:
- port:
8080
targetPort:
8080
selector:
run: mytomcat
|
1
|
[root@k
8
s-master
1
test]# kubectl apply -f mytomcat.yaml
|
配置ingress轉發文件:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
[root@k
8
s-master
1
test]# cat test-ingress.yaml
apiVersion: extensions/v
1
beta
1
kind: Ingress
metadata:
name: test-ingress
namespace:
default
spec:
rules:
- host: test.zhixin.com
http:
paths:
- path: /
backend:
serviceName: mytomcat
servicePort:
8080
|
host: 對應的域名
path: url上下文
backend:后向轉發 到對應的 serviceName: servicePort:
1
2
|
[root@k
8
s-master
1
test]# kubectl apply -f test-ingress.yaml
ingress.extensions/test-ingress created
|
nginx-ingress-controller運行在node1和nod2兩個節點上。如果網絡中有dns服務器,在dns中把這兩個域名映射到nginx-ingress-controller運行的任意一個節點上,如果沒有dns服務器只能修改host文件了。
正規的做法是在node1和node2這兩個節點上安裝keepalive,生成一個vip。在dns上把域名和vip做映射。
我這里直接在node1節點上操作了:
我這里node1節點的ip是172.16.22.201;node2節點的ip是172.16.22.202
1
2
|
[root@k
8
s-master
1
test]# echo
" 172.16.22.201 test.zhixin.com"
>> /etc/hosts
[root@k
8
s-master
1
test]# echo
"172.16.22.202 test.zhixin.com"
>> /etc/hosts
|
然后訪問測試:
看到,我們把域名test.zhixin.com綁定到Node節點的ip補上,然后我們直接訪問http://test.zhixin.com,就能訪問到k8s集群里面的pod服務。
(7)Ingress Controller及部署
(8)Ingress使用案例:發布http及https的tomcat服務
六、K8S-存儲卷
(1)存儲卷及其功用
(2)常見的存儲卷類型及應用:emptyDir、hostPath、nfs、glusterfs等
(3)PV及PVC
(4)StorageClass及PV的動態供給
(5)ConfigMap
(6)Secret
七、StatefulSet
(1)有狀態及無狀態應用對比
(2)有狀態應用的容器難題
(3)StatefulSet及其應用
(4)案例
八、網絡模型及網絡策略
(1)flannel工作原理及host-gw等實現方式
(2)calico及其應用
(3)網絡策略及其工作機制
(4)基於calico的網絡策略的實現
九、認證、授權及准入控制
(1)Kubernetes的認證、授權及准入控制機制
(2)ServiceAccount
(3)令牌認證及證書認證
(4)RBAC及其實現機制
(5)Role和RoleBinding
(6)ClusterRole和ClusterRoleBinding
十、調度器
(1)資源需求、資源限額及其應用
(2)Pod優選級類別
(3)Pod調度器工作原理
(4)預選及預選策略
(5)優選及優選算法
(6)高級調度方法
十一、資源監控及HPA(陸續上傳)
(1)HeapSter、InfluxDB及Grafana實現資源監控
(2)HPA v1
(3)Prometheus及Grafana實現資源監控
(4)Metrics-Server
(5)HPA v2
十二、helm及日志收集系統(陸續上傳)
(1)helm工作原理
(2)helm部署及其應用
(3)部署efk日志收集系統
十三、基於Kubernetes的DevOps介紹 (陸續上傳)
manifests