11、kubernetes资源对象

kubernetes资源对象

kubernetes 资源管理核心概念

Kubernetes 中的所有内容都被抽象为“资源”,如 Pod、Service、Node 等都是资源。“对象”就是“资源”的实例,是持久化的实体。比如某个具体的 Pod、某个具体的Node。Kubernetes 使用这些实体去表示整个集群的状态。对象的创建、删除、修改都是通过 “Kubernetes API”,也就是 “Api Server” 组件提供的 API 接口,这些是 RESTful 风格的 Api,与 k8s 的“万物皆对象”理念相符。命令行工具 “kubectl”,实际上也是调用 kubernetes api。K8s 中的资源类别有很多种,kubectl 可以通过配置文件来创建这些 “对象”,配置文件更像是描述对象“属性”的文件,配置文件格式可以是 “JSON” 或 “YAML”,常用 “YAML”。

学习Kubernetes ,就是学习如何对集群上的Pod、Pod控制器、Service、存储等各种资源进行操作。

kubernetes的设计理念

分层架构

API设计原则

https://www.kubernetes.org.cn/kubernetes设计理念

对于云计算系统,系统API实际上处于系统设计的统领地位,K8s集群系统每支持一项新功能,引入一项新技术,一定会新引入对应的API对象,支持对该功能的管理操作。K8s系统API的设计有以下几条原则:

  1. 所有API应该是声明式的:声明式的操作,相对于命令式操作,对于重复操作的效果是稳定的,这对于容易出现数据丢失或重复的分布式环境来说是很重要的。另外,声明式操作更容易被用户使用,可以使系统向用户隐藏实现的细节,隐藏实现的细节的同时,也就保留了系统未来持续优化的可能性。此外,声明式的API,同时隐含了所有的API对象都是名词性质的,例如Service、Volume这些API都是名词,这些名词描述了用户所期望得到的一个目标分布式对象。
  2. API对象是彼此互补而且可组合的:鼓励API对象尽量实现面向对象设计时的要求,即“高内聚,松耦合”,对业务相关的概念有一个合适的分解,提高分解出来的对象的可重用性。
  3. 高层API以操作意图为基础设计:如何能够设计好API,跟如何能用面向对象的方法设计好应用系统有相通的地方,高层设计一定是从业务出发,而不是过早的从技术实现出发。
  4. 低层API根据高层API的控制需要设计:设计实现低层API的目的,是为了被高层API使用,考虑减少冗余、提高重用性的目的,低层API的设计也要以需求为基础,要尽量抵抗受技术实现影响的诱惑。
  5. 尽量避免简单封装,不要有在外部API无法显式知道的内部隐藏的机制:简单的封装,实际没有提供新的功能,反而增加了对所封装API的依赖性。内部隐藏的机制也是非常不利于系统维护的设计方式。
  6. API操作复杂度与对象数量成正比:这一条主要是从系统性能角度考虑,要保证整个系统随着系统规模的扩大,性能不会迅速变慢到无法使用,那么最低的限定就是API的操作复杂度不能超过O(N),N是对象的数量,否则系统就不具备水平伸缩性了。
  7. API对象状态不能依赖于网络连接状态:在分布式环境下,网络连接断开是经常发生的事情,因此要保证API对象状态能应对网络的不稳定,API对象的状态就不能依赖于网络连接状态。
  8. 尽量避免让操作机制依赖于全局状态,因为在分布式系统中要保证全局状态的同步是非常困难的

kubernetes API简介

https://kubernetes.io/zh-cn/docs/concepts/overview/kubernetes-api/

Kubernetes 控制面 的核心是 API 服务器。 API 服务器负责提供 HTTP API,以供用户、集群中的不同部分和集群外部组件相互通信。

Kubernetes API 使你可以查询和操纵 Kubernetes API 中对象(例如:Pod、Namespace、ConfigMap 和 Event)的状态。

内置API: 部署好kubernetes集群后自带的API接口.

自定义资源:CRD(Custom ResourceDefinition),部署kubernetes之后通过安装其它组件等方式扩展出来的API。

可以通过以下命令查看现有的API

kubectl api-resources


通过命令查看具体api

curl --cacert /etc/kubernetes/ssl/ca.pem -H "Authorization: Bearer TOKEN" https://127.0.0.1:6443

image

对象管理

# 命令式对象管理:直接使⽤命令去操作kubernetes资源
kubectl run nginx-pod --image=nginx:1.17.1 --port=80 -n myserver
# 命令式对象配置:通过命令配置和配置⽂件去操作kubernetes资源
kubectl create/patch -f nginx-pod.yaml
# 声明式对象配置:通过apply命令和配置⽂件去操作kubernetes资源
kubectl apply -f nginx-pod.yaml

kubectl是kubernetes集群的命令行工具,通过它能够对集群本身进行管理,并能够在集群上进行容器化应用的安装部署

kubectl [command] [type] [name] [flags]
# 解释
comand:指定要对资源执行的操作,例如create、get、delete
type:指定资源类型,例如deployment、pod、service
name:指定资源的名称,名称大小写敏感
flags:指定额外的可选参数

kubernetes 内置资源对象

kubernetes中所有的内容都抽象为资源

常用资源:

资源类型 资源名称
资源对象 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

kubernetes 资源对象操作命令

https://kubernetes.io/zh-cn/docs/concepts/workloads/

k8s允许对资源进行多种操作,可以通过--help查看详细的操作命令

kubectl --help

常用命令:

image

kubernetes 资源对象详解

重要概念

  • 资源对象:kubernetes基于声明式API,和资源对象进行交互。
  • yaml文件:为了方便后期管理,通过使用yaml文件通过API来管理资源对象。
  • yaml必需字段
    1. apiVersion - 创建该对象所使用的 Kubernetes API 的版本
    2. kind - 想要创建的对象的类型
    3. metadata - 定义识别对象唯一性的数据,包括一个 name 名称 、可选的 namespace
    4. spec:定义资源对象的详细规范信息(统一的label标签、容器名称、镜像、端口映射等),它描述了对象的期望状态—— 希望对象所具有的特征。
    5. status:描述了对象的 实际状态(Actual State) ,它是由 Kubernetes 系统提供和更新的。

yaml语法规则

  • 大小写敏感

  • 使用缩进表示层级关系

  • 缩进时不允许使用Tal键,只允许使用空格

  • 缩进的空格数目不重要,只要相同层级的元素左侧对齐即可

  • ”#” 表示注释,从这个字符一直到行尾,都会被解析器忽略

注:- - - 为可选的分隔符 ,当需要在一个文件中定义多个结构的时候需要使用

示例

apiVersion: v1   # 1.9.0 之前的版本使用 apps/v1beta2,可通过命令 kubectl api-versions 查看
kind: Deployment    #指定创建资源的角色/类型
metadata:    #资源的元数据/属性
  name: nginx-deployment    #资源的名字,在同一个namespace中必须唯一
spec:
  replicas: 2    #副本数量2
  selector:      #定义标签选择器
    matchLabels:
      app: web-server
  template:      #这里Pod的定义
    metadata:
      labels:    #Pod的label
        app: web-server
    spec:        # 指定该资源的内容  
      containers:  
      - name: nginx      #容器的名字  
        image: nginx:1.12.1  #容器的镜像地址    
        ports:  
        - containerPort: 80  #容器对外的端口

对象的常用属性

name和uid

k8s 中每个对象都有 uid ,uid 是 k8s 自动为对象生成的,可以唯一标识该对象的字符串。uid 是用于给 k8s 本身管理对象的标识。

在创建对象时可以给对象指定名称。不属于同一类别的对象可以有相同的名称,而同一种类型的对象,想要赋予相同的名称,则需要用到 namespace。

NameSpace

Namespace(命名空间)是Kubernetes系统中的另一个非常重要的概念,通过将系统内部的对象“分配”到不同的Namespace中,形成逻辑上分组的不同项目、小组或用户组,便于不同的分组在共享使用整个集群的资源的同时还能被分别管理。

Kubernetes集群在启动后,会创建一个名为“default”的Namespace,通过Kubectl可以查看到。

使用Namespace来组织Kubernetes的各种对象,可以实现对用户的分组,即“多租户”管理。对不同的租户还可以进行单独的资源配额设置和管理,使得整个集群的资源配置非常灵活、方便。

label和selector

label (标签)是附加到 Kubernetes 对象(比如 Pods)上的键值对,用于区分对象。 label 旨在用于指定对用户有意义且相关的对象的标识属性,但不直接对核心系统有语义含义。 label 可以用于组织和选择对象的子集。label 可以在创建时附加到对象,随后可以随时添加和修改。可以像namespace 一样,使用 label 来获取某类对象,但 label 可以与 selector 一起配合使用,用表达式对条件加以限制,实现更精确、更灵活的资源查找。每个对象都可以定义一组键/值标签。每个键对于给定对象必须是唯一的。
  label 与 selector 配合,可以实现对象的“关联”,“Pod 控制器” 与 Pod 是相关联的 —— “Pod 控制器”依赖于 Pod,可以给 Pod 设置 label,然后给“控制器”设置对应的 selector,这就实现了对象的关联。
  每个对象都可以定义一组键/值标签。每个键对于给定对象必须是唯一的。如:

"metadata": {
  "labels": {
    "key1" : "value1",
    "key2" : "value2"
  }
}

pod

Pod 是最小的可部署的 Kubernetes 对象模型。Pod 表示集群上正在运行的进程。一个 Pod 由一个或多个容器组成,Pod 中容器共享存储和网络,运行多个容器的话,这些容器是一起被调度的。Pod的生命周期是短暂的,不会自愈,是用完就销毁的实体。一般我们是通过Controller来创建和管理pod的。

image

官方文档:https://kubernetes.io/zh-cn/docs/concepts/workloads/pods/)

示例:

#通过 explain 来查看资源文档
kubectl explain RESOURCE
#编写yaml文件
root@k8s-master-01:/opt/yaml# vim pod-test-case.yaml
apiVersion: v1  #版本号
kind: Pod     #类型:pod
metadata:     #数据源
  name: pod-test  #pod名字
  namespace: myserver  #Pod所属的命名空间,默认为"default"
spec:        #Pod中容器的详细定义
  containers: #Pod中容器列表
  - name: nginx-test  #容器名字
    image: xmtx.harbor.com/baseimages/nginx:1.9.1  #镜像
    ports:      #需要暴露的端口库号列表
    - containerPort: 80  #容器需要监听的端口号
  - name: redis-test
    image: xmtx.harbor.com/baseimages/redis:7.0
    ports:
    - containerPort: 6379
#创建
root@k8s-master-01:/opt/yaml# kubectl apply -f pod-test-case.yaml
pod/pod-test created
#查看
root@k8s-master-01:/opt/yaml# kubectl get pod -n myserver 
NAME       READY   STATUS    RESTARTS   AGE
pod-test   2/2     Running   0          3m23s

image
image

Pod的阶段

Pod 的 status 字段是一个 PodStatus 对象,其中包含一个 phase 字段。

取值 描述
Pending(悬决) Pod 已被 Kubernetes 系统接受,但有一个或者多个容器尚未创建亦未运行。此阶段包括等待 Pod 被调度的时间和通过网络下载镜像的时间。
Running(运行中) Pod 已经绑定到了某个节点,Pod 中所有的容器都已被创建。至少有一个容器仍在运行,或者正处于启动或重启状态。
Succeeded(成功) Pod 中的所有容器都已成功终止,并且不会再重启。
Failed(失败) Pod 中的所有容器都已终止,并且至少有一个容器是因为失败终止。也就是说,容器以非 0 状态退出或者被系统终止。
Unknown(未知) 因为某些原因无法取得 Pod 的状态。这种情况通常是因为与 Pod 所在主机通信失败。

Pod 中的存储

一个 Pod 可以设置一组共享的存储卷。 Pod 中的所有容器都可以访问该共享卷,从而允许这些容器共享数据。 卷还允许 Pod 中的持久数据保留下来,即使其中的容器需要重新启动。

Pod中的网络

每个 Pod 都在每个地址族中获得一个唯一的 IP 地址。 Pod 中的每个容器共享网络名字空间,包括 IP 地址和网络端口。 Pod 内的容器可以使用 localhost 互相通信。 当 Pod 中的容器与 Pod 之外的实体通信时,它们必须协调如何使用共享的网络资源(例如端口)。

对pod定义文件模板中各属性的详细说明

apiVersion: v1                    #必选,版本号,例如v1,版本号必须可以用 kubectl api-versions 查询到 .
kind: Pod                      #必选,Pod
metadata:                      #必选,元数据
  name: string                    #必选,Pod名称
  namespace: string               #必选,Pod所属的命名空间,默认为"default"
  labels:                       #自定义标签
    - name: string                 #自定义标签名字
  annotations:                           #自定义注释列表
    - name: string
spec:  #必选,Pod中容器的详细定义
  containers:                       #必选,Pod中容器列表
  - name: string                        #必选,容器名称,需符合RFC 1035规范
    image: string                       #必选,容器的镜像名称
    imagePullPolicy: [ Always|Never|IfNotPresent ]  #获取镜像的策略 Alawys表示下载镜像 IfNotPresent表示优先使用本地镜像,否则下载镜像,Nerver表示仅使用本地镜像
    command: [string]               #容器的启动命令列表,如不指定,使用打包时使用的启动命令
    args: [string]                     #容器的启动命令参数列表
    workingDir: string                     #容器的工作目录
    volumeMounts:                 #挂载到容器内部的存储卷配置
    - name: string                 #引用pod定义的共享存储卷的名称,需用volumes[]部分定义的的卷名
      mountPath: string                 #存储卷在容器内mount的绝对路径,应少于512字符
      readOnly: boolean                 #是否为只读模式
    ports:                      #需要暴露的端口库号列表
    - name: string                 #端口的名称
      containerPort: int                #容器需要监听的端口号
      hostPort: int                    #容器所在主机需要监听的端口号,默认与Container相同
      protocol: string                  #端口协议,支持TCP和UDP,默认TCP
    env:                          #容器运行前需设置的环境变量列表
    - name: string                    #环境变量名称
      value: string                   #环境变量的值
    resources:                          #资源限制和请求的设置
      limits:                       #资源限制的设置
        cpu: string                   #Cpu的限制,单位为core数,将用于docker run --cpu-shares参数
        memory: string                  #内存限制,单位可以为Mib/Gib,将用于docker run --memory参数
      requests:                         #资源请求的设置
        cpu: string                   #Cpu请求,容器启动的初始可用数量
        memory: string                    #内存请求,容器启动的初始可用数量
    livenessProbe:                    #对Pod内各容器健康检查的设置,当探测无响应几次后将自动重启该容器,检查方法有exec、httpGet和tcpSocket,对一个容器只需设置其中一种方法即可
      exec:                     #对Pod容器内检查方式设置为exec方式
        command: [string]               #exec方式需要制定的命令或脚本
      httpGet:                    #对Pod内个容器健康检查方法设置为HttpGet,需要制定Path、port
        path: string
        port: number
        host: string
        scheme: string
        HttpHeaders:
        - name: string
          value: string
      tcpSocket:            #对Pod内个容器健康检查方式设置为tcpSocket方式
         port: number
       initialDelaySeconds: 0       #容器启动完成后首次探测的时间,单位为秒
       timeoutSeconds: 0          #对容器健康检查探测等待响应的超时时间,单位秒,默认1秒
       periodSeconds: 0           #对容器监控检查的定期探测时间设置,单位秒,默认10秒一次
       successThreshold: 0
       failureThreshold: 0
       securityContext:
         privileged: false
    restartPolicy: [Always | Never | OnFailure] #Pod的重启策略,Always表示一旦不管以何种方式终止运行,kubelet都将重启,OnFailure表示只有Pod以非0退出码退出才重启,Nerver表示不再重启该Pod
    nodeSelector: obeject         #设置NodeSelector表示将该Pod调度到包含这个label的node上,以key:value的格式指定
    imagePullSecrets:         #Pull镜像时使用的secret名称,以key:secretkey格式指定
    - name: string
    hostNetwork: false            #是否使用主机网络模式,默认为false,如果设置为true,表示使用宿主机网络
    volumes:                  #在该pod上定义共享存储卷列表
    - name: string              #共享存储卷名称 (volumes类型有很多种)
      emptyDir: {}              #类型为emtyDir的存储卷,与Pod同生命周期的一个临时目录。为空值
      hostPath: string            #类型为hostPath的存储卷,表示挂载Pod所在宿主机的目录
        path: string                #Pod所在宿主机的目录,将被用于同期中mount的目录
      secret:                 #类型为secret的存储卷,挂载集群与定义的secre对象到容器内部
        scretname: string  
        items:     
        - key: string
          path: string
      configMap:                      #类型为configMap的存储卷,挂载预定义的configMap对象到容器内部
        name: string
        items:
        - key: string
          path: string

Job与cronjob

job

https://kubernetes.io/docs/concepts/workloads/controllers/job/

Job 会创建一个或者多个 Pod,并将继续重试 Pod 的执行,直到指定数量的 Pod 成功终止。 随着 Pod 成功结束,Job 跟踪记录成功完成的 Pod 个数。 当数量达到指定的成功个数阈值时,任务(即 Job)结束。 删除 Job 的操作会清除所创建的全部 Pod。 挂起 Job 的操作会删除 Job 的所有活跃 Pod,直到 Job 被再次恢复执行。

一次性任务,运行完成后Pod销毁,不再重新启动新容器。多用于数据初始化

示例:

root@k8s-master-01:/opt/yaml/job# vim job-test-case.yaml
apiVersion: batch/v1
kind: Job
metadata:
  name: job-demo
  namespace: myserver
spec:
  template:
    metadata:
      name: job-demo
    spec:
      containers:
      - name: demo
        image: xmtx.harbor.com/baseimages/busybox:1.35.0
        command: ["bin/sh","-c","for i in 9 8 7 6 5 4 3 2 1; do echo $i; done"]
        #Job的RestartPolicy仅支持Never和OnFailure两种,不支持Always
      restartPolicy: Never
#启动
root@k8s-master-01:/opt/yaml/job# kubectl apply -f job-test-case.yaml
#查看这个job completions为 1/1 表示成功运行了这个job
root@k8s-master-01:/opt/yaml/job# kubectl get job -n myserver
NAME       COMPLETIONS   DURATION   AGE
job-demo   1/1           4s         106s
#查看pod的状态
root@k8s-master-01:/opt/yaml/job# kubectl get pod -n myserver
NAME             READY   STATUS      RESTARTS      AGE
job-demo-64vq7   0/1     Completed   0             3m17s
#查看这个 pod的日志
root@k8s-master-01:/opt/yaml/job# kubectl logs job-demo-64vq7 -n myserver

image

并行执行job

可以通过 parallelism设置同时运行多个 Pod,提高 Job 的执行效率。

root@k8s-master-01:/opt/yaml/job# vim job-test-case.yaml
...
spec:
  parallelism: 6
  template:
    metadata:
      name: job-demo
...
#运行
root@k8s-master-01:/opt/yaml/job# kubectl apply -f job-test-case.yaml
#查看
root@k8s-master-01:/opt/yaml/job# kubectl get pod -n myserver
NAME             READY   STATUS      RESTARTS      AGE
job-demo-54mn4   0/1     Completed   0             8s
job-demo-bf5k5   0/1     Completed   0             8s
job-demo-bx6k7   0/1     Completed   0             8s
job-demo-g29fw   0/1     Completed   0             8s
job-demo-rm67s   0/1     Completed   0             8s
job-demo-z5pfl   0/1     Completed   0             8s
pod-test         2/2     Running     2 (79m ago)   23h
root@k8s-master-01:/opt/yaml/job# kubectl get job -n myserver
NAME       COMPLETIONS   DURATION   AGE
job-demo   6/1 of 6      5s         19s

image

cronjob

https://kubernetes.io/docs/concepts/workloads/controllers/cron-jobs/

CronJob 创建基于时隔重复调度的 job。

CronJob 用于执行周期性的动作,例如备份、报告生成等。 这些任务中的每一个都应该配置为周期性重复的(例如:每天/每周/每月一次); 你可以定义任务开始执行的时间间隔。

示例:

root@k8s-master-01:/opt/yaml/job# vim cronjob-test-case.yaml
apiVersion: batch/v1
kind: CronJob
metadata:
  name: cronjob-demo
  namespace: myserver
spec:
  schedule: "*/1 * * * *"
  jobTemplate:
    spec:
      template:
        spec:
          containers:
          - name: demo
            image: xmtx.harbor.com/baseimages/busybox:1.35.0
            command: ["echo","Hello Word"]
          restartPolicy: OnFailure
#运行
root@k8s-master-01:/opt/yaml/job# kubectl apply -f cronjob-test-case.yaml

image

副本控制器

当 Pod 被创建出来,Pod 会被调度到集群中的节点上运行,Pod 会在该节点上一直保持运行状态,直到进程终止、Pod 对象被删除、Pod 因节点资源不足而被驱逐或者节点失效为止。Pod 并不会自愈,当节点失效,或者调度 Pod 的这一操作失败了,Pod 就该被删除。如此,单单用 Pod 来部署应用,是不稳定不安全的。
  Kubernetes 使用更高级的资源对象 “控制器” 来实现对Pod的管理。控制器可以为您创建和管理多个 Pod,管理副本和上线,并在集群范围内提供自修复能力。 例如,如果一个节点失败,控制器可以在不同的节点上调度一样的替身来自动替换 Pod。
  先引入“副本”的概念——一个Pod可以被复制成多份,每一份可被称之为一个“副本”,这些“副本”除了一些描述性的信息(Pod的名字、uid等)不一样以外,其它信息都是一样的,譬如Pod内部的容器、容器数量、容器里面运行的应用等的这些信息都是一样的,这些副本提供同样的功能。Pod 的“控制器”通常包含一个名为 “replicas” 的属性。“replicas”属性则指定了特定Pod的副本的数量,当当前集群中该Pod的数量与该属性指定的值不一致时,k8s会采取一些策略去使得当前状态满足配置的要求。
  k8s的一些Pod“控制器”可以提供Pod的“滚动更新”功能,如果你的应用升级了,譬如原来应用是v1版本,现在的版本是v2,那么可以通过仅仅一条命令或一份配置文件,让k8s来自动地滚动更新应用。k8s会删除一个v1的Pod,然后新建一个v2的Pod……这样反复交替操作,直至所有v1Pod被v2Pod代替,这样就实现了不停机的应用滚动更新。k8s会保存应用的更新记录,在需要“回滚降级”时,同样可以通过仅仅一条命令或者一个配置文件实现。
  因此,虽然可以直接使用 Pod,可以直接创建Pod,但在 Kubernetes 中,更为常见的是使用控制器创建和管理 Pod。在部署应用时,“控制器” 是比简单的 Pod 更好的选择。

Replication Controller

Replication Controller: 简写 ““RC” 或 “RCS”,RC支持基于等式的标签(selector = !=)

https://kubernetes.io/zh/docs/concepts/workloads/controllers/replicationcontroller/

https://kubernetes.io/zh/docs/concepts/overview/working-with-objects/labels/

ReplicaSet

ReplicaSet:ReplicaSet 简写 “RS”,是 “Replication Controller” 的升级版。和 “ReplicationController” 一样用于确保任何给定时间指定的Pod副本数量,并提供声明式更新等功能。RC与RS唯一区别就是lable selectore支持不同,RS支持新的基于集合的标签(in notin),RC仅支持基于等式的标签。

https://kubernetes.io/zh-cn/docs/concepts/workloads/controllers/replicaset/

Deployment

一个 Deployment 为 Pod 和 ReplicaSet 提供声明式的更新能力。除了有rs的功能之外,还有很多高级功能,,比如说最重要的:滚动升级、回滚等

deployment、replicaset、pod之间的关系

ReplicaSet '明确调整 Pod 的个数',而 Deployment 是通过管理 ReplicaSet 的'数量和属性'来实现'水平扩展/收缩'以及'滚动更新'两个功能的

示例:

root@k8s-master-01:/opt/yaml/deployment# vim deployment-test.yaml
apiVersion: apps/v1
kind: Deployment
metadata: 
  name: deployment-demo
  namespace: myserver
  labels:
    app: deployment-nginx
spec:
  replicas: 2
  selector:
    matchLabels:
      app: nginx
    #matchExpressions #匹配正则,RS的支持
    #  - {key: app,operator: In,values: [nginx-01,nginx-02]}
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: xmtx.harbor.com/baseimages/nginx:1.9.1
        ports:
        - containerPort: 80
#创建
root@k8s-master-01:/opt/yaml/deployment# kubectl apply -f deployment-test.yaml
#查看
root@k8s-master-01:/opt/yaml/deployment# kubectl get pod -n myserver 
NAME                               READY   STATUS    RESTARTS   AGE
deployment-demo-64df9cfb67-2ncqp   1/1     Running   0          79s
deployment-demo-64df9cfb67-b6mmf   1/1     Running   0          79s
root@k8s-master-01:/opt/yaml/deployment# kubectl get deployment -n myserver 
NAME              READY   UP-TO-DATE   AVAILABLE   AGE
deployment-demo   2/2     2            2           85s
滚动升级
#通过 kubectl explain deployment.spec.strategy 可以查看升级策略
Recreate      -->'先删除所有'已存在的pod,'重新创建新的';
RollingUpdate -->'滚动升级','逐步替换-->灰度替换'的策略,同时滚动升级时,支持更多的'附加参数';例如设置'最大不可用'pod数量,'最小升级间隔'时间等等
  • minReadySeconds:

    • Kubernetes在等待设置的时间后才进行升级

    • 如果没有设置该值,Kubernetes会假设该容器启动起来后就提供服务了

    • 如果没有设置该值,在某些极端情况下可能会造成服务服务正常运行

  • maxSurge:

    • 升级过程中最多可以比原先设置多出的POD数量
    • 例如:maxSurage=1,replicas=5,则表示Kubernetes会先启动1一个新的Pod后才删掉一个旧的POD,整个升级过程中最多会有5+1个POD。
  • maxUnavaible:

    • 升级过程中最多有多少个POD处于无法提供服务的状态
    • maxSurge不为0时,该值也不能为0
    • 例如:maxUnavaible=1,则表示Kubernetes整个升级过程中最多会有1个POD处于无法服务的状态。
  • type=RollingUpdate

    • 表示跟新策略为滚动升级。
    • 可以设置为"Recreate"和"RollingUpdate".Recreate表示重建
    • 默认值为RollingUpdate

我们将上面的镜像版本修改为1.22,然后在spec下面添加滚动升级策略。

...
  strategy:
    type: RollingUpdate  #升级策略:滚动升级
    rollingUpdate:
      maxSurge: 1        #每次升级1个pod
      maxUnavailable: 1  #最多有1个POD处于无法服务的状态
...
#升级
root@k8s-master-01:/opt/yaml/deployment# kubectl apply -f deployment-test.yaml

使用kubectl rollout status查看升级进度

image

使用describe命令查看详细信息
image

补充:

#查看状态
kubectl rollout pause deployment <deployment>
#暂停升级
kubectl rollout pause deployment <deployment>
#继续升级
kubectl rollout resume deployment <deployment>
回滚Deployment

默认情况下,Deployment 的所有上线记录都保留在系统中,以便可以随时回滚

#检查 Deployment 修订历史
root@k8s-master-01:/opt/yaml/deployment# kubectl rollout history deployment deployment-demo -n myserver
deployment.apps/deployment-demo 
REVISION  CHANGE-CAUSE
3         <none>
4         <none>
#可以通过 --revision 参数查看具体的版本信息
root@k8s-master-01:/opt/yaml/deployment# kubectl rollout history deployment deployment-demo -n myserver --revision 3
deployment.apps/deployment-demo with revision #3
Pod Template:
  Labels:	app=nginx
	pod-template-hash=64df9cfb67
  Containers:
   nginx:
    Image:	xmtx.harbor.com/baseimages/nginx:1.9.1
    Port:	80/TCP
    Host Port:	0/TCP
    Environment:	<none>
    Mounts:	<none>
  Volumes:	<none>
#回滚到1.9.1的镜像
root@k8s-master-01:/opt/yaml/deployment# kubectl rollout undo deployment deployment-demo -n myserver --to-revision 3

image

Service

Kubernetes Service定义了这样一种抽象:逻辑上的一组 Pod,一种可以访问它们的策略 —— 通常被称为微服务。这一组 Pod 能够被 Service 访问到,通常是通过Label Selector实现的。

假如我们后端运行了3个副本,这些副本都是可以替代的,因为前端并不关心它们使用的是哪一个后端服务。尽管由于各种原因后端的Pod集合会发生变化,但是前端却不需要知道这些变化,也不需要自己用一个列表来记录这些后端的服务,Service的这种抽象就可以帮我们达到这种解耦的目的。

https://kubernetes.io/zh-cn/docs/concepts/services-networking/service/

service类型:

#通过type字段查看
kubectl explain service.spec.type
  • ClusterIP:自动分配一个仅Cluster内部可以访问的虚拟IP,用于内部服务基于service name的访问。默认类型。
  • NodePort:通过每个 Node 上的 IP 和静态端口(NodePort)暴露服务。用于kubernetes集群以外的服务主动访问运行在kubernetes集群内部的服务。
  • LoadBalancer:使用云提供商的负载均衡器,可以向外部暴露服务。用于公有云环境的服务暴露。
  • ExternalName:通过返回 CNAME 和它的值,可以将服务映射到 externalName 字段的内容。用于将k8s集群外部的服务映射至k8s集群内部访问,从而让集群内部的pod能够通过固定的service name访问集群外部的服务,有时候也用于将不同namespace之间的pod通过ExternalName进行访问。

ClusterIP

用于pod之间互访访问,访问方式:直接访问service名称

示例:

#yaml文件
root@k8s-master-01:/opt/yaml/service# vim clusterip-test-case.yaml 
apiVersion: v1
kind: Service
metadata:
  name: clusterip-demo
  namespace: myserver
spec:
  type: ClusterIP
  selector:
    app: nginx
  ports:
  - protocol: TCP
    port: 80
    targetPort: 10080
#应用
root@k8s-master-01:/opt/yaml/service# kubectl apply -f clusterip-test-case.yaml
#查看
root@k8s-master-01:/opt/yaml/service# kubectl get service -n myserver 
NAME             TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)   AGE
clusterip-demo   ClusterIP   10.100.31.166   <none>        80/TCP    8m3s
root@k8s-master-01:/opt/yaml/service# kubectl get endpoints -n myserver 
NAME             ENDPOINTS                                   AGE
clusterip-demo   100.200.44.200:10080,100.200.89.146:10080   5m9s

root@k8s-master-01:/opt/yaml/service# curl -I 100.200.44.200
HTTP/1.1 200 OK
Server: nginx/1.9.1
Date: Fri, 05 Aug 2022 09:09:59 GMT
Content-Type: text/html
Content-Length: 612
Last-Modified: Tue, 26 May 2015 15:02:09 GMT
Connection: keep-alive
ETag: "55648af1-264"
Accept-Ranges: bytes

NodePort

如果设置 type 的值为 "NodePort",Kubernetes master 将从给定的配置范围内(默认:30000-32767)分配端口,每个 Node 将从该端口(每个 Node 上的同一端口)代理到 Service。该端口将通过 Service 的 spec.ports[*].nodePort 字段被指定,如果不指定的话会自动生成一个端口。

Service 将能够通过 :spec.ports[].nodePortspec.clusterIp:spec.ports[].port 而对外可见。

示例:

#yaml文件
root@k8s-master-01:/opt/yaml/service# cat nodeport-test-case.yaml 
apiVersion: v1
kind: Service
metadata:
  name: nodeport-demo
  namespace: myserver
spec:
  type: NodePort
  selector:
    app: nginx
  ports:
  - protocol: TCP
    port: 80
    targetPort: 80
    name: nginx-http
    nodePort: 30080
  - protocol: TCP
    port: 443
    targetPort: 443
    name: nginx-https
    nodePort: 30443
#应用
root@k8s-master-01:/opt/yaml/service# kubectl apply -f nodeport-test-case.yaml
#查看
root@k8s-master-01:/opt/yaml/deployment# ipvsadm -Ln
TCP  172.31.3.110:30080 rr
  -> 100.200.44.200:80            Masq    1      0          0         
  -> 100.200.89.146:80            Masq    1      0          0
root@k8s-master-01:/opt/yaml/service# kubectl get svc -n myserver 
NAME            TYPE       CLUSTER-IP      EXTERNAL-IP   PORT(S)                      AGE
nodeport-demo   NodePort   10.100.177.49   <none>        80:30080/TCP,443:30443/TCP   89s
#测试

image

Volume-存储卷

在容器中的文件在磁盘上是临时存放的,当容器关闭时这些临时文件也会被一并清除。这给容器中运行的特殊应用程序带来一些问题。

问题一,当容器崩溃时,kubelet 将重新启动容器,容器中的文件将会丢失——因为容器会以干净的状态重建。

问题二,当在一个 Pod 中同时运行多个容器时,常常需要在这些容器之间共享文件。

Kubernetes 抽象出 Volume 对象来解决这两个问题。

常用的几种卷

  • Secret:是一种包含少量敏感信息例如密码、令牌或密钥的对象

  • configmap: 配置文件

  • emptyDir:本地临时卷

  • hostPath:本地存储卷

  • nfs等:网络存储卷

https://kubernetes.io/zh-cn/docs/concepts/storage/volumes/

emptyDir

当 Pod 创建到某个 Node 上时,emptyDir 卷会被创建,并且在 Pod 在该节点上运行期间,卷一直存在。 就像其名称表示的那样,卷最初是空的。 尽管 Pod 中的容器挂载 emptyDir 卷的路径可能相同也可能不同,这些容器都可以读写 emptyDir 卷中相同的文件。 当 Pod 因为某些原因被从节点上删除时,emptyDir 卷中的数据也会被永久删除。

emptyDir 的应用场景:

  • 缓存空间,例如基于磁盘的归并排序。
  • 为耗时较长的计算任务提供检查点,以便任务能方便地从崩溃前状态恢复执行。
  • 在 Web 服务器容器服务数据时,保存内容管理器容器获取的文件。

示例:

root@k8s-master-01:/opt/yaml/volume# vim emptyDir-test-case.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx
  namespace: myserver
spec:
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: xmtx.harbor.com/baseimages/nginx:1.19.3
        ports:
        - containerPort: 80
        volumeMounts:
        - mountPath: /cache  #挂载位置
          name: emptydir-demo  #要挂载的存储卷名
      volumes:   #存储卷
      - name: emptydir-demo   #名字
        emptyDir: {}   #类型
        
        
#进入容器
root@k8s-master-01:/opt/yaml/volume# kubectl exec -it nginx-7f4bb94fd9-rsnxv bash -n myserver
#在挂载的文件夹里创建文件
root@nginx-7f4bb94fd9-rsnxv:/cache# echo "emptyDir-test" >>  emptyDir-test.txt
root@nginx-7f4bb94fd9-rsnxv:/cache# echo "emptyDir-test" >>  emptyDir-test.txt
#在pod所在node节点查看是否存在
root@k8s-node-02:~# find / -name emptyDir-test.txt
/var/lib/kubelet/pods/df70405e-31c1-4bd6-bbdf-f70c742e98ea/volumes/kubernetes.io~empty-dir/emptydir-demo/emptyDir-test.txt
root@k8s-node-02:~# cat /var/lib/kubelet/pods/df70405e-31c1-4bd6-bbdf-f70c742e98ea/volumes/kubernetes.io~empty-dir/emptydir-demo/emptyDir-test.txt 
emptyDir-test
emptyDir-test
#我们删除pod查看文件是否还在
root@k8s-master-01:/opt/yaml/volume# kubectl delete -f emptyDir-test-case.yaml 
deployment.apps "nginx" deleted
root@k8s-node-02:~# cat /var/lib/kubelet/pods/df70405e-31c1-4bd6-bbdf-f70c742e98ea/volumes/kubernetes.io~empty-dir/emptydir-demo/emptyDir-test.txt 
cat: /var/lib/kubelet/pods/df70405e-31c1-4bd6-bbdf-f70c742e98ea/volumes/kubernetes.io~empty-dir/emptydir-demo/emptyDir-test.txt: No such file or directory
#emptyDir会随着pod的删除而删除

hostPath

emptyDir一样都是将主机节点的文件系统中的文件或目录挂载到容器中,但是pod删除的时候,卷不会被删除。

#使用以下命令查看具体信息
kubectl explain deployment.spec.template.spec.volumes.hostPath

除了必需的 path 属性之外,用户可以选择性地为 hostPath 卷指定 type

取值 行为
空字符串(默认)用于向后兼容,这意味着在安装 hostPath 卷之前不会执行任何检查。
DirectoryOrCreate 如果在给定路径上什么都不存在,那么将根据需要创建空目录,权限设置为 0755,具有与 kubelet 相同的组和属主信息。
Directory 在给定路径上必须存在的目录。
FileOrCreate 如果在给定路径上什么都不存在,那么将在那里根据需要创建空文件,权限设置为 0644,具有与 kubelet 相同的组和所有权。
File 在给定路径上必须存在的文件。
Socket 在给定路径上必须存在的 UNIX 套接字。
CharDevice 在给定路径上必须存在的字符设备。
BlockDevice 在给定路径上必须存在的块设备。

示例:

root@k8s-master-01:/opt/yaml/volume# vim hostPath-test-case.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx
  namespace: myserver
spec:
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      nodeName: 172.31.3.120  #指定node节点方便查看
      containers:
      - name: nginx
        image: xmtx.harbor.com/baseimages/nginx:1.19.3
        imagePullPolicy: IfNotPresent
        ports:
        - containerPort: 80
        volumeMounts:
        - mountPath: /cache
          name: mydir
        - mountPath: /cache/myfile/1.txt
          name: myfile
      volumes:
      - name: mydir
        hostPath:
          # 确保文件所在目录成功创建。
          path: /opt/volume/hostPath
      - name: myfile
        hostPath:
          path: /opt/volume/hostPath/myfile/1.txt
          #FileOrCreate 模式不会负责创建文件的父目录。 如果欲挂载的文件的父目录不存在,Pod 启动会失败。 
          #为了确保这种模式能够工作,可以尝试把文件和它对应的目录分开挂载
          type: FileOrCreate  #可选字段,如果在给定路径上什么都不存在,那么将在那里根据需要创建空文件。
#应用
root@k8s-master-01:/opt/yaml/volume# kubectl apply -f hostPath-test-case.yaml

进入容器查看挂载情况

image

删除pod验证本地文件是否还存在

#写入信息
root@nginx-57b99d7769-74vxd:/# echo "hostPath-test" >> /cache/myfile/1.txt
#删除pod
root@k8s-master-01:/opt/yaml/volume# kubectl delete -f hostPath-test-case.yaml 
deployment.apps "nginx" deleted
root@k8s-master-01:/opt/yaml/volume# kubectl get pods -n myserver 
No resources found in myserver namespace.
#查看 172.31.3.120 节点验证文件是否存在
root@k8s-node-01:~# ll /opt/volume/
total 12
drwxr-xr-x 3 root root 4096 Aug  5 19:56 ./
drwxr-xr-x 4 root root 4096 Aug  5 19:57 ../
drwxr-xr-x 3 root root 4096 Aug  5 20:13 hostPath/
root@k8s-node-01:~# ll /opt/volume/hostPath/
total 12
drwxr-xr-x 3 root root 4096 Aug  5 20:13 ./
drwxr-xr-x 3 root root 4096 Aug  5 19:56 ../
drwxr-xr-x 2 root root 4096 Aug  5 20:13 myfile/
root@k8s-node-01:~# ll /opt/volume/hostPath/myfile/
total 8
drwxr-xr-x 2 root root 4096 Aug  5 20:13 ./
drwxr-xr-x 3 root root 4096 Aug  5 20:13 ../
-rw-r--r-- 1 root root   14 Aug  5 20:21 1.txt
root@k8s-node-01:~# cat /opt/volume/hostPath/myfile/1.txt 
hostPath-test

nfs

nfs 卷允许将 NFS (网络文件系统) 挂载到你的 Pod 中。 且不像 emptyDir 那样会在删除 Pod 的同时也会被删除,nfs 卷的内容在删除 Pod 时会被保存,卷只是被卸载。 这意味着 NFS 卷可以预先上传好数据待pod启动后即可直接使用,并且网络存储可以在多 pod 之间共享同一份数据,即NFS 可以被多个pod同时挂载和读写。

准备NFS
#nfs配置
root@Docker-test-01:~# vim /etc/exports
/opt/data *(rw,sync,no_root_squash)
/opt/volume *(rw,sync,no_root_squash)
volumen挂载
#yaml文件
root@k8s-master-01:/opt/yaml/volume# vim NFS-test-case.yaml 

    spec:
      containers:
      - name: nginx
        image: xmtx.harbor.com/baseimages/nginx:1.19.3
        imagePullPolicy: IfNotPresent
        ports:
        - containerPort: 80
        volumeMounts:
        - mountPath: /usr/share/nginx/html/
          name: nfs1
      volumes:
      - name: nfs1
        nfs:
          server: 172.31.5.100
          path: /opt/volume
          
---       
apiVersion: v1
kind: Service
metadata:
  name: nodeport-demo
  namespace: myserver
spec:
  type: NodePort
  selector:
    app: nginx
  ports:
  - protocol: TCP
    port: 80
    targetPort: 80
    name: nginx-http
    nodePort: 30080
#应用
root@k8s-master-01:/opt/yaml/volume# kubectl apply -f NFS-test-case.yaml 
deployment.apps/nginx created
service/nodeport-demo created
验证
#创建测试首页
root@Docker-test-01:~# echo "NFS1" >> /opt/volume/index.html
#查看
root@k8s-master-01:/opt/yaml/volume# curl http://172.31.3.110:30080/index.html
NFS1

node节点查看具体挂载的nfs

image

挂载多个卷
root@k8s-master-01:/opt/yaml/volume# vim NFS-test-case.yaml
...
    spec:
      containers:
      - name: nginx
        image: xmtx.harbor.com/baseimages/nginx:1.19.3
        imagePullPolicy: IfNotPresent
        ports:
        - containerPort: 80
        volumeMounts:
        - mountPath: /usr/share/nginx/html/myapp1
          name: nfs1
        - mountPath: /usr/share/nginx/html/myapp2
          name: nfs2
      volumes:
      - name: nfs1
        nfs:
          server: 172.31.5.100
          path: /opt/volume
      - name: nfs2
        nfs:
          server: 172.31.5.100
          path: /opt/data
...
#创建测试页面
root@Docker-test-01:~# echo "NFS2" >> /opt/data/index.html
#验证
root@k8s-master-01:/opt/yaml/volume# curl http://172.31.3.110:30080/myapp1/index.html
NFS1
root@k8s-master-01:/opt/yaml/volume# curl http://172.31.3.110:30080/myapp2/index.html
NFS2

node节点上查看挂载信息

image

删除pod
root@k8s-master-01:/opt/yaml/volume# kubectl apply -f NFS-test-case.yaml 
deployment.apps/nginx unchanged
service/nodeport-demo unchanged
root@Docker-test-01:~# tree /opt/
/opt/
├── data
│   └── index.html
└── volume
    └── index.html

2 directories, 2 files

PV/PVC

概念

PV:PersistentVolume

pv是集群中已由管理员配置的一段网络存储。 集群中的资源就像一个节点是一个集群资源。 PV是诸如卷之类的卷插件,但是具有独立于使用PV的任何单个pod的生命周期。 该API对象捕获存储的实现细节,即NFS,iSCSI或云提供商特定的存储系统。

注意:PV资源属于集群全局资源,不归属于某个namespace

PVC :PersistentVolumeClaim

pvc是用户存储的请求。 它类似于pod。Pod消耗节点资源,PVC消耗存储资源。 pod可以请求特定级别的资源(CPU和内存)。 权限要求可以请求特定的大小和访问模式。

  • 用于实现pod和storage的解耦,这样我们修改storage的时候不需要修改pod。
  • 与NFS的区别,可以在PV和PVC层面实现实现对存储服务器的空间分配、存储的访问权限管理等。
  • kubernetes 从1.0版本开始支持PersistentVolume和PersistentVolumeClaim。

虽然PersistentVolumeClaims允许用户使用抽象存储资源,但是PersistentVolumes对于不同的问题,用户通常需要具有不同属性(例如性能)。群集管理员需要能够提供各种PersistentVolumes不同的方式,而不仅仅是大小和访问模式,而不会让用户了解这些卷的实现方式。对于这些需求,有StorageClass 资源。

  StorageClass为管理员提供了一种描述他们提供的存储的“类”的方法。 不同的类可能映射到服务质量级别,或备份策略,或者由群集管理员确定的任意策略。 Kubernetes本身对于什么类别代表是不言而喻的。 这个概念有时在其他存储系统中称为“配置文件”。

总结

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

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

生命周期

PV是群集中的资源。PVC是对这些资源的请求,并且还充当对资源的检查。PV和PVC之间的相互作用遵循以下生命周期:

  1. Provisioning(供应准备):这里有两种PV的提供方式:静态或者动态
    • Static:集群管理员创建多个PV。 它们携带可供集群用户使用的真实存储的详细信息。 它们存在于Kubernetes API中,可用于消费。
    • Retain:当管理员创建的静态PV都不匹配用户的PersistentVolumeClaim时,集群可能会尝试为PVC动态配置卷。 此配置基于StorageClasses:PVC必须请求一个类,并且管理员必须已创建并配置该类才能进行动态配置。 要求该类的声明有效地为自己禁用动态配置
  2. Binding(绑定) :用户创建pvc并指定需要的资源和访问模式。在找到可用pv之前,pvc会保持未绑定状态。
  3. Using(使用):用户可在pod中像volume一样使用pvc。
  4. Storage Object in Use Protection:保护使用中的存储对象(Storage Object in Use Protection) 这一功能特性的目的是确保仍被 Pod 使用的 PersistentVolumeClaim(PVC) 对象及其所绑定的 PersistentVolume(PV)对象在系统中不会被删除
  5. Releasing(释放):用户删除pvc来回收存储资源,pv将变成“released”状态。由于还保留着之前的数据,这些数据需要根据不同的策略来处理,否则这些存储资源无法被其他pvc使用。
  6. Recycling(回收):pv可以设置三种回收策略:保留(Retain),回收(Recycle)和删除(Delete)。
    • Retain:回收策略 Retain 使得用户可以手动回收资源。当 PersistentVolumeClaim 对象被删除时,PersistentVolume 卷仍然存在,对应的数据卷被视为"已释放(released)"。
    • Delete:对于支持 Delete 回收策略的卷插件,删除动作会将 PersistentVolume 对象从 Kubernetes 中移除,同时也会从外部基础设施(如 AWS EBS、GCE PD、Azure Disk 或 Cinder 卷)中移除所关联的存储资产。 Retain卷会继承其 StorageClass 中设置的回收策略, 该策略默认为 Delete
    • Recycle: 如果下层的卷插件支持,回收策略 Recycle 会在卷上执行一些基本的擦除 (rm -rf /thevolume/*)操作,之后允许该卷用于新的 PVC 申领。注意:回收策略 Recycle 已被废弃。取而代之的建议方案是使用动态制备。
卷模式

针对 PV 持久卷,Kubernetes 支持两种卷模式(volumeModes):Filesystem(文件系统)Block(块)volumeMode 是一个可选的 API 参数。 如果该参数被省略,默认的卷模式是 Filesystem

kubectl explain PersistentVolume.spec.volumeMode
访问模式

PersistentVolume 卷可以用资源提供者所支持的任何方式挂载到宿主系统上。每个 PV 卷的访问模式都会设置为对应卷所支持的模式值。 例如,NFS 可以支持多个读写客户,但是某个特定的 NFS PV 卷可能在服务器上以只读的方式导出。 每个 PV 卷都会获得自身的访问模式集合,描述的是特定 PV 卷的能力。

访问模式 作用
ReadWriteOnce 只能被单个节点以读写权限挂载,允许运行在同一节点上的多个 Pod 访问卷。
ReadOnlyMany 以可以被多个节点挂载但是权限是只读的
ReadWriteMany 可以被多个节点是读写方式挂载使用
ReadWriteOncePod 卷可以被单个 Pod 以读写方式挂载。 如果你想确保整个集群中只有一个 Pod 可以读取或写入该 PVC, 请使用 ReadWriteOncePod 访问模式。这只支持 CSI 卷以及需要 Kubernetes 1.22 以上版本。

重要提醒!每个卷同一时刻只能以一种访问模式挂载,即使该卷能够支持多种访问模式。

在命令行接口(CLI)中,访问模式也使用以下缩写形式:

  • RWO - ReadWriteOnce
  • ROX - ReadOnlyMany
  • RWX - ReadWriteMany
  • RWOP - ReadWriteOncePod

官方提供的基于各后端存储创建的PV支持的访问模式

https://kubernetes.io/zh-cn/docs/concepts/storage/persistent-volumes/#types-of-persistent-volumes

卷插件 ReadWriteOnce ReadOnlyMany ReadWriteMany ReadWriteOncePod
AWSElasticBlockStore - - -
AzureFile -
AzureDisk - - -
CephFS -
Cinder - 如果多次挂接卷可用 -
CSI 取决于驱动 取决于驱动 取决于驱动 取决于驱动
FC - -
FlexVolume 取决于驱动 -
Flocker - - -
GCEPersistentDisk - -
Glusterfs -
HostPath - - -
iSCSI - -
Quobyte -
NFS -
RBD - -
VsphereVolume - - (Pod 运行于同一节点上时可行) -
PortworxVolume - -
StorageOS - - -
挂载选项

mountOptions附加的挂载选项列表,实现更精细的权限控制

root@k8s-master-01:/opt/yaml/volume# kubectl explain PersistentVolume.spec.mountOptions
Volume-静态存储卷示例
创建pv
#nfs配置添加
/opt/pv *(rw,sync,no_root_squash)
#创建pv
root@k8s-master-01:/opt/yaml/volume# vim PersistentVolume-test-case.yaml
apiVersion: v1
kind: PersistentVolume
metadata:
  name: pv-demo
  labels:
    pv: nfs01
spec:
  accessModes: #访问模式
    - ReadWriteOnce
  capacity:  #大小
    storage: 10Gi
  nfs:
    server: 172.31.5.100
    path: /opt/pv
#检查
root@k8s-master-01:/opt/yaml/volume# kubectl get pv 
NAME      CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS      CLAIM   STORAGECLASS   REASON   AGE
pv-demo   10Gi       RWO            Retain           Available                                   7m35s
pvc创建

pvc属于namespace下的资源,其他pod想要使用必须与pv处于一个namespace下。

pvc使用与pv相同的访问模式约定

#yaml文件
root@k8s-master-01:/opt/yaml/volume# vim PersistentVolumeClaim-test-case.yaml
#pvc
apiVersion: v1
kind: PersistentVolumeClaim  #类型
metadata:
  name: pvc-demo
  namespace: myserver   #命名空间
  labels:
    pvc: nfs01
spec:
  selector:       #要使用的pv
    matchLabels:
      pv: nfs01
  accessModes:   #权限
  - ReadWriteOnce
  resources:     #资源限制
    requests:
      storage: 5Gi
---#Deployment
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx
  namespace: myserver
spec:
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: xmtx.harbor.com/baseimages/nginx:1.19.3
        imagePullPolicy: IfNotPresent
        ports:
        - containerPort: 80
        volumeMounts:
        - name: pvc-demo-nginx
          mountPath: /usr/share/nginx/html/pv
      volumes:   #挂载
      - name: pvc-demo-nginx
        persistentVolumeClaim:
          claimName: pvc-demo
---#Service
apiVersion: v1
kind: Service
metadata:
  name: nodeport-demo
  namespace: myserver
spec:
  type: NodePort
  selector:
    app: nginx
  ports:
  - protocol: TCP
    port: 80
    targetPort: 80
    name: nginx-http
    nodePort: 30080
#创建
root@k8s-master-01:/opt/yaml/volume# kubectl apply -f PersistentVolumeClaim-test-case.yaml 
persistentvolumeclaim/pvc-demo created
deployment.apps/nginx unchanged
service/nodeport-demo unchanged
测试

创建测试页面

root@Docker-test-01:~# echo "PersistentVolume&&PersistentVolumeClaim-demo" >> /opt/pv/index.html
#访问测试
root@k8s-master-01:/opt/yaml/volume# curl 172.31.3.110:30080/pv/index.html
PersistentVolume&&PersistentVolumeClaim-demo

image

删除PV

root@k8s-master-01:/opt/yaml/volume# kubectl delete -f PersistentVolumeClaim-test-case.yaml
root@k8s-master-01:/opt/yaml/volume# kubectl delete -f PersistentVolume-test-case.yaml 
persistentvolume "pv-demo" deleted
#查看nfs文件是否还在
root@Docker-test-01:~# ll /opt/pv/
total 12
drwxr-xr-x 2 root root 4096 Aug  5 16:10 ./
drwxr-xr-x 5 root root 4096 Aug  5 15:33 ../
-rw-r--r-- 1 root root   45 Aug  5 16:10 index.html

Volume-动态存储卷示例

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

StorageClass提供了一种描述存储类(class)的方法,不同的class可能会映射到不同的服务质量等级和备份策略或其他策略等。

每个 StorageClass 都包含 provisioner、parameters 和 reclaimPolicy 字段, 这些字段会在StorageClass需要动态分配 PersistentVolume 时会使用到。

NFS Client Provisioner

NFS Client Provisioner是一个automatic provisioner,使用NFS作为存储,自动创建PV和对应的PVC,本身不提供NFS存储,需要外部先有一套NFS存储服务。

PV以 namespace−namespace−{pvcName}-${pvName}的命名格式提供(在NFS服务器上)

PV回收的时候以 archieved-namespace−namespace−{pvcName}-${pvName} 的命名格式(在NFS服务器上)

官网文档:https://kubernetes.io/zh-cn/docs/concepts/storage/storage-classes/

Github项目地址:https://github.com/kubernetes-sigs/nfs-subdir-external-provisioner

创建用户和授权
root@k8s-master-01:/opt/yaml/NFSProvisioner# vim nfs-rbac.yaml

apiVersion: v1
kind: Namespace
metadata:
  name: nfs
---
apiVersion: v1
kind: ServiceAccount
metadata:
  name: nfs-client-provisioner
  namespace: nfs
---
rules:
- apiGroups: [""]
  resources: ["persistentvolumes"]
  verbs: ["get","list","watch","create","delete"]
- apiGroups: [""]
- apiGroups: ["storage.k8s.io"]
--- #角色绑定
apiVersion: v1
kind: Namespace
metadata:
  name: nfs
---
apiVersion: v1
kind: ServiceAccount
metadata:
  name: nfs-client-provisioner
  namespace: nfs
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
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"]

--- #角色绑定
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: run-nfs-client-provisioner
subjects:
- name: nfs-client-provisioner
  kidn: ServiceAccount
  namespace: nfs
roleRef:
- name: nfs-client-provisioner-runner
  kind: ClusterRole
  apiGroup: rbac.authorization.k8s.io
---
kind: Role
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: leader-locking-nfs-client-provisioner
  namespace: nfs
rules:
- apiGroups: [""]
  resources: ["endpoints"]
  verbs: ["get", "list", "watch", "create", "update", "patch"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: leader-locking-nfs-client-provisioner
  namespace: nfs
subjects:
- kind: ServiceAccount
  name: nfs-client-provisioner
  namespace: nfs
roleRef:
  kind: Role
  name: leader-locking-nfs-client-provisioner
  apiGroup: rbac.authorization.k8s.io
root@k8s-master-01:/opt/yaml/NFSProvisioner# kubectl apply -f nfs-rbac.yaml 
namespace/nfs unchanged
serviceaccount/nfs-client-provisioner unchanged
clusterrole.rbac.authorization.k8s.io/nfs-client-provisioner-runner unchanged
clusterrolebinding.rbac.authorization.k8s.io/run-nfs-client-provisioner created
role.rbac.authorization.k8s.io/leader-locking-nfs-client-provisioner created
rolebinding.rbac.authorization.k8s.io/leader-locking-nfs-client-provisioner created
创建存储类
root@k8s-master-01:/opt/yaml/NFSProvisioner# cat nfs-storage.yaml 
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:
  #- vers=4.1 #containerd有部分参数异常
  #- noresvport #告知NFS客户端在重新建立网络连接时,使用新的传输控制协议源端口
  - noatime #访问文件时不更新文件inode中的时间戳,高并发环境可提高性能
parameters:
  #mountOptions: "vers=4.1,noresvport,noatime"
  archiveOnDelete: "true"  #删除pod时保留pod数据,默认为false时为不保留数据
  
root@k8s-master-01:/opt/yaml/NFSProvisioner# kubectl apply -f nfs-storage.yaml
storageclass.storage.k8s.io/managed-nfs-storage created
部署 NFS-Subdir-External-Provisioner
root@k8s-master-01:/opt/yaml/NFSProvisioner# cat nfs-provisioner.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nfs-client-provisioner
  labels:
    app: nfs-client-provisioner
  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: xmtx.harbor.com/baseimages/nfs-subdir-external-provisioner:v4.0.2
          volumeMounts:
            - name: nfs-client-root
              mountPath: /persistentvolumes
          env:
            - name: PROVISIONER_NAME
              value: k8s-sigs.io/nfs-subdir-external-provisioner
            - name: NFS_SERVER
              value: 172.31.7.109
            - name: NFS_PATH
              value: /data/volumes
      volumes:
        - name: nfs-client-root
          nfs:
            server: 172.31.7.109
            path: /data/volumes
测试
root@k8s-master-01:/opt/yaml/NFSProvisioner# cat nfs-nginx.yaml 
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: nfs-pvc
  namespace: myserver
  labels:
    pvc: nfs-pvc01
spec:
  storageClassName: managed-nfs-storage #调用的storageclass 名称
  accessModes:
    - ReadWriteMany #访问权限
  resources:
    requests:
      storage: 500Mi #空间大小
---
apiVersion: apps/v1
kind: Deployment
metadata: 
  name: nginx
  namespace: myserver
spec:
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: xmtx.harbor.com/baseimages/nginx:1.19.3
        imagePullPolicy: IfNotPresent
        ports:
        - containerPort: 80
        volumeMounts:
        - name: nfs-pvc-nginx
          mountPath: /usr/share/nginx/html/nfs-pvc
      volumes:
      - name: nfs-pvc-nginx
        persistentVolumeClaim:
          claimName: nfs-pvc
---
apiVersion: v1
kind: Service
metadata:
  name: nodeport-demo
  namespace: myserver
spec:
  type: NodePort
  selector:
    app: nginx
  ports:
  - protocol: TCP
    port: 80
    targetPort: 80
    name: nginx-http
    nodePort: 30080
root@k8s-master-01:/opt/yaml/NFSProvisioner# kubectl apply -f nfs-nginx.yaml 
persistentvolumeclaim/nfs-pvc created
deployment.apps/nginx created
service/nodeport-demo created
#查看pvc
root@k8s-master-01:/opt/yaml/NFSProvisioner# kubectl get pvc -n myserver 
NAME      STATUS   VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS          AGE
nfs-pvc   Bound    pvc-5019096e-253d-4db7-901c-438ffe5b8981   500Mi      RWX            managed-nfs-storage   2m47s
#查看pv,pv已经与pvc绑定
root@k8s-master-01:/opt/yaml/NFSProvisioner# kubectl get pv
NAME                                       CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS   CLAIM              STORAGECLASS          REASON   AGE
pvc-5019096e-253d-4db7-901c-438ffe5b8981   500Mi      RWX            Retain           Bound    myserver/nfs-pvc   managed-nfs-storage            3m56s
#检查nfs服务器目录 pvc绑定存储类后,会在NFS server共享目录下自动创建一个存储目录
root@Docker-test-01:/opt/data# ll
total 12
drwxr-xr-x 3 root root 4096 Aug  5 17:59 ./
drwxr-xr-x 5 root root 4096 Aug  5 15:33 ../
drwxrwxrwx 2 root root 4096 Aug  5 17:57 myserver-nfs-pvc-pvc-5019096e-253d-4db7-901c-438ffe5b8981/
#创建测试页面
root@Docker-test-01:/opt/data# echo "nfs-subdir-external-provisioner" >> myserver-nfs-pvc-pvc-5019096e-253d-4db7-901c-438ffe5b8981/index.html
#访问测试
root@k8s-master-01:/opt/yaml/NFSProvisioner# curl 172.31.3.110:30080/nfs-pvc/index.html
nfs-subdir-external-provisioner

容器中查看

image

configmap

简介

ConfigMap 是一个 API 对象, 让你可以存储其他对象所需要使用的配置。 和其他 Kubernetes 对象都有一个 spec 不同的是,ConfigMap 使用 databinaryData 字段。这些字段能够接收键-值对作为其取值。databinaryData 字段都是可选的。data 字段设计用来保存 UTF-8 字符串,而 binaryData 则被设计用来保存二进制数据作为 base64 编码的字串。

ConfigMap 的名字必须是一个合法的 DNS 子域名。

使用场景:

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

注意事项:

  • Configmap需要在pod使用它之前创建。
  • pod只能使用位于同一个namespace的Configmap,及Configmap不能夸namespace使用。
  • 通常用于非安全加密的配置场景。
  • Configmap通常是小于1MB的配置。
ConfigMap创建
通过命令行创建

通过文件创建configmap

root@k8s-master-01:/opt/yaml/configmap# echo "configmap-key1" > test1.txt
root@k8s-master-01:/opt/yaml/configmap# echo "configmap-key2" > test2.txt
root@k8s-master-01:/opt/yaml/configmap# kubectl create configmap myconfigmap1 -n myserver  --from-file=key1=test1.txt --from-file=key2=test2.txt 

image

通过文件夹创建configmap

root@k8s-master-01:/opt/yaml/configmap# echo "configmap-dir-key1" > test/key1.txt
root@k8s-master-01:/opt/yaml/configmap# echo "configmap-dir-key2" > test/key2.txt
root@k8s-master-01:/opt/yaml/configmap# kubectl create configmap myconfigmap2 --from-file=./test/ -n myserver

image

通过yaml文件创建
root@k8s-master-01:/opt/yaml/configmap# cat configmap-test-case01.yaml 
apiVersion: v1
kind: ConfigMap
metadata:
  name: configmap-demo01
  namespace: myserver
data:
  key1: hello
  key2: word
root@k8s-master-01:/opt/yaml/configmap# kubectl get configmaps -n myserver 
NAME               DATA   AGE
configmap-demo01   2      18s
ConfigMap使用
#编写yaml文件
root@k8s-master-01:/opt/yaml/configmap# cat configmap-test-nginx.yaml 
apiVersion: v1
kind: ConfigMap
metadata:
  name: configmap-nginx
  namespace: myserver
data:
  username: "user1"
  password: "12345678"
  default: |   #作为配置文件
    server {
       listen       80;
       server_name  www.configmap.com;
       index        index.html index.php index.htm;

       location / {
           root /data/nginx/html;
           if (!-e $request_filename) {
               rewrite ^/(.*) /index.html last;
           }
       }
    }
---
apiVersion: apps/v1
kind: Deployment
metadata: 
  name: nginx
  namespace: myserver
spec:
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: xmtx.harbor.com/baseimages/nginx:1.19.3
        imagePullPolicy: IfNotPresent
        ports:
        - containerPort: 80
        volumeMounts:   #使用configmap作为nginx配置文件
        - name: nginx-config
          mountPath: /etc/nginx/conf.d
        env:   #使用configmap作为环境变量
        - name: MY_USERNAME
          valueFrom:
            configMapKeyRef:
              name: configmap-nginx
              key: username
        - name: MY_PASSWORD
          valueFrom:
            configMapKeyRef:
              name: configmap-nginx
              key: password
      volumes:
      - name: nginx-config
        configMap:
          name: configmap-nginx
          items:
          - key: default
            path: mysite.conf
---
apiVersion: v1
kind: Service
metadata:
  name: nodeport-demo
  namespace: myserver
spec:
  type: NodePort
  selector:
    app: nginx
  ports:
  - protocol: TCP
    port: 80
    targetPort: 80
    name: nginx-http
    nodePort: 30080
#运行
root@k8s-master-01:/opt/yaml/configmap# kubectl apply -f configmap-test-nginx.yaml 
configmap/configmap-nginx unchanged
deployment.apps/nginx configured
service/nodeport-demo unchanged
root@k8s-master-01:/opt/yaml/configmap# kubectl get pod -n myserver 
NAME                   READY   STATUS    RESTARTS   AGE
nginx-c4cd6fdc-k9kj7   1/1     Running   0          3s
#测试
root@k8s-master-01:/opt/yaml/configmap# kubectl exec -it nginx-c4cd6fdc-k9kj7 -n myserver bash
#查看变量
root@nginx-c4cd6fdc-k9kj7:/# echo $MY_USERNAME
user1
root@nginx-c4cd6fdc-k9kj7:/# echo $MY_PASSWORD
12345678
#查看配置文件
root@nginx-c4cd6fdc-k9kj7:/# cat /etc/nginx/conf.d/mysite.conf 
server {
   listen       80;
   server_name  www.configmap.com;
   index        index.html index.php index.htm;

   location / {
       root /data/nginx/html;
       if (!-e $request_filename) {
           rewrite ^/(.*) /index.html last;
       }
   }
}
#创建测试页面 
root@nginx-c4cd6fdc-k9kj7:/# mkdir /data/nginx/html -p
root@nginx-c4cd6fdc-k9kj7:/# echo "configmap-nginx" >> /data/nginx/html/index.html

image

Secret

Secret 是一种包含少量敏感信息例如密码、令牌或密钥的对象。 这样的信息可能会被放在 Pod 规约中或者镜像中。 使用 Secret 意味着你不需要在应用程序代码中包含机密数据。

由于创建 Secret 可以独立于使用它们的 Pod, 因此在创建、查看和编辑 Pod 的工作流程中暴露 Secret(及其数据)的风险较小。 Kubernetes 和在集群中运行的应用程序也可以对 Secret 采取额外的预防措施, 例如避免将机密数据写入非易失性存储。

Secret 类似于 ConfigMap 但专门用于保存机密数据。

Secret 的名称必须是合法的 DNS 子域名。

每个Secret的大小最多为1MiB,主要是为了避免用户创建非常大的Secret进而导致API服务器和kubelet内存耗尽,不过创建很多小的Secret也可能耗尽内存,可以使用资源配额来约束每个名字空间中Secret的个数。在通过yaml文件创建secret时,可以设置data或stringData字段,data和stringData字段都是可选的,data字段中所有键值都必须是base64编码的字符串,如果不希望执行这种 base64字符串的转换操作,也可以选择设置stringData字段,其中可以使用任何非加密的字符串作为其取值。

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

  • 作为挂载到一个或多个容器上的卷 中的文件(crt文件、key文件)。
  • 作为容器的环境变量。
  • 由 kubelet 在为 Pod 拉取镜像时使用(与镜像仓库的认证)。

Kubernetes默认支持多种不同类型的secret,用于一不同的使用场景,不同类型的secret的配置参数也不一样。

Secret类型 使用场景
Opaque 用户定义的任意数据
kubernetes.io/service-account-token ServiceAccount 令牌
kubernetes.io/dockercfg ~/.dockercfg 文件的序列化形式
kubernetes.io/dockerconfigjson ~/.docker/config.json 文件的序列化形式
kubernetes.io/basic-auth 用于基本身份认证的凭据
kubernetes.io/ssh-auth 用于 SSH 身份认证的凭据
kubernetes.io/tls 用于 TLS 环境,保存crt证书和key证书
bootstrap.kubernetes.io/token 启动引导令牌数据
Opaque
data类型数据

需要事先使用Base64加密字符串

#加密
root@k8s-master-01:/opt/yaml/secret# echo xmtx | base64 
eG10eAo=
root@k8s-master-01:/opt/yaml/secret# echo 123123123 | base64 
MTIzMTIzMTIzCg==
#编写yaml文件
root@k8s-master-01:/opt/yaml/secret# cat opaque-data.yaml 
apiVersion: v1
kind: Secret
metadata:
  name: secret-data
  namespace: myserver
type: Opaque
data:
  user: eG10eAo=
  password: MTIzMTIzMTIzCg==
#查看
root@k8s-master-01:/opt/yaml/secret# kubectl get secrets -n myserver 
NAME          TYPE     DATA   AGE
secret-data   Opaque   2      27s
root@k8s-master-01:/opt/yaml/secret# kubectl describe secrets secret-data -n myserver 
Name:         secret-data
Namespace:    myserver
Labels:       <none>
Annotations:  <none>

Type:  Opaque

Data
====
password:  10 bytes
user:      5 bytes
root@k8s-master-01:/opt/yaml/secret# kubectl get secrets secret-data -n myserver -o yaml

image

stringData类型数据

不用事先加密-上传到k8s会加密

root@k8s-master-01:/opt/yaml/secret# vim opaque-stringdata.yaml
apiVersion: v1
kind: Secret
metadata:
  name: secret-stringdata
  namespace: myserver
type: Opaque
stringData:
  user: 'xmtx'
  password: '123123'
#查看
root@k8s-master-01:/opt/yaml/secret# kubectl apply -f opaque-stringdata.yaml
root@k8s-master-01:/opt/yaml/secret# kubectl get secrets -n myserver 
NAME                TYPE     DATA   AGE
secret-stringdata   Opaque   2      25s
root@k8s-master-01:/opt/yaml/secret# kubectl get secrets secret-stringdata -n myserver -o yaml

image

以变量形式挂载到pod容器中
#yaml
root@k8s-master-01:/opt/yaml/secret# cat opaque-data.yaml 
apiVersion: v1
kind: Secret
metadata:
  name: secret-data
  namespace: myserver
type: Opaque
data:
  user: eG10eAo=
  password: MTIzMTIzMTIzCg==
---
apiVersion: v1
kind: Pod
metadata:
  name: secret-pod
  namespace: myserver
spec:
  containers:
  - name: nginx
    image: xmtx.harbor.com/baseimages/nginx:1.9.1
    env:
    - name: SECRET_USER
      valueFrom:
        secretKeyRef:
          name: secret-data
          key: user
    - name: SECRET_PASSWD
      valueFrom:
        secretKeyRef:
          name: secret-data
          key: password
#查看
root@k8s-master-01:/opt/yaml/secret# kubectl get pod -n myserver 
NAME         READY   STATUS    RESTARTS   AGE
secret-pod   1/1     Running   0          12s
root@k8s-master-01:/opt/yaml/secret# kubectl exec -it secret-pod -n myserver bash
kubectl exec [POD] [COMMAND] is DEPRECATED and will be removed in a future version. Use kubectl exec [POD] -- [COMMAND] instead.
root@secret-pod:/# echo $SECRET_PASSWD
123123123
root@secret-pod:/# echo $SECRET_USER  
xmtx
TLS

Kubernetes 提供一种内置的 kubernetes.io/tls Secret 类型,用来存放证书 及其相关密钥(通常用在 TLS 场合)。 此类数据主要提供给 Ingress 资源,用以终结 TLS 链接,不过也可以用于其他 资源或者负载。当使用此类型的 Secret 时,Secret 配置中的 data (或 stringData)字段必须包含 tls.keytls.crt 主键,尽管 API 服务器 实际上并不会对每个键的取值作进一步的合法性检查。

基于Secret实现nginx的tls认证

自签名证书
root@k8s-master-01:/opt/yaml/secret# mkdir certs
root@k8s-master-01:/opt/yaml/secret# cd certs/
#创建ca公钥和私钥
root@k8s-master-01:/opt/yaml/secret/certs# openssl req -x509 -sha256 -newkey rsa:4096 -keyout ca.key -out ca.crt -days 3560 -nodes -subj '/CN=www.secret.com'
#创建客户端公钥和私钥
root@k8s-master-01:/opt/yaml/secret/certs# openssl req -new -newkey rsa:4096 -keyout server.key -out server.csr -nodes -subj '/CN=www.secret.com'
#ca签发客户端私钥生成证书
root@k8s-master-01:/opt/yaml/secret/certs# openssl x509 -req -sha256 -days 3650 -in server.csr -CA ca.crt -CAkey ca.key -set_serial 01 -out server.crt
#创建secret
root@k8s-master-01:/opt/yaml/secret/certs# kubectl create secret tls nginx-tls-key --cert=./server.crt --key=./server.key -n myserver
secret/nginx-tls-key created
创建web服务nginx并使用证书
root@k8s-master-01:/opt/yaml/secret# cat TLS-nginx-test.yaml 
apiVersion: v1
kind: ConfigMap
metadata:
  name: nginx-config
  namespace: myserver
data:
 default: |
    server {
       listen       80;
       server_name  www.secret.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.secret.com permanent;
           }  

           if (!-e $request_filename) {
               rewrite ^/(.*) /index.html last;
           }
       }
    }
---
apiVersion: apps/v1
kind: Deployment
metadata: 
  name: nginx
  namespace: myserver
spec:
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: xmtx.harbor.com/baseimages/nginx:1.19.3
        imagePullPolicy: IfNotPresent
        ports:
        - containerPort: 80
        volumeMounts:
          - name: nginx-config
            mountPath: /etc/nginx/conf.d/
          - name: nginx-tls-key
            mountPath:  /etc/nginx/conf.d/certs
      volumes:
      - name: nginx-config
        configMap:
          name: nginx-config
          items:
             - key: default
               path: secret.conf
      - name: nginx-tls-key
        secret:
          secretName: nginx-tls-key 
---
apiVersion: v1
kind: Service
metadata:
  name: nodeport-demo
  namespace: myserver
spec:
  type: NodePort
  selector:
    app: nginx
  ports:
  - protocol: TCP
    port: 80
    targetPort: 80
    name: nginx-http
    nodePort: 30080
  - name: nginx-https
    port: 443
    targetPort: 443
    nodePort: 30081
    protocol: TCP

image

dockerconfigjson

存储docker registry的认证信息,在下载镜像的时候使用,这样每一个node节点就可以不登录也可以下载私有级别的镜像了。

创建secret
#方式一 通过命令创建
kubectl create secret docker-registry keyName \
--docker-server=registry.myserver.com \
--docker-username=USER\
--docker-password=PASSWORD
#方式二 通过认证文件创建,
#登录harbor,凭据文件会在/root/.docker/config.json
root@k8s-deploy-01:~# docker login --username=zx6694773 registry.cn-hangzhou.aliyuncs.com
Password: 
WARNING! Your password will be stored unencrypted in /root/.docker/config.json.
Configure a credential helper to remove this warning. See
https://docs.docker.com/engine/reference/commandline/login/#credentials-store

Login Succeeded
#创建secret
root@k8s-deploy-01:~# kubectl create secret generic aliyun-image-pull-key \
>   --from-file=.dockerconfigjson=/root/.docker/config.json \
>   --type=kubernetes.io/dockerconfigjson \
>   -n myserver
secret/aliyun-image-pull-key created
#查看
root@k8s-master-01:~# kubectl get secrets -n myserver 
NAME                    TYPE                             DATA   AGE
aliyun-image-pull-key   kubernetes.io/dockerconfigjson   1      4m46s
#上传测试镜像
root@k8s-deploy-01:~# docker tag nginx:1.9.1 registry.cn-hangzhou.aliyuncs.com/xmtx-test/nginx:1.9.1
root@k8s-deploy-01:~# docker push registry.cn-hangzhou.aliyuncs.com/xmtx-test/nginx:1.9.1

使用dockerconfigjson

#yaml
root@k8s-master-01:/opt/yaml/secret# cat dockerconfigjson-test.yaml 
apiVersion: apps/v1
kind: Deployment
metadata: 
  name: nginx
  namespace: myserver
spec:
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: registry.cn-hangzhou.aliyuncs.com/xmtx-test/nginx:1.9.1
        imagePullPolicy: Always  #策略:总是下载镜像
        ports:
        - containerPort: 80
      imagePullSecrets:   #使用刚创建的aliyun
        - name: aliyun-image-pull-key
#应用
root@k8s-master-01:/opt/yaml/secret# kubectl apply -f dockerconfigjson-test.yaml

image

posted @ 2022-08-06 22:27  xmtx97  阅读(437)  评论(0编辑  收藏  举报