Pod是可以創建和管理Kubernetes計算的最小可部署單元。pod可以理解為容器的外殼,給容器做了一層抽象封裝。一個Pod代表着集群中運行的一個進程,每個pod都有一個唯一的ip。
一個pod類似一個豌豆莢,包含一個或多個容器(通常是docker),這多個容器間共享IPC、Network和UTC,和存儲卷,存儲卷不再屬於容器,而屬於pod。
Pod分為兩類:
- 自主式Pod
- 控制器管理的Pod
- ReplicationController
- ReplicaSet
- Deployment 管理無狀態的
- StatefulSet 管理有狀態的
- Job, Ctonjob
Deployment為Pod和ReplicaSet提供了一個聲明式定義(declarative)方法,用來替代以前的ReplicationController來方便的管理應用。典型的應用場景包括:
- 定義Deployment來創建Pod和ReplicaSet
- 滾動升級和回滾應用
- 擴容和縮容
- 暫停和繼續Deployment
創建一個pod應用
kubectl run -h 查看run命令的用法
master01 # kubectl run nginx-deploy --image=nginx:1.14-alpine --port=80 --replicas=1 --record
控制器名稱 容器鏡像 容器的端口 pod的數量 在Deployment revision中可以查看到執行的歷史命令
查看
# kubectl get deployment -o wide #查看deployment控制器
NAME READY UP-TO-DATE AVAILABLE AGE CONTAINERS IMAGES SELECTOR
nginx-deploy 1/1 1 1 2m38s nginx-deploy nginx:1.14-alpine run=nginx-deploy
[master01 ]# kubectl get pods -o wide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES nginx-deploy-55d8d67cf-kckf9 1/1 Running 0 2m55s 10.244.1.2 node01 <none> <none>
可以看到pod已經運行在一個工作節點上, 這里的ip是cni0橋的ip
[node01] # ifconfig cni0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1450 inet 10.244.1.1 netmask 255.255.255.0 broadcast 0.0.0.0
# curl 10.244.1.2 可以訪問到nginx。在集群中間的任意一個節點都可以訪問到pod
在集群內部任意的節點可以訪問pod 。集群外部無法直接訪問pod
刪除pods 查看會看到自動起來另一個,因為 replicas個數為1,控制器會另外再啟動一個pod
# kubectl delete pod nginx-deploy-55d8d67cf-kckf9 pod "nginx-deploy-55d8d67cf-kckf9" deleted # kubectl get pods -o wide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES nginx-deploy-55d8d67cf-lf5xb 1/1 Running 0 2m55s 10.244.1.3 node01 <none> <none>
會看到容器已經被重建了,且pod的ip發生變化了。
service
service是一個抽象概念,定義了一個服務的多個pod邏輯合集和訪問pod的策略,一般把service稱為微服務。
舉個例子:a服務運行3個pod,b服務怎么訪問a服務的pod,pod的ip都不是持久化的重啟之后就會有變化。
這時候b服務可以訪問跟a服務綁定的service,service信息是固定的提前告訴b就行了,service通過Label Selector跟a服務的pod綁定,無論a的pod如何變化對b來說都是透明的。
客戶端的請求到service,由service代理至后端的pod。service並不是一個具體的應用程序,而是相當於一條ipvs或iptables規則。
kubectl expose -h 查看命令的用法
kubectl expose (-f FILENAME | TYPE NAME) [--port=port] [--protocol=TCP|UDP|SCTP] [--target-port=number-or-name] [--name=name] [--external-ip=external-ip-of-service] [--type=type] [options]
創建service
# kubectl expose deployment nginx-deploy --name=nginx80 --port=80 --target-port=80 --protocol=TCP
service_name service_port pod_port service/nginx exposed
查看service
# kubectl get svc -o wide NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 26d <none> nginx80 ClusterIP 10.105.125.134 <none> 80/TCP 118s run=nginx-deploy
# curl 10.105.125.134:80 在集群內部節點上可以訪問到pod
在集群節點可以使用 service_ip:service_port 訪問pod。 node訪問 -> service_ip:service_port -> pod_ip:pod:port。
在pod客戶端可以通過 service_name:service_ip 訪問到pod,這依賴於coredns解析
[master01 ] # cat /etc/resolv.conf
nameserver 114.114.114.114 # 節點上的dns服務器不是指向的coredns的地址,所以無法直接通過server_name:service_ip 訪問pod
# kubectl get svc -n kube-system #可以看到coredns的地址 NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE kube-dns ClusterIP 10.96.0.10 <none> 53/UDP,53/TCP,9153/TCP 6d3h
在pod客戶端訪問
# kubectl run client --image=busybox --replicas=1 -it --restart=Never
/ # cat /etc/resolv.conf
nameserver 10.96.0.10
search default.svc.cluster.local svc.cluster.local cluster.local
\# wget -O - -q http://nginx80 可以訪問到 # pod客戶端可以通過 server_name:server_ip 訪問到pod
kubectl describe svc nginx80 查看service詳細信息
- selector 標簽選擇器
- endpoints可以看到后端pod資源
pod被刪除掉之后會創建一個新pod,訪問nginx:80依然能訪問到,因為service通過selector標簽選擇器跟pod建立了綁定,service可以為pod提供固定訪問端點。
# kubectl get pods --show-labels # 查看標簽
NAME READY STATUS RESTARTS AGE LABELS
client 1/1 Running 0 19m run=client
nginx-deploy-54d6d94f75-b2kxf 1/1 Running 0 165m pod-template-hash=54d6d94f75,run=nginx-deploy
實踐:
創建兩個pod
# kubectl run myapp --image=ikubernetes/myapp:v1 --replicas=2
# kubectl get deployment -w # -w 監控deployment狀態
# kubectl get pods -o wide
創建一個service
# kubectl expose deployment myapp --port=8000 --target-port=80
查看svc
# kubectl describe svc myapp Name: myapp Namespace: default Labels: run=myapp Annotations: <none> Selector: run=myapp Type: ClusterIP IP: 10.99.71.37 Port: <unset> 8000/TCP TargetPort: 80/TCP Endpoints: 10.244.1.35:80,10.244.1.36:80 #service后端的兩個pod Session Affinity: None Events: <none>
創建一個pod客戶端訪問 service_name:service_port,可以看到service是隨機的將請求分發到后端的兩個pod的
# kubectl run client --image=busybox -it
/ # wget -O - -q http://myapp:8000/hostname.html
動態擴容縮容
kubectl scale --replicas=5 deployment nginx-deploy # replicas指定pod數即可擴容縮容
升級鏡像
將鏡像升級為1.16-alpine:
# kubectl set image deployment nginx-deploy nginx-deploy=nginx:1.16-alpine --record deployment.extensions/nginx-deploy image updated
另開一個窗口監控升級過程:
# kubectl get pod -w
升級完成后查看:
# kubectl get pods NAME READY STATUS RESTARTS AGE nginx-deploy-56457775df-ptx9f 1/1 Running 0 2m25s
# kubectl get deployment -o wide NAME READY UP-TO-DATE AVAILABLE AGE CONTAINERS IMAGES SELECTOR nginx-deploy 1/1 1 1 23d nginx-deploy nginx:1.16-alpine run=nginx-deploy
# kubectl describe pod nginx-deploy-56457775df-ptx9f
回滾操作
# kubectl rollout undo deployment/nginx-deploy
deployment.extensions/nginx-deploy rolled back
--to-revision 參數可以指定回退的版本
# kubectl rollout undo deploy/nginx-deploy --to-revision=1
# kubectl rollout history deployment/nginx-deploy #查看歷史版本
這里CHANGE-CAUSE顯示為空是因為操作deployment的時候沒有加--record。如果加上應該顯示:
外部客戶端訪問pod
k8s中的三種網絡:
Node Network: 與外部網絡接口
Service Network:又叫集群網絡,與pod不在一個網段,只存在於iptables或ipvs規則中,是虛擬的
Pod Network: 節點當中pod的內部網絡,可以ping通
如果端口暴露類型為NodePort,那么外部客戶端可以通過集群內任意一台主機ip加暴露的端口進行訪問
1. # kubectl edit svc myapp 修改service的type為NodePort
ClusterIP: 默認類型,自動分配一個僅集群內部可以訪問的虛擬IP
NodePort: 在ClusterIP基礎上為Service在每台機器上綁定一個端口,這樣就可以通過 NodeIP:NodePort 來訪問該服務
2. 也可以在創建service時指定type
kubectl expose deployment nginx-deploy --name=nginx --port=80 --target-port=80 --
type
=NodePort
# kubectl get svc -o wide
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 26d <none> nginx80 NodePort 10.105.125.134 <none> 80:32441/TCP 35m run=nginx-deploy
使用集群外客戶端訪問,需要使用集群任意一個節點的IP地址加上暴露的端口號