Kubernetes -2

Cronjob是比job控制器更加高级的一种控制器类型。Cronjob基于job,并且增加了时间调度

(1)在未来的某个指定时间运行一次Job,比如执行某个临时的任务

(2)周期性的运行job,比如定期备份、清理系统文件

CronJob的模板

[root@master ~]# vi cronjobv1.yaml

apiVersion: batch/v1beta1  #此控制器目前只存在于beta1

kind: CronJob

metadata:

  name: String

  namespace: String

  labels:      #元数据的标签列表

    key:       #标签的键值对

  annotations: #自定义注解列表 

    key: value   #定义多个注解的键值对

spec:

  schedule: #指定的任务运行周期,格式和Cron类似

  jobTemplate: {JobTemplate}   #job的模板

  startingDeadSeconds: int  #启动job的期限(秒为单位),若执行时间超出期限,Job则认定为失败,没有指定则>没有期限

  concurrencyPolicy: Allow/Forbid/Replace   #如果上一个周期的Job未执行完毕,而下一个周期已经开始,在这种

并发的场景下采用的策略。默认为Allow,允许并发运行Job;Forbid禁止并发运行,如果上一个周期的Job未执行完毕>,下一个Job直接忽略掉;Replace表示取消正在运行的Job,用一个新的来替换

  suspend: boolean  #如果设置未True,上一个Job的周期为执行完成,下一周期已经开始,则后续所有的执行都会被挂起

  successfulJobsHistoryLimit: int  #保留多少条执行成功的Job记录,默认为3

  failedJobsHistoryLimit: int  ##保留多少条执行失败的Job记录,默认为1

[root@master ~]# vi testcronjobv1.yaml

apiVersion: batch/v1beta1  #此控制器目前只存在于beta1

kind: CronJob

metadata:

  name: testcronjob

spec:

  schedule: "*/1 * * * *"

  jobTemplate: 

    spec:

      template:

        spec:

          restartPolicy: Never

          containers:

          - name: testcronjob

            image: busybox

            imagePullPolicy: IfNotPresent

            command: ['sh','-c']

            args: ['echo "Start Job!";sleep 20; echo "Job Done!"']

[root@master ~]# kubectl  apply -f testcronjobv1.yaml

Warning: batch/v1beta1 CronJob is deprecated in v1.21+, unavailable in v1.25+; use batch/v1 CronJob

cronjob.batch/testcronjob created

[root@master ~]# kubectl  get CronJob

NAME          SCHEDULE      SUSPEND   ACTIVE   LAST SCHEDULE   AGE

testcronjob   */1 * * * *   False     1        3s              58s

[root@master ~]# kubectl  get job

NAME                   COMPLETIONS   DURATION   AGE

testcronjob-28078629   1/1           23s        106s

testcronjob-28078630   1/1           21s        46s

其他控制器的使用(ReplicationController ReplicaSet

两者之间并无差异,只是名字不同,Controller是最早的控制版本,后来被Set取代,到了Deployment控制器出现,两者很少单独使用。

[root@master ~]# cat testdeployment.yaml

apiVersion: apps/v1              

kind: ReplicaSet                 

metadata:    

  name: testdeployment           

spec:                          

  replicas: 3                

  selector:                       

    matchLabels:

      example: deploymentnginx

  template:

    metadata:

      labels:

        example: deploymentnginx

    spec:

      containers:

      - name: nginx

        image: nginx:1.7.9

        ports:

        - containerPort: 80


在Kubernetes中,Service是充当了基础内部负载均衡器的一种组件。Service会将相同功能的Pod在逻辑上进行组合到一起,一般会采用标签选择器(label selector)来进行组合。

Service可以发布服务,可以跟踪并路由到所有指定类型的后端容器。针对于内部使用者而言,只需要直到对应的端点即可访问服务。

[root@master ~]# vi servicetemplate.yaml

apiVersion: v1

kind: Service

metadata:        #元数据

  name:          #Service的名称

  namespace:     #创建Service指定的命名空间

  labels:        #service的标签

    - name:

  annotations:   #Service的注解

    - name:

spec:

  selector: []    #标签选择器,选择具有指定标签的Pod作为管理范围

type:            #Service的类型

  clusterIP:      #虚拟服务的地址

  sessionAffinity:  #指定是否支持session,[ClinentIP|None]表示将同一个客户端的访问请求发送到同一个后端

  ports:          #Service需要暴露的端口

  - name:        #端口的名称

    protocol:    #采用的协议类型

    port:        #Service监听的端口

    targetPort:  #发送到后端应用的端口

    nodePort:    #当service的tpye为NodePort时,指定映射到物理机的端口

  status:        #当service的tpye为LoadBalancer时,需要设置外部负载均衡器的地址

    loadbalancer:

      ingress:

        ip:    #外部负载均衡器的地址

        hostname: 外部负载均衡器的主机名

Service的类型目前分为五大类。通过type可以进行定义ClusterIP\NodePort\LoadBalancer\ExternalName,ClusterIP又分为普通Service和无头Service

Service向外发布的方式:

(1)ClusterIP(普通):为默认的方式,在使用时可以无需指定。自动分配一个仅 cluster 内部可以访问的虚拟 IP,集群中的任何机器和Pod都可以访问这个IP

(2)NodePort:在 ClusterIP 基础上为 Service 在每台机器上绑定一个端口,这样就可以通过 <NodeIP>:NodePort 来访问该服务。

(3)LoadBalancer:基于ClusterIP和NodePort两种方式,除此之外,还会申请使用外部负载均衡器,由负载均衡器映射到各个“NodePort:端口”上,这样K8S集群外部的机器可以通过负载均衡器的方式访问Service。

Service向内发布的方式:

ExternalName:将服务通过 DNS CNAME 记录方式转发到指定的域名(通过 spec.externlName 设定)

ClusterIP(无头Service):通过DNS提供的网络ID进行访问,DNS会将无头Service的后端直接解析为Pod的IP地址列表,这种类型的Pod只能在集群内的Pod中访问,集群中的机器没法直接访问。主要给statefulSet提供服务。

[root@master ~]# vi testdeployment.yaml

apiVersion: apps/v1

apiVersion: apps/v1

kind: Deployment

metadata:

  name: deploymenthttp          

spec:

  replicas: 3

  selector:

    matchLabels:

      example: deploymenthttp

  template:

    metadata:

      labels:

        example: deploymenthttp

    spec:

      containers:

      - name: pythonservice

        image: python:3.7

        imagePullPolicy: IfNotPresent

        command: ['sh','-c']

        args: ['echo "<p> The host is $(hostname) </p>" > index.html; python -m http.server 80']

        ports:

[root@master ~]# kubectl  get pod -o wide  |grep deploymenthttp   //查询pod状态

deploymenthttp-7fbc9958f5-jrf2n   1/1     Running     0               109s    10.244.1.177   worker2   <none>           <none>

deploymenthttp-7fbc9958f5-s5fwq   1/1     Running     0               109s    10.244.1.175   worker2   <none>           <none>

deploymenthttp-7fbc9958f5-w9b8g   1/1     Running     0               109s    10.244.1.176   worker2   <none>           <none>

从以上内容可以看出我们创建了三个pod,分别对应了三个IP,因为在pod中已经构建了web服务(端口是80),所以可以通过这个端口去进行访问。

[root@master ~]# curl  10.244.1.175

<p> The host is deploymenthttp-7fbc9958f5-s5fwq </p>

因为Pod的IP地址是不固定的,而且直接访问Pod IP地址也是没有办法满足负载均衡的功能,所以我们需要以Service作为入口,来提供稳定的IP和负载均衡功能给集群内外使用。

通过ClusterIP的方式向外发布服务

1.普通Service的发布

在K8S集群内部发布服务,并且会为Service分配一个在集群内访问的固定虚拟IP。可以在集群内部的节点中通过ClusterIP进行访问服务,也可以在Pod中通过ClusterIP地址访问服务,单集群外部的地址无法访问。

[root@master ~]# vi testhttpservice.yaml

apiVersion: v1

kind: Service

metadata:

  name: deploymenthttp

spec:

  selector:

    example: deploymenthttp

  ports:

    - port: 8080          #Service端口

      targetPort: 80        #后端(pod)端口

      protocol: TCP        #协议

  type: ClusterIP

[root@master ~]# kubectl  apply -f testhttpservice.yaml

service/deploymenthttp created

[root@master ~]# kubectl  get svc

NAME              TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)        AGE

deploymenthttp    ClusterIP   10.1.245.237   <none>        8080/TCP       60s

[root@master ~]# curl   10.1.245.237:8080    //通过集群地址访问服务

<p> The host is deploymenthttp-7fbc9958f5-w9b8g </p>

[root@master ~]# curl   10.1.245.237:8080

<p> The host is deploymenthttp-7fbc9958f5-s5fwq </p>

[root@master ~]# curl   10.1.245.237:8080

<p> The host is deploymenthttp-7fbc9958f5-jrf2n </p>

//经过多次访问后,我们可以看出service已经实现了负载均衡的功能,在访问时可以按照比例随机分配到3个pod中,并且在访问的过程中无需关注pod具体IP。

[root@master ~]# kubectl  describe svc deploymenthttp

Name:              deploymenthttp

Namespace:         default

Labels:            <none>

Annotations:       <none>

Selector:          example=deploymenthttp

Type:              ClusterIP

IP Family Policy:  SingleStack

IP Families:       IPv4

IP:                10.1.245.237

IPs:               10.1.245.237

Port:              <unset>  8080/TCP

TargetPort:        80/TCP

Endpoints:         10.244.0.73:80,10.244.1.175:80,10.244.1.176:80 + 3 more...

Session Affinity:  None

Events:            <none>

//在详细信息中需要注意endpoint的信息,它列出了所有的Pod地址与公布的端口,在调用Service时,会按照比例随机转发给其中的一个地址。


向外发布-NodePort

通过NodePort的方式向外发布,基于ClusterIP的方式,首先要生成一个虚拟IP,然后将虚拟IP和端口映射到集群中的节点上,这样的话我们就可以通过节点本身加端口的方式来进行访问Service。

因为ClusterIP本身就已经提供了负载均衡的功能,所以在NodePort模式下,不管访问的时集群中的哪个节点地址,实现的负载均衡效果都是一样的,这个过程会先由某台机器通过映射关系转发到ClusterIP,然后由ClusterIP通过比例随机算法转发到对应的Pod。

[root@master ~]# vi testnodeportservice.yaml

apiVersion: v1

kind: Service

metadata:

  name: deploymenthttp

spec:

  selector:

    example: deploymenthttp

  ports:

    - port: 8080

      targetPort: 80

      protocol: TCP

      nodePort: 30002   #将ClusterIP及Port属性,来映射到集群中的各个机器的30001端口,这样的话,就可以通过集群节点ip加映射端口访问,nodePort取值范围时30000至32767

  type: NodePort

[root@master ~]# kubectl  apply -f testnodeportservice.yaml

service/deploymenthttp configured

[root@master ~]# kubectl  get svc

NAME              TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)          AGE

deploymenthttp    NodePort    10.1.245.237   <none>        8080:30002/TCP   65m

[root@master ~]# curl  10.1.245.237:8080    //因为是基于ClusterIP的方式进行访问,所以通过集群地址的方式依然可以访问到服务

<p> The host is deploymenthttp-7fbc9958f5-jrf2n </p>

访问成功,我们便可以在物理节点加上端口的方式进行访问,集群中的每一个节点都可以进行访问

[root@master ~]# curl  192.168.200.11:30002

<p> The host is deploymenthttp-7fbc9958f5-w9b8g </p>

[root@master ~]# curl  192.168.200.12:30002

<p> The host is deploymenthttp-7fbc9958f5-s5fwq </p>

[root@master ~]# curl  192.168.200.13:30002

<p> The host is deploymenthttp-7fbc9958f5-w9b8g </p>


向外发布-通过loadbalancer的方式

它是基于ClusterIP和NodePort两种方式来发布服务,,除此之外还会使用外部负载均衡器,由负载均衡器映射到各个“NodeIP:端口”上,那么K8S外部的机器就可以通过负载均衡器来进行访问。

K8S没有为私有集群提供网络负载均衡器的实现,如果K8S集群没有在公有云上运行,那么Loadbalancer则无限期的处于一个pending的状态,只有公有云厂商的k8s支持Loadbalancer。

MetalLB,这个服务可以为不在公有云平台上运行的私有K8S集群,提供网络负载均衡器的实现,从而有效的解决在任何集群中使用Loadbalancer。

首先会在K8S内运行,监控服务对象的变化。一旦察觉有新的Loadbalancer Service在运行,并没有可申请的负载均衡器之后,就分别完成两个内容:

(1)地址分配:MetalLB会把用户配置的地址池中选区的地址分配给Service

(2)地址广播:根据不同的配置,MetalLB会以二层(ARP/NDP)或者BGP的方式进行地址广播。

安装MetalLB

[root@master~]#kubectl apply -f https://raw.githubusercontent.com/metallb/metallb/v0.12.1/manifests/namespace.yaml

[root@master~]#kubectl apply -f https://raw.githubusercontent.com/metallb/metallb/v0.12.1/manifests/metallb.yaml

//首先下载yaml文件,

[root@master ~]# kubectl  get  pods -n metallb-system

NAME                          READY   STATUS    RESTARTS   AGE

controller-66445f859d-hwc5b   1/1     Running   0          3h7m

speaker-lb6gs                 1/1     Running   0          3h7m

speaker-pdgx8                 1/1     Running   0          3h7m

speaker-xlszp                 1/1     Running   0          3h7m

[root@master ~]# vi Configmap.yaml

apiVersion: v1

kind: ConfigMap

metadata:

  namespace: metallb-system

  name: config

data:

  config: |

    address-pools:

    - name: default

      protocol: layer2

      addresses:

      - 192.168.1.30-192.168.1.49

[root@master ~]# kubectl apply -f Configmap.yaml

configmap/config created

创建Service

[root@master ~]# vi testloadbalancer.yaml

apiVersion: v1

kind: Service

metadata:

  name: loadbalancer

spec:

  selector:

    example: deploymenthttp

  ports:

   - protocol: TCP

     port: 8080

     targetPort: 80

  type: LoadBalancer

[root@master ~]# kubectl  apply -f testloadbalancer.yaml

service/loadbalancer created

验证

对于Service,可以通过ClusterIP的方式进行访问,也可以通过NodePort的方式进行访问,通过NodePort的方式访问如下:

通过Loadbalancer的方式访问

在这个案例中,Loadbalancer对外的IP是192.168.1.30,端口为8080,所以外部机器直接可以通过这个地址进行访问。


向内发布-无头Service

无头Service(headless service),是一种比较特殊的Service的类型。通过这种无头的Service发布,不会分配任何的ClusterIP地址,也不会通过kube-proxy进行反向代理和负载均衡。

无头Service是通过DNS来提供稳定的网络ID进行访问,DNS会将无头Service的后端直接解析为Pod的IP地址列表,并且通过标签选择器将后端的Pod列表进行返回调用的客户端。

这种类型的Service只能再集群内的Pod中访问,集群内的节点没有办法直接访问,集群外部的机器也是没有办法直接访问。无头Service只要给statefulSet进行使用。

[root@master ~]# vi testheadless.yaml

apiVersion: v1

kind: Service

metadata:

  name: testheadless

spec:

  selector:

    example: deploymenthttp

  clusterIP: None

  ports:

    - protocol: TCP

      port: 8080

      targetPort: 80

  type: ClusterIP

//这个实例,与前面的ClusterIP不同的是,我们再这个属性中设置了一个clusterIP的属性为None,不分配任何的虚拟IP地址。

[root@master ~]# kubectl  apply -f testheadless.yaml

service/testheadless created

[root@master ~]# kubectl  get svc

NAME              TYPE        CLUSTER-IP    EXTERNAL-IP   PORT(S)        AGE

chinaskill-mall   NodePort    10.1.35.95    <none>        80:30080/TCP   10d

kubernetes        ClusterIP   10.1.0.1      <none>        443/TCP        12d

test-nginx        NodePort    10.1.39.206   <none>        80:32217/TCP   6d23h

testheadless      ClusterIP   None          <none>        8080/TCP       14s

由于这个Service没有办法通过集群内外的机器直接访问,所以只能由Pod进行访问,而且需要通过DNS,访问的形式为{ServiceName}.{Namespace}.svc.{ClusterDoamin},其中ClusterDomain代表集群域,,默认集群域为cluster.local。

[root@master ~]# vi testheadless1.yaml

apiVersion: v1

kind: Pod

metadata:

  name: testheadless1

spec:

  containers:

  - name: testheadles1

    image: docker.io/appropriate/curl

    imagePullPolicy: IfNotPresent

    command: ['sh','-c']

    args: ['echo "This is test pod for headless service!"; sleep 3600']

以上可知此pod并无特殊之处,镜像采用的是curl,此pod是一种是一个网络工具箱,里面包含了curl等一些常用的命令,执行3600的意义在于使容器处于一个长期运行的状态。

[root@master ~]# kubectl  apply -f testheadless1.yaml

pod/testheadless1 created

[root@master ~]# kubectl  get pod

NAME                              READY   STATUS    RESTARTS       AGE

testheadless1                     1/1     Running   0              4s

[root@master ~]# kubectl  exec -it testheadless1  -- /bin/sh

/ # nslookup  testheadless.default.svc.cluster.local

nslookup: can't resolve '(null)': Name does not resolve

Name:      testheadless.default.svc.cluster.local

Address 1: 10.244.1.49 10-244-1-49.testheadless.default.svc.cluster.local

Address 2: 10.244.1.50 10-244-1-50.testheadless.default.svc.cluster.local

Address 3: 10.244.1.52 10-244-1-52.testheadless.default.svc.cluster.local

/ # curl  10-244-1-49.testheadless.default.svc.cluster.local    //通过curl来测试访问的域名,可以看出结果

<p> The host is deploymenthttp-7fbc9958f5-w9b8g </p>

//由以上内容可知,总共返回了三个IP地址,这些IP是之前创建的每个Pod的IP地址,并且每个地址对应了不同的域名10-244-1-49.testheadless.default.svc.cluster.local,只不过是Pod中的地址不是固定的,所以域名并无任何作用。

向内发布-ExternalName

这种发布的方式是将外部的服务引进来,通过一定的格式映射到K8S集群,从而为集群内部提供服务。这种方式的服务没有选择器,也不需要定义任何的端口和端点,相反对于运行在集群外部的服务,通过返回外部服务别名的方式来提供服务。

[root@master ~]# vi testexternalname.yaml

apiVersion: v1

kind: Service

metadata:

  name: testexternalname

spec:

  type: ExternalName

  externalName: www.baidu.com

//这种类型的Service定义的属性非常简单,只需要声明type类型即可,并通过设置externalName引入外部服务的地址即可。

[root@master ~]# kubectl  apply -f testexternalname.yaml

service/testexternalname created

[root@master ~]# kubectl  get svc

NAME               TYPE           CLUSTER-IP    EXTERNAL-IP     PORT(S)        AGE

testexternalname   ExternalName   <none>        www.baidu.com   <none>         22s

在前面我们已经创建了一个测试Service的Pod,现在需要基于这个pod来验证。

[root@master ~]# kubectl  exec -it testheadless1 -- /bin/sh

/ # nslookup  testexternalname.default.svc.cluster.local

nslookup: can't resolve '(null)': Name does not resolve

Name:      testexternalname.default.svc.cluster.local

Address 1: 110.242.68.4

Address 2: 110.242.68.3

/ # nslookup  www.baidu.com

nslookup: can't resolve '(null)': Name does not resolve

Name:      www.baidu.com

Address 1: 110.242.68.4

Address 2: 110.242.68.3

//从以上结果可知,我们已经解析出来了两个地址,这两个地址就是百度的网址,所以使用这两个地址也可以直接访问百度。


Ingress

在使用Ingress时,服务无需对外暴露端口直接向外发布服务,而是统一由Ingress接受外部请求,然后通过域名配置转发给各个后端服务。

在使用Ingress时一般要涉及三个组件:

(1)反向代理的负载均衡器:类似于Nginx的应用。它可以通过Deployment或者DaemonSet控制器来自由部署。

(2)Ingress控制器:实质上起到监控作用。与API server不断进行交互,实时的感知后端的Service与Pod的变化,接收到这些信息之后,Ingress控制器在和Ingress生成配置,然后更新反向代理负载均衡器并刷新配置,达到服务发现的目的。

(3)Ingress:定义访问规则。

Ingress的安装

首先部署一个RBAC(基于角色的访问控制),Role Based Acess Control,作用是与K8s的资源和API 进行交互控制(细粒度)。

[root@master ~]# cat traefik-rabc.yaml

---

kind: ClusterRole

apiVersion: rbac.authorization.k8s.io/v1

metadata:

  name: traefik-ingress-controller

rules:

  - apiGroups:

      - ""

    resources:

      - services

      - endpoints

      - secrets

    verbs:

      - get

      - list

      - watch

  - apiGroups:

      - extensions

    resources:

      - ingresses

    verbs:

      - get

      - list

      - watch

  - apiGroups:

    - extensions

    resources:

    - ingresses/status

    verbs:

    - update

---

kind: ClusterRoleBinding

apiVersion: rbac.authorization.k8s.io/v1

metadata:

  name: traefik-ingress-controller

roleRef:

  apiGroup: rbac.authorization.k8s.io

  kind: ClusterRole

  name: traefik-ingress-controller

subjects:

- kind: ServiceAccount

  name: traefik-ingress-controller

  namespace: kube-system

[root@master ~]# kubectl  apply -f traefik-rabc.yaml

clusterrole.rbac.authorization.k8s.io/traefik-ingress-controller created

clusterrolebinding.rbac.authorization.k8s.io/traefik-ingress-controller created


[root@master ~]# kubectl  apply  -f traefik-ds.yaml

serviceaccount/traefik-ingress-controller created

daemonset.apps/traefik-ingress-controller created

service/traefik-ingress-service created

[root@master ~]#   kubectl  get rc,svc -n kube-system

NAME                              TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)                  AGE

service/kube-dns                  ClusterIP   10.1.0.10    <none>        53/UDP,53/TCP,9153/TCP   14d

service/traefik-ingress-service   ClusterIP   10.1.69.70   <none>        80/TCP,8080/TCP          28s

[root@master ~]# kubectl get pods --all-namespaces  -o wide --selector=k8s-app=traefik-ingress-lb

NAMESPACE     NAME                               READY   STATUS    RESTARTS   AGE   IP             NODE      NOMINATED NODE   READINESS GATES

kube-system   traefik-ingress-controller-b2vqt   1/1     Running   0          49s   10.244.1.64    worker2   <none>           <none>

kube-system   traefik-ingress-controller-nx6d8   1/1     Running   0          49s   10.244.0.132   master    <none>           <none>

kube-system   traefik-ingress-controller-s8plk   1/1     Running   0          49s   10.244.2.205   worker1   <none>           <none>

[root@master ~]# kubectl  describe pod traefik-ingress-controller-6b7f594d46-4ltw6 -n kube-system  |grep IP

IP:           10.244.0.128

IPs:

  IP:           10.244.0.128

//通过命令查询Pod的地址,然后使用命令去访问

[root@master ~]# curl   10.244.0.128

404 page not found

//由访问结果可知,我们的服务已经成功部署,但是访问失败,是因为我们没有配置资源,所以显示404 page not found,接下分别使用宿主机加端口的方式进行访问(浏览器)。

[root@master ~]# curl  192.168.200.11:30265

404 page not found

[root@master ~]# curl  192.168.200.12:30265

404 page not found

[root@master ~]# curl  192.168.200.13:30265

404 page not found

//因为traefik会在每个node上暴露80端口提供服务,所以我们可以采用宿主机去进行访问

[root@master ~]# curl  192.168.200.11

404 page not found

[root@master ~]# curl  192.168.200.12

404 page not found

Ingress基本操作

首先创建两个实例,分别为nginx和httpd,这两个服务分别是由Deployment和Service组成。

(1)创建Deployment-nginx和Deployment-http

[root@master ~]# cat deployment-ingress-web.yaml

apiVersion: apps/v1

kind: Deployment

metadata:

  name: deployment-ingress-nginx

spec:

  replicas: 1

  selector:

    matchLabels:

      example: deployment-ingress-nginx

  template:

    metadata:

      labels:

        example: deployment-ingress-nginx

    spec:

      containers:

      - name: nginx

        image: nginx:1.7.9

        ports:

        - containerPort: 80

---

apiVersion: apps/v1

kind: Deployment

metadata:

  name: deployment-ingress-http

spec:

  replicas: 1

  selector:

    matchLabels:

      example: deployment-ingress-http

  template:

    metadata:

      labels:

        example: deployment-ingress-http

    spec:

      containers:

      - name: http

        image: httpd:2.2

        ports:

        - containerPort: 80

[root@master ~]# kubectl  apply -f deployment-ingress-web.yaml

deployment.apps/deployment-ingress-nginx created

deployment.apps/deployment-ingress-http created

[root@master ~]# kubectl  get pod

NAME                                       READY   STATUS    RESTARTS         AGE

deployment-ingress-http-57cc6785c4-n69jx   1/1     Running   0                11s

deployment-ingress-nginx-9d9bd84d9-qpt4g   1/1     Running   0                11s

(2)创建对应的Service

[root@master ~]# cat service-ingress-web.yaml

apiVersion: v1

kind: Service

metadata:

  name: servicenginx

spec:

  selector:

    example: deployment-ingress-nginx

  ports:

    - protocol: TCP

      port: 8081

      targetPort: 80

---

apiVersion: v1

kind: Service

metadata:

  name: servicehttp

spec:

  selector:

    example: deployment-ingress-http

  ports:

    - protocol: TCP

      port: 8081

      targetPort: 80

[root@master ~]# kubectl  apply -f service-ingress-web.yaml

service/servicenginx created

service/servicehttp created

[root@master ~]# kubectl  get svc

NAME               TYPE           CLUSTER-IP    EXTERNAL-IP     PORT(S)        AGE

servicehttp        ClusterIP      10.1.76.137   <none>          8081/TCP       108s

servicenginx       ClusterIP      10.1.8.103    <none>          8081/TCP       109s

(3)分别采用集群地址访问这两个服务

[root@master ~]# curl  10.1.76.137:8081

<html><body><h1>It works!</h1></body></html>

[root@master ~]# curl  10.1.8.103:8081

<!DOCTYPE html>

<html>

<head>

<title>Welcome to nginx!</title>

<style>

    body {

        width: 35em;

        margin: 0 auto;

        font-family: Tahoma, Verdana, Arial, sans-serif;

    }

</style>

</head>

<body>

<h1>Welcome to nginx!</h1>

<p>If you see this page, the nginx web server is successfully installed and

working. Further configuration is required.</p>

<p>For online documentation and support please refer to

<a href="http://nginx.org/">nginx.org</a>.<br/>

Commercial support is available at

<a href="http://nginx.com/">nginx.com</a>.</p>

<p><em>Thank you for using nginx.</em></p>

</body>

</html>


定义存储卷与配置

在K8S中定义的存储卷主要包含了四种类型。

(1)本地存储卷:主要适用于Pod中容器之间的数据共享,或者实现Pod与Node数据存储和共享

(2)网络存储卷:主要是用于多个Pod之间或者多个Node之间的数据存储和共享。

(3)持久存储卷:基于网络存储卷,用户无需关心存储卷所使用的存储系统,只需要定义所需要消费的资源,可以将Pod与具体的存储系统解耦。

(4)配置存储卷:用于向各个Pod注入配置信息。

1.本地存储卷

本地存储卷包含了emptyDir和HostPath两种类型,都会使用本地文件系统,用于Pod中容器之间的数据共享,或者Pod与Node中的数据存储和共享。

(1)emptyDir(干净的空目录)

把这个目录来映射到主机的一个临时目录下,Pod中的所有的容器都可以读写这个目录,对其生命周期管理和Pod完全一致。其作用主要是用于存放和共享Pod的不同容器之间在运行过程中产生的文件。

[root@master ~]# vi testemptyDir.yaml

apiVersion: v1

kind: Pod

metadata:

  name: testemptydir

spec:

apiVersion: v1

kind: Pod

metadata:

  name: testemptydir

spec:

  containers:

  - name: containerwrite

    image: busybox

    imagePullPolicy: IfNotPresent

    command: ['sh','-c']

    args: ['echo "This is a test data!" >/write_dir/data; sleep 3600']

    volumeMounts:

    - name: filedata

      mountPath: /write_dir

  - name: containerread

    image: busybox

    imagePullPolicy: IfNotPresent

    command: ['sh','-c']

    args: ['cat /read_dir/data; sleep 3600']

    volumeMounts:

    - name: filedata

      mountPath: /read_dir

  volumes:

  - name: filedata

    emptyDir: {}

[root@master ~]# kubectl  apply -f testemptyDir.yaml

pod/testemptydir created

[root@master ~]# kubectl  get pod

NAME                                       READY   STATUS    RESTARTS       AGE

testemptydir                               1/1     Running   0              20s

[root@master ~]# kubectl  logs testemptydir containerread

This is a test data!

(2)HostPtah

把主机上指定的目录映射到Pod中的容器上,如果Pod需要在主机上存储或共享文件,或者使用主机上的文件,就可以采用这种方式。存放在主机上的文件不会被销毁,会永久保存。Pod被销毁后,如果在这条台机器上重建,可以再次读取原来的内容,但是如果这台机器出现故障或者Pod被调度在了其他节点上,就无法再次读取原来内容。

这种方式比较适合DaemonSet控制器,运行于DaemonSet控制器下的Pod可以直接操作或者使用主机上的文件。

[root@master ~]# vi testhostpath.yaml

apiVersion: v1

kind: Pod

metadata:

  name: testhostpath

spec:

  containers:

  - name: containerhostpath

    image: busybox

    imagePullPolicy: IfNotPresent

    command: ['sh','-c']

    args: ['echo "This is a test data!" >/write_dir/data; sleep 3600']

    volumeMounts:

    - name: filedata

      mountPath: /write_dir

  volumes:

  - name: filedata

    hostPath:

      path: /home/k8sadmin/testhostpath

//在这个yaml文件中,我们创建了一个名字为containerhostpath的容器,然后需要向这个容器中写入数据,数据为“This is a test data!”,容器内数据卷的地址为/write_dir,引用的存储卷为filedata。在这个例子中存储卷的名字为filedata,这个存储卷会被容器设置的数据卷所引用。存储卷的类型为hostPath,代表主机上指定的目录,路径为/home/k8sadmin/testhostpath,容器中的 /write_dir会映射到主机的 /home/k8sadmin/testhostpath目录下。

[root@master ~]# kubectl  apply -f testhostpath.yaml

pod/testhostpath created

[root@master ~]# kubectl  get pod

NAME                                       READY   STATUS    RESTARTS       AGE

testhostpath                               1/1     Running   0              15s

[root@master ~]# kubectl  describe pod testhostpath |grep Node

Node:         worker2/192.168.200.13

//可以从pod详细信息中查看到pod调度的位置在worker2节点,所以需要去worker2节点上,查找宿主机的映射目录

[root@worker2 ~]# cat /home/k8sadmin/testhostpath/data

This is a test data!

//我们可以看到容器中的数据已经被同步映射到宿主机目录下,然后可以对数据进行修改

[root@worker2 ~]# echo  "This is test data! change1" >  /home/k8sadmin/testhostpath/data

//再次查看,容器中的数据

[root@master ~]# kubectl  exec -it testhostpath -- /bin/sh

/ # cat /write_dir/data

This is test data! change1


网络存储卷(以NFS为例)

网络存储卷能够满足数据持久化的需求,能够永久保存数据。

一、安装NFS服务

1.安装NFS服务器(master节点)

[root@master ~]# yum -y install nfs-utils  rpcbind

2.创建共享目录

[root@master ~]# mkdir -p /data/k8snfs

3.配置共享参数

[root@master ~]# vi /etc/exports

/data/k8snfs 192.168.200.0/24(rw,sync,insecure,no_subtree_check,no_root_squash)

// /data/k8snfs:共享目录  192.168.200.0/24:共享网段,也可以改为*,表示不限制网段  rw:表示读写权限  sync:表示所有数据在请求时写入共享目录 insecure:表示NFS通过1024以上的端口进行发送  no_subtree_check:不检查父目录的权限  no_root_squash:表示root用户对根目录具有完全管理访问的权限

4.重启nfs服务

[root@master ~]# systemctl  restart rpcbind

[root@master ~]# systemctl  restart nfs

5.检查是否加载nfs服务端的配置

[root@master ~]# exportfs  -r

[root@master ~]# showmount -e 192.168.200.11

Export list for 192.168.200.11:

/data/k8snfs 192.168.200.0/24

6.K8S集群客户端的两台机器安装nfs(以worker1为例)

[root@worker1 ~]# yum -y install nfs-utils  rpcbind

[root@worker1 ~]# systemctl  restart nfs

[root@worker1 ~]# showmount  -e 192.168.200.11

Export list for 192.168.200.11:

/data/k8snfs 192.168.200.0/24

二、使用NFS服务

1.书写yaml文件

接下来使用NFS作为存储卷,NFS中的数据能够被永久的存储,而且能够被多个Pod同时读写。

[root@master ~]# vi testk8snfs.yaml

apiVersion: apps/v1

kind: Deployment

metadata:

  name: testk8snfs

spec:

  replicas: 2

  selector:

    matchLabels:

      example: testk8snfs

  template:

    metadata:

      labels:

        example: testk8snfs

    spec:

      containers:

      - name: containersnfs

        image: busybox

        imagePullPolicy: IfNotPresent

        command: ['sh','-c']

        args: ['echo "The host is $(hostname)" >> /dir/data; sleep 3600']

        volumeMounts:

        - name: nfsdata

          mountPath: /dir

      volumes:

      - name: nfsdata

        nfs:

          path: /data/k8snfs/

          server: 192.168.200.11

2.创建服务

[root@master ~]# kubectl  apply -f testk8snfs.yaml

deployment.apps/testk8snfs created

3.查看控制器以及pod

[root@master ~]# kubectl  get deploy

NAME                       READY   UP-TO-DATE   AVAILABLE   AGE

testk8snfs                 2/2     2            2           32s

[root@master ~]# kubectl  get pod  |grep testk8s

testk8snfs-7b89b86bd5-d9p44                1/1     Running   0              67s

testk8snfs-7b89b86bd5-kxnhm                1/1     Running   0              67s

4.验证两个pod是否都读写了同一存储卷上的同一个文件

【第一个pod】

[root@master ~]# kubectl  exec -it testk8snfs-7b89b86bd5-d9p44 -- /bin/sh

/ # cat /dir/data

The host is testk8snfs-7b89b86bd5-d9p44

The host is testk8snfs-7b89b86bd5-kxnhm

//通过Deployment控制器创建的两个Pod都已经成功的将信息,写入进了同一个文件,接下来我们验证一下另外一个pod的同步,首先在第一个Pod上修改data文件内容,如下:

/ # vi /dir/data

The host is testk8snfs-7b89b86bd5-d9p44

The host is testk8snfs-7b89b86bd5-kxnhm

Hello gongfanggaoshou!

/ # exit

command terminated with exit code 130

【第二个pod】

[root@master ~]# kubectl  exec -it testk8snfs-7b89b86bd5-kxnhm -- /bin/sh

/ # cat /dir/data

The host is testk8snfs-7b89b86bd5-d9p44

The host is testk8snfs-7b89b86bd5-kxnhm

Hello gongfanggaoshou!

/ # exit

//从以上结果可知,两个pod之间已经实现了文件同步,另外利用NFS还实现了pod与宿主机之间的共享。接下来回到宿主机查看。

【宿主机】

[root@master ~]# cat /data/k8snfs/data

The host is testk8snfs-7b89b86bd5-d9p44

The host is testk8snfs-7b89b86bd5-kxnhm

Hello gongfanggaoshou!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值