k8s集群升级、yaml详解、etcd、常用维护命令及资源对象

1. k8s集群升级

k8s二进制文件下载地址:https://github.com/kubernetes/kubernetes/releases

1.1 查看集群版本信息

root@k8s-ansible-client:~# kubectl get node -A
NAME             STATUS                     ROLES    AGE   VERSION
192.168.20.147   Ready                      node     13d   v1.21.0
192.168.20.189   Ready,SchedulingDisabled   master   13d   v1.21.0
192.168.20.201   Ready,SchedulingDisabled   master   13d   v1.21.0
192.168.20.236   Ready                      node     13d   v1.21.0
192.168.20.249   Ready,SchedulingDisabled   master   13d   v1.21.0
192.168.20.253   Ready                      node     13d   v1.21.0

1.2 二进制包下载

下载页面

root@k8s-ansible-client:/usr/local/src# wget https://dl.k8s.io/v1.22.2/kubernetes.tar.gz
root@k8s-ansible-client:/usr/local/src# wget https://dl.k8s.io/v1.22.2/kubernetes-client-linux-amd64.tar.gz
root@k8s-ansible-client:/usr/local/src# wget https://dl.k8s.io/v1.22.2/kubernetes-server-linux-amd64.tar.gz
root@k8s-ansible-client:/usr/local/src# https://dl.k8s.io/v1.22.2/kubernetes-node-linux-amd64.tar.gz
root@k8s-ansible-client:/usr/local/src# ll -lrt
total 488340
drwxr-xr-x 10 root root      4096 Aug 24 16:42 ../
-rw-r--r--  1 root root 342548639 Sep 16 07:37 kubernetes-server-linux-amd64.tar.gz
-rw-r--r--  1 root root 126097180 Sep 16 07:37 kubernetes-node-linux-amd64.tar.gz
-rw-r--r--  1 root root  30821781 Sep 16 07:37 kubernetes-client-linux-amd64.tar.gz
-rw-r--r--  1 root root    566795 Sep 16 07:37 kubernetes.tar.gz
drwxr-xr-x  2 root root      4096 Oct  8 22:28 ./
root@k8s-ansible-client:/usr/local/src# 

1.3 升级版本

# 解压二进制包
root@k8s-ansible-client:/usr/local/src# tar xf kubernetes.tar.gz 
root@k8s-ansible-client:/usr/local/src# tar xf kubernetes-server-linux-amd64.tar.gz
root@k8s-ansible-client:/usr/local/src# tar xf kubernetes-node-linux-amd64.tar.gz
root@k8s-ansible-client:/usr/local/src# tar xf kubernetes-client-linux-amd64.tar.gz

1.3.1 master版本升级

先升级master-1

# 将master上kube-lb里面的配置文件去掉master-1
root@k8s-master-1:~# vim /etc/kube-lb/conf/kube-lb.conf
root@k8s-master-2:~# vim /etc/kube-lb/conf/kube-lb.conf
root@k8s-master-3:~# vim /etc/kube-lb/conf/kube-lb.conf

# 重启kube-lb服务
root@k8s-master-1:~# systemctl restart kube-lb
root@k8s-master-2:~# systemctl restart kube-lb
root@k8s-master-3:~# systemctl restart kube-lb

# 关闭mater-1上的服务
root@k8s-master-1:~# systemctl stop kube-apiserver kube-controller-manager kube-proxy kube-scheduler kubelet

# 覆盖mater-1上的二进制文件
root@k8s-ansible-client:/usr/local/src/kubernetes/server/bin# scp kube-apiserver kube-controller-manager kube-scheduler kube-proxy kubelet kubectl root@k8s-master-1:/usr/local/bin
The authenticity of host 'k8s-master-1 (192.168.20.201)' can't be established.
ECDSA key fingerprint is SHA256:mEyjijhaO0Gy5tMg1uTqQXjWOPiW1tf491hnlWUT3Wk.
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
Warning: Permanently added 'k8s-master-1' (ECDSA) to the list of known hosts.
kube-apiserver                                                                                                                                             100%  119MB 108.8MB/s   00:01    
kube-controller-manager                                                                                                                                    100%  113MB  98.9MB/s   00:01    
kube-scheduler                                                                                                                                             100%   47MB  93.8MB/s   00:00    
kube-proxy                                                                                                                                                 100%   41MB 104.8MB/s   00:00    
kubelet                                                                                                                                                    100%  146MB 107.2MB/s   00:01    
kubectl                                                                                                                                                    100%   45MB  95.3MB/s   00

# 启动服务
root@k8s-master-1:~# systemctl start kube-apiserver kube-controller-manager kube-proxy kube-scheduler kubelet

验证版本

root@k8s-master-1:~# kubectl get node -A
NAME             STATUS                     ROLES    AGE   VERSION
192.168.20.147   Ready                      node     13d   v1.21.0
192.168.20.189   Ready,SchedulingDisabled   master   13d   v1.21.0
192.168.20.201   Ready,SchedulingDisabled   master   13d   v1.22.2
192.168.20.236   Ready                      node     13d   v1.21.0
192.168.20.249   Ready,SchedulingDisabled   master   13d   v1.21.0
192.168.20.253   Ready                      node     13d   v1.21.0

将master上kube-lb配置文件mater-1加回来,去掉其他两台master节点,进行升级,步骤参考mater-1升级

root@k8s-master-2:~# vim /etc/kube-lb/conf/kube-lb.conf
root@k8s-master-2:~# systemctl restart kube-lb
root@k8s-master-2:~# systemctl stop kube-apiserver kube-controller-manager kube-proxy kube-scheduler kubelet
root@k8s-master-3:~# vim /etc/kube-lb/conf/kube-lb.conf
root@k8s-master-3:~# systemctl restart kube-lb
root@k8s-master-3:~# systemctl stop kube-apiserver kube-controller-manager kube-proxy kube-scheduler kubelet

# 覆盖mater-2、master-3上的二进制文件
root@k8s-ansible-client:/usr/local/src/kubernetes/server/bin# scp kube-apiserver kube-controller-manager kube-scheduler kube-proxy kubelet kubectl root@k8s-master-2:/usr/local/bin
root@k8s-ansible-client:/usr/local/src/kubernetes/server/bin# scp kube-apiserver kube-controller-manager kube-scheduler kube-proxy kubelet kubectl root@k8s-master-3:/usr/local/bin

# 启动服务
root@k8s-master-2:~# systemctl start kube-apiserver kube-controller-manager kube-proxy kube-scheduler kubelet
root@k8s-master-3:~# systemctl start kube-apiserver kube-controller-manager kube-proxy kube-scheduler kubelet

版本验证

root@k8s-master-1:~# kubectl get node -A
NAME             STATUS                     ROLES    AGE   VERSION
192.168.20.147   Ready                      node     14d   v1.21.0
192.168.20.189   Ready,SchedulingDisabled   master   14d   v1.22.2
192.168.20.201   Ready,SchedulingDisabled   master   14d   v1.22.2
192.168.20.236   Ready                      node     14d   v1.21.0
192.168.20.249   Ready,SchedulingDisabled   master   14d   v1.22.2
192.168.20.253   Ready                      node     14d   v1.21.0

最后恢复kube-lb配置文件,并且重启kube-lb服务

1.3.2 work节点版本升级

work节点认证信息存在 /root/.kube/config文件下

升级work-1节点

# 先停服务
root@k8s-work-1:~# systemctl stop kubelet kube-proxy

#scp二进制文件
root@k8s-ansible-client:/usr/local/src/kubernetes/server/bin# scp kube-proxy kubelet kubectl k8s-work-1:/usr/local/bin

# 启动服务
root@k8s-work-1:~# systemctl start kubelet kube-proxy

升级work-2节点

# 先停服务
root@k8s-work-2:~# systemctl stop kubelet kube-proxy

#scp二进制文件
root@k8s-ansible-client:/usr/local/src/kubernetes/server/bin# scp kube-proxy kubelet kubectl k8s-work-2:/usr/local/bin

# 启动服务
root@k8s-work-2:~# systemctl start kubelet kube-proxy

升级work-3节点

# 先停服务
root@k8s-work-3:~# systemctl stop kubelet kube-proxy

#scp二进制文件
root@k8s-ansible-client:/usr/local/src/kubernetes/server/bin# scp kube-proxy kubelet kubectl k8s-work-3:/usr/local/bin

# 启动服务
root@k8s-work-3:~# systemctl start kubelet kube-proxy

验证版本

root@k8s-master-1:~# kubectl get node -A
NAME             STATUS                     ROLES    AGE   VERSION
192.168.20.147   Ready                      node     14d   v1.22.2
192.168.20.189   Ready,SchedulingDisabled   master   14d   v1.22.2
192.168.20.201   Ready,SchedulingDisabled   master   14d   v1.22.2
192.168.20.236   Ready                      node     14d   v1.22.2
192.168.20.249   Ready,SchedulingDisabled   master   14d   v1.22.2
192.168.20.253   Ready                      node     14d   v1.22.2

2. k8s yaml文件详解

Kubernetes只支持YAML和JSON格式创建资源对象
JSON格式用于接口之间消息的传递,YAML格式用于配置和管理
YAML是专门用来写配置文件的语言,非常简洁和强大,使用比json更方便。它实质上是一种通用的数据串行化格式。

2.1 YAML文件优点

  • YAML文件易于人类阅读,具有表达性和可扩展性。
  • YAML文件易于实现和使用。
  • 可在编程语言之间轻松移植。
  • 与敏捷语言的原生数据结构相匹配。
  • YAML文件具有一致模型,支持通用工具。
  • YAML文件支持One-pass处理。
  • 使用方便,因此您无需再将所有的参数添加到命令行中。
  • 易于维护 – 可以将YAML文件添加到源控件中以跟踪更改。
  • 灵活便捷 – 可以使用YAML创建更加复杂的结构(相对于使用命令行可以创建的结构)

2.2 YAML与 JSON 和 XML 的关系

image.png
  • XML 是许多领域的优先采用格式。XML 最初设计为与标准通用标记语言 (SGML) 向后兼容,后者旨在支持结构化文档。因此,XML存在许多设计上的约束。
  • JSON 的设计理念是简单性和通用性,并且易于生成和解析。JSON 格式的可读性低,但是这种格式的数据每一种现代编程环境都可以轻松处理。
  • YAML 的设计目标是提升可读性,提供更加完善的信息模型。YAML 的生成和解析更加复杂,因此可以将其视为 JSON 的自然超集。每个JSON 文件都是一个有效的 YAML 文件。

2.3 YAML文件的结构

键值对 – YAML 文件中的基本条目类型是键值对。键值对的格式是键和冒号,之后是空格,然后是值。

数组/列表 – 列表会在列表名称下列出一些项目。列表的元素以 - 开头。可以有 n 个列表,但是,数组中各个元素的缩进非常重要。

字典/地图 – YAML 文件的更复杂类型是字典和地图。

编写yaml文件的准则,如下:

  • 大小写敏感
  • 缩进标识层级关系
  • 不支持制表符缩进,使用空格缩进
  • 通常开头缩进两个空格
  • 字符后缩进一个空格,如冒号,逗号等
  • “—”表示YAML格式,一个文件的开始
  • “#”表示注释
  • 在Kubernetes中,只需要知道两种结构类型即可:
    • Lists
    • Maps

2.4 YAML在Kubernetes中的使用

  • Kubernetes 资源是通过声明的方式创建的,因此可以使用 YAML 文件。
  • Kubernetes 资源(比如 Pod、服务和部署)是使用 YAML 文件创建的。

2.4.1 YAML Maps

Map顾名思义指的是字典,即一个Key:Value 的键值对信息。例如:

apiVersion: v1
kind: Pod
  注:---为可选的分隔符 ,当需要在一个文件中定义多个结构的时候需要使用。上述内容表示有两个键apiVersion和kind,分别对应的值为v1和Pod。

Maps的value既能够对应字符串也能够对应一个Maps。例如:

apiVersion: v1
kind: Pod
metadata:
  name: kube100-site
  labels:
    app: web

注:上述的YAML文件中,metadata这个KEY对应的值为一个Maps,而嵌套的labels这个KEY的值又是一个Map。实际使用中可视情况进行多层嵌套。

YAML处理器根据行缩进来知道内容之间的关联。上述例子中,使用两个空格作为缩进,但空格的数据量并不重要,只是至少要求一个空格并且所有缩进保持一致的空格数 。例如,name和labels是相同缩进级别,因此YAML处理器知道他们属于同一map;它知道app是lables的值因为app的缩进更大。

注意:在YAML文件中绝对不要使用tab键

2.4.2 YAML Lists

List即列表,就是数组,例如:

args:
 -beijing
 -shanghai
 -shenzhen
 -guangzhou
 -wuhan

可以指定任何数量的项在列表中,每个项的定义以破折号(-)开头,并且与父元素之间存在缩进。在JSON格式中,表示如下:

{
  "args": ["beijing", "shanghai", "shenzhen", "guangzhou"]
}

当然Lists的子项也可以是Maps,Maps的子项也可以是List,例如:

apiVersion: v1
kind: Pod
metadata:
  name: kube100-site
  labels:
    app: web
spec:
  containers:
    - name: front-end
      image: nginx
      ports:
        - containerPort: 80
    - name: flaskapp-demo
      image: jcdemo/flaskapp
      ports: 8080

如上述文件所示,定义一个containers的List对象,每个子项都由name、image、ports组成,每个ports都有一个KEY为containerPort的Map组成,转成JSON格式文件

{
  "apiVersion": "v1",
  "kind": "Pod",
  "metadata": {
        "name": "kube100-site",
        "labels": {
            "app": "web"
        },
 
  },
  "spec": {
        "containers": [{
            "name": "front-end",
            "image": "nginx",
            "ports": [{
                "containerPort": "80"
            }]
        }, {
            "name": "flaskapp-demo",
            "image": "jcdemo/flaskapp",
            "ports": [{
                "containerPort": "5000"
            }]
        }]
  }
}

2.5 使用YAML创建Pod

K8S有两种创建资源的方式:kubectl 命令和 yaml 配置文件
kubectl命令行:最为简单,一条命令就OK
yaml配置文件,例如:

apiVersion: v1       #必选,版本号,例如v1
kind: Pod       #必选,Pod
metadata:       #必选,元数据
  name: string       #必选,Pod名称
  namespace: string    #必选,Pod所属的命名空间
  labels:      #自定义标签
    - name: string     #自定义标签名字
  annotations:       #自定义注释列表
    - name: string
spec:         #必选,Pod中容器的详细定义
  containers:      #必选,Pod中容器列表
  - name: string     #必选,容器名称
    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

apiVersion:此处值是v1,这个版本号需要根据安装的Kubernetes版本和资源类型进行变化,记住不是写死的。
kind:此处创建的是Pod,根据实际情况,此处资源类型可以是Deployment、Job、Ingress、Service等。
metadata:包含Pod的一些meta信息,比如名称、namespace、标签等信息。
spec:包括一些container,storage,volume以及其他Kubernetes需要的参数,以及诸如是否在容器失败时重新启动容器的属性。可在特定Kubernetes API找到完整的Kubernetes Pod的属性

查看apiVersion

root@k8s-ansible-client:~# kubectl api-versions
admissionregistration.k8s.io/v1
apiextensions.k8s.io/v1
apiregistration.k8s.io/v1
apps/v1
authentication.k8s.io/v1
authorization.k8s.io/v1
autoscaling/v1
autoscaling/v2beta1
autoscaling/v2beta2
batch/v1
batch/v1beta1
certificates.k8s.io/v1
coordination.k8s.io/v1
discovery.k8s.io/v1
discovery.k8s.io/v1beta1
events.k8s.io/v1
events.k8s.io/v1beta1
flowcontrol.apiserver.k8s.io/v1beta1
networking.k8s.io/v1
node.k8s.io/v1
node.k8s.io/v1beta1
policy/v1
policy/v1beta1
rbac.authorization.k8s.io/v1
scheduling.k8s.io/v1
storage.k8s.io/v1
storage.k8s.io/v1beta1
v1

下面是一个典型的容器定义

spec:
  containers:
    - name: front-end
      image: nginx
      ports:
        - containerPort: 80

上述例子只是一个简单的最小定义:一个名字(front-end)、基于nginx的镜像,以及容器将会监听的指定端口号(80)。

除了上述的基本属性外,还能够指定复杂的属性,包括容器启动运行的命令、使用的参数、工作目录以及每次实例化是否拉取新的副本。 还可以指定更深入的信息,例如容器的退出日志的位置。容器可选的设置属性包括:

name、image、command、args、workingDir、ports、env、resource、volumeMounts、livenessProbe、readinessProbe、livecycle、terminationMessagePath、imagePullPolicy、securityContext、stdin、stdinOnce、tty

kubectl创建pod

root@k8s-ansible-client:~/yaml# kubectl apply -f test_pod.yaml
pod/kube100-site created

2.6 创建Deployment

apiVersion: extensions/v1beta1   #接口版本
kind: Deployment                 #接口类型
metadata:
  name: ptengine-demo               #Deployment名称
  namespace: ptengine-prd           #namespace 名称
  labels:
    app: ptengine-demo              #标签
spec:
  replicas: 3
   strategy:
    rollingUpdate:  ##由于replicas为3,则整个升级,pod个数在2-4个之间
      maxSurge: 1       #滚动升级时会先启动1个pod
      maxUnavailable: 1 #滚动升级时允许的最大Unavailable的pod个数
  template:         
    metadata:
      labels:
        app: ptengine-demo  #模板名称必填
    sepc: #定义容器模板,该模板可以包含多个容器
      containers:                                                                   
        - name: ptengine-demo                                                           #镜像名称
          image: reg.pt1.com/ptengine-prd/ptengine-demo:0.0.1-SNAPSHOT #镜像地址
          CMD: [ "/bin/sh","-c","cat /etc/config/path/to/special-key" ]    #启动CMD
          args:                                                                #启动参数
            - '-storage.local.retention=$(STORAGE_RETENTION)'
            - '-web.external-url=$(EXTERNAL_URL)'

          imagePullPolicy: IfNotPresent  #如果不存在则拉取
          livenessProbe:       #表示container是否处于live状态。如果LivenessProbe失败,LivenessProbe将会通知kubelet对应的container不健康了。随后kubelet将kill掉container,并根据RestarPolicy进行进一步的操作。默认情况下LivenessProbe在第一次检测之前初始化值为Success,如果container没有提供LivenessProbe,则也认为是Success;
            httpGet:
              path: /health #如果没有心跳检测接口就为/
              port: 8080
              scheme: HTTP
            initialDelaySeconds: 60 ##启动后延时多久开始运行检测
            timeoutSeconds: 5
            successThreshold: 1
            failureThreshold: 5
            readinessProbe:
          readinessProbe:
            httpGet:
              path: /health #如果没有健康检测接口就为/
              port: 8080
              scheme: HTTP
            initialDelaySeconds: 30 ##启动后延时多久开始运行检测
            timeoutSeconds: 5
            successThreshold: 1
            failureThreshold: 5
          resources:              ##CPU内存限制
            requests:
              cpu: 2
              memory: 2048Mi
            limits:
              cpu: 2
              memory: 2048Mi
          env:                    ##通过环境变量的方式,直接传递pod=自定义Linux OS环境变量
            - name: LOCAL_KEY     #本地Key
              value: value
            - name: CONFIG_MAP_KEY  #local策略可使用configMap的配置Key,
              valueFrom:
                configMapKeyRef:
                  name: special-config   #configmap中找到name为special-config
                  key: special.type      #找到name为special-config里data下的key
          ports:
            - name: http
              containerPort: 8080 #对service暴露端口
          volumeMounts:     #挂载volumes中定义的磁盘
          - name: log-cache
            mount: /tmp/log
          - name: sdb       #普通用法,该卷跟随容器销毁,挂载一个目录
            mountPath: /data/media    
          - name: nfs-client-root    #直接挂载硬盘方法,如挂载下面的nfs目录到/mnt/nfs
            mountPath: /mnt/nfs
          - name: example-volume-config  #高级用法第1种,将ConfigMap的log-script,backup-script分别挂载到/etc/config目录下的一个相对路径path/to/...下,如果存在同名文件,直接覆盖。
            mountPath: /etc/config       
          - name: rbd-pvc                #高级用法第2中,挂载PVC(PresistentVolumeClaim)

#使用volume将ConfigMap作为文件或目录直接挂载,其中每一个key-value键值对都会生成一个文件,key为文件名,value为内容,
  volumes:  # 定义磁盘给上面volumeMounts挂载
  - name: log-cache
    emptyDir: {}
  - name: sdb  #挂载宿主机上面的目录
    hostPath:
      path: /any/path/it/will/be/replaced
  - name: example-volume-config  # 供ConfigMap文件内容到指定路径使用
    configMap:
      name: example-volume-config  #ConfigMap中名称
      items:
      - key: log-script           #ConfigMap中的Key
        path: path/to/log-script  #指定目录下的一个相对路径path/to/log-script
      - key: backup-script        #ConfigMap中的Key
        path: path/to/backup-script  #指定目录下的一个相对路径path/to/backup-script
  - name: nfs-client-root         #供挂载NFS存储类型
    nfs:
      server: 10.42.0.55          #NFS服务器地址
      path: /opt/public           #showmount -e 看一下路径
  - name: rbd-pvc                 #挂载PVC磁盘
    persistentVolumeClaim:
      claimName: rbd-pvc1         #挂载已经申请的pvc磁盘

创建一个yaml文件

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
spec:
  replicas: 3
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:1.10
        ports:
        - containerPort: 80

创建deployment

root@k8s-ansible-client:~/yaml# kubectl create -f nginx-deployment.yaml
deployment.apps/nginx-deployment created
root@k8s-ansible-client:~/yaml# kubectl get pod -o wide
NAME                                READY   STATUS    RESTARTS       AGE   IP              NODE             NOMINATED NODE   READINESS GATES
alpine-test                         1/1     Running   25 (10h ago)   14d   172.20.108.65   192.168.20.236   <none>           <none>
kube100-site                        2/2     Running   0              11m   172.20.213.6    192.168.20.253   <none>           <none>
nginx-deployment-748755bf57-8w4jc   1/1     Running   0              15s   172.20.191.12   192.168.20.147   <none>           <none>
nginx-deployment-748755bf57-k5nlx   1/1     Running   0              15s   172.20.191.11   192.168.20.147   <none>           <none>
nginx-deployment-748755bf57-ltldz   1/1     Running   0              15s   172.20.108.67   192.168.20.236   <none>           <none>
nginx-test-001                      1/1     Running   1 (11h ago)    25h   172.20.191.10   192.168.20.147   <none>           <none>
nginx-test1                         1/1     Running   25 (10h ago)   14d   172.20.191.2    192.168.20.147   <none>           <none>
nginx-test2                         1/1     Running   25 (10h ago)   14d   172.20.213.3    192.168.20.253   <none>           <none>
nginx-test3                         1/1     Running   25 (10h ago)   14d   172.20.191.3    192.168.20.147   <none>           <none>
root@k8s-ansible-client:~/yaml# kubectl get deployment
NAME               READY   UP-TO-DATE   AVAILABLE   AGE
nginx-deployment   3/3     3            3           56s

3. ETCD

ETCD是用于共享配置和服务发现的分布式,一致性的KV存储系统。Github

ETCD是分布式系统中最关键数据的分布式可靠键值存储,重点在于:

  • 简单:定义明确、面向用户的 API (gRPC)
  • 安全:具有可选客户端证书身份验证的自动 TLS
  • 快速:基准测试为 10,000 次写入/秒
  • 可靠:使用 Raft 正确分布

3.1工作原理

ETCD使用Raft协议来维护集群内各个节点状态的一致性。简单说,ETCD集群是一个分布式系统,由多个节点相互通信构成整体对外服务,每个节点都存储了完整的数据,并且通过Raft协议保证每个节点维护的数据是一致的。


image.png

如图所示,每个ETCD节点都维护了一个状态机,并且,任意时刻至多存在一个有效的主节点。主节点处理所有来自客户端写操作,通过Raft协议保证写操作对状态机的改动会可靠的同步到其他节点。

ETCD工作原理核心部分在于Raft协议。

Raft协议正如论文所述,确实方便理解。主要分为三个部分:

  • 选主
  • 日志复制
  • 安全性

3.1.1 选主

Raft协议是用于维护一组服务节点数据一致性的协议。这一组服务节点构成一个集群,并且有一个主节点来对外提供服务。当集群初始化,或者主节点挂掉后,面临一个选主问题。集群中每个节点,任意时刻处于Leader, Follower, Candidate这三个角色之一。选举特点如下:

  • 当集群初始化时候,每个节点都是Follower角色;
  • 集群中存在至多1个有效的主节点,通过心跳与其他节点同步数据;
  • 当Follower在一定时间内没有收到来自主节点的心跳,会将自己角色改变为Candidate,并发起一次选主投票;当收到包括自己在内超过半数节点赞成后,选举成功;当收到票数不足半数选举失败,或者选举超时。若本轮未选出主节点,将进行下一轮选举(出现这种情况,是由于多个节点同时选举,所有节点均为获得过半选票)。
  • Candidate节点收到来自主节点的信息后,会立即终止选举过程,进入Follower角色。
    为了避免陷入选主失败循环,每个节点未收到心跳发起选举的时间是一定范围内的随机值,这样能够避免2个节点同时发起选主。

3.1.2 日志复制

所谓日志复制,是指主节点将每次操作形成日志条目,并持久化到本地磁盘,然后通过网络IO发送给其他节点。其他节点根据日志的逻辑时钟(TERM)和日志编号(INDEX)来判断是否将该日志记录持久化到本地。当主节点收到包括自己在内超过半数节点成功返回,那么认为该日志是可提交的(committed),并将日志输入到状态机,将结果返回给客户端。

这里需要注意的是,每次选主都会形成一个唯一的TERM编号,相当于逻辑时钟。每一条日志都有全局唯一的编号。


image.png

主节点通过网络IO向其他节点追加日志。若某节点收到日志追加的消息,首先判断该日志的TERM是否过期,以及该日志条目的INDEX是否比当前以及提交的日志的INDEX跟早。若已过期,或者比提交的日志更早,那么就拒绝追加,并返回该节点当前的已提交的日志的编号。否则,将日志追加,并返回成功。

当主节点收到其他节点关于日志追加的回复后,若发现有拒绝,则根据该节点返回的已提交日志编号,发生其编号下一条日志。

主节点像其他节点同步日志,还作了拥塞控制。具体地说,主节点发现日志复制的目标节点拒绝了某次日志追加消息,将进入日志探测阶段,一条一条发送日志,直到目标节点接受日志,然后进入快速复制阶段,可进行批量日志追加。

按照日志复制的逻辑,我们可以看到,集群中慢节点不影响整个集群的性能。另外一个特点是,数据只从主节点复制到Follower节点,这样大大简化了逻辑流程。

3.1.3 安全性

截止此刻,选主以及日志复制并不能保证节点间数据一致。试想,当一个某个节点挂掉了,一段时间后再次重启,并当选为主节点。而在其挂掉这段时间内,集群若有超过半数节点存活,集群会正常工作,那么会有日志提交。这些提交的日志无法传递给挂掉的节点。当挂掉的节点再次当选主节点,它将缺失部分已提交的日志。在这样场景下,按Raft协议,它将自己日志复制给其他节点,会将集群已经提交的日志给覆盖掉。

这显然是不可接受的。

其他协议解决这个问题的办法是,新当选的主节点会询问其他节点,和自己数据对比,确定出集群已提交数据,然后将缺失的数据同步过来。这个方案有明显缺陷,增加了集群恢复服务的时间(集群在选举阶段不可服务),并且增加了协议的复杂度。

Raft解决的办法是,在选主逻辑中,对能够成为主的节点加以限制,确保选出的节点已定包含了集群已经提交的所有日志。如果新选出的主节点已经包含了集群所有提交的日志,那就不需要从和其他节点比对数据了。简化了流程,缩短了集群恢复服务的时间。

这里存在一个问题,加以这样限制之后,还能否选出主呢?答案是:只要仍然有超过半数节点存活,这样的主一定能够选出。因为已经提交的日志必然被集群中超过半数节点持久化,显然前一个主节点提交的最后一条日志也被集群中大部分节点持久化。当主节点挂掉后,集群中仍有大部分节点存活,那这存活的节点中一定存在一个节点包含了已经提交的日志了。

3.2 ETCD接口

ETCD提供HTTP协议,在最新版本中支持Google gRPC方式访问。具体支持接口情况如下:

  • ETCD是一个高可靠的KV存储系统,支持PUT/GET/DELETE接口;
  • 为了支持服务注册与发现,支持WATCH接口(通过http long poll实现);
  • 支持KEY持有TTL属性;
  • CAS(compare and swap)操作;
  • 支持多key的事务操作;
  • 支持目录操作

3.3 ETCD集群

官网说明文档,提供了3种集群启动方式,实际上按照其实现原理分为2类:

  • 通过静态配置方式启动
  • 通过服务发现方式启动

3.3.1 集群节点数量与网络分割

ETCD使用RAFT协议保证各个节点之间的状态一致。根据RAFT算法原理,节点数目越多,会降低集群的写性能。这是因为每一次写操作,需要集群中大多数节点将日志落盘成功后,Leader节点才能将修改内部状态机,并返回将结果返回给客户端。

也就是说在等同配置下,节点数越少,集群性能越好。显然,只部署1个节点是没什么意义的。通常,按照需求将集群节点部署为3,5,7,9个节点。

这里能选择偶数个节点吗? 最好不要这样。原因有二:

  • 偶数个节点集群不可用风险更高,表现在选主过程中,有较大概率或等额选票,从而触发下一轮选举。
  • 偶数个节点集群在某些网络分割的场景下无法正常工作。试想,当网络分割发生后,将集群节点对半分割开。此时集群将无法工作。按照RAFT协议,此时集群写操作无法使得大多数节点同意,从而导致写失败,集群无法正常工作。

当网络分割后,ETCD集群如何处理的呢?

  • 当集群的Leader在多数节点这一侧时,集群仍可以正常工作。少数节点那一侧无法收到Leader心跳,也无法完成选举。
  • 当集群的Leader在少数节点这一侧时,集群仍可以正常工作,多数派的节点能够选出新的Leader, 集群服务正常进行。

当网络分割恢复后,少数派的节点会接受集群Leader的日志,直到和其他节点状态一致。

3.3.2 ETCD参数说明

这里只列举一些重要的参数,以及其用途。

  • —data-dir 指定节点的数据存储目录,这些数据包括节点ID,集群ID,集群初始化配置,Snapshot文件,若未指定—wal-dir,还会存储WAL文件;
  • —wal-dir 指定节点的was文件的存储目录,若指定了该参数,wal文件会和其他数据文件分开存储。
  • —name 节点名称
  • —initial-advertise-peer-urls 告知集群其他节点url.
  • — listen-peer-urls 监听URL,用于与其他节点通讯
  • — advertise-client-urls 告知客户端url, 也就是服务的url
  • — initial-cluster-token 集群的ID
  • — initial-cluster 集群中所有节点

3.3.3 ETCD命令操作

# 查看心跳信息
root@k8s-master-1:~# export NODE_IPS="192.168.20.201 192.168.20.189 192.168.20.249"
root@k8s-master-1:~# for ip in ${NODE_IPS}; do ETCDCTL_API=3 /usr/local/bin/etcdctl --endpoints=https://${ip}:2379 --cacert=/etc/kubernetes/ssl/ca.pem --cert=/etc/kubernetes/ssl/etcd.pem --key=/etc/kubernetes/ssl/etcd-key.pem endpoint health; done
https://192.168.20.201:2379 is healthy: successfully committed proposal: took = 17.919907ms
https://192.168.20.189:2379 is healthy: successfully committed proposal: took = 10.841348ms
https://192.168.20.249:2379 is healthy: successfully committed proposal: took = 11.216277ms

# 显示集群成员信息
root@k8s-master-1:~# ETCDCTL_API=3 /usr/local/bin/etcdctl --write-out=table member list --endpoints=https://192.168.20.201:2379 --cacert=/etc/kubernetes/ssl/ca.pem --cert=/etc/kubernetes/ssl/etcd.pem --key=/etc/kubernetes/ssl/etcd-key.pem
+------------------+---------+---------------------+-----------------------------+-----------------------------+------------+
|        ID        | STATUS  |        NAME         |         PEER ADDRS          |        CLIENT ADDRS         | IS LEARNER |
+------------------+---------+---------------------+-----------------------------+-----------------------------+------------+
|  569e391105c011f | started | etcd-192.168.20.189 | https://192.168.20.189:2380 | https://192.168.20.189:2379 |      false |
|  f212819f18bbd3b | started | etcd-192.168.20.201 | https://192.168.20.201:2380 | https://192.168.20.201:2379 |      false |
| 846cf490f28e27e2 | started | etcd-192.168.20.249 | https://192.168.20.249:2380 | https://192.168.20.249:2379 |      false |
+------------------+---------+---------------------+-----------------------------+-----------------------------+------------+

# 以表格方式显示节点详细状态
root@k8s-master-1:~# for ip in ${NODE_IPS}; do ETCDCTL_API=3 /usr/local/bin/etcdctl --write-out=table endpoint status --endpoints=https://${ip}:2379 --cacert=/etc/kubernetes/ssl/ca.pem --cert=/etc/kubernetes/ssl/etcd.pem --key=/etc/kubernetes/ssl/etcd-key.pem; done
+-----------------------------+-----------------+---------+---------+-----------+------------+-----------+------------+--------------------+--------+
|          ENDPOINT           |       ID        | VERSION | DB SIZE | IS LEADER | IS LEARNER | RAFT TERM | RAFT INDEX | RAFT APPLIED INDEX | ERRORS |
+-----------------------------+-----------------+---------+---------+-----------+------------+-----------+------------+--------------------+--------+
| https://192.168.20.201:2379 | f212819f18bbd3b |  3.4.13 |  3.8 MB |     false |      false |         7 |    3596022 |            3596021 |        |
+-----------------------------+-----------------+---------+---------+-----------+------------+-----------+------------+--------------------+--------+
+-----------------------------+-----------------+---------+---------+-----------+------------+-----------+------------+--------------------+--------+
|          ENDPOINT           |       ID        | VERSION | DB SIZE | IS LEADER | IS LEARNER | RAFT TERM | RAFT INDEX | RAFT APPLIED INDEX | ERRORS |
+-----------------------------+-----------------+---------+---------+-----------+------------+-----------+------------+--------------------+--------+
| https://192.168.20.189:2379 | 569e391105c011f |  3.4.13 |  3.9 MB |      true |      false |         7 |    3596022 |            3596022 |        |
+-----------------------------+-----------------+---------+---------+-----------+------------+-----------+------------+--------------------+--------+
+-----------------------------+------------------+---------+---------+-----------+------------+-----------+------------+--------------------+--------+
|          ENDPOINT           |        ID        | VERSION | DB SIZE | IS LEADER | IS LEARNER | RAFT TERM | RAFT INDEX | RAFT APPLIED INDEX | ERRORS |
+-----------------------------+------------------+---------+---------+-----------+------------+-----------+------------+--------------------+--------+
| https://192.168.20.249:2379 | 846cf490f28e27e2 |  3.4.13 |  3.8 MB |     false |      false |         7 |    3596022 |            3596022 |        |
+-----------------------------+------------------+---------+---------+-----------+------------+-----------+------------+--------------------+--------+

# 列出所有key信息
root@k8s-master-1:~# /usr/local/bin/etcdctl get / --prefix --keys-only
/calico/ipam/v2/assignment/ipv4/block/172.20.108.64-26

/calico/ipam/v2/assignment/ipv4/block/172.20.168.0-26

/calico/ipam/v2/assignment/ipv4/block/172.20.182.64-26

/calico/ipam/v2/assignment/ipv4/block/172.20.191.0-26

/calico/ipam/v2/assignment/ipv4/block/172.20.196.0-26

/calico/ipam/v2/assignment/ipv4/block/172.20.213.0-26

/calico/ipam/v2/handle/ipip-tunnel-addr-k8s-master-1

/calico/ipam/v2/handle/ipip-tunnel-addr-k8s-master-2

/calico/ipam/v2/handle/ipip-tunnel-addr-k8s-master-3

/calico/ipam/v2/handle/ipip-tunnel-addr-k8s-work-1

/calico/ipam/v2/handle/ipip-tunnel-addr-k8s-work-2

/calico/ipam/v2/handle/ipip-tunnel-addr-k8s-work-3
...


3.3.4 ETCD数据备份与恢复机制

# 备份数据
root@k8s-master-1:~# ETCDCTL_API=3 /usr/local/bin/etcdctl snapshot save snapshot.db
{"level":"info","ts":1633877806.220544,"caller":"snapshot/v3_snapshot.go:119","msg":"created temporary db file","path":"snapshot.db.part"}
{"level":"info","ts":"2021-10-10T22:56:46.221+0800","caller":"clientv3/maintenance.go:200","msg":"opened snapshot stream; downloading"}
{"level":"info","ts":1633877806.2211795,"caller":"snapshot/v3_snapshot.go:127","msg":"fetching snapshot","endpoint":"127.0.0.1:2379"}
{"level":"info","ts":"2021-10-10T22:56:46.306+0800","caller":"clientv3/maintenance.go:208","msg":"completed snapshot read; closing"}
{"level":"info","ts":1633877806.3121157,"caller":"snapshot/v3_snapshot.go:142","msg":"fetched snapshot","endpoint":"127.0.0.1:2379","size":"3.8 MB","took":0.091485483}
{"level":"info","ts":1633877806.31222,"caller":"snapshot/v3_snapshot.go:152","msg":"saved","path":"snapshot.db"}
Snapshot saved at snapshot.db

# 恢复数据
root@k8s-master-1:~# ETCDCTL_API=3 /usr/local/bin/etcdctl snapshot restore snapshot.db --data-dir=/opt/etcd-testdir #将数据恢复到一个新的不存在的目录中
{"level":"info","ts":1633877847.2969198,"caller":"snapshot/v3_snapshot.go:296","msg":"restoring snapshot","path":"snapshot.db","wal-dir":"/opt/etcd-testdir/member/wal","data-dir":"/opt/etcd-testdir","snap-dir":"/opt/etcd-testdir/member/snap"}
{"level":"info","ts":1633877847.3445005,"caller":"mvcc/kvstore.go:380","msg":"restored last compact revision","meta-bucket-name":"meta","meta-bucket-name-key":"finishedCompactRev","restored-compact-revision":2749686}
{"level":"info","ts":1633877847.3551688,"caller":"membership/cluster.go:392","msg":"added member","cluster-id":"cdf818194e3a8c32","local-member-id":"0","added-peer-id":"8e9e05c52164694d","added-peer-peer-urls":["http://localhost:2380"]}
{"level":"info","ts":1633877847.373978,"caller":"snapshot/v3_snapshot.go:309","msg":"restored snapshot","path":"snapshot.db","wal-dir":"/opt/etcd-testdir/member/wal","data-dir":"/opt/etcd-testdir","snap-dir":"/opt/etcd-testdir/member/snap"}

# 自动备份数据
root@k8s-master-1:~# mkdir /data/etcd-backup/ -p
root@k8s-master-1:/data/etcd-backup# cat script.sh 
#!/bin/bash
source /etc/profile

DATE=`date +%Y-%m-%d_%H-%M-%S`

ETCDCTL_API=3 /usr/local/bin/etcdctl snapshot save /data/etcd-backup-dir/etcd-snapshot-${DATE}.db

ETCD数据恢复流程
当etd集群宕机数量超过集群总节点数一半以上的时候(如总数为三台宕机两台),就会导致整个集群宕机,后期需要重新恢复数据,则恢复流程如下:

    1. 恢复服务器系统
    1. 重新部署etcd集群
    1. 停止kube-apiserver/controller-manager/scheduler/kubelet/kube-proxy
    1. 停止etcd集群
    1. 各ETCD节点恢复同一份备份数据
    1. 启动各节点并验证ETCD集群
    1. 启动kube-apiserver/controller-manager/scheduler/kubelet/kube-proxy
    1. 验证k8s master状态及pod数据

4. k8s集群常用维护命令

4.1 查看信息的命令

# 查看所有pod信息
root@k8s-master-1:~# kubectl get pods -A
NAMESPACE              NAME                                         READY   STATUS    RESTARTS         AGE
default                alpine-test                                  1/1     Running   27 (6h40m ago)   15d
default                kube100-site                                 2/2     Running   0                23h
default                nginx-deployment-748755bf57-8w4jc            1/1     Running   0                23h
default                nginx-deployment-748755bf57-k5nlx            1/1     Running   0                23h
default                nginx-deployment-748755bf57-ltldz            1/1     Running   0                23h
default                nginx-test-001                               1/1     Running   3 (7h17m ago)    2d
default                nginx-test1                                  1/1     Running   27 (6h50m ago)   15d
default                nginx-test2                                  1/1     Running   27 (6h50m ago)   15d
default                nginx-test3                                  1/1     Running   27 (6h50m ago)   15d
kube-system            calico-kube-controllers-647f956d86-mtpdr     1/1     Running   0                15d
kube-system            calico-node-7tqpw                            1/1     Running   0                15d
kube-system            calico-node-hv6xc                            1/1     Running   0                15d
kube-system            calico-node-jcnlw                            1/1     Running   0                15d
kube-system            calico-node-lktp8                            1/1     Running   0                15d
kube-system            calico-node-mv7lp                            1/1     Running   0                15d
kube-system            calico-node-wqbnr                            1/1     Running   0                15d
kube-system            coredns-f97dc456d-9cncc                      1/1     Running   0                15d
kubernetes-dashboard   dashboard-metrics-scraper-856586f554-xms2j   1/1     Running   0                15d
kubernetes-dashboard   kubernetes-dashboard-67484c44f6-2cjtp        1/1     Running   0                15d

# 列出资源信息
root@k8s-master-1:~# kubectl get deployment -A
NAMESPACE              NAME                        READY   UP-TO-DATE   AVAILABLE   AGE
default                nginx-deployment            3/3     3            3           23h
kube-system            calico-kube-controllers     1/1     1            1           15d
kube-system            coredns                     1/1     1            1           15d
kubernetes-dashboard   dashboard-metrics-scraper   1/1     1            1           15d
kubernetes-dashboard   kubernetes-dashboard        1/1     1            1           15d

# 展示出来pod所在的节点信息
root@k8s-master-1:~# kubectl get pods -o wide
NAME                                READY   STATUS    RESTARTS         AGE    IP              NODE             NOMINATED NODE   READINESS GATES
alpine-test                         1/1     Running   27 (6h43m ago)   15d    172.20.108.65   192.168.20.236   <none>           <none>
kube100-site                        2/2     Running   0                23h    172.20.213.6    192.168.20.253   <none>           <none>
nginx-deployment-748755bf57-8w4jc   1/1     Running   0                23h    172.20.191.12   192.168.20.147   <none>           <none>
nginx-deployment-748755bf57-k5nlx   1/1     Running   0                23h    172.20.191.11   192.168.20.147   <none>           <none>
nginx-deployment-748755bf57-ltldz   1/1     Running   0                23h    172.20.108.67   192.168.20.236   <none>           <none>
nginx-test-001                      1/1     Running   3 (7h20m ago)    2d1h   172.20.191.10   192.168.20.147   <none>           <none>
nginx-test1                         1/1     Running   27 (6h53m ago)   15d    172.20.191.2    192.168.20.147   <none>           <none>
nginx-test2                         1/1     Running   27 (6h53m ago)   15d    172.20.213.3    192.168.20.253   <none>           <none>
nginx-test3                         1/1     Running   27 (6h53m ago)   15d    172.20.191.3    192.168.20.147   <none>           <none>

# 以yaml文件形式显示一个pod详细信息
root@k8s-master-1:~# kubectl get pods alpine-test -o yaml

# 以json文件形式显示一个pod详细信息
root@k8s-master-1:~# kubectl get pods alpine-test -o json

# pod启动过程中遇到问题可以使用describe 进行排查
root@k8s-master-1:~# kubectl describe pods alpine-test

4.2 apply命令

apply命令提供了比patch,edit等更严格的更新resource的方式。通过apply,用户可以将resource的configuration使用source control的方式维护在版本库中。每次有更新时,将配置文件push到server,然后使用kubectl apply将更新应用到resource。kubernetes会在引用更新前将当前配置文件中的配置同已经应用的配置做比较,并只更新更改的部分,而不会主动更改任何用户未指定的部分。

apply命令的使用方式同replace相同,不同的是,apply不会删除原有resource,然后创建新的。apply直接在原有resource的基础上进行更新。同时kubectl apply还会resource中添加一条注释,标记当前的apply。类似于git操作。

# 命令使用
root@k8s-master-1:~# kubectl apply -f xxx.yaml

4.3 delete命令

根据resource名或label删除resource。
命令格式:

root@k8s-master-1:~# kubectl delete -f xxx.yaml
root@k8s-master-1:~# kubectl delete pods xxxx-xx
root@k8s-master-1:~# kubectl delete pods -lapp=nginx-test

4.4 查看字段帮助信息

使用 kubectl explain命令可以查看yaml文件的字段中可以使用那些信息字段
例如:查看pod资源中spec下的containers下的ports可以使用哪些信息字段

root@k8s-ansible-client:~/yaml#  kubectl explain pod.spec.containers.ports
KIND:     Pod
VERSION:  v1

RESOURCE: ports <[]Object>

DESCRIPTION:
     List of ports to expose from the container. Exposing a port here gives the
     system additional information about the network connections a container
     uses, but is primarily informational. Not specifying a port here DOES NOT
     prevent that port from being exposed. Any port which is listening on the
     default "0.0.0.0" address inside a container will be accessible from the
     network. Cannot be updated.

     ContainerPort represents a network port in a single container.

FIELDS:
   containerPort    <integer> -required-
     Number of port to expose on the pod's IP address. This must be a valid port
     number, 0 < x < 65536.

   hostIP   <string>
     What host IP to bind the external port to.

   hostPort <integer>
     Number of port to expose on the host. If specified, this must be a valid
     port number, 0 < x < 65536. If HostNetwork is specified, this must match
     ContainerPort. Most containers do not need this.

   name <string>
     If specified, this must be an IANA_SVC_NAME and unique within the pod. Each
     named port in a pod must have a unique name. Name for the port that can be
     referred to by services.

   protocol <string>
     Protocol for port. Must be UDP, TCP, or SCTP. Defaults to "TCP".

4.5 deployment常见操作

更新deploy的镜像

# kubectl set image deploy nginx nginx=nginx:1.14.2
#可以使用 –-record 参数保留更新记录,后面截图的版本记录中1、2都是没有使用该参数的,3、4是使用了的

查看更新过程

# kubectl rollout status deploy nginx
# kubectl describe deploy nginx

回滚

# kubectl rollout history deploy nginx #查看历史版本
# kubectl rollout undo deploy nginx #回滚到上一个版本
# kubectl rollout history deploy nginx #查看历史记录
# kubectl rollout history deploy nginx --revision=3 #查看某个版本的详细信息
# kubectl rollout undo deploy nginx --to-revision=3 #回滚到某个版本

每次更新都会引发deploy的更新,可以先把更新暂停掉,然后调整配置,回复后就可以将暂停期间的操作一次更新。

# kubectl rollout pause deployment nginx #暂停
# kubectl rollout resume deploy nginx #恢复

5. 资源对象

5.1 资源控制器

Kubernetes的资源控制器ReplicationController(RC)、ReplicaSet(RS)、Deployment(Deploy)

5.1.1 什么是控制器

kubernetes中内建了很多controller(控制器),这些相当于一个状态机,用来控制pod的具体状态和行为。

部分控制器类型如下:

  • ReplicationController 和 ReplicaSet
  • Deployment
  • DaemonSet
  • StatefulSet
  • Job/CronJob
  • HorizontalPodAutoscaler

5.1.2 Replication Controller

RC独立于所控制的pod,通过label标签来控制目标pod的创建和销毁,他能够保证Pod持续运行,并且在任何时候都有指定数量的Pod副本。也就是说,Replication Controller可确保一个Pod或一组同类Pod总是可用。

如果存在的Pod大于设定的值,则Replication Controller将终止多余的Pod。如果太少,Replication Controller将启动更多的Pod用于保证达到设定的期望值。与手动创建Pod不同的是,用Replication Controller管理的Pod在失败、删除或终止时会自动替换。

所以,建议哪怕应用程序只需要一个Pod,也应该使用Replication Controller这种自动管理的方式来管理pod。Replication Controller所管理的pod不局限于某个节点,而是监视k8s集群的多个节点上的多个Pod。
示例:

root@k8s-ansible-client:~/yaml/20210926/01# vim rc.yaml
apiVersion: v1  
kind: ReplicationController  
metadata:  
  name: ng-rc
spec:  
  replicas: 2
  selector:  
    app: ng-rc-80 
    #app1: ng-rc-81
  template:   
    metadata:  
      labels:  
        app: ng-rc-80
        #app1: ng-rc-81
    spec:  
      containers:  
      - name: ng-rc-80 
        image: nginx  
        ports:  
        - containerPort: 80 

root@k8s-ansible-client:~/yaml/20210926/01# kubectl apply -f rc.yaml 
replicationcontroller/ng-rc created
root@k8s-ansible-client:~/yaml/20210926/01# kubectl get pods
NAME                                READY   STATUS    RESTARTS        AGE
alpine-test                         1/1     Running   29 (140m ago)   16d
kube100-site                        2/2     Running   0               47h
ng-rc-jxdn4                         1/1     Running   0               12s
ng-rc-s667h                         1/1     Running   0               12s
nginx-deployment-748755bf57-8w4jc   1/1     Running   0               47h
nginx-deployment-748755bf57-k5nlx   1/1     Running   0               47h
nginx-deployment-748755bf57-ltldz   1/1     Running   0               47h
nginx-test-001                      1/1     Running   5 (176m ago)    3d
nginx-test1                         1/1     Running   29 (150m ago)   16d
nginx-test2                         1/1     Running   29 (150m ago)   16d
nginx-test3                         1/1     Running   29 (150m ago)   16d

5.1.3 ReplicaSet

ReplicaSet可以视为Replication Controller的增强版,他主要用作协调创建、删除和更新Pod,和Replication Controller唯一的区别是,ReplicaSet支持灵活的标签选择器,对比RC只能选择一个标签而言,RS的标签选择器是集合式的,使用这种集合方式可以实现滚动升级,包括Deployment也是通过ReplicaSet实现了POD副本自动控制功能。

官方建议虽然ReplicaSet可以单独使用,还是最好使用Deployment对象来控制Pod副本数。
示例:

root@k8s-ansible-client:~/yaml/20210926/01# vim rs.yaml
#apiVersion: extensions/v1beta1
apiVersion: apps/v1 
kind: ReplicaSet
metadata:
  name: frontend
spec:
  replicas: 2
  selector:
#    matchLabels:
#      app: ng-rs-80
    matchExpressions:
      - {key: app, operator: In, values: [ng-rs-80,ng-rs-81]}
  template:
    metadata:
      labels:
        app: ng-rs-80
    spec:  
      containers:  
      - name: ng-rs-80 
        image: nginx  
        ports:  
        - containerPort: 80

root@k8s-ansible-client:~/yaml/20210926/01# kubectl apply -f rs.yaml 
replicaset.apps/frontend created
root@k8s-ansible-client:~/yaml/20210926/01# kubectl get pods
NAME                                READY   STATUS    RESTARTS        AGE
alpine-test                         1/1     Running   29 (142m ago)   16d
frontend-78qz8                      1/1     Running   0               6s
frontend-kvxph                      1/1     Running   0               6s
kube100-site                        2/2     Running   0               47h
nginx-deployment-748755bf57-8w4jc   1/1     Running   0               47h
nginx-deployment-748755bf57-k5nlx   1/1     Running   0               47h
nginx-deployment-748755bf57-ltldz   1/1     Running   0               47h
nginx-test-001                      1/1     Running   5 (178m ago)    3d
nginx-test1                         1/1     Running   29 (151m ago)   16d
nginx-test2                         1/1     Running   29 (151m ago)   16d
nginx-test3                         1/1     Running   29 (151m ago)   16d

Replication Controller(复制控制器,RC)和ReplicaSet(复制集,RS)是两种简单部署Pod的方式。他们在创建和删除pod时区别不大,生产环境中用的也很少,基本使用比较高级的Deployment等资源进行pod管理。

5.1.4 Deployment

Deployment是 1.2版本引入的,用于更好的解决Pod的编排问题,内部使用了ReplicaSet实现目的。

Deployment用于部署无状态的服务,是最常用的控制器。

Deployment对于RC的最大优势是可以随时知道Pod的部署进度。处于pod的创建、调度、绑定节点及在目标节点启动对应容器哪一个过程。

典型的应用场景包括:

  • 定义Deployment来创建Pod和ReplicaSet
  • 滚动升级和回滚应用
  • 扩容和缩容
  • 暂停和继续Deployment

示例:

root@k8s-ansible-client:~/yaml/20210926/01# vim deployment.yaml
#apiVersion: extensions/v1beta1
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.1
        ports:
        - containerPort: 80

root@k8s-ansible-client:~/yaml/20210926/01# kubectl apply -f deployment.yaml
deployment.apps/nginx-deployment created
root@k8s-ansible-client:~/yaml/20210926/01# kubectl get pods,deploy
NAME                                    READY   STATUS              RESTARTS        AGE
pod/alpine-test                         1/1     Running             29 (146m ago)   16d
pod/kube100-site                        2/2     Running             0               47h
pod/nginx-deployment-5d76cf6966-m89gf   0/1     ContainerCreating   0               5s
pod/nginx-deployment-5d76cf6966-x5f8m   0/1     ContainerCreating   0               5s
pod/nginx-test-001                      1/1     Running             5 (3h3m ago)    3d
pod/nginx-test1                         1/1     Running             29 (156m ago)   16d
pod/nginx-test2                         1/1     Running             29 (156m ago)   16d
pod/nginx-test3                         1/1     Running             29 (156m ago)   16d

NAME                               READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/nginx-deployment   0/2     2            0           5s

5.2 Service

service是k8s中的一个重要概念,主要是提供负载均衡和服务自动发现

它定义了一组Pods的逻辑集合和一个用于访问它们的策略 - 有的时候被称之为微服务。一个Service的目标Pod集合通常是由Label Selector 来决定的。

举个例子,想象一个处理图片的后端运行了三个副本。这些副本都是可以替代的 - 前端不关心它们使用的是哪一个后端。尽管实际组成后端集合的Pod可能会变化,前端的客户端却不需要知道这个变化,也不需要自己有一个列表来记录这些后端服务。Service抽象能让你达到这种解耦。

不像 Pod 的 IP 地址,它实际路由到一个固定的目的地,Service 的 IP 实际上不能通过单个主机来进行应答。 相反,我们使用 iptables(Linux 中的数据包处理逻辑)来定义一个虚拟IP地址(VIP),它可以根据需要透明地进行重定向。 当客户端连接到 VIP 时,它们的流量会自动地传输到一个合适的 Endpoint。 环境变量和 DNS,实际上会根据 Service 的 VIP 和端口来进行填充。

k8s支持的4种类型的Service:

  • ClusterIP
  • NodePort
  • LoadBalancer
  • ExternalName

5.2.1 ClusterIP

这种类型的service 只能在集群内访问


image.png

先创建一个nginx-deployment:

root@k8s-ansible-client:~/yaml/20210926/02# vim deploy_node.yaml
#apiVersion: extensions/v1beta1
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-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
        image: nginx:1.16.1
        ports:
        - containerPort: 80
      #nodeSelector:
      #  env: group1

root@k8s-ansible-client:~/yaml/20210926/02# kubectl apply -f deploy_node.yaml 
deployment.apps/nginx-deployment created
root@k8s-ansible-client:~/yaml/20210926/02# kubectl get pods,deploy
NAME                                    READY   STATUS    RESTARTS        AGE
pod/alpine-test                         1/1     Running   29 (164m ago)   16d
pod/kube100-site                        2/2     Running   0               47h
pod/nginx-deployment-5d76cf6966-2426g   1/1     Running   0               6s
pod/nginx-test-001                      1/1     Running   5 (3h20m ago)   3d
pod/nginx-test1                         1/1     Running   29 (173m ago)   16d
pod/nginx-test2                         1/1     Running   29 (173m ago)   16d
pod/nginx-test3                         1/1     Running   29 (173m ago)   16d

NAME                               READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/nginx-deployment   1/1     1            1           6s

创建ClusterIP的Service yaml:

root@k8s-ansible-client:~/yaml/20210926/02# vim svc_service.yaml
apiVersion: v1
kind: Service
metadata:
  name: ng-deploy-80 
spec:
  ports:
  - name: http
    port: 88
    targetPort: 80
    protocol: TCP
  type: ClusterIP
  selector:
    app: ng-deploy-80

root@k8s-ansible-client:~/yaml/20210926/02# kubectl apply -f svc_service.yaml 
service/ng-deploy-80 created
root@k8s-ansible-client:~/yaml/20210926/02# kubectl get svc
NAME           TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)   AGE
kubernetes     ClusterIP   10.68.0.1       <none>        443/TCP   16d
ng-deploy-80   ClusterIP   10.68.185.107   <none>        88/TCP    8s

验证,访问svc的ip:

root@k8s-master-1:~# curl http://10.68.185.107:88
<!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>

5.2.2 NodePort

提供集群外业务访问

image.png

创建NodePort 类型service 如下:

root@k8s-ansible-client:~/yaml/20210926/02# vim svc_NodePort.yaml
apiVersion: v1
kind: Service
metadata:
  name: ng-deploy-80 
spec:
  ports:
  - name: http
    port: 90
    targetPort: 80
    nodePort: 30012
    protocol: TCP
  type: NodePort
  selector:
    app: ng-deploy-80

root@k8s-ansible-client:~/yaml/20210926/02# kubectl apply -f svc_NodePort.yaml 
service/ng-deploy-80 created
root@k8s-ansible-client:~/yaml/20210926/02# kubectl get svc -o wide
NAME           TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)        AGE   SELECTOR
kubernetes     ClusterIP   10.68.0.1       <none>        443/TCP        17d   <none>
ng-deploy-80   NodePort    10.68.144.210   <none>        90:30012/TCP   7s    app=ng-deploy-80

从本地浏览器访问,如截图:

image.png

5.2.3 LoadBalancer

LoadBalancer类型的service 是可以实现集群外部访问服务的另外一种解决方案。不过并不是所有的k8s集群都会支持,大多是在公有云托管集群中会支持该类型。负载均衡器是异步创建的,关于被提供的负载均衡器的信息将会通过Service的status.loadBalancer字段被发布出去。

5.2.4 ExternalName

类型为 ExternalName 的service将服务映射到 DNS 名称,而不是典型的选择器,例如my-service或者cassandra。 您可以使用spec.externalName参数指定这些服务。

5.3 k8s的存储Volume

5.3.1 简介

我们经常会说:容器和 Pod 是短暂的。
其含义是它们的生命周期可能很短,会被频繁地销毁和创建。容器销毁时,保存在容器内部文件系统中的数据都会被清除。

为了持久化保存容器的数据,可以使用 Kubernetes Volume。

Volume 的生命周期独立于容器,Pod 中的容器可能被销毁和重建,但 Volume 会被保留。

本质上,Kubernetes Volume 是一个目录,这一点与 Docker Volume 类似。当 Volume 被 mount 到 Pod,Pod 中的所有容器都可以访问这个 Volume。Kubernetes Volume 也支持多种 backend 类型,包括 emptyDir、hostPath、GCE Persistent Disk、AWS Elastic Block Store、NFS、Ceph 等。

Volume 提供了对各种 backend 的抽象,容器在使用 Volume 读写数据的时候不需要关心数据到底是存放在本地节点的文件系统中呢还是云硬盘上。对它来说,所有类型的 Volume 都只是一个目录。

5.3.2 EmptyDir

生命周期和pod一样。emptyDir的初始状态为一个没有任何内容的volume。如果Pod从集群节点上移除,那么emptyDir类型的volume中的内容会被清除。

Container遇到崩溃或重启,这时候Pod本身不会受任何影响,这种情况下emptyDir volume中的数据会保留。Container重启之后数据仍然可见。

emptyDir volume具有的这种特性适合如下场景使用:

  • 存放临时文件
  • 存放检查点,供container崩溃后恢复用

默认来说emptyDir类型volume的物理存储在硬盘,SSD或网络设备上。可以设置emptyDir.medium为Memory,这时候k8s会使用tempfs(基于内存的文件系统)。此时volume的容量限制收到container的内存配额的制约。

配置如下:

root@k8s-ansible-client:~/yaml/20210926/03# vim deploy_empty.yaml
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
          name: cache-volume-n56
      volumes:
      - name: cache-volume-n56
        emptyDir: {}

root@k8s-ansible-client:~/yaml/20210926/03# kubectl apply -f deploy_empty.yaml 
deployment.apps/nginx-deployment created
root@k8s-ansible-client:~/yaml/20210926/03# kubectl get pods,deploy -o wide
NAME                                    READY   STATUS    RESTARTS         AGE    IP              NODE             NOMINATED NODE   READINESS GATES
pod/alpine-test                         1/1     Running   29 (3h6m ago)    16d    172.20.108.65   192.168.20.236   <none>           <none>
pod/kube100-site                        2/2     Running   0                2d     172.20.213.6    192.168.20.253   <none>           <none>
pod/nginx-deployment-7d4dcd7f7d-fsj6k   1/1     Running   0                6s     172.20.191.14   192.168.20.147   <none>           <none>
pod/nginx-test-001                      1/1     Running   5 (3h42m ago)    3d1h   172.20.191.10   192.168.20.147   <none>           <none>
pod/nginx-test1                         1/1     Running   29 (3h15m ago)   16d    172.20.191.2    192.168.20.147   <none>           <none>
pod/nginx-test2                         1/1     Running   29 (3h15m ago)   16d    172.20.213.3    192.168.20.253   <none>           <none>
pod/nginx-test3                         1/1     Running   29 (3h15m ago)   16d    172.20.191.3    192.168.20.147   <none>           <none>

NAME                               READY   UP-TO-DATE   AVAILABLE   AGE   CONTAINERS     IMAGES   SELECTOR
deployment.apps/nginx-deployment   1/1     1            1           6s    ng-deploy-80   nginx    app=ng-deploy-80

验证

root@k8s-ansible-client:~/yaml/20210926/03# kubectl exec -it pod/nginx-deployment-7d4dcd7f7d-fsj6k bash
kubectl exec [POD] [COMMAND] is DEPRECATED and will be removed in a future version. Use kubectl exec [POD] -- [COMMAND] instead.
root@nginx-deployment-7d4dcd7f7d-fsj6k:/# df -Th
Filesystem                        Type     Size  Used Avail Use% Mounted on
overlay                           overlay   20G  7.2G   12G  39% /
tmpfs                             tmpfs     64M     0   64M   0% /dev
tmpfs                             tmpfs    2.0G     0  2.0G   0% /sys/fs/cgroup
/dev/mapper/ubuntu--vg-ubuntu--lv ext4      20G  7.2G   12G  39% /cache
shm                               tmpfs     64M     0   64M   0% /dev/shm
tmpfs                             tmpfs    3.2G   12K  3.2G   1% /run/secrets/kubernetes.io/serviceaccount
tmpfs                             tmpfs    2.0G     0  2.0G   0% /proc/acpi
tmpfs                             tmpfs    2.0G     0  2.0G   0% /proc/scsi
tmpfs                             tmpfs    2.0G     0  2.0G   0% /sys/firmware

5.3.3 HostPath

此模式挂载pod宿主机文件系统中的文件或目录到pod。

hostPath必须指定一个path参与,用于指定使用宿主机哪个目录。

除此之外还有一个可选的type参数,有如下值可供配置:

  • (空,什么都不写):不进行任何检查
  • DirectoryOrCreate:如果path对应的目录不存在,自动创建一个目录,权限为0755,所属用户和用户组于kubelet相同。
  • Directory:path对应的目录必须存在。
  • FileOrCreate:如果path对应的文件不存在,自动创建一个空文件,权限为0644,所属用户和用户组于kubelet相同。
  • File:path对应的文件必须存在。
  • Socket:path必须对应一个unix socket。
  • CharDevice:path必须对应一个character device。
  • BlockDevice:path必须对应一个block device。

需要注意的是由于hostPath类型volume的数据和宿主机强绑定,如果pod停止后被schedule到其他节点,pod读取到的数据会有变化。

配置如下:

root@k8s-ansible-client:~/yaml/20210926/03# vim deploy_hostPath.yaml
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: /data/pop
          name: cache-n56-volume
      volumes:
      - name: cache-n56-volume
        hostPath:
          path: /opt/pop

root@k8s-ansible-client:~/yaml/20210926/03# kubectl apply -f deploy_hostPath.yaml 
deployment.apps/nginx-deployment created
root@k8s-ansible-client:~/yaml/20210926/03# kubectl get pods,deploy -o wide
NAME                                    READY   STATUS    RESTARTS         AGE    IP              NODE             NOMINATED NODE   READINESS GATES
pod/alpine-test                         1/1     Running   29 (3h14m ago)   16d    172.20.108.65   192.168.20.236   <none>           <none>
pod/kube100-site                        2/2     Running   0                2d     172.20.213.6    192.168.20.253   <none>           <none>
pod/nginx-deployment-79995cfd5d-nxhp4   1/1     Running   0                9s     172.20.191.15   192.168.20.147   <none>           <none>
pod/nginx-test-001                      1/1     Running   5 (3h50m ago)    3d1h   172.20.191.10   192.168.20.147   <none>           <none>
pod/nginx-test1                         1/1     Running   29 (3h23m ago)   16d    172.20.191.2    192.168.20.147   <none>           <none>
pod/nginx-test2                         1/1     Running   29 (3h23m ago)   16d    172.20.213.3    192.168.20.253   <none>           <none>
pod/nginx-test3                         1/1     Running   29 (3h23m ago)   16d    172.20.191.3    192.168.20.147   <none>           <none>

NAME                               READY   UP-TO-DATE   AVAILABLE   AGE   CONTAINERS     IMAGES   SELECTOR
deployment.apps/nginx-deployment   1/1     1            1           9s    ng-deploy-80   nginx    app=ng-deploy-80

验证

root@k8s-ansible-client:~/yaml/20210926/03# kubectl exec -it pod/nginx-deployment-79995cfd5d-nxhp4 bash
kubectl exec [POD] [COMMAND] is DEPRECATED and will be removed in a future version. Use kubectl exec [POD] -- [COMMAND] instead.
root@nginx-deployment-79995cfd5d-nxhp4:/# df -Th
Filesystem                        Type     Size  Used Avail Use% Mounted on
overlay                           overlay   20G  7.2G   12G  39% /
tmpfs                             tmpfs     64M     0   64M   0% /dev
tmpfs                             tmpfs    2.0G     0  2.0G   0% /sys/fs/cgroup
/dev/mapper/ubuntu--vg-ubuntu--lv ext4      20G  7.2G   12G  39% /data/pop
shm                               tmpfs     64M     0   64M   0% /dev/shm
tmpfs                             tmpfs    3.2G   12K  3.2G   1% /run/secrets/kubernetes.io/serviceaccount
tmpfs                             tmpfs    2.0G     0  2.0G   0% /proc/acpi
tmpfs                             tmpfs    2.0G     0  2.0G   0% /proc/scsi
tmpfs                             tmpfs    2.0G     0  2.0G   0% /sys/firmware

5.3.3 Nfs

在k8s-ansible-client上配置一个nfs,如下:

root@k8s-ansible-client:~# apt install nfs-kernel-server -y
root@k8s-ansible-client:~# mkdir -p /data/pop/{d11,js}
root@k8s-ansible-client:~# vim /etc/exports
/data/pop *(rw,sync,no_subtree_check)

root@k8s-ansible-client:~# systemctl restart nfs-kernel-server
root@k8s-ansible-client:~# showmount -e 192.168.20.250
Export list for 192.168.20.250:
/data/pop *

配置:

root@k8s-ansible-client:~/yaml/20210926/04# vim deloy_nfs.yaml
#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
        - mountPath: /usr/share/nginx/html/js
          name: my-nfs-js
      volumes:
      - name: my-nfs-volume
        nfs:
          server: 192.168.20.250
          path: /data/pop/d11
      - name: my-nfs-js
        nfs:
          server: 192.168.20.250
          path: /data/pop/js
---
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


root@k8s-ansible-client:~/yaml/20210926/04# kubectl apply -f deloy_nfs.yaml 
deployment.apps/nginx-deployment created
service/ng-deploy-80 created
root@k8s-ansible-client:~/yaml/20210926/04# kubectl get pods,deploy -o wide
NAME                                   READY   STATUS    RESTARTS         AGE    IP              NODE             NOMINATED NODE   READINESS GATES
pod/alpine-test                        1/1     Running   29 (3h26m ago)   16d    172.20.108.65   192.168.20.236   <none>           <none>
pod/kube100-site                       2/2     Running   0                2d     172.20.213.6    192.168.20.253   <none>           <none>
pod/nginx-deployment-f868c4766-crtjs   1/1     Running   0                3s     172.20.108.72   192.168.20.236   <none>           <none>
pod/nginx-test-001                     1/1     Running   5 (4h3m ago)     3d1h   172.20.191.10   192.168.20.147   <none>           <none>
pod/nginx-test1                        1/1     Running   29 (3h36m ago)   16d    172.20.191.2    192.168.20.147   <none>           <none>
pod/nginx-test2                        1/1     Running   29 (3h36m ago)   16d    172.20.213.3    192.168.20.253   <none>           <none>
pod/nginx-test3                        1/1     Running   29 (3h36m ago)   16d    172.20.191.3    192.168.20.147   <none>           <none>

NAME                               READY   UP-TO-DATE   AVAILABLE   AGE   CONTAINERS     IMAGES   SELECTOR
deployment.apps/nginx-deployment   1/1     1            1           3s    ng-deploy-80   nginx    app=ng-deploy-80
root@k8s-ansible-client:~/yaml/20210926/04# kubectl get svc
NAME           TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)        AGE
kubernetes     ClusterIP   10.68.0.1       <none>        443/TCP        17d
ng-deploy-80   NodePort    10.68.201.133   <none>        81:30016/TCP   7s

验证

root@k8s-ansible-client:~/yaml/20210926/04# kubectl exec -it pod/nginx-deployment-f868c4766-crtjs /bin/bash
kubectl exec [POD] [COMMAND] is DEPRECATED and will be removed in a future version. Use kubectl exec [POD] -- [COMMAND] instead.
root@nginx-deployment-f868c4766-crtjs:/# df -Th
Filesystem                        Type     Size  Used Avail Use% Mounted on
overlay                           overlay   20G  7.4G   12G  40% /
tmpfs                             tmpfs     64M     0   64M   0% /dev
tmpfs                             tmpfs    2.0G     0  2.0G   0% /sys/fs/cgroup
/dev/mapper/ubuntu--vg-ubuntu--lv ext4      20G  7.4G   12G  40% /etc/hosts
shm                               tmpfs     64M     0   64M   0% /dev/shm
192.168.20.250:/data/pop/js       nfs4      20G   13G  6.2G  67% /usr/share/nginx/html/js
tmpfs                             tmpfs    3.2G   12K  3.2G   1% /run/secrets/kubernetes.io/serviceaccount
192.168.20.250:/data/pop/d11      nfs4      20G   13G  6.2G  67% /usr/share/nginx/html/mysite
tmpfs                             tmpfs    2.0G     0  2.0G   0% /proc/acpi
tmpfs                             tmpfs    2.0G     0  2.0G   0% /proc/scsi
tmpfs                             tmpfs    2.0G     0  2.0G   0% /sys/firmware

# 创建两个文件
root@k8s-ansible-client:/data/pop# cd d11/
root@k8s-ansible-client:/data/pop/d11# ls
root@k8s-ansible-client:/data/pop/d11# echo "test202110112338" > index.html
root@k8s-ansible-client:/data/pop/d11# cd ../js/
root@k8s-ansible-client:/data/pop/js# ls
root@k8s-ansible-client:/data/pop/js# echo "111111111" > test.js

浏览器访问,如截图:

image.png

image.png

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,185评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,445评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,684评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,564评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,681评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,874评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,025评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,761评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,217评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,545评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,694评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,351评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,988评论 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,778评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,007评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,427评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,580评论 2 349

推荐阅读更多精彩内容