K8S的概念:
- Node(節(jié)點(diǎn))澎媒,節(jié)點(diǎn)機(jī)器间景,可以是物理機(jī)或虛擬機(jī),比如ECS摊滔,運(yùn)行了各種進(jìn)程和docker等勋篓。
- Pod(容器組)咬扇,應(yīng)用的執(zhí)行單元,創(chuàng)建和部署的單元鸡挠;包含一個(gè)或多個(gè)容器辉饱,存儲(chǔ)和網(wǎng)絡(luò)資源,以及配置項(xiàng)拣展。
- Controller(應(yīng)用)彭沼,管理Pods、復(fù)制和自愈备埃,例如Node失敗時(shí)自動(dòng)遷移Pods到其他節(jié)點(diǎn)姓惑。
- Deployment(無(wú)狀態(tài)),無(wú)狀態(tài)Controller(應(yīng)用)按脚。
- Container(容器)于毙,一個(gè)Pod可以跑N>=1個(gè)Container,這些Container可以共享一些東西辅搬。
K8S命令
在macOS下可以直接用brew安裝:
brew install kubectl
常用的K8S命令:
kubectl cluster-info
kubectl get cm --all-namespaces
kubectl get cm -n kube-system
kubectl get cm/srs3-config
kubectl get cm/cluster-info -n kube-public -o yaml
kubectl get cm/cluster-info -n kube-public -o json
kubectl get deploy
kubectl get deploy/nginx-deployment -o yaml
kubectl get deploy/nginx-deployment -o json
kubectl get rs
kubectl get rs -w
kubectl get pods
kubectl get pods --show-labels
kubectl edit deployment.v1.apps/nginx-deployment
kubectl api-resources # 可以查詢(xún)到縮寫(xiě)望众。
kubectl get services
kubectl get svc/nginx-service -o yaml
kubectl exec srs-deployment-f4cd6b6cc-c74bm -c nginx env
kubectl get pods -o jsonpath="{.items[*].spec.containers[*].name}"
kubectl delete po/srs-origin-deployment-577cf4c7b7-zp7bs --force --grace-period=0
kubectl get po --show-labels
kubectl label deploy/srs-origin-deployment app=srs --overwrite
kubectl label po/srs-origin-deployment-6b4fcf6674-qphdz app=srs --overwrite
kubectl exec srs-edge-deploy-58d9999b7c-f4rtr -- ./objs/srs -v
kubectl set image deploy/srs-edge-deploy srs=ossrs/srs:v4.0.6
kubectl set image deploy/srs-edge-deploy srs=ossrs/srs:v4.0.6 --record
kubectl rollout history deploy/srs-edge-deploy
kubectl get rs
kubectl get rs -w # 可以Watch變化。
kubectl scale --replicas=3 deploy/srs-edge-deploy
kubectl logs srs-edge-deploy-d4cfc9d8b-5wnw7
kubectl describe po/srs-edge-deploy-d4cfc9d8b-85nkf |grep -A 3 Events
kubectl get nodes
kubectl describe nodes/cn-beijing.172.17.232.153
kubectl config get-contexts
切換集群
查看集群:
kubectl config get-contexts
設(shè)置默認(rèn)集群:
kubectl config use-context kubernetes-admin-xxx
ConfigMap保存證書(shū)
ConfigMap可以配置多個(gè)文件伞辛,比如證書(shū)的私鑰(*.key
)和公鑰(*.pem
),后臺(tái)添加配置夯缺,或者用yaml:
cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: ConfigMap
metadata:
name: https-config
data:
https.key: |-
-----BEGIN RSA PRIVATE KEY-----
MIIEowIBAAKCAQEA8mEyACKNJcxAfPWvAYr0uy/wVtd16LPEpy7w1l9WD9+SBsOj
n0QZSc2+y/mEpwXA65irqUply42NabB6rgfsfbcLra8SA5CbyHtrIP4fT6jnBA85
Jzmznp/q/1n4nlfaqawFyOB2IzPjPiwzexN/gv2wWC+5wSQ9yq2k
-----END RSA PRIVATE KEY-----
https.pem: |-
-----BEGIN CERTIFICATE-----
MIIFfjCCBGagAwIBAgIQD8reYBHHOc99faMYlJ0lazANBgkqhkiG9w0BAQsFADBu
MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
d3cuZGlnaWNlcnQuY29tMS0wKwYDVQQDEyRFbmNyeXB0aW9uIEV2ZXJ5d2hlcmUg
-----END CERTIFICATE-----
EOF
掛到容器作為配置文件:
cat <<EOF | kubectl apply -f -
apiVersion: apps/v1
kind: Deployment
metadata:
name: srs
labels:
app: srs
spec:
selector:
matchLabels:
app: srs
template:
metadata:
labels:
app: srs
spec:
volumes:
- name: ssl-volume
configMap:
name: https-config
containers:
- name: srs
image: registry.cn-hangzhou.aliyuncs.com/ossrs/srs:3
imagePullPolicy: IfNotPresent
volumeMounts:
- name: ssl-volume
mountPath: /usr/local/srs/etc
EOF
可以查看etc目錄蚤氏,就有了證書(shū)文件:
$ kubectl get pods -l app=srs
NAME READY STATUS RESTARTS AGE
srs-77b446fbfc-ftz7c 1/1 Running 0 4m50s
$ kubectl exec srs-77b446fbfc-ftz7c -- ls -lh etc
lrwxrwxrwx 1 root root 16 Feb 1 07:06 https.key -> ..data/https.key
lrwxrwxrwx 1 root root 16 Feb 1 07:06 https.pem -> ..data/https.pem
Volume
Volumes,docker有這個(gè)概念但比較簡(jiǎn)單且無(wú)生命周期管理踊兜,k8s提供各種復(fù)雜的volume竿滨,而且volume是隨pod的生命周期(大于container)。
emptyDir捏境,臨時(shí)的空目錄于游,在pod刪除時(shí)會(huì)情況竭钝,container crash后目錄數(shù)據(jù)還在砍艾,可用于crash后的恢復(fù)。
比如SRS寫(xiě)到nginx目錄后鸳吸,nginx可以分發(fā)切片文件筷频。
- nginx默認(rèn)目錄是:/usr/share/nginx/html
- SRS的默認(rèn)目錄是:/usr/local/srs/objs/nginx/html
起一個(gè)Pod運(yùn)行這兩個(gè)容器蚌成,共享這個(gè)目錄,這樣就可以實(shí)現(xiàn)SRS寫(xiě)Nginx讀了凛捏。
Container Args
設(shè)置container的命令和參數(shù)担忧。
使用command和args,command是命令坯癣,args是它的參數(shù)瓶盛,一般需要一起設(shè)置。可以command指定為/bin/sh惩猫,用shell執(zhí)行腳本芝硬,參數(shù)就是:
command: ["/bin/sh"]
args: ["-c", "cp -R ./objs/nginx/html/* /tmp/html/; sleep infinity"]
也可以在里面寫(xiě)for循環(huán):
command: ["/bin/sh"]
args: ["-c", "while true; do echo hello; sleep 10;done"]
還可以寫(xiě)成數(shù)組的方式,字符串用長(zhǎng)字符串換行:
command: ["/bin/sh"]
args:
- "-c"
- >
while true; do
ffmpeg -re -i ./doc/source.200kbps.768x320.flv \
-c copy -f flv rtmp://srs/live/livestream
done
可以用腳本做初始化的事情帆锋。也可以只用args吵取,會(huì)從args中解析出command:
args:
- /bin/sh
- -c
- echo hello
Resource
管理容器使用的計(jì)算資源,Resource锯厢。
可以創(chuàng)建Pod時(shí)指定需要的CPU和內(nèi)存皮官,這樣調(diào)度時(shí)知道調(diào)度到哪個(gè)節(jié)點(diǎn);還可以指定資源的限額实辑。資源限額定義捺氢,Quota。
資源的要求和限制剪撬,指定在:
- spec.containers[].resources.limits.cpu
- spec.containers[].resources.limits.memory
- spec.containers[].resources.requests.cpu
- spec.containers[].resources.requests.memory
CPU摄乒,比如
cpu: 0.1
就是100m
,m就是千分之残黑,millicpu馍佑,millicores。
Memory梨水,比如memory:100Mi
就是100MiB
拭荤,還有Ki,Gi疫诽,Ti舅世,Pi。
limits是最多使用的限制奇徒;requests是需要使用的雏亚,也就是要求的資源。
0<=Request<=Limit<=Infinity (如果Limit為0表示不對(duì)資源進(jìn)行限制摩钙,這時(shí)可以小于Request)
關(guān)于調(diào)度:
- 調(diào)度時(shí)會(huì)根據(jù)request的資源罢低,保障總的request資源小于Node容量。所以request的資源腺律,是比實(shí)際運(yùn)行的要小的奕短。
- 或者可以認(rèn)為,低峰期時(shí)空閑時(shí)CPU是1%匀钧,高峰時(shí)可能request到30%翎碑,limit到50%。調(diào)度時(shí)就根據(jù)各個(gè)Pod的30%作為上限之斯。
關(guān)于limit:
- K8S啟動(dòng)容器時(shí)日杈,會(huì)把request cpu傳遞到容器runtime中,docker run的-c參數(shù):
- 默認(rèn)是1024,至少是2莉擒。如果某個(gè)容器是空閑的酿炸,其他容器可以使用剩下的全部的CPU。某個(gè)容器能使用的最多CPU是變化的涨冀。
- 例如如果一個(gè)是1024填硕,兩個(gè)是512,如果容器內(nèi)的CPU都跑到100%了鹿鳖,那么實(shí)際上第一個(gè)是50%扁眯,剩下兩個(gè)是25%。
- 如果再加第四個(gè)容器也是1024翅帜,那么第一個(gè)是33%姻檀,第二和三是16.5%,第四是33%涝滴。
- 雖然每個(gè)容器的CPU份額是小于100%的绣版,但在多核的機(jī)器上可能讓多個(gè)CPU跑100%。
- 比如有3個(gè)CPU歼疮,第一個(gè)容器是512杂抽,另外是1024,那么可能CPU0是100%跑第一個(gè)容器韩脏,CPU1和CPU2也是100%跑第二個(gè)容器默怨。從系統(tǒng)總體看CPU是300%,100%給了第一個(gè)容器骤素,200%給了第二個(gè)容器。
- 而limit cpu愚屁,則會(huì)傳遞到docker的cpu-quota參數(shù)济竹。
- 而limit memory,則會(huì)傳遞到docker的memory參數(shù):
- 如果容器超過(guò)內(nèi)存限制limits.memory霎槐,很可能重啟送浊。內(nèi)存和磁盤(pán)是不可壓縮資源。
- 如果容器超過(guò)要求的內(nèi)存requests.memory丘跌,在節(jié)點(diǎn)超過(guò)能力時(shí)會(huì)被遷移袭景。
- 容器可能會(huì)被允許超過(guò)CPU的限制,但不會(huì)因?yàn)镃PU過(guò)高而被KILL闭树。CPU是可壓縮資源耸棒。
- 如果容器因?yàn)橘Y源限制被終止:
- 查看容器的事件:kubectl describe po/srs-edge-deploy-d4cfc9d8b-85nkf |grep -A 3 Events
- 查看節(jié)點(diǎn)調(diào)度的資源情況:kubectl describe nodes/cn-beijing.172.17.232.153
改進(jìn):
關(guān)于QoS:
- Guranteed,最高保障报辱,request和limit相等与殃,只指定了limit(就默認(rèn)request等于limit)。
*Burstable,Strong wish幅疼,強(qiáng)烈要求米奸,request和limit有設(shè)置,但不相等爽篷。 - Best-Effort悴晰,最好能支持,完全不設(shè)置逐工。
OOM時(shí)KILL的順序:最先KILL Best-Effort铡溪,然后是Burstable,最后是Guranteed钻弄。
Config Reload
ConfigMap修改后佃却,文件會(huì)變。
注意:fsnotify signal可能因?yàn)榉?hào)鏈接收不到窘俺。
Linux是使用inotify機(jī)制饲帅,用inotify_init返回fd,watch后如果有變化可以read出來(lái)瘤泪。
可以偵聽(tīng)所有事件:IN_ALL_EVENTS灶泵,但主要是IN_MODIFY和IN_CREATE。
返回的內(nèi)容轉(zhuǎn)換成結(jié)構(gòu)體:inotify_event
对途。
YAML格式
-表示列表赦邻,比如ports可以指定多個(gè),所以就以-開(kāi)頭实檀。
管道命令行apply:
cat <<EOF | kubectl apply -f -
apiVersion: v1
EOF
可以把多個(gè)yaml寫(xiě)在一起惶洲,用三個(gè)橫杠分割,比如stateful:
cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: Service
---
apiVersion: apps/v1
kind: StatefulSet
EOF
配置鏡像拉取膳犹,如果存在就不拉取images:
spec.containers[*].imagePullPolicy: IfNotPresent
如果總是拉取恬吕,則設(shè)置為Always
。
Service
Service就是如何讓Pods提供服務(wù)须床,或微服務(wù)铐料,涉及服務(wù)發(fā)現(xiàn)和負(fù)載均衡。
一般服務(wù)發(fā)現(xiàn)使用的是label selector豺旬,有時(shí)候也需要無(wú)selector的Service(必須后端是另外一個(gè)K8S或非Pod)钠惩。標(biāo)簽(label)就是分組的一種方式了,或者一種ID族阅。
定義服務(wù)時(shí)篓跛,需要指定selector比如app=nginx,指定服務(wù)端口port坦刀,以及后端端口targetPort(默認(rèn)等于port)举塔。
注意targetPort可以是字符串绑警,會(huì)解析成對(duì)應(yīng)的端口,這樣后端服務(wù)會(huì)比較靈活央渣。
下面是一個(gè)服務(wù)的描述计盒。
cat <<EOF | kubectl apply -f -
kind: Service
apiVersion: v1
metadata:
name: nginx-service
spec:
selector:
app: nginx
ports:
- protocol: TCP
port: 80
EOF
查詢(xún)?cè)摲?wù):
$ kubectl get svc/nginx-service
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
nginx-service ClusterIP 172.21.7.190 <none> 80/TCP 3m13s
服務(wù)是由kube-proxy分配的VIP并進(jìn)行代理,沒(méi)有采用DNS因?yàn)橛芯彺娴葐?wèn)題:
kube-proxy有幾種不同的代理方式:
- user space proxy mode芽丹,用戶空間代理模式北启,proxy為每個(gè)service偵聽(tīng)一個(gè)端口,通過(guò)iptables將服務(wù)的請(qǐng)求轉(zhuǎn)發(fā)到這個(gè)端口然后轉(zhuǎn)給pod拔第。
- iptables proxy mode咕村,iptables代理,proxy為每個(gè)service新增一條轉(zhuǎn)發(fā)規(guī)則蚊俺,負(fù)載高應(yīng)該是內(nèi)核netfilter轉(zhuǎn)發(fā)懈涛,但出錯(cuò)后不會(huì)重試。
- IPVS proxy mode泳猬,1.11后支持了IPVS代理批钠,使用的是內(nèi)核的netlink,比iptables性能更高吞吐率也更高得封。
如果殺掉nginx的pod埋心,如果只有一個(gè)pod會(huì)服務(wù)不可用,但過(guò)一會(huì)兒K8S會(huì)重新啟動(dòng)pod忙上,服務(wù)就可以了拷呆。
Service Type
ServiceTypes服務(wù)類(lèi)型,一般ClusterIP就是內(nèi)部服務(wù)疫粥,還有其他的:
- ClusterIP茬斧,默認(rèn)就是這種,集群內(nèi)部可以訪問(wèn)梗逮。分配的是Service網(wǎng)段IP(172.21.*)啥供,有內(nèi)部端點(diǎn)無(wú)外部端點(diǎn)。
- NodePort库糠,綁定到Node上,也就是Node(ECS)網(wǎng)段(172.17.*)涮毫,會(huì)自動(dòng)創(chuàng)建ClusterIP服務(wù)瞬欧。外部可以通過(guò)Node的IP訪問(wèn)服務(wù)。
- LoadBalancer罢防,通過(guò)云服務(wù)的負(fù)載均衡實(shí)現(xiàn)艘虎,會(huì)自動(dòng)創(chuàng)建NodePort和ClusterIP。外部訪問(wèn)的是負(fù)載均衡咒吐。
- ExternalName野建,綁定到CNAME属划,比如foo.example.com,不會(huì)創(chuàng)建代理候生,coredns1.7及以上才支持同眯。
默認(rèn)是ClusterIP,看到內(nèi)網(wǎng)的IP(ClusterIP)唯鸭,但無(wú)外部IP(ExternalIP)须蜗,ClusterIP 172.21.89.226 <none> 80/TCP,可訪問(wèn)性如下:
- nginx的realserver是在172.17.232.153
- nginx的POD的IP目溉,可在跳板機(jī)訪問(wèn):curl http://172.20.0.24
- nginx-service的IP是172.21.89.226明肮,無(wú)法在跳板機(jī)訪問(wèn),但可以在node上訪問(wèn):curl http://172.21.89.226
LoadBalancer負(fù)載均衡缭付,一般阿里云標(biāo)準(zhǔn)用法是EIP綁定到SLB上柿估,通過(guò)SLB對(duì)外提供服務(wù)。SLB創(chuàng)建時(shí)選內(nèi)部SLB陷猫,交換機(jī)選k8s-node使用的秫舌,比如IP是172.17.232.159。然后再買(mǎi)EIP綁定到SLB烙丛。不用創(chuàng)建SLB偵聽(tīng)舅巷,k8s會(huì)自動(dòng)做這事,創(chuàng)建后是這樣:
$ kubectl get svc/nginx-service
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
nginx-service LoadBalancer 172.21.113.176 172.17.232.159 80:30589/TCP 6s
可以發(fā)現(xiàn)河咽,類(lèi)型是LoadBalancer钠右,設(shè)置了ExternalIP。
Service Discovery
服務(wù)發(fā)現(xiàn)可以用ENV環(huán)境變量忘蟹,或者DNS飒房。
當(dāng)注冊(cè)Service后,K8S會(huì)在POD啟動(dòng)時(shí)媚值,增加服務(wù)對(duì)應(yīng)的環(huán)境變量狠毯,那么POD就可以用這個(gè)環(huán)境變量來(lái)發(fā)現(xiàn)服務(wù)了。
CoreDNS
組件開(kāi)啟后褥芒,創(chuàng)建了Service就會(huì)創(chuàng)建對(duì)應(yīng)ServiceName的DNS記錄嚼松,比如nginx-service。
$ kubectl get service/nginx-service
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
nginx-service ClusterIP 172.21.7.190 <none> 80/TCP 16m
$ kubectl exec srs3-demo-deploy-55df684cbb-5dzsh -- ping nginx-service
PING nginx-service.default.svc.cluster.local (172.21.7.190) 56(84) bytes of data.
64 bytes from nginx-service.default.svc.cluster.local (172.21.7.190): icmp_seq=1 ttl=64 time=0.033 ms
StatefulSets
時(shí)锰扶,需要給每個(gè)Pod分配可達(dá)的地址献酗,這就是HeadlessServices。通過(guò)配置:ClusterIP: None 來(lái)指定的坷牛。
聲明式更新
Declarative updates罕偎,聲明式更新:
However, a Deployment is a higher-level concept that manages
ReplicaSets and provides declarative updates to Pods along with
a lot of other useful features.
這文章說(shuō)declarative updates:
-
kubectl apply
一般是declarative。參考#1和 #2 -
kubectl run
會(huì)轉(zhuǎn)成declaratively Deployment:kubectl translates your imperative command into a declarative Kubernetes Deployment object. A Deployment is a higher-level API that allows rolling updates (see below). - 意味著保持期望狀態(tài)和實(shí)際狀態(tài)一致:The Kubernetes API is fundamentally declarative, which means that the controllers always work to reconcile the observed state with the desired state. Therefore, if we delete a Pod, the ReplicaSet controller will create a new one to replace it, to maintain the desired replica count.
- 配置你想要的京闰,K8S知道怎么實(shí)現(xiàn):However, the power of Kubernetes is in its declarative API and controllers. You can just tell Kubernetes what you want, and it will know what to do.
- apply是
冪等
操作颜及,可以執(zhí)行多次:The kubectl apply command is idempotent. We can reuse it after modifying the manifests.
官方也有幾個(gè)文章說(shuō)Imperative命令式和Declarative聲明式:
- 命令式甩苛,Managing Kubernetes Objects Using Imperative Commands
- 聲明式,Declarative Management of Kubernetes Objects Using Configuration Files
- Kubernetes Object Management俏站,對(duì)比了命令式和聲明式的差異讯蒲。
Aliyun ACK
ACK托管集群,需要的基本資源:
- 至少
1
個(gè)worker乾翔,2CPU
爱葵,2GB
。包括反浓,Replicas:10個(gè)萌丈,內(nèi)存:850m,CPU:1030Mi雷则。 - 雖然coredns是兩個(gè)replicas辆雾,但是也可以運(yùn)行在一個(gè)worker上面。
- 至少
3
個(gè)IP月劈,1個(gè)是kubectl訪問(wèn)集群用度迂,1個(gè)是SLB對(duì)外提供服務(wù)用,1個(gè)是綁定到worker訪問(wèn)外網(wǎng)用(比如下載更新docker鏡像)猜揪。