K8S0423

  • Post author:
  • Post category:其他




K8S设计理念-分层架构





核心层


包括K8S的API(内置API:部署好后自带的API接口;自定义资源:CRD,部署K8S后通过安装其他组件等方式扩展出来的API。/apis分类/myapiAPI组/v1API版本/pods)资源对象、控制器、service、namespace、node等,是运行pod的基础环境。



应用层


实现服务部署(

无状态应用

如nginx使用deployment,

有状态应用

如mysql主从redis选举使用statefulSet)和路由(通过service实现服务之间调用)



管理层


实现自动化(如pod弹性伸缩,动态存储卷创建和回收)和策略管理(资源限制,RBAC授权,NetworkPolicy等,主要解决项目之间的pod隔离,网络安全和自动伸缩等功能)



接口层


包括kubectl命令行客户端工具和SDK(dashboard)等客户端访问接口



云原生生态系统


是在接口层只是的K8S集群管理调度生态系统,有两个范畴:K8S内部:CRI(容器运行时接口,主要实现容器运行)、CNI(网络接口,创建容器和删除容器时地址分配和回收,创建容器网络规则如calicoctl,flannel)、CSI(存储接口如nfs)、镜像仓库;K8S外部:监控、日志、CI/CD、配置管理等



K8S设计理念-API设计原则


  1. 所有API应该是声明式的。
  2. ·API对象是彼此互补而且可组合的。·
  3. 高层API以操作意图为基础设计。·
  4. 低层API根据高层API的控制需要设计.
  5. ·尽量避免简单封装,不要有在外部API无法显式知道的内部隐藏的机制。
  6. API操作复杂度与对象数量成正比。
  7. API对象状态不能依赖于网络连接状态
  8. ·尽量避免让操作机制依赖于全局状态,因为在分布式系统中要保证全局状态的同步是非常困难的



K8S 内置API以及资源对象简介




内置API接口查询方法


#kubectl get secrets -A | grep admin
kubernetes-dashboard   admin-token-fsfb2                                kubernetes.io/service-account-token   3      4d22h
kubectl describe secrets admin-token-fsfb2 -n kubernetes-dashboard #获取token


curl -k --cacert /etc/kubeasz/clusters/k8s-cluster1/ssl/ca.pem -H "Authorization: Bearer eyJhbGciOiJSUzI1NiIsImtpZCI6IlJjVXRjX0FEemIxb0Y0OFIyOU03OFEyNkxNbUJNOV9JS25JNmtXbFBKeWsifQ.eyJpc3MiOiJrdWJlcm5ldGVzL3NlcnZpY2VhY2NvdW50Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9uYW1lc3BhY2UiOiJrdWJlcm5ldGVzLWRhc2hib2FyZCIsImt1YmVybmV0ZXMuaW8vc2VydmljZWFjY291bnQvc2VjcmV0Lm5hbWUiOiJhZG1pbi10b2tlbi1mc2ZiMiIsImt1YmVybmV0ZXMuaW8vc2VydmljZWFjY291bnQvc2VydmljZS1hY2NvdW50Lm5hbWUiOiJhZG1pbiIsImt1YmVybmV0ZXMuaW8vc2VydmljZWFjY291bnQvc2VydmljZS1hY2NvdW50LnVpZCI6ImFhZmFhY2RjLWUzZWQtNDI0Ni1iOGU5LWQ3NmRlNGJlMmMxZCIsInN1YiI6InN5c3RlbTpzZXJ2aWNlYWNjb3VudDprdWJlcm5ldGVzLWRhc2hib2FyZDphZG1pbiJ9.KTsRFF2WW8tC4J34RV-w2JJdWSYnwfrJwZAvg2JAN3In-2bk5Y_P41y6M-KlxdR05N5oEZPLu3lyFOvvZdVXaS94U0FBBGmk0IWT89J7Dlw3m3Gt5YZDTW7EdulQl_BAc_OUhYV_yJwKx6CdcAEhfrneLSCm0QX4P1L1ahuaUfAkPLnfyI7taUiJFpGL6roOhEob_zASQ6VrjvyCCONVzmeJPBF-xs2Dnf1kd4GcMOuy1sjgEaCn3JPNnAx-NsTfpgQRMn5U4z8lLzkm5KShVBwNTLTs9U8ynhnb8yVgtxE_AbCL6Jj4I4oVZTjvzPdw2HDSY0AlJhVWU__b364r6Q"  https://192.168.226.144:6443


调API接口查询node信息

curl -k --cacert /etc/kubeasz/clusters/k8s-cluster1/ssl/ca.pem -H "Authorization: Bearer eyJhbGciOiJSUzI1NiIsImtpZCI6IlJjVXRjX0FemIxb0Y0OFIyOU03OFEyNkxNbUJNOV9JS25JNmtXbFBKeWsifQ.eyJpc3MiOiJrdWJlcm5ldGVzL3NlcnZpY2VhY2NvdW50Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9uYW1lc3BhY2UiOiJrdWJlcm5ldGVzLWRhc2hib2FyZCIsImt1YmVybmV0ZXMuaW8vc2VydmljZWFjY291bnQvc2VjcmV0Lm5hbWUiOiJhZG1pbi10b2tlbi1mc2ZiMiIsImt1YmVybmV0ZXMuaW8vc2VydmljZWFjY291bnQvc2VydmljZS1hY2NvdW50Lm5hbWUiOiJhZG1pbiIsImt1YmVybmV0ZXMuaW8vc2VydmljZWFjY291bnQvc2VydmljZS1hY2NvdW50LnVpZCI6ImFhZmFhY2RjLWUzZWQtNDI0Ni1iOGU5LWQ3NmRlNGJlMmMxZCIsInN1YiI6InN5c3RlbTpzZXJ2aWNlYWNjb3VudDprdWJlcm5ldGVzLWRhc2hib2FyZDphZG1pbiJ9.KTsRFF2WW8tC4J34RV-w2JJdWSYnwfrJwZAvg2JAN3In-2bk5Y_P41y6M-KlxdR05N5oEZPLu3lyFOvvZdVXaS94U0FBBGmk0IWT89J7Dlw3m3Gt5YZDTW7EdulQl_BAc_OUhYV_yJwKx6CdcAEhfrneLSCm0QX4P1L1ahuaUfAkPLnfyI7taUiJFpGL6roOhEob_zASQ6VrjvyCCONVzmeJPBF-xs2Dnf1kd4GcMOuy1sjgEaCn3JPNnAx-NsTfpgQRMn5U4z8lLzkm5KShVBwNTLTs9U8ynhnb8yVgtxE_AbCL6Jj4I4oVZTjvzPdw2HDSY0AlJhVWU__b364r6Q"  https://192.168.226.144:6443/api/v1/nodes



资源类型


资源类型 资源名称
资源对象 Pod、ReplicaSet、ReplicationController、Deployment、StatefulSet、DaemonSet、Job、CronJob.HorizontalPodAutoscaling、Node、Namespace、Service、Ingress、Label、CustomResourceDefinition
存储对象 Volume、PersistentVolume、PersistentVolumeClaim、Secret、ConfigMap
策略对象 SecurityContext.ResourceQuota、LimitRange
身份对象 ServiceAccount、Role、ClusterRole



资源对象操作命令



命令集

命令

用途

基础命令

create/delete/edit/get/describe/logs/exec/scale

增删改查

explain

命令说明

配置命令

Label:给node标记label,实现亲pod 与node亲和性

标签管理

apply

动态配置

集群管理命令

cluster-info/top

集群状态

cordon:警戒线,标记node不被调度

uncordon:取消警戒标记为cordon的node

drain:驱逐node上的pod,用于node下线等场景

taint:给node标记污点,实现反亲pod 与node反亲和性

node节点管理

config

客户端kube-ininfig配置

api-resources/api-versions/version

api资源



K8S的重要概念



  • 资源对象:K8S基于声明式API,和资源对象进行交互


  • yaml文件,为了方便后期管理,通过使用yaml文件通过API管理资源对象


  • yaml必须要的字段:


  1. apiVersion:创建该对象所使用的API的版本

  2. kind:创建的对象类型

  3. metadata:定义识别对象的唯一性的数据,包括一个name名称,可选的namespace

  4. spec(


    期望状态)


    :定义资源对象的详细规范信息(统一的label标签、容器名称、镜像、端口映射等)

  5. status(


    实际状态


    ):Pod创建完成后K8S自动生成的status状态(实时更新)



job与cronjob区别


Job,主要用于负责批量处理(一次要处理指定数量任务)短暂的一次性(每个任务仅运行一次就结束)任务。Job特点如下:

  • 当Job创建的pod执行成功结束时,Job将记录成功结束的pod数量
  • 当成功结束的pod达到指定的数量时,Job将完成执行
apiVersion: batch/v1
kind: Job
metadata:
  name: job-mysql-init
  namespace: linux66
spec:
  template:
    spec:
      containers:
      - name: job-mysql-init-container
        image: centos:7.9.2009
        command: ["/bin/sh"]
        args: ["-c", "echo data init job at `date +%Y-%m-%d_%H-%M-%S` >> /cache/data.log"]
        volumeMounts:
        - mountPath: /cache
          name: cache-volume
      volumes:
      - name: cache-volume
        hostPath:
          path: /tmp/jobdata
      restartPolicy: Never  # 重启策略只能设置为Never或者OnFailure



关于重启策略设置的说明



  • 如果指定为OnFailure,则job会在pod出现故障时重启容器,而不是创建pod,failed次数不变
  • 如果指定为Never,则job会在pod出现故障时创建新的pod,并且故障pod不会消失,也不会重启,failed次数加1
  • 如果指定为Always的话,就意味着一直重启,意味着job任务会重复去执行了,当然不对,所以不能设置为Always

CronJob控制器以Job控制器资源为其管控对象,并借助它管理pod资源对象,Job控制器定义的作业任务在其控制器资源创建之后便会立即执行,但CronJob可以以类似于Linux操作系统的周期性任务作业计划的方式控制其运行时间点及重复运行的方式。也就是说,CronJob可以在特定的时间点(反复的)去运行job任务。

apiVersion: batch/v1
kind: CronJob
metadata:
  name: cronjob-mysql-databackup
spec:
  #schedule: "30 2 * * *"
  schedule: "* * * * *"
  jobTemplate:
    spec:
      template:
        spec:
          containers:
          - name: cronjob-mysql-databackup-pod
            image: centos:7.9.2009
            #imagePullPolicy: IfNotPresent
            command: ["/bin/sh"]
            args: ["-c", "echo mysql databackup cronjob at `date +%Y-%m-%d_%H-%M-%S` >> /cache/data.log"]
            volumeMounts: 
            - mountPath: /cache
              name: cache-volume
          volumes:
          - name: cache-volume
            hostPath:
              path: /tmp/cronjobdata
          restartPolicy: OnFailure

schedule: cron表达式,⽤于指定任务的执⾏时间

*/1     *     *    *      *

<分钟> <⼩时> <⽇> <⽉份> <星期>

分钟 值从 0 到 59.

⼩时 值从 0 到 23.

⽇ 值从 1 到 31.

⽉ 值从 1 到 12.

星期 值从 0 到 6, 0 代表星期⽇

多个时间可以⽤逗号隔开; 范围可以⽤连字符给出;*可以作为通配符; /表示每…

concurrencyPolicy:

Allow: 允许Jobs并发运⾏(默认)

Forbid: 禁⽌并发运⾏,如果上⼀次运⾏尚未完成,则跳过下⼀次运⾏

Replace: 替换,取消当前正在运⾏的作业并⽤新作业替换它



RC/RS副本控制器




Replication Controller


:副本控制器,只通过selector标签进行匹配,操作符只支持= !=。创建pod失败、被删除或者被终止时会自动替换

ReplicaSet:与上面区别是除了支持selector,还支持in notin



Deployment控制器



比rs更高一级的控制器,除了拥有rs功能外,还有滚动升级(按照pod数量的25%,

会新启动rs进行创建pod

),回滚(kubectl rollout undo deployment nginx-deployment -n default)等功能

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
spec:
  replicas: 2
  selector:
    #app: ng-deploy-80 #rc
    matchLabels: #rs or deployment
      app: ng-deploy-80

    #matchExpressions:
    #  - {key: app, operator: In, values: [ng-deploy-80,ng-rs-81]}
  template:
    metadata:
      labels:
        app: ng-deploy-80
    spec:
      containers:
      - name: ng-deploy-80
        image: nginx:1.16.0
        ports:
        - containerPort: 80



deployment名称-rs名称-pod名称



Service简介



  • 由于pod重建之后ip就变了,因此pod之间使用pod的IP直接访问会出现无法访问的问题,而service则解耦了服务和应用,service的实现方式就是通过label标签动态匹配后端endpoint.

  • kube-proxy监听着k8s-apiserver,一旦service资源发生变化(调k8s-api修改service信息), kube-proxy就会生成对应的负载调度的调整,这样就保证service的最新状态.

  • kube-proxy有三种调度模型:userspace: k8s1.1之前;kube-proxy有三种调度模型:userspace: k8s1.1之前;ipvs: k8s 1.11之后,如果没有开启ipvs,则自动降级为iptables。

ingress将请求发送给Kube API Server,Kube API Server创建规则关联到ingress。

客户端通过访问ingresscontroller,ingresscontroller根据现有规则将域名与规则进行匹配,并将请求转给对应service,service(只会请求当前namespace)将请求(默认轮询)转给pod


service类型



ClusterlP


:用于内部服务基于service name的访问,默认



NodePort


:用于kubernetes集群以外的服务主动访问运行在kubernetes集群内部的服务。



LoadBalancer


:用于公有云环境的服务暴露。



ExternalName


:用于将k8s集群外部的服务映射至k8s集群内部访问,从而让集群内部的pod能够通过固定的servicename访问集群外部的服务,有时候也用于将不同namespace之间的pod通过ExternalName进行访问.



ClusterlP


#apiVersion: extensions/v1beta1
apiVersion: apps/v1
kind: Deployment
metadata:
  name: ng-deployment
spec:
  replicas: 1
  selector:
    #matchLabels: #rs or deployment
    #  app: ng-deploy3-80
    matchExpressions:
      - {key: app, operator: In, values: [ng-deploy-80,ng-rs-81]}
  template:
    metadata:
      labels:
        app: ng-deploy-80
    spec:
      containers:
      - name: ng-deploy-80-pod
        image: nginx:1.17.5
        ports:
        - containerPort: 80
      #nodeSelector:
      #  env: group1

service.yaml

apiVersion: v1
kind: Service
metadata:
  name: ng-deploy-80
spec:
  ports:
  - name: http
    port: 80
    targetPort: 80
    protocol: TCP
  type: ClusterIP
  selector:
    app: ng-deploy-80    #与默认目模板下的app:ng-deploy-80保持一致


NodePort

apiVersion: v1
kind: Service
metadata:
  name: ng-deploy-80
spec:
  ports:
  - name: http
    port: 81
    targetPort: 80
    nodePort: 30012    #不指定会随机分配,每台节点包括master都会监听,访问哪台都可以
    protocol: TCP
  type: NodePort
  selector:
    app: ng-deploy-80



Vilume-存储卷简介


Volume将容器中指定数据和容器解耦,并将数据存储到指定位置,不同的存储卷功能不一样,如果基于网络存储的存储卷可实现容器间数据共享和持久化

静态存储卷需要在使用前手动创建PV和PVC,然后绑定到pod使用

常用的几种存储卷:

  • emptyDir:本地临时卷。容器所在宿主机本地,不会持久化,容器删除数据删除。用于同一pod内多个数据共享如两个容器日志共享
  • hostPath:本地存储卷。容器所在宿主机本地,容器删除不会删除数据,但是容器a迁到b主机,日志数据没法迁移到b主机。
  • configmap:配置文件。
  • Secret:一种包含少了敏感信息如密码、令牌或密钥的对象
  • nfs等:网络存储卷



emptyDir


  • 当Pod被分配给节点时,首先创建emptyDir卷,并且只要该Pod在该节点上运行,该卷就会存在,正如卷的名字所述,它最初是空的(联合文件系统),Pod中的容器可以读取和写入emptyDir卷中的相同文件,尽管该卷可以挂载到每个容器中的相同或不同路径上.当出于任何原因从节点中删除Pod时,emptyDir 中的数据将被永久删除。
  • /var/lib/kubelet/pods/$ID/volumes/kubernetes.io~empty-dir/cache-volume/$FILE(默认路径)

#apiVersion: extensions/v1beta1
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
spec:
  replicas: 1
  selector:
    matchLabels: #rs or deployment
      app: ng-deploy-80
  template:
    metadata:
      labels:
        app: ng-deploy-80
    spec:
      containers:
      - name: ng-deploy-80
        image: nginx 
        ports:
        - containerPort: 80
        volumeMounts:   #卷挂载指令
        - mountPath: /cache    #挂载node节点路径
          name: cache-volume    #通过卷名称匹配挂载
      volumes:
      - name: cache-volume  #声明卷名称
        emptyDir: {}    #默认信息



容器删除,数据就会被删除



hostPath



hostPath卷将主机节点的文件系统中的文件或目录挂载到集群中,pod删除的时候,卷不会被删除。类似docker -v

容器删除数据还会保留,这是与emptyDir区别



nfs等共享存储


nfs卷允许将现有的NFS(网络文件系统)共享挂载到你的容器中.不像emptyDir,当删除Pod时, nfs卷的内容被保留,卷仅仅是被卸载.这意味着NFS卷可以预填充数据,并且可以在pod之间“切换”数据.NFS 可以被多个写入者同时挂载。


单个共享路径



准备nfs挂载路径


[root@k8s-master1 case7-nfs]# vim /etc/exports
/data/k8sdata/ *(rw,no_root_squash)# *与(中间不能有空格,IP写时候要包括宿主机ip。no_root_squash  不做权限映射,普通用户写的文件不修改为root用户

systemctl restart nfs.service#重启
#验证挂载是否成功
[root@k8s-master1 case7-nfs]# showmount -e 192.168.226.144
Export list for 192.168.226.144:
/data/k8sdata *
#apiVersion: extensions/v1beta1
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
spec:
  replicas: 1
  selector:
    matchLabels:
      app: ng-deploy-80
  template:
    metadata:
      labels:
        app: ng-deploy-80
    spec:
      containers:
      - name: ng-deploy-80
        image: nginx 
        ports:
        - containerPort: 80
        volumeMounts:
        - mountPath: /usr/share/nginx/html/mysite
          name: my-nfs-volume
      volumes:
      - name: my-nfs-volume
        nfs:    #命令kubectl explain Deployment.spec.template.spec.volumes.nfs 查看使用方法
          server: 192.168.226.144  #写server地址和共享路径,确保安装nfs-server(yum install nfs-common)并启动
          path: /data/k8sdata/linux66

---
apiVersion: v1
kind: Service
metadata:
  name: ng-deploy-80
spec:
  ports:
  - name: http
    port: 81
    targetPort: 80
    nodePort: 30016
    protocol: TCP
  type: NodePort
  selector:
    app: ng-deploy-80

容器中没有内核,node节点没有nfs。所以不会是这两个进行挂载,实际是宿主机把192.168.226.144:/data/k8sdata/nfsdata挂载到容器的工作目录,在使用联合文件系统映射到容器中使用



多个共享路径


#apiVersion: extensions/v1beta1
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment-site2
spec:
  replicas: 1
  selector:
    matchLabels:
      app: ng-deploy-81
  template:
    metadata:
      labels:
        app: ng-deploy-81
    spec:
      containers:
      - name: ng-deploy-81
        image: nginx 
        ports:
        - containerPort: 80
        volumeMounts:
        - mountPath: /usr/share/nginx/html/mysite
          name: my-nfs-volume
        - mountPath: /usr/share/nginx/html/magedu
          name: magedu-statics-volume
      volumes:
      - name: my-nfs-volume
        nfs:
          server: 172.31.7.109
          path: /data/k8sdata/linux66
      - name: magedu-statics-volume
        nfs:
          server: 172.31.7.110
          path: /data/magedu

---
apiVersion: v1
kind: Service
metadata:
  name: ng-deploy-81
spec:
  ports:
  - name: http
    port: 80
    targetPort: 80
    nodePort: 30017
    protocol: TCP
  type: NodePort
  selector:
    app: ng-deploy-81



PV/PVC



PersistentVolume(PV)是集群中已经由kubernetes管理员配置的一个网络存储,集群中的存储资源一个集群资源,即不隶属于任何namespace(kubectl api-resources 查看,namespaced那列是false),PV的数据最终存储在硬件存储,pod不能直接挂载PV,PV需要绑定给PVC并最终由pod挂载PVC使用,PV其支持NFS、Ceph、商业存储或云提供商的特定的存储等,可以自定义PV的类型是块还是文件存储、存储空间大小、访问模式等,PV的生命周期独立于Pod,即当使用PV的Pod被删除时可以对PV中的数据没有影响。


PersistentVolumeClaim(PVC):是pod对存储的请求,pod挂载PVC并将数据存储在PVC,而PVC需要绑定到PV才能使用,另外PVC在创建的时侯要知道namespace,即pod要和PVC运行在同一个namespace,可以对PVC设置特定的空间大小和访问模式,使用PVC的pod在删除时也可以对PVC中的数据没有影响。


两者都是逻辑组卷,并不是真正的存储数据


用于实现pod和storage的解耦,这样我们修改storage的时候不需要修改pod。


与NFS的区别,可以在PV和PVC层面实现实现对存储服务器的空间分配、存储的访问权限管理等。kubernetes 从1.0版本开始支持PersistentVolume和PersistentVolumeClaim。



PV挂载模式








:每个卷同一时刻只能以一种模式访问,即使该卷支持多种模式





  • ReadWriteOnce(RWO):被单个客户端以读写权限挂载,适合有状态服务如MySQL主从
  • ReadOnlyMany(ROX):可以被多个节点挂载但权限只读比如挂载nginx前端
  • ReadWriteMany(RWX):可以被多个节点读写方式挂载使用,如java程序
  • ReadWriteOncePod:单次临时挂载



PV/PVC总结



  • PV是对底层网络存储的抽象,即将网络存储定义为一种存储资源,将一个整体的存储资源拆分成多份后给不同的业务使用。

  • PVC是对PV资源的申请调用,pod是通过PVC将数据保存至PV,PV再把数据保存至真正的硬件存储.


PV回收策略

  • Retain:删除PV后保持原状,需要管理员手动删除,推荐策略
  • Recycle:空间回收,删除存储卷所有数据,目前仅支持nfs和hostPath
  • Delete:自动删除存储卷


PV



卷类型



定义存储卷使用的文件系统是块设备还是文件系统,默认为文件系统



PVC参数


  • ReadWriteOnce(RWO):被单个客户端以读写权限挂载,适合有状态服务如MySQL主从
  • ReadOnlyMany(ROX):可以被多个节点挂载但权限只读比如挂载nginx前端
  • ReadWriteMany(RWX):可以被多个节点读写方式挂载使用,如java程序
  • resources:定义PVC创建存储卷的空间大小,小于等于PV
  • selector:#标签选择器,选择要绑定的PV
  • matchLabels#匹配标签名称,1
  • matchExpressions #基于正则表达式匹配,模糊匹配,2
  • volumeName要绑定的PV名称,精确指定,3



Volume 存储卷类型



  1. static:静态存储卷,需要在使用前手动创建PV、然后创建PVC并绑定到PV,然后挂载至pod使用,适用于PV和PVC相对比较固定的业务场景。

  2. dynamin:动态存储卷,先创建一个存储类storageclass,1后期pod在使用PVC的时候可以通过存储类动态创建PvC,适用于有状态服务集群如MySQL一主多从、zookeeper集群等。



创建静态存储卷




创建PV


apiVersion: v1 #api版本
kind: PersistentVolume    #类型为PV
metadata:
  name: myserver-myapp-static-pv #PV的名称
spec:
  capacity:
    storage: 10Gi    #分配PV空间大小
  accessModes:
    - ReadWriteOnce    #访问模式,单个pod以读写权限挂载
  nfs:    #类型为nfs
    path: /data/k8sdata/pv-static    #nfs路径
    server: 192.168.226.144     #nfs地址



验证PV状态


[root@k8s-master1 case8-pv-static]# kubectl get pv    #状态必须为Available
NAME                       CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS      CLAIM   STORAGECLASS   REASON   AGE
myserver-myapp-static-pv   10Gi       RWO            Retain           Available                                   8s



创建PVC绑定PV


apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: myserver-myapp-static-pvc    #pvc名称
  namespace: myserver    #pvc的namespace,必须要与业务pod在同一个namespace
spec:
  volumeName: myserver-myapp-static-pv    #要绑定的PV
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 10Gi



验证PVC是否绑定到PV


[root@k8s-master1 case8-pv-static]# kubectl get pvc -n myserver
NAME                        STATUS   VOLUME                     CAPACITY   ACCESS MODES   STORAGECLASS   AGE
myserver-myapp-static-pvc   Bound    myserver-myapp-static-pv   10Gi       RWO                           17s



创建业务容器绑定到pvc


kind: Deployment
#apiVersion: extensions/v1beta1
apiVersion: apps/v1
metadata:
  labels:
    app: myserver-myapp 
  name: myserver-myapp-deployment-name
  namespace: myserver
spec:
  replicas: 3
  selector:
    matchLabels:
      app: myserver-myapp-frontend
  template:
    metadata:
      labels:
        app: myserver-myapp-frontend
    spec:
      containers:
        - name: myserver-myapp-container
          image: nginx:1.20.0 
          #imagePullPolicy: Always
          volumeMounts:
          - mountPath: "/usr/share/nginx/html/statics"    #将容器中该路径进行挂载
            name: statics-datadir
      volumes:
        - name: statics-datadir    #声明卷
          persistentVolumeClaim:    #卷类型为pvc
            claimName: myserver-myapp-static-pvc #pvc名称

---
kind: Service
apiVersion: v1
metadata:
  labels:
    app: myserver-myapp-service
  name: myserver-myapp-service-name
  namespace: myserver
spec:
  type: NodePort
  ports:
  - name: http
    port: 80
    targetPort: 80
    nodePort: 30080
  selector:
    app: myserver-myapp-frontend



验证




创建动态存储卷


动态需要定义存储类。StorageClass为管理员提供了描述存储”类”的方法。不同的类型可能会映射到不同的服务质量等级或备份策略,或是由集群管理员制定的任意策略。Kubernetes本身并不清楚各种类代表的什么。这个类的概念在其他存储系统中有时被称为”配置文件”。



授权


apiVersion: v1
kind: Namespace
metadata:
  name: nfs
---
apiVersion: v1
kind: ServiceAccount
metadata:
  name: nfs-client-provisioner    #创建账号用于集群内认证
  # replace with namespace where provisioner is deployed
  namespace: nfs
---
kind: ClusterRole    #角色绑定
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: nfs-client-provisioner-runner
rules:
  - apiGroups: [""]
    resources: ["nodes"]
    verbs: ["get", "list", "watch"]
  - apiGroups: [""]
    resources: ["persistentvolumes"]
    verbs: ["get", "list", "watch", "create", "delete"]
  - apiGroups: [""]
    resources: ["persistentvolumeclaims"]
    verbs: ["get", "list", "watch", "update"]
  - apiGroups: ["storage.k8s.io"]
    resources: ["storageclasses"]
    verbs: ["get", "list", "watch"]
  - apiGroups: [""]
    resources: ["events"]
    verbs: ["create", "update", "patch"]
---
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: run-nfs-client-provisioner
subjects:
  - kind: ServiceAccount
    name: nfs-client-provisioner
    # replace with namespace where provisioner is deployed
    namespace: nfs
roleRef:
  kind: ClusterRole
  name: nfs-client-provisioner-runner
  apiGroup: rbac.authorization.k8s.io
---
kind: Role
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: leader-locking-nfs-client-provisioner
  # replace with namespace where provisioner is deployed
  namespace: nfs
rules:
  - apiGroups: [""]
    resources: ["endpoints"]
    verbs: ["get", "list", "watch", "create", "update", "patch"]
---
kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: leader-locking-nfs-client-provisioner
  # replace with namespace where provisioner is deployed
  namespace: nfs
subjects:
  - kind: ServiceAccount
    name: nfs-client-provisioner
    # replace with namespace where provisioner is deployed
    namespace: nfs
roleRef:
  kind: Role
  name: leader-locking-nfs-client-provisioner
  apiGroup: rbac.authorization.k8s.io



创建存储类


apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: managed-nfs-storage    #存储类名称
provisioner: k8s-sigs.io/nfs-subdir-external-provisioner # or choose another name, must match deployment's env PROVISIONER_NAME'
reclaimPolicy: Retain #PV的删除策略,默认为delete,删除PV后立即删除NFS server的数据
mountOptions:
  - noresvport #告知NFS客户端在重新建立网络连接时,使用新的传输控制协议源端口
  - noatime #访问文件时不更新文件inode中的时间戳,高并发环境可提高性能
parameters:
  mountOptions: "vers=4.1,noresvport,noatime"
  archiveOnDelete: "true"  #删除pod时保留pod数据,默认为false时为不保留数据 



创建pod


apiVersion: apps/v1
kind: Deployment
metadata:
  name: nfs-client-provisioner
  labels:
    app: nfs-client-provisioner
  # replace with namespace where provisioner is deployed
  namespace: nfs
spec:
  replicas: 1
  strategy: #部署策略
    type: Recreate    #回收策略,重建
  selector:
    matchLabels:
      app: nfs-client-provisioner
  template:
    metadata:
      labels:
        app: nfs-client-provisioner
    spec:
      serviceAccountName: nfs-client-provisioner
      containers:
        - name: nfs-client-provisioner
          #image: k8s.gcr.io/sig-storage/nfs-subdir-external-provisioner:v4.0.2 
          image: docker.io/shuaigege/nfs-subdir-external-provisioner:v4.0.2    #负责动态创建PV
          volumeMounts:
            - name: nfs-client-root
              mountPath: /persistentvolumes
          env:    #声明环境变量到192.168.226.144:/data/k8sdata/pv-dynamic创建PV
            - name: PROVISIONER_NAME
              value: k8s-sigs.io/nfs-subdir-external-provisioner
            - name: NFS_SERVER
              value: 192.168.226.144
            - name: NFS_PATH
              value: /data/k8sdata/pv-dynamic
      volumes:
        - name: nfs-client-root
          nfs:
            server: 192.168.226.144
            path: /data/k8sdata/pv-dynamic



创建PVC


# Test PVC
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
  name: myserver-myapp-dynamic-pvc
  namespace: myserver
spec:
  storageClassName: managed-nfs-storage #调用的storageclass 名称
  accessModes:
    - ReadWriteMany #访问权限
  resources:
    requests:
      storage: 500Mi #空间大小



创建nginx容器挂载pvc


kind: Deployment
#apiVersion: extensions/v1beta1
apiVersion: apps/v1
metadata:
  labels:
    app: myserver-myapp 
  name: myserver-myapp-deployment-name
  namespace: myserver
spec:
  replicas: 1 
  selector:
    matchLabels:
      app: myserver-myapp-frontend
  template:
    metadata:
      labels:
        app: myserver-myapp-frontend
    spec:
      containers:
        - name: myserver-myapp-container
          image: nginx:1.20.0 
          #imagePullPolicy: Always
          volumeMounts:
          - mountPath: "/usr/share/nginx/html/statics"
            name: statics-datadir
      volumes:
        - name: statics-datadir
          persistentVolumeClaim:
            claimName: myserver-myapp-dynamic-pvc 

---
kind: Service
apiVersion: v1
metadata:
  labels:
    app: myserver-myapp-service
  name: myserver-myapp-service-name
  namespace: myserver
spec:
  type: NodePort
  ports:
  - name: http
    port: 80
    targetPort: 80
    nodePort: 30080
  selector:
    app: myserver-myapp-frontend



ConfigMaps



Configmap配置信息和镜像解耦,实现方式为将配置信息放到configmap对象中,然后在pod的中作为Volume挂载到pod中,从而实现导入配置的目的。



使用场景

  • ·通过Configmap给pod定义全局环境变量
  • ·通过Configmap给pod传递命令行参数,如mysql -u -p中的账户名密码可以通过Configmap传递.·
  • 通过Configmap给pod中的容器服务提供配置文件,配置文件以挂载到容器的形式使用.



注意事项:


Configmap需要在pod使用它之前创建。


pod只能使用位于同一个namespace的Configmap,及Configmap不能夸namespace使用。通常用于非安全加密的配置场景。


Configmap通常是小于1MB的配置。



案例一


apiVersion: v1
kind: ConfigMap
metadata:
  name: nginx-config    #指定configmap名称
data:
 default: |    #内容
    server {
       listen       80;
       server_name  www.mysite.com;
       index        index.html index.php index.htm;

       location / {
           root /data/nginx/html;
           if (!-e $request_filename) {
               rewrite ^/(.*) /index.html last;
           }
       }
    }


---
#apiVersion: extensions/v1beta1
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
spec:
  replicas: 1
  selector:
    matchLabels:
      app: ng-deploy-80
  template:
    metadata:
      labels:
        app: ng-deploy-80
    spec:
      containers:
      - name: ng-deploy-80
        image: nginx:1.20.0
        ports:
        - containerPort: 80
        volumeMounts:
        - name: nginx-config
          mountPath:  /etc/nginx/conf.d/mysite
        - name: myserver-nfs
          mountPath: /etc/nginx
      volumes:
      - name: nginx-config    #卷名称,随意
        configMap:
          name: nginx-config   #匹配configmap名
          items:
             - key: default    #匹配上面的data.default    
               path: mysite.conf    #将配置文件挂在/etc/nginx/conf.d/mysite
      
       - name: myserver-nfs
         nfs:
          server: 192.168.226.144
          path: /data/k8sdata/configdata     
---
apiVersion: v1
kind: Service
metadata:
  name: ng-deploy-80
spec:
  ports:
  - name: http
    port: 81
    targetPort: 80
    nodePort: 30019
    protocol: TCP
  type: NodePort
  selector:
    app: ng-deploy-80



Secret




Secret的功能类似于ConfigMap给pod提供额外的配置信息,但是Secret是一种包含少量敏感信息例如密码、令牌或密钥的对象。Secret的名称必须是合法的DNS子域名。



每个Secret的大小最多为1MiB,主要是为了避免用户创建非常大的Secret进而导致API服务器和kubelet内存耗尽,不过创建很多小的Secret也可能耗尽内存,可以使用资源配额来约束每个名字空间中Secret的个数。



在通过yaml文件创建secret时,可以设置data或stringData字段, dat和stringData字段都是可选的, data字段中所有键值都必须是base64编码的字符串,如果不希望执行这种base64字符串的转换操作,也可以选择设置stringData字段,其中可以使用任何非加密的字符串竹为其取值。



Pod可以用三种方式的任意一种来使用Secret:



  • 作为挂载到一个或多个容器上的卷中的文件(crt文件、 key文件).作为容器的环境变量.



  • 由kubelet在为Pod拉取镜像时使用(与镜像仓库的认证)



Secret类型




  • Opaque:用户定义的任意数据



  • kubernetes.io/service-account-token:ServiceAccount令牌



  • kubernetes.io/dockercfg:~/.dockercfg文件的序列化形式



  • kubernetes.io/dockerconfigjson:~l.dockerlconfig.json文件的序列化形式



  • kubernetes.io/basic-auth:用于基本身份认证的凭据



  • kubernetes.io/ssh-auth:用于SSH身份认证的凭据



  • kubernetes.io/tls:用于TLS环境,保存crt证书和key证书



  • bootstrap.kubernetes.io/token:启动引导令牌数据


案例一



创建secret

apiVersion: v1
kind: Secret
metadata:
  name: mysecret-data
  namespace: myserver
type: Opaque
data:
  user: YWRtaW4K
  password: MTIzNDU2Cg==



容器启动并读取secret


#apiVersion: extensions/v1beta1
apiVersion: apps/v1
kind: Deployment
metadata:
  name: myserver-myapp-app1-deployment
  namespace: myserver
spec:
  replicas: 1
  selector:
    matchLabels:
      app: myserver-myapp-app1
  template:
    metadata:
      labels:
        app: myserver-myapp-app1
    spec:
      containers:
      - name: myserver-myapp-app1
        image: tomcat:7.0.94-alpine
        ports:
        - containerPort: 8080
        volumeMounts:
        - mountPath: /data/myserver/auth
          name: myserver-auth-secret 
      volumes:
      - name: myserver-auth-secret
        secret:
          secretName: mysecret-data

---
apiVersion: v1
kind: Service
metadata:
  name: myserver-myapp-app1
  namespace: myserver
spec:
  ports:
  - name: http
    port: 8080
    targetPort: 8080
    nodePort: 30018
    protocol: TCP
  type: NodePort
  selector:
    app: myserver-myapp-app1



流程




创建secret,api-server将数据写到etcd中。在使用时,kubelet调api-server将数据拿到本地宿主机,在挂到容器中使用



案例二-自签名证书



生成自签名证书

openssl req -x509 -sha256 -newkey rsa:4096 -keyout ca.key -out ca.crt -days 3560 -nodes -subj '/CN=www.ca.com'
openssl req -new -newkey rsa:4096 -keyout server.key -out server.csr -nodes -subj '/CN=www.mysite.com'
openssl x509 -req -sha256 -days 3650 -in server.csr -CA ca.crt -CAkey ca.key -set_serial 01 -out server.crt
kubectl create secret tls myserver-tls-key --cert=./server.crt --key=./server.key -n myserver


kubectl get secrets myserver-tls-key -n myserver -o yaml



创建web服务


apiVersion: v1
kind: ConfigMap
metadata:
  name: nginx-config
  namespace: myserver
data:
 default: |
    server {
       listen       80;
       server_name  www.mysite.com;
       listen 443 ssl;
       ssl_certificate /etc/nginx/conf.d/certs/tls.crt;
       ssl_certificate_key /etc/nginx/conf.d/certs/tls.key;

       location / {
           root /usr/share/nginx/html; 
           index index.html;
           if ($scheme = http ){  #未加条件判断,会导致死循环
              rewrite / https://www.mysite.com permanent;
           }  

           if (!-e $request_filename) {
               rewrite ^/(.*) /index.html last;
           }
       }
    }

---
#apiVersion: extensions/v1beta1
apiVersion: apps/v1
kind: Deployment
metadata:
  name: myserver-myapp-frontend-deployment
  namespace: myserver
spec:
  replicas: 1
  selector:
    matchLabels:
      app: myserver-myapp-frontend
  template:
    metadata:
      labels:
        app: myserver-myapp-frontend
    spec:
      containers:
      - name: myserver-myapp-frontend
        image: nginx:1.20.2-alpine 
        ports:
          - containerPort: 80
        volumeMounts:
          - name: nginx-config
            mountPath:  /etc/nginx/conf.d/myserver
          - name: myserver-tls-key
            mountPath:  /etc/nginx/conf.d/certs
      volumes:
      - name: nginx-config
        configMap:
          name: nginx-config
          items:
             - key: default
               path: mysite.conf
      - name: myserver-tls-key
        secret:
          secretName: myserver-tls-key #把这个挂载在/etc/nginx/conf.d/certs


---
apiVersion: v1
kind: Service
metadata:
  name: myserver-myapp-frontend
  namespace: myserver
spec:
  type: NodePort
  ports:
  - name: http    #http
    port: 80
    targetPort: 80
    nodePort: 30018
    protocol: TCP
  - name: https#https 是30020
    port: 443
    targetPort: 443
    nodePort: 30020
    protocol: TCP
  selector:
    app: myserver-myapp-frontend 



验证




案例三-不需要登录下载私有仓库文件




通过docker认证文件创建


docker login k8s-harbor.com

kubectl create secret generic aliyun-registry-image-pull-key \
--from-file=.dockerconfigjson=/root/.docker/config.json \
--type=kubernetes.io/dockerconfigjson \
-n myserver



创建pod


#apiVersion: extensions/v1beta1
apiVersion: apps/v1
kind: Deployment
metadata:
  name: myserver-myapp-frontend-deployment
  namespace: myserver
spec:
  replicas: 1
  selector:
    matchLabels:
      app: myserver-myapp-frontend
  template:
    metadata:
      labels:
        app: myserver-myapp-frontend
    spec:
      containers:
      - name: myserver-myapp-frontend
        image: k8s-harbor.com/test/nginx:v1   
        ports:
          - containerPort: 80
      imagePullSecrets:
        - name: aliyun-registry-image-pull-key    

---
apiVersion: v1
kind: Service
metadata:
  name: myserver-myapp-frontend
  namespace: myserver
spec:
  ports:
  - name: http
    port: 80
    targetPort: 80
    nodePort: 30018
    protocol: TCP
  type: NodePort
  selector:
    app: myserver-myapp-frontend 



验证


kubuectl将请求发给api-server,apiserver将请求写到etcd中,node节点上kubelet发现事件,从api-server拿到secret,并将创建容器请求传给docker,由docker携带认证来下载镜像



版权声明:本文为weixin_47876662原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。