Kubernetes(K8S)入门到运维 ( 四 ) > 网络与存储
Kubernetes(K8S)网络ServiceService即SVC。一个Pod的逻辑分组,一种可以访问它们的策略,通常称为微服务,这一组Pod能够被Service访问到,通常是通过Label Selector。如果Pod挂了,此时新建一个的Pod,此时的网络可能改变了,此时的Nginx在履行IP地址还是旧的IP地址,而SVC则是相当于一个路由器的作用,会记录内部匹配...
Kubernetes(K8S)网络
Service
Service即SVC。一个Pod的逻辑分组,一种可以访问它们的策略,通常称为微服务,这一组Pod能够被Service访问到,通常是通过Label Selector。
如果Pod挂了,此时新建一个的Pod,此时的网络可能改变了,此时的Nginx在履行IP地址还是旧的IP地址,而SVC则是相当于一个路由器的作用,会记录内部匹配到的Pod的地址,而Nginx的访问是访问SVC,而SVC相当于做转发,即类路由器功能。
注意:Service能够提供负载均衡的能力,但使用上有限制的, Service只提供4层负载均衡能力,即只能通过IP和端口进行转发。而没有7层功能,但有时我们可能需要更多的匹配规则来转发请求,这点上4层负载均衡是不支持的。
Service的类型:
Service在K8S中有四种类型:
ClusterIP:默认类型,自动分配一个仅集群内部可以访问的虚拟IP。
NodePort:在ClusterIP基础上为Service在每台机器上绑定一个端口,这样就可以通过NodePort来访问该服务。NodePort的原理在于在Node上开了一个端口,将向该端口的流量导入到kube-proxy,然后由kube-proxy进一步给到对应的Pod
LoadBalancer:在NodePort的基础上,借助Cloud Provider创建一个外部负载均衡器,并将请求转发到NodePort,即比NodePort多了一步,就是可以调用Cloud Provider去创建LoadBalancer来向节点导流,但这个服务需要花钱,因这个服务是提供商提供的叫LAPS,根据流量收费的。
ExternalName:把集群外部的服务引入到集群内部来,在集群内部直接使用。没有任何类型代理被创建,这只有K8S 1.7或更高版本的kube-dns才支持。
VIP(虚拟IP)和Service代理:
在K8S集群中,每个Node运行一个kube-proxy进程,kube-proxy负责为Service实现一种VIP(虚拟IP)的形式,而不是ExternalName的形式。
在K8S V1.0版本,代理完全在userspace。在K8S V1.1版本新增了IPTables代理,但并不是默认的运行模式;从K8S V1.2起,默认就是IPTables代理;在K8S V1.8中,添加了IPVS代理;在K8S V1.14版本中,默认就使用IPVS代理。
K8S V1.0版本中,Service是4层(TCP/IP OverIP)概念,在K8S V1.1版本,新增了Ingress API,用来表示7层(Http)服务。
为什么不使用Round-Robin DNS?
DNS最大的特点是都会产生缓存,因此负载均衡就不在进行负载均衡了,继而只能作为辅助。
代理模式的分类:
userspace代理模式
iptables代理模式
ipvs代理模式
这种模式,kube-proxy会监视K8S Service对象和EndPoints,调用netlink接口以相应的创建ipvs规则并定期与K8S Service对象和EndPoints对象同步ipvs规则,以确保ipvs状态与期望一致。访问服务时,流量将被重定向到其中一个后端Pod。
与iptables类似,ipvs与netfilter的hook功能,但使用哈希表作为底层数据结构并在内核空间中工作。这意味着ipvs可以更快的重定向流量,并且在同步代理规则时具有更好的性能。此外,ipvs为负载均衡算法提供了更多的选项:rr轮询调度;lc最小连接数;dh目标哈希;sh源哈希;sed最短期望延迟;nq不排队调度;
注意:ipvs模式假定运行在kube-proxy之前,在节点都安装了ipvs内核模块。当kube-proxy以ipvs代理模式启动时,kube-proxy将验证节点上是否安装了ipvs模块,如果未安装,则kube-proxy将回退到IPTables代理模式。
#查看 ipvsadm -L
#查看对应的地址 kubectl get svc |
ClusterIP
ClusterIP主要在每个Node节点使用iptables,将发向ClusterIP对应端口的数据,转发到kube-proxy中,然后kube-proxy自己内部实现现有负载均衡的方法,并可以查询到这个Service下对应Pod的地址和端口,进而把数据转发给对应的Pod的地址和端口。
实现上图的功能,需要几个组件共同工作:
APIServer用户通过kubectl命令向APIServer发送创建Service命令,APIServer接收到请求后将数据存储到Etcd中。
K8S中每个节点都会有一个叫kube-proxy的进程,这个进程负责感知Service,Pod的变化,并将变化信息写入本地的IPTables规则中。
vi svc-deploy.yaml 〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓 #api版本 apiVersion: apps/v1 #资源 kind: Deployment metadata: #运行名称 name: myapp-deploy #名称空间 namespace: default spec: #副本 replicas: 3 #选择器 selector: #规则 matchLabels: app: myapp release: stable #运行的Job template: metadata: #标签 labels: app: myapp release: stable env: test spec: #容器 containers: #容器名称 - name: myapp image: levi.harbor.com/library/nginx:1.9.1 imagePullPolicy: IfNotPresent #端口 ports: - name: http containerPort: 80
〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓
kubectl apply -f svc-deploy.yaml
#每一个Pod都会有自己的Pod,并且Pod死亡后Pod的地址和之前是不一致的,要进行可靠性的访问需要借助SVC kubectl get pod -o wide
curl 地址
#service信息 vi svc.yaml 〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓 #api版本 apiVersion: v1 #资源 kind: Service metadata: #资源运行名称 name: mysvc #名称空间 namespace: default spec: #类型 type: ClusterIP #SVC想要匹配到Pod的话是使用标签选择器的,此处是按照选择器选中的资源进行选中 selector: app: myapp release: stable #端口 ports: - name: http #端口 port: 80 #容器端口 targetPort: 80 〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓
kubectl apply -f svc.yaml
kubectl get svc
#访问成功 curl IP
ipvsadm -L
kubectl get pod -o wide
#把标签修改到和svc-deploy.yaml的标签一致就可以匹配了 kubectl delete -f svc.yaml
#修改selector下的标签(myapp1、stable1) vi svc.yaml
kubectl apply -f svc.yaml
kubectl get svc
#访问不到,因为只是创建了自己的端点,并没有实际的后端端点 curl IP
ipvsadm -L
kubectl get pod |
Headless Service:
有时不需要或不想要负载均衡,以及单独的ServiceIP。遇到这种情况,可以通过指定Cluster IP(spec.clusterIP)的值为None来创建Headless Service。这类Service并不会分配ClusterIP,kube-proxy不会处理它们,而且平台也不会为它们进行负载均衡和路由。
这也是一种Cluster,只是一种特殊的ClusterIP。
vi svc-none.yaml 〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓 apiVersion: v1 #资源类型 kind: Service metadata: #运行名 name: myapp-headless namespace: default spec: #选中标签 selector: app: myapp clusterIP: "None" #端口映射配置 ports: - port: 80 targetPort: 80 〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓
kubectl apply -f svc-none.yaml
kubectl get svc
#SVC会有一个主机名,这个写入的规则就是SVC名称+名称空间+集群域名 kubectl get pod -n kebe-system
#安装解析工具 yum -y install bind-utils
#查看coredns-xxx的IP地址 kubectl get pod -n kube-system -o wide
#解析这个域名,在kubectl get pod -n kube-system中可以看到 dig -t A SVC名称+名称空间+集群域名 @地址
#查看ANSWER SECTION:这一栏解析出来的地址 dig -t A myapp-headless.default.svc.cluster.local. @10.244.0.4
#和ANSWER SECTION:的地址进行校对 #虽然没有了IP,但是可以通过访问域名的方案进行访问 kubectl get pod -o wide
ipvsadm -L |
NodePort
#NodePort的原理在于在Node上开了一个端口,将向该端口的流量导入到kube-proxy,然后由kube-proxy进一步给到对应的Pod vi nodeport.yaml 〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓 apiVersion: v1 #资源 kind: Service metadata: #运行名称 name: myapp namespace: default spec: type: NodePort #标签选择器,选择要为此服务的Pod selector: app: myapp release: stable #端口映射 ports: - name: http port: 80 targetPort: 80 〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓
kubectl apply -f nodeport.yaml
#对应的是一组标签 kubectl get pod --show-labels -o wide
#可以访问所在Node的IP地址 + 端口即可 kubectl get svc
#使用浏览器访问http://192.168.70.110 ~ 112:32570/(三台机器都可以)
#可以在三台机器都可以看到都有这么个端点信息 netstat -anpt | grep :32570
#查看规则 ipvsadm -L |
ExternalName
#ExternalName这种类型的Service返回CNAME和它的值,可以将服务映射到externalName字段的内容(如:levi.svc.com)。如这个K8S Service的特例,它没有selector,也没有定义任何的端口和Endpoint。相反的,对于运行在集群外部的服务,它通过返回该外部服务的别名这种方式来提供服务。
vi ex.yaml 〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓 apiVersion: v1 #资源 kind: Service metadata: #运行名称 name: myservice namespace: default spec: type: ExternalName externalName: levi.svc.com 〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓 kubectl create -f ex.yaml
kubectl get svc
#查看coredns-xxx的地址 kubectl get pod -o wide -n kube-system
dig -t A SVC名称+名称空间+集群域名 @地址
#ANSWER SECTION:相当于做了个DNS别名,将Web服务引入集群内部 dig -t A myservice.default.svc.cluster.local. @10.244.0.3
#当查询主机myservice.default.svc.cluster.local.(SVC_NAME.NAMESPACE.svc.cluster.local)时,集群的DNS服务将返回一个值my.database.example.com的CNAME记录。访问这个服务的工作方式和其他的相同,唯一不同的是重定向发生在DNS层,而且不会进行代理或转发 |
Service Ingress
Ingress就是提供一个7层的Http访问的解决方案,而实现这种方案的方式有很多。
场景就是对内的集群不是采用Http链接,对外采用Http链接。
我们采用Ingress Nginx的解决方案。
Ingress-Nginx github 地址:https://github.com/kubernetes/ingress-nginx
Ingress-Nginx 官方网站:https://kubernetes.github.io/ingress-nginx/
Nginx常用的访问方式还是NodePort部署方案,这样Nginx就会把内部服务暴露给外部。
Ingress-Nginx其实就是创建一个SVC与Nginx与之关联,在被Ingress链接进去,即以往需要修改Nginx配置文件,此时会自动添加进去。具体过程如上图。
安装Ingress
#获取到配置文件 mkdir /usr/local/kubernetes/plugin/ingress
cd /usr/local/kubernetes/plugin/ingress
wget https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/static/mandatory.yaml
cat mandatory.yaml | grep image
#使用阿里云的镜像仓库,也可以修改配置文件 docker pull registry.aliyuncs.com/google_containers/nginx-ingress-controller:0.26.1 docker tag registry.aliyuncs.com/google_containers/nginx-ingress-controller:0.26.1 quay.io/kubernetes-ingress-controller/nginx-ingress-controller:0.26.1
kubectl apply -f /usr/local/kubernetes/plugin/ingress/mandatory.yaml
kubectl apply -f mandatory.yaml
kubectl get pod -n ingress-nginx -o wide
#暴露方案:Bare-metal:https://kubernetes.github.io/ingress-nginx/deploy/
wget https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/static/provider/baremetal/service-nodeport.yaml
kubectl apply -f service-nodeport.yaml
kubectl get svc -n ingress-nginx |
实验:
#deloyment和Service vi ingress.http.yaml 〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓 apiVersion: extensions/v1beta1 #资源 kind: Deployment metadata: #运行名称 name: nginx-dm spec: #运行副本数 replicas: 2 #运行的Pod template: metadata: #标签 labels: name: nginx spec: #容器 containers: - name: nginx image: levi.harbor.com/library/nginx:1.9.1 #镜像拉取策略 imagePullPolicy: IfNotPresent ports: - containerPort: 80 --- apiVersion: v1 #资源类型 kind: Service metadata: #运行名 name: nginx-svc spec: #端口 ports: - port: 80 targetPort: 80 protocol: TCP #应用选择器 selector: name: nginx 〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓 kubectl apply -f ingress.http.yaml
kubectl get deployment
kubectl get rs
kubectl get pod
kubectl get svc
curl IP
#实现Nginx-Ingress暴露方案,实现访问效果 vi ingress.yaml 〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓 apiVersion: extensions/v1beta1 #资源 kind: Ingress metadata: #运行名 name: nginx-test spec: #规则 rules: #访问域名 - host: www.leviigress.com #访问协议 http: #路径 paths: - path: / backend: #服务名 serviceName: nginx-svc #端口 servicePort: 80 〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓
kubectl apply -f ingress.yaml
#修改本地host文件,访问地址为ingress.yaml配置地址,即192.168.70.110 www.leviigress.com
#查看Ingress的端口 kubectl get svc -n ingress-nginx
#浏览器访问https://www.leviigress.com:31224/
kubectl get svc
kubectl deelte svc --all
kubectl delete deployment –all
#2个域名的访问方案,访问到不同的地址 vi ingress-http-two.yaml 〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓 #=============== 第一个 Start apiVersion: extensions/v1beta1 #资源 kind: Deployment metadata: #运行名称 name: nginx-dm1 spec: #Pod运行副本 replicas: 2 #运行的Pod template: metadata: #标签 labels: name: nginx1 spec: #容器 containers: - name: nginx image: levi.harbor.com/library/nginx:1.9.1 #镜像拉取策略 imagePullPolicy: IfNotPresent #端口 ports: - containerPort: 80 --- apiVersion: v1 #资源类型 kind: Service metadata: #运行 name: nginx-svc1 spec: #端口 ports: #外部访问端口 - port: 80 #外部访问端口映射到内部的端口 targetPort: 80 protocol: TCP #选择器 selector: name: nginx1 #=============== 第一个 End
#=============== 第二个 Start --- apiVersion: extensions/v1beta1 #资源 kind: Deployment metadata: #运行名称 name: nginx-dm2 spec: #Pod运行副本 replicas: 2 #运行的Pod template: metadata: #标签 labels: name: nginx2 spec: #容器 containers: - name: nginx image: levi.harbor.com/library/nginx:1.9.1 #镜像拉取策略 imagePullPolicy: IfNotPresent #端口 ports: - containerPort: 80 --- apiVersion: v1 #资源类型 kind: Service metadata: #运行 name: nginx-svc2 spec: #端口 ports: #外部访问端口 - port: 80 #外部访问端口映射到内部的端口 targetPort: 80 protocol: TCP #选择器 selector: name: nginx2
#=============== 第二个 End 〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓
kubectl apply -f ingress-http-two.yaml
kubectl get deployment
kubectl get rs
kubectl get pod
kubectl get svc
#Ingress规则 vi ingress-rule-two.yaml 〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓 apiVersion: extensions/v1beta1 #资源 kind: Ingress metadata: #运行 name: nginx-test1 spec: #规则 rules: #访问域名 - host: www.leviigress1.com #访问协议 http: #路径 paths: - path: / backend: #服务名 serviceName: nginx-svc1 servicePort: 80 --- apiVersion: extensions/v1beta1 kind: Ingress metadata: #运行 name: nginx-test1 spec: #规则 rules: #访问域名 - host: www.leviigress2.com #访问协议 http: #路径 paths: - path: / backend: #服务名 serviceName: nginx-svc2 servicePort: 80 〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓
kubectl apply -f ingress-rule-two.yaml
#修改本地host文件,访问地址为ingress.yaml配置地址,即192.168.70.110 www.leviigress1.com、192.168.70.110 www.leviigress2.com
#查看Ingress的端口 kubectl get svc -n ingress-nginx
#浏览器访问https://www.leviigress1.com:31224/、https://www.leviigress2.com:31224/
#查询pod的容器名 kubectl get pod -n ingress-nginx
#进入容器 kubectl exec 容器名 -n ingress-nginx -it -- /bin/bash #查看配置文件,配置规则是自动注入的,可以看到Ingress会把规则自动转换 cat /etc/nginx/nginx.conf cat /etc/nginx/nginx.conf | grep www
#Ingress Https代理访问 #创建证书,看文件 openssl req -x509 -sha256 -nodes -days 365 -newkey rsa:2048 -keyout tls.key -out tls.crt -subj "/CN=nginxsvc/O=nginxsvc"
kubectl create secret tls tls-secret --key tls.key --cert tls.crt
#创建对应的deployment、service、ingress的yaml文件
#直接复制Ingress HTTP代理访问的deployment、service即可 vi deployment3.yaml 〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓 apiVersion: extensions/v1beta1 #资源 kind: Deployment metadata: #运行名称 name: nginx-dm spec: #运行副本数 replicas: 2 #运行的Pod template: metadata: #标签 labels: name: nginx spec: #容器 containers: - name: nginx image: levi.harbor.com/library/nginx:1.9.1 #镜像拉取策略 imagePullPolicy: IfNotPresent ports: - containerPort: 80 --- apiVersion: v1 #资源类型 kind: Service metadata: #运行名 name: nginx-svc spec: #端口 ports: - port: 80 targetPort: 80 protocol: TCP #应用选择器 selector: name: nginx 〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓
kubectl apply -f deployment3.yaml
kubectl get svc
curl IP
vi https-ingress.yaml 〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓 #资源 kind: Ingress metadata: name: nginx-test spec: tls: - hosts: - www.levi.com #使用已建立的证书 secretName: tls-secret rules: #访问域名 - host: www.levi.com #访问协议 http: #访问域名 paths: - path: / #Ingress绑定的SVC backend: serviceName: nginx-svc servicePort: 80 〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓
#修改域名,2处 kubectl apply -f https-ingress.yaml
kubectl get svc -n ingress-nginx
#添加hosts,浏览器访问192.168.70.110 www.levi.com,https://www.levi.com:31224/
# Nginx进行BasicAuth #Nginx的认证是使用Apache的,因此Master需要安装 yum -y install httpd
#输入对应的密码,要记住,后面页面访问时需要用到 htpasswd -c auth levi
kubectl create secret generic basic-auth --from-file=auth
#使用刚上面的测试deployment3.yaml
vi basicauth.yaml 〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓 apiVersion: extensions/v1beta1 #资源 kind: Ingress metadata: #运行 name: ingress-with-auth annotations: nginx.ingress.kubernetes.io/auth-type: basic nginx.ingress.kubernetes.io/auth-secret: basic-auth nginx.ingress.kubernetes.io/auth-realm: 'Authentication Required - levi' spec: #规则 rules: #访问域名 - host: www.levi1.com #访问协议 http: #访问路径 paths: - path: / #关联的SVC backend: serviceName: nginx-svc servicePort: 80 〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓 kubectl apply -f basicauth.yaml
kubectl get svc -n ingress-nginx
#添加hosts,192.168.70.110 www.levi1.com,浏览器访问https://www.levi1.com:31224/ #输入刚配置的密码
#测试Nginx进行重写 #修改对应的nginx.ingress.kubernetes.io/rewrite-target:域名,跳转到别的地址中,如百度
#使用刚上面的测试deployment3.yaml
vi nginx-rewrite.yaml 〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓 #资源 kind: Ingress metadata: name: nginx-test annotations: #跳转到这个目标地址 nginx.ingress.kubernetes.io/rewrite-target: https://www.baidu.com/ spec: #规则 rules: - host: www.levi2.com #访问协议 http: paths: - path: / #绑定的SVC backend: serviceName: nginx-svc servicePort: 80 〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓
kubectl apply -f nginx-rewrite.yaml
kubectl get svc -n ingress-nginx
#添加hosts(192.168.70.110 www.levi2.com),浏览器访问https://www.levi2.com:31224/
kubectl delete ingress --all |
Kubernetes(K8S)存储
ConfigMap
ConfigMap是在K8S V1.2引入的,许多应用程序会从配置文件、命令行参数或环境变量中读取配置信息,提供了向容器中注入配置信息的几只,ConfigMap可以被用来保存单个属性,也可以用来保存整个配置文件或者JSON二进制大对象。类似配置文件的注册中心。
ConfigMap创建方式:目录、文件、字面值。
实验:
#目录创建 mkdir configmap
#复制内容 vi game.properties 〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓 enemies=aliens lieves=3 enemies.cheat=true enemies.cheat.level=noGoodRotten secret.code.passphrase=UUDDLRLRBABAS secret.code.allowed=true secret.code.leves=30 〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓
vi ui.properties 〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓 color.good=purple color.bad=yellow allow.textmode=true how.nice.to.look=fairlyNice 〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓
#--from-file这个参数可以使用多次,可以使用两次分别指定上个实例中的那两个配置文件,效果就跟指定整个目录是一样的 kubectl create configmap game-config --from-file=../configmap/
kubectl get cm
kubectl get cm game-config
#data:栏 kubectl get cm game-config -o yaml
kubectl describe cm game-config
kubectl delete cm --all
#文件创建 kubectl create configmap game-config --from-file=../configmap/game.properties
kubectl get configmaps game-config -o yaml
kubectl describe configmap game-config
#字面值创建 kubectl create configmap special-config --from-literal=special.how=very --from-literal=special.type=charm
kubectl get cm
kubectl describe configmap special-config
#Pod中使用ConfigMap #1.使用ConfigMap来替代环境变量 kubectl get cm
#第一个文本 vi special.yaml 〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓 apiVersion: v1 #资源类型 kind: ConfigMap metadata: #运行名称 name: special-config namespace: default data: special.how: very special.type: test 〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓 kubectl apply -f special.yaml
kubectl get cm
kubectl describe cm special-config
#第二个文本 vi env.yaml 〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓 apiVersion: v1 #资源 kind: ConfigMap metadata: name: env-config namespace: default data: log_level: INFO 〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓 kubectl apply -f env.yaml
kubectl get cm
kubectl describe cm env-config
#第三个文本 vi pod.yaml 〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓 apiVersion: v1 #资源 kind: Pod metadata: name: data-test-pod spec: #容器 containers: - name: test-container image: levi.harbor.com/library/nginx:1.9.1 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 #重启策略 restartPolicy: Never 〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓
kubectl apply -f pod.yaml
kubectl get pod
#关注对应的环境变量 kubectl log pod名
#====== 使用configMap设置命令行参数
#还是使用special.yaml和env.yaml
vi pod1.yaml 〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓 apiVersion: v1 #资源 kind: Pod metadata: name: data-test-pod2 spec: #容器 containers: - name: test-container2 image: levi.harbor.com/library/nginx:1.9.1 command: ["/bin/sh","-c","echo $(SPECIAL_LEVEL_KEY) and $(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 #设置环境变量来源的引用 envFrom: - configMapRef: name: env-config #重启策略 restartPolicy: Never 〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓
kubectl apply -f pod1.yaml
kubectl get pod
kubectl log pod名
#通过数据卷插件使用ConfigMap #在数据卷里面使用这个ConfigMap,有不同的选项,最基本的就是将文件填入数据卷,在这个文件中,键就是文件名,键值就是文件内容
#还是使用special.yaml和env.yaml
vi pod2.yaml 〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓 apiVersion: v1 #资源 kind: Pod metadata: name: data-test-pod3 spec: containers: - name: test-container3 image: levi.harbor.com/library/nginx:1.9.1 command: ["/bin/sh","-c","cat /etc/config/special.how"] #数据卷 volumeMounts: - name: config-volume #数据卷的位置 mountPath: /etc/config volumes: - name: config-volume configMap: name: special-config #重启策略 restartPolicy: Never 〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓
kubectl apply -f pod2.yaml
kubectl get pod
kubectl log pod名
#进入容器查看 kubectl exec pod名 -it -- /bin/sh ls /etc/config cat /etc/config/*
#ConfigMap热更新 kubectl delete pod --all
kubectl delete cm --all
kubectl get cm
vi hotupdate.yaml 〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓 #定义ConfigMap apiVersion: v1 #资源 kind: ConfigMap metadata: name: log-config namespace: default #数据 data: log_level: INFO --- apiVersion: extensions/v1beta1 kind: Deployment metadata: #运行名 name: my-nginx spec: #副本 replicas: 1 template: metadata: #标签 labels: run: my-nginx spec: #容器 containers: - name: my-nginx image: levi.harbor.com/library/nginx:1.9.1 ports: - containerPort: 80 #存储卷 volumeMounts: #引用 - name: config-volume mountPath: /etc/config #存储卷的数据是来自于ConfigMap volumes: - name: config-volume configMap: name: log-config 〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓
kubectl apply -f hotupdate.yaml
kubectl get pod
kubectl log pod名
kubectl exec pod名 -it -- cat /etc/config/log_level
kubectl get cm
kubectl get deployment
kubectl get rs
kubectl get pod
#INFO改为DEBUG kubectl edit configmap log-config
kubectl exec pod名 -it -- cat /etc/c/log_level
#ConfigMap更新,并不会触发相关pod的滚动更新,可以通过修改pod annotations的方式强制触发滚动更新 kubectl get pod
|
Secret
Secret解决了密码、Token、秘钥等敏感数据的配置文件,而不需要把这些敏感数据暴露到镜像或Pod Spec中,Secret可以以Volume或者环境变量的方式使用。
Secrt的三种类型:
ServiceAccount:用来访问K8S API,由K8S自动创建,并且自动挂载到Pod的/run/secrets/kubernetes.io/serviceaccount目录中
Opaque:base64编码格式的Secret,用来存储密码、秘钥等
Kubernetes.io/dockerconfigjson:用来存储私有registry的认证信息
kubectl get pod -n kube-system
#进入kube-proxy的容器中 kubectl exec kube-proxy-xxx -n kube-system -it -- /bin/bash
#可以看到其中的加密文件和加密内容 cd /run/secrets/kubernetes.io/serviceaccount ls cat *
#Opaque Secret:类型是一个map类型,要求value是base64编码格式 echo -n "admin" | base64
echo -n "test123" | base64
vi secrets.yml 〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓 apiVersion: v1 #资源 kind: Secret metadata: name: mysecret #加密类型 type: Opaque data: username: YWRtaW4= password: dGVzdDEyMw== 〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓
kubectl apply -f secrets.yml
kubectl get secret
kubectl get secret -n kube-system
#将Secret挂载到volume中 vi secrets1.yaml 〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓 apiVersion: v1 #资源类型 kind: Pod metadata: #运行名 name: seret-volume #标签 labels: name: seret-test spec: #数据卷 volumes: #关联到下面的容器数据卷配置 - name: secrets #数据卷数据来源secret,来自运行中的mysecret secret: secretName: mysecret #容器 containers: - image: levi.harbor.com/library/nginx:1.9.1 name: db volumeMounts: - name: secrets mountPath: /etc/config readOnly: true 〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓
kubectl apply -f secrets1.yml
kubectl get pod
#进入容器进行查看 kubectl exec seret-volume -it -- /bin/bash
cd /etc/config/ ls #保存时自动解密 cat *
#将Secret导出到环境变量中,不需要以明文声明 vi secrets2.yaml 〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓 apiVersion: extensions/v1beta1 #资源类型 kind: Deployment metadata: name: pod-deployment spec: #运行的副本 replicas: 2 #Pod配置 template: metadata: #标签 labels: app: pod-deployment spec: #容器 containers: - name: pod-1 image: levi.harbor.com/library/nginx:1.9.1 #运行的端口 ports: - containerPort: 80 #环境变量 env: - name: TEST_USER #数据来源 valueFrom: #关联secret secretKeyRef: #来源mysecret这个secret name: mysecret #key: username key: password 〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓 kubectl apply -f secrets2.yml
kubectl get pod
kubectl get secret
#进入容器 kubectl exec pod名 -it -- /bin/sh echo $TEST_USER
#使用K8S Secret 保存Harbor密码
kubectl delete deployment --all
kubectl delete pod --all
#每台node都需要做退出docker操作 docker images
#删除旧的镜像,实验密码下载 docker rmi levi.harbor.com/library/nginx:1.9.1
#退出登录,注意缓存和/etc/docker/key.json docker logout levi.harbor.com
#拉取镜像,看是否需要输入密码 docker pull levi.harbor.com/library/nginx:1.9.1
#Image为指定的harbor的镜像,不需要复制imagePullSecrets: - name: myregistryke vi pod.yaml 〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓 apiVersion: v1 kind: Pod metadata: name: harbor-pod spec: containers: - name: harbor-container image: levi.harbor.com/library/nginx:1.9.1 〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓
kubectl apply -f pod.yaml
kubectl get pod
#失败 kubectl describe pod harbor-pod
kubectl create secret docker-registry myregistrykey --docker-username=admin --docker-password=Harbor12345 --docker-email=admin@example.com
#新增imagePullSecrets: - name: myregistryke vi pod.yaml 〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓 apiVersion: v1 kind: Pod metadata: name: harbor-pod spec: containers: - name: harbor-container image: levi.harbor.com/library/nginx:1.9.1 #镜像拉取的秘钥 imagePullSecrets: #使用myregistrykey这个Secret - name: myregistrykey 〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓
kubectl delete pod --all
kubectl apply -f pod.yaml
kubectl get pod
docker images |
Volume
容器磁盘上的文件的生命周期是短暂的,这就使得在容器中运行重要应用时,会出现一些问题。
首先容器崩溃时,kubelet会重启它,但是容器中的文件将丢失—容器以干净的状态(镜像最初状态)重新启动。其次在Pod中同时运行多个容器时,这些容器之间通常需要共享文件。K8S中的Volume抽象就很好的解决了这些问题。
K8S中的卷有明确的生命周期,与封装它的Pod相同。所以,卷的生命比Pod中的所有容器都长,当这个容器重启时,数据仍然得以保存。当然,当Pod不再存在时,卷也将不复存在。也许更重要的是,K8S支持多种类型的卷,Pod可以同时使用任意数据的卷。
K8S支持以下的卷:
awsElasticBlockStore、azureDisk、azureFile、cephfs、csi、downwardAPI、emptyDir
fc、flocker、gcePersistenDisk、gitRepo、glusterfs、hostPath、iscsi、local、nfs
persistenVolumeClaim、projected、portworxVolume、quobyte、rbd、scaleIO、secret
storageos、vsphereVolume
emptyDir卷:
当Pod被分配给节点时,首先创建emptyDir卷,并且该Pod在该节点上运行,该卷就会存在。正如卷的名字,最初是空的。Pod中的容器可以读取和写入,emptyDir卷中的相同文件,尽管卷可以挂载到每个容器中的相同或不同路径上。当出于任何原因从节点中删除Pod时,emptyDir中的数据将被永久删除。
使用场景:
暂存空间:例如用于基于磁盘的合并排序
用作长时间计算崩溃恢复时的检查点
Web服务器容器提供数据时,保存内存管理容器提取的文件
注意:容器崩溃不会从节点中移除Pod,因此emptyDir卷中的数据在容器崩溃时是安全的。
实验:
vi empty.yaml 〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓 apiVersion: v1 kind: Pod metadata: #运行的资源类型的名称 name: empty-pod spec: #运行的容器配置 containers: - name: test-container image: levi.harbor.com/library/nginx:1.9.1 #数据卷 volumeMounts: #关联到下面的配置· - name: cache-volume mountPath: /cache #数据卷 volumes: - name: cache-volume emptyDir: {} 〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓
kubectl apply -f empty.yaml
kubectl get pod
kubectl exec empty-pod -it -- /bin/bash
#挂载目录 cd /cache ls |
hostPath卷:
hostPath卷将主机节点的文件系统中的文件或目录挂在到集群中。
用途:运行需要访问Docker内部的容器,使用/var/lib/docker的hostPath;在容器中运行cAdvisor,使用/dev/cgroups的hostPath;允许Pod指定给定的hostPath是否应该在Pod运行之前存在,是否应该创建,以及它应该以书面形式存在。
除了使用所需的Path属性之外,还可以给hostPath卷指定type。
hostPath卷的type值:
值 | 行为 |
| 空字符串(默认)用于向后兼容,这意味着在挂载hostPath卷之前不会执行任何检查。 |
DirectoryOrCreate | 如果给定的路径上没有任何东西存在,那么将根据需要在那里创建一个空目录,权限设置为0755,与kubelet具有相同的组合所有权。 |
Directory | 给定的路径下必须存在目录 |
FileOrCreate | 如果在给定的路径上没有任何东西存在,那么会根据需要创建一个空文件,权限设置为0644,与kubelet具有相同的组和所有权 |
File | 给定的路径下必须存在文件 |
Socket | 给定的路径下必须存在Unix套接字 |
CharDevice | 给定的路径下必须存在字符设备 |
BlockDevice | 给定的路径下必须存在块设备 |
注意:
由于每个节点上的文件都不同,具有相同配置(例如从podTemplate创建)的Pod在不同节点上的行为可能会不同;
当K8S按照计划添加资源感知调度时,将无法考虑hostPath使用的资源;
在底层主机上创建的文件或目录只能由root写入。因此需要再特权容器中以root身份运行进程,或修改主机上的文件权限以便写入hostPath卷。
实验:
vi hostpath.yaml 〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓 apiVersion: v1 kind: Pod metadata: #运行的资源类型的名称 name: hostpath-pod spec: #容器配置 containers: - name: test-container image: levi.harbor.com/library/nginx:1.9.1 #容器内的数据卷配置 volumeMounts: - name: test-volume mountPath: /test-hp #数据卷配置 volumes: - name: test-volume hostPath: #本地目录 path: /tmp #类型 type: Directory 〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓
kubectl delete pod --all
kubectl apply -f hostpath.yaml
kubectl get pod -o wide
#进入容器 kubectl exec -it hostpath-pod -- /bin/bash cd /test-pd/ ls echo "test" >> 666.txt
#到对应的机器上查看 cat /tmp/666.txt
#与本机互操作 |
PersistentVolume (PV) & PersistentVolumeClaim (PVC)
PVC是PV的请求匹配方案,主要解决有前往各PV时,一一绑定不合适。
PersistentVolume(PV)是由管理员设置的存储,是集群的一部分。就像节点集群中的资源一样,PV也是集群中的资源。PV是Volume之类的卷插件,但具有独立于使用PV的Pod的生命周期。此API对象包含存储实现的细节,即NFS、iSCSI或特定与云供应商的存储系统。
PersistentVolumeClaim(PVC)是用户存储的请求,与Pod相似。Pod消耗节点资源,PVC消耗PV资源。Pod可以请求特定级别的资源(CPU和内存)。声明可以请求特定的大小和访问模式(例如,可以以读/写或只读多次模式挂载)。
静态PV:是集群管理员创建一些PV。它们带有可供集群用户使用的实际存储的细节。它们存在于K8S API中,可用于消费。
动态PV:当管理员创建的静态PV都不匹配用户的PersistentVolumeClaim(PVC)时,集群可能会尝试动态为PVC创建卷。此配置基于StorageClasses:PVC必须请求存储类,且管理员必须创建并配置该类才能进行动态创建。声明类为""可以有效的禁用其动态配置。要重启基于存储级别的动态存储配置,集群管理员需要启用API Server是哪个的DefaultStorageClass准入控制器。例如通过确保DefaultStorageClass位于APIServer组件的—admission-control标志,使用逗号分隔的有序值列表中,可以完成此操作。
绑定:master中的控制环境监视新的PVC,寻找匹配的PV(如果可能),并将它们绑定在一起,如果为新的PV动态调配PV,则该环路将始终将PV绑定到PVC。否则用户总会得到它们所请求的存储,但是容器可能会超出要求的数量。一旦PV和PVC绑定后,PersistentVolumeClaim绑定是排他性的,不管它们是如何绑定的PVC跟PV是一对一的映射。
持久化卷声明的保护:PVC保护的目的是确保由Pod正在使用的PVC不会从系统中移除,因为如果被移除的话,可能会导致数据丢失。
注意:当Pod状态为Pending,并且Pod已经分配给节点或Pod为Running状态时,PVC处于活动状态。当启动PVC保护alpha功能时,如果用户删除了一个Pod正在使用的PVC,则该PVC不会被利己删除。PVC的删除将会被延迟,知道PVC不在被任何Pod使用。
持久化卷类型:
PV类型以插件形式实现,K8S支持这些插件类型:
GCEPersistentDisk、AWSElasticBlockStore、AzureFile、AzureDisk、FC(Fibre Channel)
FlexVolume、Flocker、NFS、iSCSI、RBD(Ceph Block Device)、CephFS
hostPath、VMware Photon、Portworx Volumes、ScaleIO Volumes、StorageOS
PV访问模式:
PV可以以资源提供者支持的任何方式挂载到主机上,如下表所示,供应商具有不同功能,每个PV访问模式都将被设置为该卷支持的特定模式,例如NFS可以支持多个读/写客户端,但特定的NFS PV可能以只读方式导出到服务器上。每个PV都有一套主机的用来描述特定功能的访问模式。
命令行中的缩写:
RWO – ReadWriteOnce (单个节点以读写挂载)
ROX – ReadOnlyMany (多个节点以读挂载)
RWX – ReadWriteMany (多节点读写挂载)
Volume插件 | ReadWriteOnce | ReadOnlyMany | ReadWriteMany |
AWSElasticBlockStoreAWSElasticBlockStore | √ |
|
|
AzureFile | √ | √ | √ |
AzureDisk | √ |
|
|
CephFS | √ | √ |
|
Cinder | √ |
|
|
FC | √ | √ |
|
FlexVolume | √ | √ |
|
Flocker | √ | √ |
|
GCEPersistentDisk | √ |
|
|
Glusterfs | √ | √ |
|
HostPath | √ | √ | √ |
iSCSI | √ |
|
|
PhotonPersistentDisk | √ | √ |
|
Quobyte | √ |
|
|
NFS | √ | √ | √ |
RBD | √ | √ | √ |
VsphereVolume | √ | √ |
|
PortworxVolume | √ |
| √(当 pod 并列时有效) |
ScaleIO | √ | √ |
|
StorageOS | √ |
|
|
回收策略:
Retain(保留):手动回收
Recycle(回收):基本擦除(rm –rf /thevolume/*)
Delete(删除):关联的存储资产(例如AWS EBS、GCE PD、Azure Disk和OpenStack Cinder卷)
注意:当前只有NFS和hostPath支持回收策略。AWS EBS、GCE PD、Azure Disk和Cinder卷支持删除策略。
卷状态:
Available(可用):一块空闲资源还没有被任何声明绑定
Bound(已绑定):已被声明绑定
Released(已释放):声明被删除,但是资源还未被集群重新声明
Failed(失败):该卷的自动回收失败
安装NFS:
#Harbor机器上安装NFS服务器 yum install -y nfs-common nfs-utils rpcbind mkdir /nfs chmod 666 /nfs chown nfsnobody /nfs
vi /etc/exports /nfs *(rw,no_root_squash,no_all_squash,sync)
systemctl start rpcbind systemctl start nfs
#在所有K8S节点上执行 yum -y install nfs-utils rpcbind
#在安装完成了,则在客户端访问 #注意是否有关闭防火墙,systemctl stop firewalld showmount -e Harbor机器的IP
#挂载 mkdir /test mount -t nfs Harbor机器的IP:/nfs /test
#测试 cd test echo "111" >> 1.html
#Harbor机器上看 ll /nfs/
#取消挂载 cd ~ umount /test rm -rf /test
#开始准备测试 #进入Harbor机器上,即NFS服务器,新建多几个共享目录 vi /etc/exports /nfs *(rw,no_root_squash,no_all_squash,sync) /nfs1 *(rw,no_root_squash,no_all_squash,sync) /nfs2 *(rw,no_root_squash,no_all_squash,sync)
mkdir /nfs1 mkdir /nfs2 chmod 777 /nfs1 /nfs2 chown nfsnobody /nfs1 /nfs2
systemctl restart rpcbind systemctl restart nfs #通过之前的步骤,在别的机器测试下挂载目录 |
实验:
#部署PV,修改为Retain kubectl delete pod --all kubectl delete pv --all
vi pv.yaml 〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓 apiVersion: v1 #资源类型PV kind: PersistentVolume metadata: name: nfspv1 spec: capacity: #存储1G storage: 1Gi #访问模式,RWO单个节点以读写挂载,ROX多个节点读挂载,RWX多节点读写挂载 accessModes: - ReadWriteOnce #回收策略,Retain保留,Recycle回收,Delete删除 persistentVolumeReclaimPolicy: Retain #存储关联NFS storageClassName: nfs nfs: #共享目录 path: /nfs #nfs服务器的IP server: 192.168.70.113 --- apiVersion: v1 #资源类型PV kind: PersistentVolume metadata: name: nfspv2 spec: capacity: #存储1G storage: 2Gi #访问模式,RWO单个节点以读写挂载,ROX多个节点读挂载,RWX多节点读写挂载 accessModes: - ReadOnlyMany #回收策略,Retain保留,Recycle回收,Delete删除 persistentVolumeReclaimPolicy: Retain #存储关联NFS storageClassName: nfs nfs: #共享目录 path: /nfs1 #nfs服务器的IP server: 192.168.70.113 --- apiVersion: v1 #资源类型PV kind: PersistentVolume metadata: name: nfspv3 spec: capacity: #存储3G storage: 3Gi #访问模式,RWO单个节点以读写挂载,ROX多个节点读挂载,RWX多节点读写挂载 accessModes: - ReadWriteMany #回收策略,Retain保留,Recycle回收,Delete删除 persistentVolumeReclaimPolicy: Retain #存储关联NFS storageClassName: slow nfs: #共享目录 path: /nfs2 #nfs服务器的IP server: 192.168.70.113 〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓
kubectl apply -f pv.yaml
kubectl get pv
#注意:要建立StatefulSet必须要建立一个None Service
#创建服务并使用PVC vi pod.yaml 〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓 apiVersion: v1 kind: Service metadata: #资源的运行名称 name: nginx #标签 labels: app: nginx spec: #端口 ports: - name: web port: 80 #由于下面要用到StatefulSet,因此SVC是None clusterIP: None selector: app: nginx --- apiVersion: apps/v1 #资源类型 kind: StatefulSet metadata: name: web spec: #应用匹配选择器 selector: matchLabels: app: nginx serviceName: "nginx" #运行副本 replicas: 3 #运行的Pod template: metadata: labels: app: nginx spec: #容器 containers: - name: nginx image: levi.harbor.com/library/nginx:1.9.1 ports: - containerPort: 80 name: web #数据卷 volumeMounts: - name: www mountPath: /usr/share/nginx/html volumeClaimTemplates: - metadata: name: www spec: accessModes: [ "ReadWriteOnce" ] storageClassName: "nfs" resources: requests: storage: 1Gi
〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓
kubectl apply -f pod.yaml
kubectl get pod
kubectl get pv
kubectl get pvc
#可以看到有一个失败了 kubectl get pod #出现的是1失败,也证明了是顺序创建的 #pod has unbound immediate PersistentVolumeClaims (repeated 2 times) kubectl describe pod web-1
#可以看到绑定类型是nfs,并且模式是ReadWriteOnce即RWO的 cat pod.yaml
#可以看到RWO的已经给绑定了,没了 kubectl get pv
kubectl describe pv nfspv1
#也可通过修改对应的storage和访问模式等,再次查看匹配模式,自己去实验
#在nfs服务器上的对应目录新建一个index.html vi index.html chmod 777 index.html
kubectl get pod -o wide
curl IP |
StatefulSet:
匹配Pod Name(网络标识)的模式为:$(statefulset名称)-$(序号),如web-0
StatefulSet为每个Pod副本创建了一个DNS域名,这个域名的格式为:$(podname).(headless server name),也意味着服务间是通过Pod域名拉通信而非Pod IP,因为当Pod所在Node发生故障时,Pod会被飘移到其他Node上,PodIP会发生变化,但Pod域名不会有变化。
kubectl get pod -o wide
kubectl delete pod web-0
#会发现地址变了,但是Name还是没有变 kubectl get pod -o wide
#DNS域名没有变 kubectl exec web-0 -it -- /bin/sh ping web-0.nginx(pod名.SVC名) |
StatefulSet使用Headless服务来控制Pod的域名,这个域名的FQDN为:$(service name).$(namespace).svc.cluster.local,其中cluster.local指的是集群的域名。
kubectl get pod -o wide -n kube-system #IP用coredns的IP dig -t A nginx.default.svc.cluster.local. @IP |
StatefulSet根据volumeClaimTemplates,为每个Pod创建一个PVC,PVC的命名规则匹配模式(volumeClaimTemplates.name)-(pod_name),比如volumeMounts.name=www,Podname=www-[0 - 2],因此创建出来的PVC是www-web-0、www-web-1、www-web-2。
删除Pod不会删除其PVC,手动删除PVC将会自动释放PV。
Statefulset启停顺序:
有序部署:部署StatefulSet时,如果有多个Pod副本,它们会被顺序创建(从0到N-1)并且,在下一个Pod运行之前所有之前的Pod必须都是Running和Ready状态。
有序删除:当Pod被删除时,它们的终止的顺序是从N – 1到0。
有序扩展:当对Pod执行扩展操作时,与部署一样,它前面的Pod必须都处于Running和Ready状态。
#有序删除 kubectl delete statefulset --all
#从后到前删除 kubectl get pod -w
#有序扩展 kubectl delete statefulset --all kubectl delete svc --all
kubectl create -f pod.yaml
kubectl get pod -o wide
curl IP
kubectl delete -f pod.yaml
kubectl get pod
kubectl get svc
#手动释放资源,要删除nfs的数据,但还是会正常的状态,因不会去看文件夹内是否有内容,在描述数据里,依然有这个信息 kubectl get pv
#查看描述数据 kubectl get pv nfspv1 -o yaml
#删除claimRef的内容 kubectl edit pv nfspv1 kubectl get pv |
StatefulSet使用场景:
稳定的持久化存储,即Pod重新调度后还是能访问到相同的持久化数据,基于PVC来实现。
稳定的网络标识符,即Pod重新调度后其PodName和HostName不变。
有序部署、有序扩展,基于Init Contaniners来实现。
有序收缩。
更多推荐
所有评论(0)