为什么要学习 Kubernetes?
虽然 Docker 已经很强大了,但是在实际使用上还是有诸多不便,比如集群管理、资源调度、文件管理等等。
kubernetes 介绍
Kubernetes 解决的核心问题
Kubernetes 的出现不仅主宰了容器编排的市场,更改变了过去的运维方式,不仅将开发与运维之间边界变得更加模糊,而且让 DevOps 这一角色变得更加清晰,每一个软件工程师都可以通过 Kubernetes 来定义服务之间的拓扑关系、线上的节点个数、资源使用量并且能够快速实现水平扩容、蓝绿部署等在过去复杂的运维操作。
Kubernetes 知识图谱
架构说明
Kubernetes 遵循非常传统的客户端/服务端的架构模式,客户端可以通过 RESTful 接口或者直接使用 kubectl 与 Kubernetes 集群进行通信,这两者在实际上并没有太多的区别,后者也只是对 Kubernetes 提供的 RESTful API 进行封装并提供出来。每一个 Kubernetes 集群都是由一组 Master 节点和一系列的 Worker 节点组成,其中 Master 节点主要负责存储集群的状态并为 Kubernetes 对象分配和调度资源。
主节点服务 - Master 架构
作为管理集群状态的 Master 节点,它主要负责接收客户端的请求,安排容器的执行并且运行控制循环,将集群的状态向目标状态进行迁移。Master 节点内部由下面三个组件构成:
工作节点 - Node 架构
Worker 节点实现就相对比较简单了,它主要由 kubelet 和 kube-proxy 两部分组成。
主要由以下几个核心组件组成:
除了核心组件,还有一些推荐的插件:
安装v1.16.0版本,竟然成功了。记录在此,避免后来者踩坑。
本章节,安装大步骤如下:
安装docker-ce 18.09.9(所有机器)
设置k8s环境前置条件(所有机器)
安装k8s v1.16.0 master管理节点
安装k8s v1.16.0 node工作节点
安装flannel(master)
详细安装步骤参考:CentOS 搭建 K8S,一次性成功,收藏了!
集群安装教程请参考:全网最新、最详细基于V1.20版本,无坑部署最小化 K8S 集群教程
Pod 就是最小并且最简单的 Kubernetes 对象
Pod、Service、Volume 和 Namespace 是 Kubernetes 集群中四大基本对象,它们能够表示系统中部署的应用、工作负载、网络和磁盘资源,共同定义了集群的状态。Kubernetes 中很多其他的资源其实只对这些基本的对象进行了组合。
详细介绍请参考:Kubernetes 之 Pod 实现原理
https://mp.weixin.qq.com/s?__biz=MzI0MDQ4MTM5NQ==&mid=2247511562&idx=2&sn=cc8aa9ddbf373a41af579186cd889574&chksm=e918cb16de6f42003fe7d8fdc623c246daf2beff249166e225e6fb5c045c88bd82d24f7673d7&cur_album_id=1790241575034290179&scene=21#wechat_redirect
Kuternetes 企业级 Docker 私有仓库 Harbor 工具。
Harbor 的每个组件都是以 Docker 容器的形式构建的,使用 Docker Compose 来对它进行部署。用于部署 Harbor 的 Docker Compose 模板位于 /Deployer/docker-compose.yml 中,其由 5 个容器组成,这几个容器通过 Docker link 的形式连接在一起,在容器之间通过容器名字互相访问。对终端用户而言,只需要暴露 Proxy(即Nginx) 的服务端口即可。
详细介绍与搭建步骤请参考:企业级环境中基于 Harbor 搭建
https://mp.weixin.qq.com/s?__biz=MzI0MDQ4MTM5NQ==&mid=2247512177&idx=2&sn=e14e94410df53c74e99aac958a9b5658&chksm=e918d56dde6f5c7bc9ff13c39f6c8add6398babe3cdeb188bf38fd7be6a3ca527f53e11d3472&scene=21&cur_album_id=1790241575034290179#wechat_redirect
Kubernetes 中为了实现服务实例间的负载均衡和不同服务间的服务发现,创造了 Service 对象,同时又为从集群外部访问集群创建了 Ingress 对象。
可参考:Kubernetes 之服务发现
Kubernetes 中为了实现服务实例间的负载均衡和不同服务间的服务发现,创造了 Service 对象,同时又为从集群外部访问集群创建了 Ingress 对象。
Service 在 K8S 中有以下四种类型
VIP(虚拟 IP 地址)和 Service 代理
注意,ipvs 模式假定在运行 kube-proxy 之前的节点上都已经安装了 IPVS 内核模块。当 kube-proxy 以 ipvs 代理模式启动时,kube-proxy 将验证节点上是否安装了 IPVS 模块。如果未安装的话,则 kube-proxy 将回退到 iptables 的代理模式。
为什么不适用 Round-robin DNS 的形式进行负载均衡呢?
代理模式
使用 iptables代理模式
使用 ipvs 代理模式
这种模式,kube-proxy 会监视 Kubernetes Service 对象和 Endpoints,调用 netlink 接口以相应地创建 ipvs 规则并定期与 Kubernetes Service 对象和 Endpoints 对象同步 ipvs 规则,以确保 ipvs 状态与期望一致。访问服务时,流量将被重定向到其中一个后端 Pod。
与 iptables 类似,ipvs 于 netfilter 的 hook 功能,但使用哈希表作为底层数据结构并在内核空间中工作。这意味着 ipvs 可以更快地重定向流量,并且在同步代理规则时具有更好的性能。此外,ipvs 为负载均衡算法提供了更多选项,例如:
# 启动服务
$ kubectl create -f myapp-deploy.yaml
$ kubectl create -f myapp-service.yaml
# 查看SVC服务
$ ipvsadm -Ln
IP Virtual Server version 1.2.1 (size=4096)
Prot LocalAddress:Port Scheduler Flags
-> RemoteAddress:Port Forward Weight ActiveConn InActConn
TCP 10.96.0.1:443 rr
-> 192.168.66.10:6443 Masq 1 0 0
# 查看对应的IPVS防火墙规则
$ kubectl get svc -n default
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 125d
ClusterIP
ClusterIP 主要在每个 node 节点使用 ipvs/iptables,将发向 ClusterIP 对应端口的数据,转发到 kube-proxy 中。然后 kube-proxy 自己内部实现有负载均衡的方法,并可以查询到这个 Service 下对应 pod 的地址和端口,进而把数据转发给对应的 pod 的地址和端口。
为了实现图上的功能,主要需要以下几个组件的协同工作:
对应配置文件,如下所示:
myapp-deploy.yaml
# myapp-deploy.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: myapp-deploy
namespace: default
spec:
replicas: 3
selector:
matchLabels:
app: myapp
release: stabel
template:
metadata:
labels:
app: myapp
release: stabel
env: test
spec:
containers:
- name: myapp
image: escape/nginx:v2
imagePullPolicy: IfNotPresent
ports:
- name: http
containerPort: 80
正确的Deployment书写方式,是要让spec.selector.matchLabels值和spec.template.metadata.lables值完全匹配,这样才不会报错。
在定义pod模板时,必须定义spec.template.metadata.lables,因为spec.selector.matchLabels是必须字段,而它又必须和spec.template.metadata.lables的键值一致
myapp-service.yaml
apiVersion: apps/v1
kind: Service
metadata:
name: myapp
namespace: default
spec:
type: ClusterIP
selector:
app: myapp
release: stabel
ports:
- name: http
port: 80
targetPort: 80
启动服务之后,可以查到对应的防火墙规则和默认的 SVC 服务。
# 启动服务
$ kubectl create -f myapp-deploy.yaml
$ kubectl create -f myapp-service.yaml
# 查看SVC服务
$ kubectl get svc -n default
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 125d
myapp ClusterIP 10.99.10.103 <none> 80/TCP 12s
# 查看POD服务
$ kubectl get pod -n default
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
myapp-deploy-5cxxc8c94-4fb9g 1/1 Running 0 18s 10.244.1.66 k8s-node01 <none> <none>
myapp-deploy-ddxx88794-r5qgw 1/1 Running 0 18s 10.244.1.68 k8s-node01 <none> <none>
myapp-deploy-68xxfd677-5q4s2 1/1 Running 0 18s 10.244.1.69 k8s-node01 <none> <none>
# 查看对应的IPVS防火墙规则
$ ipvsadm -Ln
IP Virtual Server version 1.2.1 (size=4096)
Prot LocalAddress:Port Scheduler Flags
-> RemoteAddress:Port Forward Weight ActiveConn InActConn
TCP 10.99.10.103:80 rr
-> 10.244.1.66:80 Masq 1 0 0
-> 10.244.1.68:80 Masq 1 0 0
-> 10.244.1.69:80 Masq 1 0 0
Headless:
有时不需要或不想要负载均衡,以及单独的 Service IP。遇到这种情况,可以通过指定 Cluster IP(spec.clusterIP) 的值为 “None” 来创建 Headless Service。这类 Service 并不会分配 Cluster IP,kube-proxy 不会处理它们,而且平台也不会为它们进行负载均衡和路由。
Headless Services 应用场景
# myapp-svc-headless.yaml
apiVersion: v1
kind: Service
metadata:
name: myapp-headless
namespace: default
spec:
selector:
app: myapp
clusterIP: "None"
ports:
- port: 80
targetPort: 80
启动服务之后,可以查到对应的防火墙规则和默认的 SVC 服务。
# 启动服务
$ kubectl create -f myapp-svc-headless.yaml
# 查看SVC服务
$ kubectl get svc -n default
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 125d
myapp-headless ClusterIP none <none> 80/TCP 19m
# 查找K8S上面的DNS服务对应IP地址(任意一个即可)
$ kubectl get pod -n kube-system -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
coredns-12xxcxc5a-4129z 1/1 Running 3 23h 10.244.0.7 k8s-master01 <none> <none>
# 查找对应无头服务的SVC解析的A记录
$ dig -t A myapp-headless.default.svc.cluster.local. @10.244.0.7
;; ANSWER SECTION:
myapp-headless.default.svc.cluster.local. 30 IN A 10.244.1.66
myapp-headless.default.svc.cluster.local. 30 IN A 10.244.1.68
myapp-headless.default.svc.cluster.local. 30 IN A 10.244.1.69
NodePort
nodePort 的原理在于在 node 上开了一个端口,将向该端口的流量导入到 kube-proxy,然后由 kube-proxy 进一步到给对应的 pod。
对应配置文件,如下所示:
# myapp-svc-nodeport.yaml
apiVersion: v1
kind: Service
metadata:
name: myapp
namespace: default
spec:
type: NodePort
selector:
app: myapp
release: stabel
ports:
- name: http
port: 80
targetPort: 80
service的spec.selector.app与deployment的pod名字保持一致
启动服务之后,可以查到对应的防火墙规则和默认的 SVC 服务。
# 启动服务
$ kubectl create -f myapp-svc-nodeport.yaml
# 查看SVC服务
$ kubectl get svc -n default
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 125d
myapp NodePort 10.99.10.103 <none> 80:30715/TCP 1m
myapp-headless ClusterIP none <none> 80/TCP 19m
# 通过Node的服务器地址访问
$ curl -I http://192.168.66.21:30715
# 查询流程(在Node02上面查询的结果)
$ ipvsadm -Ln
IP Virtual Server version 1.2.1 (size=4096)
Prot LocalAddress:Port Scheduler Flags
-> RemoteAddress:Port Forward Weight ActiveConn InActConn
TCP 192.168.66.21:30715 rr
-> 10.244.1.66:80 Masq 1 0 0
-> 10.244.1.68:80 Masq 1 0 0
-> 10.244.1.69:80 Masq 1 0 0
LoadBalancer
loadBalancer 和 nodePort 其实是同一种方式。区别在于 loadBalancer 比 nodePort 多了一步,就是可以调用 cloud provider 去创建 LB 来向节点导流。
ExternalName
这种类型的 Service 通过返回 CNAME 和它的值,可以将服务映射到 externalName 字段的内容,例如:hub.escapelife.site。ExternalName Service是 Service 的特例,它没有 selector,也没有定义任何的端口和 Endpoint。相反的,对于运行在集群外部的服务,它通过返回该外部服务的别名这种方式来提供服务。
当查询主机 my-service.defalut.svc.cluster.local 时,集群的 DNS 服务将返回一个值 hub.escapelife.site 的 CNAME 记录。访问这个服务的工作方式和其他的相同,唯一不同的是重定向发生在 DNS 层,而且不会进行代理或转发。
对应配置文件,如下所示:
# myapp-svc-externalname.yaml
# SVC_NAME.NAMESPACE.svc.cluster.local
kind: Service
apiVersion: v1
metadata:
name: my-service-1
namespace: default
spec:
type: ExternalName
externalName: hub.escapelife.site
启动服务之后,可以查到对应的防火墙规则和默认的 SVC 服务。
# 查看SVC服务
$ kubectl get svc -n default
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 125d
my-service-1 ExternalName <none> hub.escapelife.site <none> 3m
myapp NodePort 10.99.10.103 <none> 80:30715/TCP 24m
myapp-headless ClusterIP none <none> 80/TCP 45m
# 查找对应无头服务的SVC解析的A记录
$ dig -t A my-service-1.default.svc.cluster.local. @10.244.0.7
;; ANSWER SECTION:
my-service-1.default.svc.cluster.local. 30 IN CNAME hub.escapelife.site
https://kubernetes.github.io/ingress-nginx/deploy/
https://github.com/kubernetes/ingress-nginx/blob/main/docs/deploy/index.md
kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v1.1.2/deploy/static/provider/cloud/deploy.yaml
ConfigMap API 给我们提供了向容器中注入配置信息的机制,ConfigMap 可以被用来保存单个属性,也可以用来保存整个配置文件或者 JSON 二进制大对象
ConfigMap的创建
--from-file
指定在目录下的所有文件都会用在ConfigMap里面创建一个键值对,键的名字就是文件名,值就是文件的内容。$ ls docs/user-guide/config-map/kubectl/
game.properties
ui.properties
# game.properties
$ cat docs/user-guide/config-map/kubectl/game.properties
enemies=aliens
lives= 3
enemies.cheat=true
enemies.cheat.level=noGoodRotten
secret.code.passphrase=UUDDLRLRBABAS
secret.code.allowed=true
secret.code.lives= 30
# ui.properties
$ cat docs/user-guide/config-map/kubectl/ui.properties
color.good=purple
color.bad=yellow
allow.textmode=true
how.nice.to.look=fairlyNice
# 创建名称为game-config的ConfigMap配置
$ kubectl create configmap game-config \
--from-file=docs/user-guide/config-map/kubectl
# 查看存储的ConfigMap列表
$ kubectl get configmap
NAME DATA AGE
game-config 2 22s
# 查看对应内容
$ kubectl describe configmap game-config
$ kubectl get configmap game-config -o yaml
--from-file
这个参数可以使用多次,你可以使用两次分别指定上个实例中的那两个配置文件,效果就跟指定整个目录是一样的。# 创建名称为game-config-2的ConfigMap配置
$ kubectl create configmap game-config-2 \
--from-file=docs/user-guide/config-map/kubectl/game.properties
# 查看存储的ConfigMap列表
$ kubectl get configmap
NAME DATA AGE
game-config 2 34s
game-config-2 1 2s
# 查看对应内容
$ kubectl describe configmap game-config-2
$ kubectl get configmap game-config-2 -o yaml
--from-literal
参数传递配置信息,该参数可以使用多次,格式如下。# 创建名称为special-config的ConfigMap配置
$ kubectl create configmap special-config \
--from-literal=special.how=very \
--from-literal=special.type=charm
# 查看对应内容
$ kubectl get configmaps special-config -o yaml
ConfigMap 的使用
apiVersion: v1
kind: ConfigMap
metadata:
name: special-config
namespace: default
data:
special.how: very
special.type: charm
yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: env-config
namespace: default
data:
log_level: INFO
yaml
apiVersion: v1
kind: Pod
metadata:
name: myapp-test-pod
spec:
restartPolicy: Never
containers:
- name: test-container
image: hub.escape.com/library/myapp:v1
command: ["/bin/sh", "-c", "env"]
env:
- name: SPECIAL_LEVEL_KEY
valueFrom:
configMapKeyRef:
name: special-config
key: special.how
- name: SPECIAL_TYPE_KEY
valueFrom:
configMapKeyRef:
name: special-config
key: special.type
envFrom:
- configMapRef:
name: env-config
apiVersion: v1
kind: ConfigMap
metadata:
name: special-config
namespace: default
data:
special.how: very
special.type: charm
yaml
apiVersion: v1
kind: Pod
metadata:
name: myapp-test-pod
spec:
restartPolicy: Never
containers:
- name: test-container
image: hub.escape.com/library/myapp:v1
command: ["/bin/sh", "-c", "echo $(SPECIAL_LEVEL_KEY) $(SPECIAL_TYPE_KEY)"]
env:
- name: SPECIAL_LEVEL_KEY
valueFrom:
configMapKeyRef:
name: special-config
key: special.how
- name: SPECIAL_TYPE_KEY
valueFrom:
configMapKeyRef:
name: special-config
key: special.type
apiVersion: v1
kind: ConfigMap
metadata:
name: special-config
namespace: default
data:
special.how: very
special.type: charm
yaml
apiVersion: v1
kind: Pod
metadata:
name: myapp-test-pod
spec:
restartPolicy: Never
containers:
- name: test-container
image: hub.escape.com/library/myapp:v1
command: ["/bin/sh", "-c", "cat /etc/config/special.how"]
volumeMounts:
- name: config-volume
mountPath: /etc/config
volumes:
- name: config-volume
configMap:
name: special-config
ConfigMap 热更新
正常情况下,我们可以通过如下配置,在启动的 Pod 容器里面获取到 ConfigMap 中配置的信息。
apiVersion: v1
kind: ConfigMap
metadata:
name: log-config
namespace: default
data:
log_level: INFO
---
apiVersion: extensions/v1beta
kind: Deployment
metadata:
name: my-nginx
spec:
replicas: 1
template:
metadata:
labels:
run: my-nginx
spec:
containers:
- name: my-nginx
image: hub.escape.com/library/myapp:v1
ports:
- containerPort: 80
volumeMounts:
- name: config-volume
mountPath: /etc/config
volumes:
- name: config-volume
configMap:
name: log-config
# 查找对应信息
$ kubectl exec \
`kubectl get pods -l run=my-nginx -o=name | cut -d "/" -f2` \
cat /etc/config/log_level
INFO
修改 ConfigMap 配置,修改 log_level 的值为 DEBUG 等待大概 10 秒钟时间,再次查看环境变量的值。
# 修改ConfigMap配置
$ kubectl edit configmap log-config
# 查找对应信息
$ kubectl exec \
`kubectl get pods -l run=my-nginx -o=name|cut -d "/" -f2` \
cat /etc/config/log_level
DEBUG
ConfigMap 更新后滚动更新 Pod,更新 ConfigMap 目前并不会触发相关 Pod 的滚动更新,可以通过修改 pod annotations 的方式强制触发滚动更新。这个例子里我们在 .spec.template.metadata.annotations 中添加 version/config,每次通过修改 version/config 来触发滚动更新。
$ kubectl patch deployment my-nginx \
--patch '{"spec": {"template": {"metadata": {"annotations": \
{"version/config": "20190411" }}}}}'
更新 ConfigMap 后:
Secret 解决了密码、token、密钥等敏感数据的配置问题,而不需要把这些敏感数据暴露到镜像或者 Pod Spec 中。Secret 可以以 Volume 或者环境变量的方式使用。Secret 有三种类型,分别是:
Service Account
Service Account 是用来访问 Kubernetes API 接口的,由 Kubernetes 自动创建和管理的,并且会自动挂载到 Pod 的 /run/secrets/kubernetes.io/serviceaccount 目录中。
$ kubectl get pods -n kube-system
NAME READY STATUS RESTARTS AGE
kube-proxy-md1u2 1/1 Running 0 13d
$ kubectl exec kube-proxy-md1u2 -- \
ls /run/secrets/kubernetes.io/serviceaccount
ca.crt
namespace
token
Opaque
$ echo -n "admin" | base
YWRtaW4=
$ echo -n "1f2d1e2e67df" | base
MWYyZDFlMmU2N2Rm
apiVersion: v1
kind: Secret
metadata:
name: mysecret
type: Opaque
data:
password: MWYyZDFlMmU2N2Rm
username: YWRtaW4=
使用方式 —— 将 Secret 挂载到 Volume 中
apiVersion: v1
kind: Pod
metadata:
labels:
name: seret-test
spec:
containers:
- name: db
image: hub.escape.com/library/myapp:v1
volumeMounts:
- name: secrets
mountPath: "readOnly: true"
volumes:
- name: secrets
secret:
secretName: mysecret
使用方式 —— 将 Secret 导出到环境变量中
apiVersion: extensions/v1beta
kind: Deployment
metadata:
name: pod-deployment
spec:
replicas: 2
template:
metadata:
labels:
app: pod-deployment
spec:
containers:
- name: pod-1
image: hub.escape.com/library/myapp:v1
ports:
- containerPort: 80
env:
- name: TEST_USER
valueFrom:
secretKeyRef:
name: mysecret
key: username
- name: TEST_PASSWORD
valueFrom:
secretKeyRef:
name: mysecret
key: password
volumes:
- name: config-volume
configMap:
name: mysecret
容器磁盘上的文件的生命周期是短暂的,这就使得在容器中运行重要应用时会出现一些问题。首先,当容器崩溃时,kubelet 会重启它,但是容器中的文件将丢失——容器以干净的状态(镜像最初的状态)重新启动。其次,在 Pod 中同时运行多个容器时,这些容器之间通常需要共享文件。Kubernetes 中的 Volume 抽象就很好的解决了这些问题。
Kubernetes 中的卷有明确的寿命 —— 与封装它的 Pod 相同。所以,卷的生命比 Pod 中的所有容器都长,当这个容器重启时数据仍然得以保存。当然,当 Pod 不再存在时,卷也将不复存在。也许更重要的是,Kubernetes 支持多种类型的卷,Pod 可以同时使用任意数量的卷。
Kubernetes 支持以下类型的卷
nfs、emptyDir、local
awsElasticBlockStore、azureDisk、azureFile
cephfs、csi、downwardAPI、fc、flocker、scaleIO
gcePersistentDisk、gitRepo、glusterfs、hostPath、iscsi
persistentVolumeClaim、projected、portworxVolume
quobyte、rbd、secret、storageos、vsphereVolume
PersistentVolume(PV)
是由管理员设置的存储,它是群集的一部分,用于描述一个具体的 Volume 属性,比如 Volume 的类型、挂载目录、远程存储服务器地址等。就像节点是集群中的资源一样,PV 也是集群中的资源。PV 是 Volume 之类的卷插件,但具有独立于使用 PV 的 Pod 的生命周期。此 API 对象包含存储实现的细节,即 NFS、iSCSI 或特定于云供应商的存储系统。
PersistentVolumeClaim(PVC)
是用户存储的请求,用于描述 Pod 想要使用的持久化属性,比如存储大小、读写权限等。它与 Pod 相似。Pod 消耗节点资源,PVC 消耗 PV 资源。Pod 可以请求特定级别的资源(CPU 和内存)。声明可以请求特定的大小和访问模式(例如,可以以读/写一次或只读多次模式挂载)。
StorageClass(SC)
充当 PV 的模板,自动为 PVC 创建 PV。
动态PV
PV访问模式
ReadWriteOnce
回收策略
Retain(保留)—— 手动回收
Recycle(回收)—— 基本擦除
Delete(删除)—— 关联的存储资产将被删除
状态
卷可以处于以下的某种状态(命令行会显示绑定到 PV 的 PVC 的名称):
Available(可用)—— 块空闲资源还没有被任何声明绑定
Bound(已绑定)—— 卷已经被声明绑定
Released(已释放)—— 声明被删除但是资源还未被集群重新声明
Failed(失败)—— 该卷的自动回收失败
emptyDir
hostPath 为静态存储机制 - 同一 Pod 内的不同容器之间共享工作过程
EmptyDir 是一个空目录,他的生命周期和所属的 Pod 是完全一致的,它用处是把同一 Pod 内的不同容器之间共享工作过程产生的文件。当 Pod 被分配给节点时,首先创建 emptyDir 卷,并且只要该 Pod 在该节点上运行,该卷就会存在。正如卷的名字所述,它最初是空的。
Pod 中的容器可以读取和写入 emptyDir 卷中的相同文件,尽管该卷可以挂载到每个容器中的相同或不同路径上。当出于任何原因从节点中删除 Pod 时,emptyDir 中的数据将被永久删除。emptyDir 的用法有:
apiVersion: v1
kind: Pod
metadata:
name: pod-demo
namespace: default
labels:
app: myapp
tier: frontend
annotations:
youmen.com/created-by: "youmen admin"
spec:
containers:
- name: myapp
image: ikubernetes/myapp:v1
imagePullPolicy: IfNotPresent
ports:
- name: http
containerPort: 80
volumeMounts:
- name: html
mountPath: /usr/share/nginx/html/
- name: busybox
image: busybox:latest
imagePullPolicy: IfNotPresent
volumeMounts:
- name: html
mountPath: /data/
command: ["/bin/sh", "-c"]
args:
- "while true; do echo $(date) >> /data/index.html; sleep 3; done"
volumes:
- name: html
emptyDir: {}
hostPath
hostPath 为静态存储机制 - 主机目录挂载
hostPath 卷将主机节点的文件系统中的文件或目录挂载到集群中,hostPath 的用途如下所示:
除了所需的 path 属性之外,用户还可以为 hostPath 卷指定 type。使用这种卷类型是请注意,因为:
apiVersion: v1
kind: Pod
metadata:
name: test-pd
spec:
containers:
- name: test-container
image: k8s.gcr.io/test-webserver
volumeMounts:
- mountPath: /test-pd
name: test-volume
volumes:
- name: test-volume
hostPath:
path: /data
type: Directory
nfs
使用 nfs-client-provisioner 插件来动态创建 pv
nfs-client-provisioner 是一个 Kubernetes 的简易 NFS 的外部 provisioner,本身不提供 NFS,需要现有的 NFS 服务器提供存储。
namespace-${pvcName}-${pvName}
的命名格式提供(在 NFS 服务器上)archieved-${pvcName}-${pvName}
的命名格式(在 NFS 服务器上)创建完成之后再来创建 StorageClass
# nfs-class.yaml
# kubectl apply -f nfs-class.yaml
# kubectl get storageclass
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: managed-nfs-storage
provisioner: fuseim.pri/ifs
parameters:
archiveOnDelete: "false"
集群调度:
https://mp.weixin.qq.com/s?__biz=MzI0MDQ4MTM5NQ==&mid=2247512338&idx=2&sn=2618b76560d10da849b3cc6163b1968b&chksm=e918d40ede6f5d18813348bbbed70379788a23347f575014ffab08dd6afa160d99bf5dd1947b&scene=21&cur_album_id=1790241575034290179#wechat_redirect
get #显示一个或多个资源
describe #显示资源详情
create #从文件或标准输入创建资源
update #从文件或标准输入更新资源
delete #通过文件名、标准输入、资源名或者 label 删除资源
log #输出 pod 中一个容器的日志
rolling-update #对指定的 RC 执行滚动升级
exec #在容器内部执行命令
port-forward #将本地端口转发到 Pod
proxy #为 Kubernetes API server 启动代理服务器
run #在集群中使用指定镜像启动容器
expose #将 SVC 或 pod 暴露为新的 kubernetes service
label #更新资源的 label
config #修改 kubernetes 配置文件
cluster-info #显示集群信息
api-versions #以”组/版本”的格式输出服务端支持的 API 版本
version #输出服务端和客户端的版本信息
help #显示各个命令的帮助信息
ingress-nginx #管理 ingress 服务的插件(官方安装和使用方式)
创建资源对象
# yaml
kubectl create -f xxx-rc.yaml
kubectl create -f xxx-service.yaml
# json
kubectl create -f ./pod.json
cat pod.json | kubectl create -f -
# yaml2json
kubectl create -f docker-registry.yaml --edit -o json
滚动更新
# 滚动更新 pod frontend-v1
kubectl rolling-update frontend-v1 -f frontend-v2.json
# 更新资源名称并更新镜像
kubectl rolling-update frontend-v1 frontend-v2 --image=image:v2
# 更新 frontend pod 中的镜像
kubectl rolling-update frontend --image=image:v2
# 退出已存在的进行中的滚动更新
kubectl rolling-update frontend-v1 frontend-v2 --rollback
# 强制替换; 删除后重新创建资源; 服务会中断
kubectl replace --force -f ./pod.json
# 添加标签
kubectl label pods my-pod new-label=awesome
# 添加注解
kubectl annotate pods my-pod icon-url=http://goo.gl/XXBTWq
修补资源
# 部分更新节点
kubectl patch node k8s-node-1 -p '{"spec":{"unschedulable":true}}'
# 更新容器镜像;spec.containers[*].name 是必须的,因为这是合并的关键字
kubectl patch pod valid-pod -p \
'{"spec":{"containers":[{"name":"kubernetes-serve-hostname","image":"new image"}]}}'
Scale 资源
# Scale a replicaset named 'foo' to 3
kubectl scale --replicas=3 rs/foo
# Scale a resource specified in "foo.yaml" to 3
kubectl scale --replicas=3 -f foo.yaml
# If the deployment named mysql's current size is 2, scale mysql to 3
kubectl scale --current-replicas=2 --replicas=3 deployment/mysql
# Scale multiple replication controllers
kubectl scale --replicas=5 rc/foo rc/bar rc/baz
删除资源对象
基于 xxx.yaml 文件删除 Pod 对象
# yaml文件名字按照你创建时的文件一致
kubectl delete -f xxx.yaml
删除包括某个 label 的 pod 对象
kubectl delete pods -l name=<label-name>
删除包括某个 label 的 service 对象
kubectl delete services -l name=<label-name>
删除包括某个 label 的 pod 和 service 对象
kubectl delete pods,services -l name=<label-name>
删除所有 pod/services 对象
kubectl delete pods --all
kubectl delete service --all
kubectl delete deployment --all
直接查看日志
# 不实时刷新kubectl logs mypod
kubectl logs mypod --namespace=test
查看日志实时刷新
kubectl logs -f mypod -c ruby-container
1、如何删除不一致状态下的 rc,deployment,service
在某些情况下,经常发现 kubectl 进程挂起现象,然后在 get 时候发现删了一半,而另外的删除不了
2、删除Pod一直处于Terminating状态
可以通过下面命令强制删除
kubectl delete pod NAME --grace-period=0 --force
3、删除namespace一直处于Terminating状态
一个目标:容器操作;两地三中心;四层服务发现;五种 Pod 共享资源;六个 CNI 常用插件;七层负载均衡;八种隔离维度;九个网络模型原则;十类 IP 地址;百级产品线;千级物理机;万级容器;相如无亿,k8s 有亿:亿级日服务人次。
组成:
五种 Pod 共享资源
一个 Pod 可以被一个容器化的环境看作应用层的“逻辑宿主机”;一个 Pod 中的多个容器应用通常是紧密耦合的,Pod 在 Node 上被创建、启动或者销毁;每个 Pod 里运行着一个特殊的被称之为 Volume 挂载卷
同一个 Pod 里的容器之间仅需通过 localhost 就能互相通信。
一个 Pod 中的应用容器共享五种资源:
Pod 的生命周期通过 Replication Controller 来管理;通过模板进行定义,然后分配到一个 Node 上运行,在 Pod 所包含容器运行结束后,Pod 结束。
六个 CNI 常用插件
CNI(Container Network Interface)容器网络接口是 Linux容器网络配置的一组标准和库,用户需要根据这些标准和库来开发自己的容器网络插件。CNI只专注解决容器网络连接和容器销毁时的资源释放,提供一套框架。所以 CNI 可以支持大量不同的网络模式,并且容易实现。
下面用一张图表示六个 CNI 常用插件: