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目录中

    Opaquebase64编码格式的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来实现。

    有序收缩。

Logo

K8S/Kubernetes社区为您提供最前沿的新闻资讯和知识内容

更多推荐