Skip to content

6 Kubernetes-存储

一、configmap

1)应用场景

传统运维的配置中心:批量修改受管机的配置文件:

​ 客户端监听配置文件服务端的config变化,从而实现修改变化

image-20230202091748351

云计算运维:pod通过监听apiversion,从 ETCD 中注入式传输配置文件到 pod

image-20230202091935769

注意:注入与共享

​ 注入: ​ 每次触发,仅传输一次,传输时有磁盘 I/O;无并发压力。

​ 共享: ​ 按需请求,每次请求都有磁盘 I/O;有并发压力

2)ConfigMap的创建

1、使用目录创建

​ 在目录中访问文件。文件内部若需要声明环境变量(格式为: key=value)

​ 文件内部若无需声明环境变量,仅传递值到pod中(格式: value)

​ 文件每行最后没有空格

​ 采用命令创建configmap(避免yaml需要指定的文件过繁)

​ 核心选项: --from-file= <Dir>

# 在目录中创建文件
[root@k8s-master01 ~]# mkdir 7;cd 7
[root@k8s-master01 7]# vim game.file
[root@k8s-master01 7]# cat game.file 
version=1.17
name=dave
age=18
[root@k8s-master01 7]# vim ui.properties
[root@k8s-master01 7]# cat ui.properties 
level=2
color=yellow
[root@k8s-master01 7]# pwd
/root/7

# 使用目录创建ConfigMap
[root@k8s-master01 7]# kubectl create configmap game-config --from-file=/root/7/

#查看创建configmap
[root@k8s-master01 7]# kubectl get configmap
NAME          DATA   AGE
game-config   2      11m

查看 configmap 中的信息:(对应指定路径下的文件内容)

image-20230202204315991

image-20230202204408178

2、使用文件创建

​ 仅指定文件创建 ConfigMap 。核心选项: --from-file=<fileName>

[root@k8s-master01 7]# kubectl create configmap ui-config --from-file=/root/7/ui.properties
configmap/ui-config created


[root@k8s-master01 7]# kubectl get cm ui-config
NAME        DATA   AGE
ui-config   1      9s
[root@k8s-master01 7]# kubectl get cm ui-config -o yaml
apiVersion: v1
data:
  ui.properties: |
    level=2
    color=yellow
kind: ConfigMap
metadata:
  creationTimestamp: "2023-02-02T12:45:37Z"
  name: ui-config
  namespace: default
  resourceVersion: "1160730"
  selfLink: /api/v1/namespaces/default/configmaps/ui-config
  uid: 75e79970-45bc-44e0-8a85-51f780ba974c
[root@k8s-master01 7]# kubectl describe cm ui-config
Name:         ui-config
Namespace:    default
Labels:       <none>
Annotations:  <none>

Data
====
ui.properties:
----
level=2
color=yellow

Events:  <none>

3、使用字面值创建

​ 仅指定单独 key 和 value 创建 ConfigMap

kubectl create configmap literal-config --from-literal=name=yangqin --from-literal=password=123456

image-20230202205312118

image-20230202205425328

3)pod 中使用 configmap

​ 将 configmap 的环境变量应用到 pod 中

1、使用 ConfigMap 来代替环境变量

​ 情况1:envFrom 选项。将指定的 ConfigMap 的环境变量直接应用到 pod 中

​ 情况2:env 选项。更改变量的 key,仍用 ConfigMap 中定义的环境变量的值

# 1.configmap.yaml 文件详解
apiVersion: v1              #使用 核心组v1版
kind: ConfigMap             #资源对象为 configmap
metadata:                   #定义资源对象中的元数据信息
  name: literal-config          #定义资源对象的名称为: literal-config
  namespace: default            #定义资源对象所在名字空间为:default,若不指定,默认也在default中
data:                       #定义资源对象中的存储信息
  name: dave                    #key=name;value=dave
  password: pass                #key=password;value=pass
# 2.configmap.yaml 文件详解
apiVersion: v1
kind: ConfigMap
metadata:
  name: env-config
  namespace: default
data:
  log_level: INFO               #key=log_level;value=INFO
Ⅰ、创建两个 configmap
[root@k8s-master01 7]# kubectl delete cm --all

[root@k8s-master01 7]# vim 1.configmap.yaml
[root@k8s-master01 7]# cat 1.configmap.yaml 
apiVersion: v1
kind: ConfigMap
metadata:
  name: literal-config
  namespace: default
data:
  name: dave
  password: pass


[root@k8s-master01 7]# kubectl apply -f 1.configmap.yaml 
configmap/literal-config created
[root@k8s-master01 7]# vim 2.configmap.yaml
[root@k8s-master01 7]# cat 2.configmap.yaml 
apiVersion: v1
kind: ConfigMap
metadata:
  name: env-config
  namespace: default
data:
  log_level: INFO
[root@k8s-master01 7]# kubectl apply -f 2.configmap.yaml 
configmap/env-config created


[root@k8s-master01 7]# kubectl get cm
NAME             DATA   AGE
env-config       1      3s
literal-config   2      24s
# 3.cm-pod.yaml 文件详解
apiVersion: v1                          #使用api版本为 core/v1
kind: Pod                               #指定创建的资源对象为 pod
metadata:                               #定义资源对象的元数据信息
  name: cm-env-test-pod                     #定义pod的名称为 cm-env-test-pod
spec:                                   #定义pod的期望
  containers:                               #指定容器的期望
    - name: test-container                      #定义容器名
      image: wangyanglinux/myapp:v1             #定义容器创建使用的镜像
      command: [ "/bin/sh", "-c", "env" ]       #定义容器启动的命令,启动时执行命令: env
      env:                                      #定义容器中的env环境变量(能更改key)
        - name: USERNAME                            #一个的key为 USERNAME
          valueFrom:                                #一个value的来源
            configMapKeyRef:                            #来源于configmap的其中的key的定义
              name: literal-config                          #来源configmpa的名称
              key: name                                     #来源configmap的key
        - name: PASSWORD                            #另一个的key为 PASSWORD
          valueFrom:                                #另一个value的来源
            configMapKeyRef:                            #来源于configmap的其中的key的定义
              name: literal-config                          #来源configmap的名称
              key: password                                 #来源configmap的key
      envFrom:                                  #定义容器中env环境变量(直接使用configmap中的定义)
        - configMapRef:                             #来源于configmap定义
            name: env-config                            #来源configmap的名称
  restartPolicy: Never
Ⅱ、使用 configmap 代替 pod中的环境变量
[root@k8s-master01 7]# vim 3.cm-pod.yaml
[root@k8s-master01 7]# cat 3.cm-pod.yaml
apiVersion: v1
kind: Pod
metadata:
  name: cm-env-test-pod
spec:
  containers:
    - name: test-container
      image: wangyanglinux/myapp:v1
      command: [ "/bin/sh", "-c", "env" ]
      env:
        - name: USERNAME
          valueFrom:
            configMapKeyRef:
              name: literal-config
              key: name
        - name: PASSWORD
          valueFrom:
            configMapKeyRef:
              name: literal-config
              key: password
      envFrom:
        - configMapRef:
            name: env-config
  restartPolicy: Never
[root@k8s-master01 7]# kubectl apply -f 3.cm-pod.yaml
Ⅲ、查看pod中的环境变量定义成功
[root@k8s-master01 7]# kubectl get cm,pod
NAME                       DATA   AGE
configmap/env-config       1      2m2s
configmap/literal-config   2      2m2s

NAME                  READY   STATUS      RESTARTS   AGE
pod/cm-env-test-pod   0/1     Completed   0          2m2s


# 容器中成功定义环境变量,来源于configmap
[root@k8s-master01 7]# kubectl logs cm-env-test-pod |egrep "USERNAME|PASSWORD|log_level"
USERNAME=dave
log_level=INFO
PASSWORD=pass

2、用 ConfigMap 设置命令行参数

环境变量可以当成启动命令被调用

# 4.cm-pod.yaml 文件详解
apiVersion: v1
kind: Pod
metadata:
  name: cm-command-dapi-test-pod
spec:
  containers:
    - name: test-container
      image: wangyanglinux/myapp:v1
      command: [ "/bin/sh", "-c", "echo $(USERNAME) $(PASSWORD)" ]      #定义启动命令为 输出环境变量
      env:                                                              #定义容器中的环境变量(更改key)
        - name: USERNAME                                                    #定义的key
          valueFrom:                                                        #值来源
            configMapKeyRef:                                                    #来源configmap
              name: literal-config                                                  #configmap名称
              key: name                                                             #configmap的key
        - name: PASSWORD
          valueFrom:
            configMapKeyRef:
              name: literal-config
              key: password
  restartPolicy: Never                                                      #定义pod重启策略:无论成功失败都不重启
Ⅰ、根据4.cm-pod.yaml 创建pod
[root@k8s-master01 7]# vim 4.cm-pod.yaml 
[root@k8s-master01 7]# cat 4.cm-pod.yaml 
apiVersion: v1
kind: Pod
metadata:
  name: cm-command-dapi-test-pod
spec:
  containers:
    - name: test-container
      image: wangyanglinux/myapp:v1
      command: [ "/bin/sh", "-c", "echo $(USERNAME) $(PASSWORD)" ]
      env:
        - name: USERNAME
          valueFrom:
            configMapKeyRef:
              name: literal-config
              key: name
        - name: PASSWORD
          valueFrom:
            configMapKeyRef:
              name: literal-config
              key: password
  restartPolicy: Never


[root@k8s-master01 7]# kubectl apply -f 4.cm-pod.yaml
Ⅱ、命令调用环境变量成功
[root@k8s-master01 7]# kubectl logs cm-command-dapi-test-pod
dave pass

3、通过数据卷插件使用 ConfigMap

volume + volumeMounts 将文件填入数据卷,在这个文件中 key 为文件名,value 为文件内容

​ 在 pod 的容器中实现挂载

# 创建
    文件名  key  文件内容  value

# 使用
    key 变成文件名
    value 变成文件内容
# 5.cm-volume-pod.yaml 文件详解
apiVersion: v1
kind: Pod
metadata:
  name: cm-volume-test-pod
spec:
  containers:
    - name: test-container
      image: wangyanglinux/myapp:v1
      volumeMounts:                     # pod期望中,容器中使用数据卷插件挂载
      - name: config-volume                 # 数据卷名为 config-volume
        mountPath: /etc/config              # 挂载到容器中位置 /etc/config
  volumes:                              # pod期望中,定义数据卷
    - name: config-volume                   # 数据卷名 config-volume
      configMap:                            # 使用configmap
        name: literal-config                    # configmap的名称
  restartPolicy: Never                  # 重启策略:无论成功与否,都不重启
Ⅰ、依据 5.cm-volume-pod.yaml 创建pod
[root@k8s-master01 7]# vim 5.cm-volume-pod.yaml
[root@k8s-master01 7]# cat 5.cm-volume-pod.yaml 
apiVersion: v1
kind: Pod
metadata:
  name: cm-volume-test-pod
spec:
  containers:
    - name: test-container
      image: wangyanglinux/myapp:v1
      volumeMounts:
      - name: config-volume
        mountPath: /etc/config
  volumes:
    - name: config-volume
      configMap:
        name: literal-config
  restartPolicy: Never

[root@k8s-master01 7]# kubectl apply -f 5.cm-volume-pod.yaml
Ⅱ、进入 pod 的容器,检查挂载
[root@k8s-master01 7]# kubectl exec -it cm-volume-test-pod -- /bin/sh
/ # ls /etc/config
name      password
/ # ls -l /etc/config
total 0
lrwxrwxrwx    1 root     root            11 Feb  2 15:06 name -> ..data/name
lrwxrwxrwx    1 root     root            15 Feb  2 15:06 password -> ..data/password
/ # cat /etc/config/name
dave/ # 
/ # cat /etc/config/password
pass/ # 

4)ConfigMap 热更新

​ pod 无需挂掉,即可实现更新(通过数据卷插件使用 ConfigMap 实现)

Ⅰ、使用 default.conf 文件创建 configmap

[root@k8s-master01 7]# vim default.conf 
[root@k8s-master01 7]# 
[root@k8s-master01 7]# cat default.conf 
server {
    listen 80 default_server;
    server_name example.com www.example.com;
    location / {
        root   /usr/share/nginx/html;
        index  index.html index.htm;
    }
}


[root@k8s-master01 7]# kubectl create configmap default-nginx --from-file=default.conf --dry-run -o yaml > 6.configmap.yaml
[root@k8s-master01 7]# cat 6.configmap.yaml 
apiVersion: v1
data:
  default.conf: |
    server {
        listen 80 default_server;
        server_name example.com www.example.com;
        location / {
            root   /usr/share/nginx/html;
            index  index.html index.htm;
        }
    }
kind: ConfigMap
metadata:
  creationTimestamp: null
  name: default-nginx


[root@k8s-master01 7]# kubectl apply -f 6.configmap.yaml 
configmap/default-nginx created

Ⅱ、创建 deployment 控制器

​ 定义副本模板,通过数据卷插件实现将 ConfigMap 存储在pod中挂载

[root@k8s-master01 7]# vim 7.deployment.yaml
[root@k8s-master01 7]# cat 7.deployment.yaml 
apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: nginx-test
  name: nginx-test
spec:
  replicas: 4
  selector:
    matchLabels:
      app: nginx-test
  template:
    metadata:
      labels:
        app: nginx-test
    spec:
      containers:
      - image: nginx
        name: nginx
        volumeMounts:
        - name: config-volume
          mountPath: /etc/nginx/conf.d/
      volumes:
        - name: config-volume
          configMap:
            name: default-nginx

[root@k8s-master01 7]# kubectl apply -f 7.deployment.yaml 
deployment.apps/nginx-test created

测试访问nginx:

$ kubectl get pod  -o wide      #获取nginx地址
$ curl <ip>

进入pod中的容器查看挂载:

[root@k8s-master01 7]# kubectl get pod 
NAME                          READY   STATUS    RESTARTS   AGE
nginx-test-65cd59dccb-7kj9k   1/1     Running   0          50s
nginx-test-65cd59dccb-mttkf   1/1     Running   0          50s
nginx-test-65cd59dccb-trvnn   1/1     Running   0          50s
nginx-test-65cd59dccb-wvbbz   1/1     Running   0          50s
[root@k8s-master01 7]# kubectl exec -it nginx-test-65cd59dccb-7kj9k -- /bin/sh
# cat /etc/nginx/conf.d/default.conf
server {
    listen 80 default_server;
    server_name example.com www.example.com;
    location / {
        root   /usr/share/nginx/html;
        index  index.html index.htm;
    }
}
# 

Ⅲ、修改 ConfigMap

$ kubectl edit configmap default-nginx


# 此处也可以通过 yaml 文件进行修改
[root@k8s-master01 7]# cp -a 6.configmap.yaml 8.configmap.yaml 
[root@k8s-master01 7]# vim 8.configmap.yaml 
[root@k8s-master01 7]# cat 6.configmap.yaml |grep 80
        listen 80 default_server;
[root@k8s-master01 7]# cat 8.configmap.yaml |grep 80
        listen 8080 default_server;
[root@k8s-master01 7]# kubectl apply -f 8.configmap.yaml 
configmap/default-nginx configured

等待一段时间后(大约十几秒)进入pod中的容器查看挂载:

# cat /etc/nginx/conf.d/default.conf
server {
    listen 8080 default_server;
    server_name example.com www.example.com;
    location / {
        root   /usr/share/nginx/html;
        index  index.html index.htm;
    }
}

Ⅳ、ConfigMap 更新后滚动更新 pod

​ 由于仅修改了配置文件,而未触发nginx的重启。configmap 更新后,还需要滚动更新pod

​ 打补丁。核心选项:.spec.template.metadata.annotations 中的 version/config

​ 每次通过修改 version/config 来触发滚动更新

1、查看默认情况下控制器信息:

image-20230202233520279

2、打补丁:
kubectl patch deployment nginx-test --patch '{"spec": {"template": {"metadata": {"annotations": {"version/config": "20190411" }}}}}'
3、再次查看控制器信息:

image-20230202233832631

4、打补丁之前到打补丁之后,实现了滚动更新

image-20230203090150770

5、测试访问
[root@k8s-master01 7]# kubectl get pod -o wide
NAME                          READY   STATUS    RESTARTS   AGE   IP              NODE         NOMINATED NODE   READINESS GATES
nginx-test-6ddcdb857d-45mrl   1/1     Running   0          17m   172.100.2.164   k8s-node02   <none>           <none>
nginx-test-6ddcdb857d-pcj5d   1/1     Running   0          17m   172.100.1.144   k8s-node01   <none>           <none>
nginx-test-6ddcdb857d-pvrgb   1/1     Running   0          17m   172.100.1.143   k8s-node01   <none>           <none>
nginx-test-6ddcdb857d-xwsgp   1/1     Running   0          17m   172.100.2.165   k8s-node02   <none>           <none>
[root@k8s-master01 7]# curl 172.100.2.164
curl: (7) Failed connect to 172.100.2.164:80; 拒绝连接
[root@k8s-master01 7]# curl 172.100.2.164:8080
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
html { color-scheme: light dark; }
body { width: 35em; margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif; }
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>

<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>

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

拓展:K8S 中的镜像下载策略

​ 默认情况下:imagePullPolicy: Always

​ Always:若指定的镜像为 latest 版,则每次构建容器都会进行镜像下载(无论本地有无此镜像)(

​ Never:若指定的镜像,本地没有 latest 版,则不使用

​ IfNotPresent:若指定的镜像,本地没有 latest 版,则进行下载;本地有 latest 版,则不进行下载。

​ 总结:镜像的版本号,尽量不要用 latest 定义版本

二、secret

为解决配置文件中存在敏感信息的问题(加密)

三种类型:

  • Service Account: 用来访问 Kubernetes API,由 Kubernetes 自动创建,并且会自动挂载到 Pod 的 /run/secrets/kubernetes.io/serviceaccount 目录中

  • Opaque Secret: base64编码格式的 Secret ,以此存储密码、密钥等

​ 拓展:base64编码加密、解密

# 加密:
    $ echo -n "yangqin" | base64
# 解密:
    $ echo -n "加密密文" | base64 -d
  • Kubernetes.io/dockerconfigjson:用于存储私有仓库信息

类型详解和实验:

1)Service Account

Service Account 用来访问 Kubernetes API,由 Kubernetes 自动创建,并且会自动挂载到 Pod的 /run/secrets/kubernetes.io/serviceaccount 目录中

$ kubectl run nginx --image nginx
deployment "nginx" created
$ kubectl get pods
NAME                     READY     STATUS    RESTARTS   AGE
nginx-3137573019-md1u2   1/1       Running   0          13s
$ kubectl exec nginx-3137573019-md1u2 ls /run/secrets/kubernetes.io/serviceaccount
ca.crt
namespace
token

2)Opaque Secret

Ⅰ、创建 Secret 对象

注意:key 为明文,value 必须为加密密文

#生成加密信息
[root@k8s-master01 7]# pwd
/root/7
[root@k8s-master01 7]# mkdir 2;cd 2
[root@k8s-master01 2]# echo -n "admin" | base64
YWRtaW4=
[root@k8s-master01 2]# echo -n "123456" | base64
MTIzNDU2

根据 1.secret.yaml 创建secret

# 1.secret.yaml 文件详解
apiVersion: v1                  #使用api版本 core/v1
kind: Secret                    #指定创建的资源对象为 Secret
metadata:                       #元数据信息
  name: mysecret                    #创建的secret名称为 mysecret
type: Opaque                    #创建的类型为 Opaque
data:                           #指定信息
  password: MTIzNDU2
  username: YWRtaW4=
[root@k8s-master01 2]# kubectl delete deployment --all
[root@k8s-master01 2]# vim 1.secret.yaml 
[root@k8s-master01 2]# cat 1.secret.yaml 
apiVersion: v1
kind: Secret
metadata:
  name: mysecret
type: Opaque
data:
  password: MTIzNDU2
  username: YWRtaW4=

[root@k8s-master01 2]# kubectl apply -f 1.secret.yaml 
secret/mysecret created

查看创建的 secret

[root@k8s-master01 2]# kubectl get secret mysecret
NAME       TYPE     DATA   AGE
mysecret   Opaque   2      2m42s

[root@k8s-master01 2]# kubectl describe secret mysecret
Name:         mysecret
Namespace:    default
Labels:       <none>
Annotations:  
Type:         Opaque

Data
====
password:  6 bytes
username:  5 bytes

[root@k8s-master01 2]# kubectl get secret mysecret -o yaml
apiVersion: v1
data:
  password: MTIzNDU2
  username: YWRtaW4=
kind: Secret
metadata:
  annotations:
    kubectl.kubernetes.io/last-applied-configuration: |
      {"apiVersion":"v1","data":{"password":"MTIzNDU2","username":"YWRtaW4="},"kind":"Secret","metadata":{"annotations":{},"name":"mysecret","namespace":"default"},"type":"Opaque"}
  creationTimestamp: "2023-02-03T01:33:18Z"
  name: mysecret
  namespace: default
  resourceVersion: "1182319"
  selfLink: /api/v1/namespaces/default/secrets/mysecret
  uid: a5f2344d-9bb5-42f0-ad59-a479fbf1590c
type: Opaque

[root@k8s-master01 2]# echo -n "MTIzNDU2" | base64 -d 
123456[root@k8s-master01 2]# 
[root@k8s-master01 2]# echo -n "YWRtaW4=" | base64 -d 
admin[root@k8s-master01 2]# 

Ⅱ、使用 Secret 方式

1、Secret 挂载到 volume中(数据卷实现)

volume+volumeMounts 基于 secret 挂载,会自动解码,且不可关闭(value必须为加密)

创建 pod ,将secret 挂载到 volume 中

[root@k8s-master01 2]# vim 2.pod.yaml 
[root@k8s-master01 2]# cat 2.pod.yaml 
apiVersion: v1
kind: Pod
metadata:
  labels:
    name: secret-test
  name: secret-test
spec:
  volumes:
  - name: volumes12
    secret:
      secretName: mysecret
  containers:
  - image: wangyanglinux/myapp:v1
    name: db
    volumeMounts:
    - name: volumes12
      mountPath: "/data"
[root@k8s-master01 2]# kubectl apply -f 2.pod.yaml

进入 pod 检查挂载

[root@k8s-master01 2]# kubectl get pod 
NAME          READY   STATUS    RESTARTS   AGE
secret-test   1/1     Running   0          12s
[root@k8s-master01 2]# kubectl exec -it secret-test -- /bin/sh
/ # cd /data
/data # ls
password  username
/data # cat password
123456/data # 
/data # cat username
2、Secret 导出到 pod 的环境变量中

​ env 中的 valueFrom 实现

创建pod,将secret导出到pod的环境变量中

[root@k8s-master01 2]# vim 3.pod.yaml
[root@k8s-master01 2]# cat 3.pod.yaml 
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  name: pod-deployment
spec:
  replicas: 2
  template:
    metadata:
      labels:
        app: pod-deployment
    spec:
      containers:
      - name: pod-1
        image: wangyanglinux/myapp:v1
        ports:
        - containerPort: 80
        env:
        - name: TEST_USER
          valueFrom:
            secretKeyRef:
              name: mysecret
              key: username
        - name: TEST_PASSWORD
          valueFrom:
            secretKeyRef:
              name: mysecret
              key: password
[root@k8s-master01 2]# kubectl apply -f 3.pod.yaml

进入pod的容器中查看环境变量

[root@k8s-master01 2]# kubectl get pod 
NAME                              READY   STATUS    RESTARTS   AGE
pod-deployment-747f78bc67-k2mvf   1/1     Running   0          20s
pod-deployment-747f78bc67-vhb9n   1/1     Running   0          20s
secret-test                       1/1     Running   0          5m18s

[root@k8s-master01 2]# kubectl exec -it pod-deployment-747f78bc67-k2mvf -- /bin/sh

/ # env |egrep "TEST_USER|TEST_PASSWORD"
TEST_PASSWORD=123456
TEST_USER=admin

3)dockerconfigjson

​ 封装仓库认证信息,在下载私有仓库中的镜像时,自动认证

Ⅰ、准备新的虚拟机安装私有仓库---harbor

前提准备:

配置harbor网络,仅留一张网卡,加入ikuai路由

​ ikuai地址为 192.168.20.199

[root@localhost network-scripts]# vim ifcfg-ens33 
[root@localhost network-scripts]# tail -n 5 ifcfg-ens33
IPADDR=192.168.20.206
PREFIX=24
GATEWAY=192.168.20.199
DNS1=114.114.114.114
DNS2=8.8.8.8
[root@localhost network-scripts]# vim ifcfg-ens34 
[root@localhost network-scripts]# cat ifcfg-ens34|grep ONBOOT
ONBOOT=no
[root@localhost network-scripts]# systemctl restart network


[root@localhost network-scripts]# ping www.baidu.com
PING www.a.shifen.com (110.242.68.4) 56(84) bytes of data.
64 bytes from 110.242.68.4 (110.242.68.4): icmp_seq=1 ttl=127 time=11.2 ms
^C
--- www.a.shifen.com ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 11.253/11.253/11.253/0.000 ms


# 设置主机名
$ hostnamectl set-hostname harbor.yq.com
$ reboot

每个节点的docker配置文件中,有信任的私有仓库信息字段

# master01节点中
[root@k8s-master01 ~]# cat /etc/docker/daemon.json 
{
  "exec-opts": ["native.cgroupdriver=systemd"],
  "log-driver": "json-file",
  "log-opts": {
    "max-size": "100m"
  },
  "insecure-registries": ["harbor.yq.com"],
  "registry-mirrors": ["https://kfp63jaj.mirror.aliyuncs.com"]
}

# node01节点中
[root@k8s-node01 ~]# cat /etc/docker/daemon.json 
{
  "exec-opts": ["native.cgroupdriver=systemd"],
  "log-driver": "json-file",
  "log-opts": {
    "max-size": "100m"
  },
  "insecure-registries": ["harbor.yq.com"],
  "registry-mirrors": ["https://kfp63jaj.mirror.aliyuncs.com"]
}


# node02节点中
[root@k8s-node02 ~]# cat /etc/docker/daemon.json 
{
  "exec-opts": ["native.cgroupdriver=systemd"],
  "log-driver": "json-file",
  "log-opts": {
    "max-size": "100m"
  },
  "insecure-registries": ["harbor.yq.com"],
  "registry-mirrors": ["https://kfp63jaj.mirror.aliyuncs.com"]
}

检查每个节点的hosts解析

[root@k8s-master01 ~]# vim /etc/hosts
[root@k8s-master01 ~]# cat /etc/hosts
127.0.0.1   localhost localhost.localdomain localhost4 localhost4.localdomain4
::1         localhost localhost.localdomain localhost6 localhost6.localdomain6

192.168.20.201  k8s-master01    m1
192.168.20.202  k8s-node01  n1
192.168.20.203  k8s-node02  n2

192.168.20.206  harbor.yq.com harbor


[root@k8s-master01 ~]# scp /etc/hosts root@n1:/etc/

[root@k8s-master01 ~]# scp /etc/hosts root@n2:/etc/

[root@k8s-master01 ~]# scp /etc/hosts root@harbor:/etc/

每个节点访问测试

节点访问测试

1、上传所需文件到harbor

image-20230203101631731

2、本地安装docker
[root@harbor ~]# ls
anaconda-ks.cfg                                       docker-compose
docker-ce-17.03.0.ce-1.el7.centos.x86_64.rpm          harbor-offline-installer-v1.2.0.tgz
docker-ce-selinux-17.03.0.ce-1.el7.centos.noarch.rpm  harbor.zip
[root@harbor ~]# 
[root@harbor ~]# 
[root@harbor ~]# yum -y install docker-c*
3、配置docker

拓展:br_netfilter 内核模块

​ 让经过网桥的流量必须经过防火墙处理(加上此模块节点不用重启,即可让docker运行)

$ modprobe br_netfilter         # 加载模块
$ modprobe -r br_netfilter      # 移除
[root@harbor ~]# modprobe br_netfilter      # 开启br_netfilter模块
[root@harbor ~]# mkdir /etc/docker          # 从n1节点配置docker配置文件
[root@harbor ~]# scp root@n1:/etc/docker/daemon.json /etc/docker/
[root@harbor ~]# systemctl enable docker --now      #运行docker
4、安装harbor
# 配置docker-compose命令
[root@harbor ~]# mv docker-compose /usr/local/bin/
[root@harbor ~]# chmod a+x /usr/local/bin/docker-compose 

# 修改harbor配置文件(主机名、https协议)
[root@harbor ~]# tar -xf harbor-offline-installer-v1.2.0.tgz 
[root@harbor ~]# mv harbor /usr/local/ ; cd /usr/local/harbor
[root@harbor harbor]# pwd
/usr/local/harbor
[root@harbor harbor]# vim harbor.cfg
[root@harbor harbor]# cat harbor.cfg |egrep "^hostname|ui_url_protocol"
hostname = harbor.yq.com
ui_url_protocol = https

# 根据harbor配置文件,在指定的证书位置创建证书
[root@harbor harbor]# mkdir -p /data/cert
[root@harbor harbor]# cd !$
cd /data/cert

# 创建证书
[root@harbor cert]# openssl genrsa -des3 -out server.key 2048
[root@harbor cert]# openssl req -new -key server.key -out server.csr
[root@harbor cert]# cp -a server.key server.key.org
[root@harbor cert]# openssl rsa -in server.key.org -out server.key
[root@harbor cert]# openssl x509 -req -days 365 -in server.csr -signkey server.key -out server.crt

# 安装harbor
[root@harbor cert]# cd -
/usr/local/harbor
[root@harbor harbor]# ./install.sh 
6、检查windows的hosts解析,浏览器访问
# Windows的hosts文件
192.168.20.206      harbor.yq.com

image-20230203104911768

7、harbor创建私有仓库

harbor创建私有仓库.md

docker tag SOURCE_IMAGE[:TAG] harbor.yq.com/dev/IMAGE[:TAG]

docker push harbor.yq.com/dev/IMAGE[:TAG]
8、在harbor中导入镜像到私有仓库
# 从官方下载镜像到本地
[root@harbor harbor]# docker pull wangyanglinux/myapp:v6

# 重新标记镜像
[root@harbor harbor]# docker tag wangyanglinux/myapp:v6 harbor.yq.com/dev/myapp:v6

# 登录私有仓库,并上传镜像
[root@harbor harbor]# docker login harbor.yq.com
Username: admin
Password: 
Login Succeeded
[root@harbor harbor]# docker push harbor.yq.com/dev/myapp:v6

​ harbor中存在私有仓库的镜像

image-20230203112022917

9、未加入认证信息的选项使用私有仓库的镜像
[root@k8s-master01 2]# ls
1.secret.yaml  2.pod.yaml  3.pod.yaml
[root@k8s-master01 2]# pwd
/root/7/2
[root@k8s-master01 2]# cp -a 3.pod.yaml 4.pod.yaml
[root@k8s-master01 2]# vim 4.pod.yaml
[root@k8s-master01 2]# cat 4.pod.yaml
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  name: dockerconfigjson
spec:
  replicas: 2
  template:
    metadata:
      labels:
        app: pod-deployment
    spec:
      containers:
      - name: pod-1
        image: harbor.yq.com/dev/myapp:v6
        ports:
        - containerPort: 80
        env:
        - name: TEST_USER
          valueFrom:
            secretKeyRef:
              name: mysecret
              key: username
        - name: TEST_PASSWORD
          valueFrom:
            secretKeyRef:
              name: mysecret
              key: password

# 清理
[root@k8s-master01 2]# kubectl delete deployment --all
[root@k8s-master01 2]# kubectl delete pod --all

# 创建pod发现镜像下载失败。因为没有认证信息
[root@k8s-master01 2]# kubectl apply -f 4.pod.yaml 
deployment.extensions/dockerconfigjson created
[root@k8s-master01 2]# kubectl get pod 
NAME                                READY   STATUS             RESTARTS   AGE
dockerconfigjson-755598986f-bt5cn   0/1     ImagePullBackOff   0          17s
dockerconfigjson-755598986f-zb5fq   0/1     ImagePullBackOff   0          17s

Ⅱ、创建dockerconfigjson

命令模板:

kubectl create secret docker-registry myregistrykey --docker-server=DOCKER_REGISTRY_SERVER --docker-username=DOCKER_USER --docker-password=DOCKER_PASSWORD --docker-email=DOCKER_EMAIL
$ kubectl create secret docker-registry myregistrykey --docker-server=harbor.yq.com --docker-username=admin --docker-password=Harbor12345 --docker-email=yq@qq.com

Ⅲ、创建控制器

​ 实现:根据认证信息的认证,从私有仓库下载镜像

加入认证信息的选项使用私有仓库的镜像
[root@k8s-master01 2]# vim 5.pod.yaml 
[root@k8s-master01 2]# cat 5.pod.yaml 
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  name: dockerconfigjson-1
spec:
  replicas: 2
  template:
    metadata:
      labels:
        app: pod-deployment
    spec:
      imagePullSecrets:
        - name: myregistrykey
      containers:
      - name: pod-1
        image: harbor.yq.com/dev/myapp:v6
        ports:
        - containerPort: 80
        env:
        - name: TEST_USER
          valueFrom:
            secretKeyRef:
              name: mysecret
              key: username
        - name: TEST_PASSWORD
          valueFrom:
            secretKeyRef:
              name: mysecret
              key: password
[root@k8s-master01 2]# kubectl apply -f 5.pod.yaml 
[root@k8s-master01 2]# kubectl get pod 
NAME                                  READY   STATUS    RESTARTS   AGE
dockerconfigjson-1-67476858d7-ctttj   1/1     Running   0          5s
dockerconfigjson-1-67476858d7-n22tz   1/1     Running   0          5s

注意:在使用 imagePullSecrets 时可以使用多个认证信息的 dockerconfigjson

apiVersion: v1
kind: Pod
metadata:
  name: foo
spec:
  containers:
    - name: foo
      image: hub.hongfu.com/wangyang/myapp:v1
  imagePullSecrets:
    - name: myregistrykey
    - name: yqregistrykey
    - name: xxhfregistrykey

三、volume

拓展:mfs 对接到 K8S 集群

​ mfs 挂载到 K8S 集群中,利用 hostpath 的方式

image-20230202193457734

1)卷的类型

Kubernetes 支持以下类型的卷:

  • awsElasticBlockStore azureDisk azureFile cephfs csi downwardAPI emptyDir
  • fc flocker gcePersistentDisk gitRepo glusterfs hostPath iscsi local nfs
  • persistentVolumeClaim projected portworxVolume quobyte rbd scaleIO secret
  • storageos vsphereVolume

2)emptyDir

​ 临时卷

​ 生命周期==pod生命周期

​ 应用场景:a.容器间的共享存储

​ b.恢复点,暂存空间

实验:实现暂存空间

​ 核心部分:

      volumes:
        - name: input
          emptyDir: {}
        - name: output
          emptyDir: {}

image-20230202194413400

Ⅰ、创建
[root@k8s-master01 2]# vim 6.job.yaml
[root@k8s-master01 2]# cat 6.job.yaml
apiVersion: batch/v1
kind: Job
metadata:
  name: jobs-empty
spec:
  template:
    spec:
      restartPolicy: Never
      initContainers:
        - name: job-1
          image: busybox:1.34.1
          command:
            - 'sh'
            - '-c'
            - >
              for i in 1 2 3;
              do
                echo "job-1 `date`";
                sleep 1s;
              done;
              echo job-1 GG > /srv/input/code
          volumeMounts:
            - mountPath: /srv/input/
              name: input
        - name: job-2
          image: busybox:1.34.1
          command:
            - 'sh'
            - '-c'
            - >
              for i in 1 2 3;
              do
                echo "job-2 `date`";
                sleep 1s;
              done;
              cat /srv/input/code &&
              echo job-2 GG  > /srv/input/output/file
          volumeMounts:
            - mountPath: /srv/input/
              name: input
            - mountPath: /srv/input/output/
              name: output
      containers:
        - name: job-3
          image: busybox:1.34.1
          command:
            - 'sh'
            - '-c'
            - >
              echo "job-1 and job-2 completed";
              sleep 3s;
              cat /srv/output/file
          volumeMounts:
            - mountPath: /srv/output/
              name: output
      volumes:
        - name: input
          emptyDir: {}
        - name: output
          emptyDir: {}


[root@k8s-master01 2]# kubectl apply -f 6.job.yaml
Ⅱ、验证
[root@k8s-master01 2]# kubectl get pod 
NAME                                  READY   STATUS      RESTARTS   AGE
dockerconfigjson-1-67476858d7-ctttj   1/1     Running     0          10m
dockerconfigjson-1-67476858d7-n22tz   1/1     Running     0          10m
dockerconfigjson-755598986f-5q5bb     1/1     Running     0          9m51s
dockerconfigjson-755598986f-m4jb6     1/1     Running     0          9m51s
jobs-empty-tgv7v                      0/1     Completed   0          55s


[root@k8s-master01 2]# kubectl logs jobs-empty-tgv7v -c job-1
job-1 Fri Feb  3 03:49:24 UTC 2023
job-1 Fri Feb  3 03:49:25 UTC 2023
job-1 Fri Feb  3 03:49:26 UTC 2023
[root@k8s-master01 2]# kubectl logs jobs-empty-tgv7v -c job-2
job-2 Fri Feb  3 03:49:28 UTC 2023
job-2 Fri Feb  3 03:49:29 UTC 2023
job-2 Fri Feb  3 03:49:30 UTC 2023
job-1 GG
[root@k8s-master01 2]# kubectl logs jobs-empty-tgv7v -c job-3
job-1 and job-2 completed
job-2 GG

3)hostpath

​ 主机中的路径,挂载到集群中

hostpath 的用途:

  • 运行的容器,需要访问 docker 中其他的容器。使用 /var/lib/dockerhostpath
  • 在容器中运行 cAdvisor(猫头鹰)监控。/dev/cgrouphostpath
  • 存在的 hostpath,创建 pod时,是否在运行pod之前运行hostpath,是否应该创建,创建的 hostpath 形式

除了所需的 path 属性之外,用户还可以为 hostPath 卷指定 type


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

注意:

​ a、hostpath 声明的节点主机路径,若在每个节点中路径下内容不同,即使其他配置相同,也可能会导致 pod 的行为不同

​ b、若 Kubernetes 按照计划,添加资源感知调度时,将无法考虑 hostpath 使用的资源(挂载的位置控制无法判断)

​ c、确认主机路径的权限,能否被容器所调用

实验:使用hostpath挂载

[root@k8s-master01 2]# vim 7.pod.yaml 
[root@k8s-master01 2]# cat 7.pod.yaml 
apiVersion: v1
kind: Pod
metadata:
  name: test-pd
spec:
  containers:
  - image: wangyanglinux/myapp:v1
    name: test-container
    volumeMounts:
    - mountPath: /test-pd
      name: test-volume
  volumes:
  - name: test-volume
    hostPath:
      path: /data
      type: DirectoryOrCreate
[root@k8s-master01 2]# kubectl apply -f 7.pod.yaml 
pod/test-pd configured
[root@k8s-master01 2]# kubectl get pod 
NAME                                  READY   STATUS      RESTARTS   AGE
dockerconfigjson-1-67476858d7-ctttj   1/1     Running     0          21m
dockerconfigjson-1-67476858d7-n22tz   1/1     Running     0          21m
dockerconfigjson-755598986f-5q5bb     1/1     Running     0          20m
dockerconfigjson-755598986f-m4jb6     1/1     Running     0          20m
jobs-empty-tgv7v                      0/1     Completed   0          11m
test-pd     

四、PersistentVolume(PV)

1)概念

1、PersistentVolume (PV):由管理员设置的存储

2、PersistentVolumeClain (PVC):用户存储的请求

3、PV 分类:

​ 静态pv:存储工程师提前创建好了 PV ,业务工程师后期创建 PVC直接进行绑定

​ 动态pv:由云供应商提供,云供应商的对象存储,根据业务工程师创建PVC的需求创建PV

image-20230203180044327

image-20230203180101363

4、对象与过程

​ 面对对象:更偏向模块的使用

​ 面对过程:更偏向最底层开始,进行使用

5、PVC 与 PV 进行绑定

  • 容量
  • 读写策略( PV 访问模式)(一 一匹配)(并非所有存储服务都有这三个,对应后面的 PVC指出的插件类型)
  • 单节点读写---ReadWriteOnce---RWO
  • 多节点读写---ReadWriteMany---RWX
  • 多节点只读---ReadOnlyMany---ROX
  • 类(一 一匹配)
  • 回收策略
  • 保留---Retain---手动回收
  • 回收---Recycle---基本擦除( rm -rf /thevolume/*
  • 删除---Delete---关联的存储资产将被删除

6、PVC 支持的插件类型

Volume 插件 ReadWriteOnce ReadOnlyMany ReadWriteMany
AWSElasticBlockStoreAWSElasticBlockStore - -
AzureFile
AzureDisk - -
CephFS
Cinder - -
FC -
FlexVolume -
Flocker - -
GCEPersistentDisk -
Glusterfs
HostPath - -
iSCSI -
PhotonPersistentDisk - -
Quobyte
NFS
RBD -
VsphereVolume - - (当 pod 并列时有效)
PortworxVolume -
ScaleIO -
StorageOS - -

7、状态

  • 卷可以处于以下的某种状态:
  • Available(可用)——一块空闲资源还没有被任何声明绑定

  • Bound(已绑定)——卷已经被声明绑定

  • Released(已释放)——声明被删除,但是资源还未被集群重新声明(不能被别的 PVC 绑定,需要修复)

  • Failed(失败)——该卷的自动回收失败

命令行会显示绑定到 PV 的 PVC 的名称

8、持久化卷声明的保护(PVC保护)

​ 若pod存储在,PVC 无法删除

2)实验

1、在 harbor 中部署 NFS

​ NFS 工作原理: rpc服务端启动

​ nfs服务端启动,并向rpc服务端注册端口信息

​ nfs客户端启动rpc,向rpc服务端获取nfs信息

​ nfs客户端获取nfs信息后,建立连接

/etc/exports 中的 sync:同步共享

​ async:异步共享

# 安装软件包
    [root@harbor ~]# yum -y install nfs-common nfs-utils rpcbind

# 配置存储位置、文件
[root@harbor ~]# mkdir /nfsdata
[root@harbor nfsdata]# for i in {1..10};do mkdir $i;echo "yangqin---$i"> $i/index.html ; done
[root@harbor nfsdata]# for i in {1..10};do cat $i/index.html;done
yangqin---1
yangqin---2
yangqin---3
yangqin---4
yangqin---5
yangqin---6
yangqin---7
yangqin---8
yangqin---9
yangqin---10


# 设置权限相关、启动服务
    # 此处一般为666,为了避免K8S集群中反复调整权限,所以给777(生产环境中需要严格设置权限)
[root@harbor nfsdata]# chmod -R 777 /nfsdata/       
[root@harbor nfsdata]# chown -R nfsnobody /nfsdata/

[root@harbor nfsdata]# vim /etc/exports
[root@harbor nfsdata]# cat /etc/exports
/nfsdata/1 *(rw,no_root_squash,no_all_squash,sync)
/nfsdata/2 *(rw,no_root_squash,no_all_squash,sync)
/nfsdata/3 *(rw,no_root_squash,no_all_squash,sync)
/nfsdata/4 *(rw,no_root_squash,no_all_squash,sync)
/nfsdata/5 *(rw,no_root_squash,no_all_squash,sync)
/nfsdata/6 *(rw,no_root_squash,no_all_squash,sync)
/nfsdata/7 *(rw,no_root_squash,no_all_squash,sync)
/nfsdata/8 *(rw,no_root_squash,no_all_squash,sync)
/nfsdata/9 *(rw,no_root_squash,no_all_squash,sync)
/nfsdata/10 *(rw,no_root_squash,no_all_squash,sync)

# 重启服务
[root@harbor nfsdata]# systemctl restart nfs rpcbind


# 在每一个节点中都安装nfs的客户端
$ yum -y install nfs-common nfs-utils rpcbind

2、节点测试 NFS 挂载

[root@k8s-master01 ~]# mkdir /test
[root@k8s-master01 ~]# mount -t nfs 192.168.20.206:/nfsdata/1/ /test/
[root@k8s-master01 ~]# cd /test/;ls
index.html
[root@k8s-master01 test]# cat index.html 
yangqin---1
[root@k8s-master01 test]# echo yangqin >> index.html ;cat index.html 
yangqin---1
yangqin
[root@k8s-master01 test]# cd ;umount /test;rm -rf /test/

3、K8S 中创建 PV

# 1.pv.yaml 文件模板详解
apiVersion: v1                              # 使用接口组版本为 core/v1
kind: PersistentVolume                      # 资源对象为 PersistentVolume
metadata:                                   # 定义资源对象的元数据
  name: nfspv1                                  # 定义资源对象名称为 nfspv1
spec:                                       # 资源对象的期望
  capacity:                                     # 指定容量
    storage: 1Gi                                    # 指定存储容量为 1G
  accessModes:                                  # 指定读写策略
    - ReadWriteOnce                                 # 读写策略为 单节点读写
  persistentVolumeReclaimPolicy: Retain         # 指定回收策略为 保留
  storageClassName: nfs                         # 指定存储类 nfs
  nfs:                                          # nfs相关
    path: /nfsdata/1                                # nfs服务端路径
    server: 192.168.20.206                          # nfs服务端地址
[root@k8s-master01 ~]# mkdir 8;cd 8

# 确定nfs服务端的路径,在 1.pv.yaml 中写入
[root@k8s-master01 8]# showmount -e 192.168.20.206
Export list for 192.168.20.206:
/nfsdata/10 *
/nfsdata/9  *
/nfsdata/8  *
/nfsdata/7  *
/nfsdata/6  *
/nfsdata/5  *
/nfsdata/4  *
/nfsdata/3  *
/nfsdata/2  *
/nfsdata/1  *

[root@k8s-master01 8]# vim 1.pv.yaml 
[root@k8s-master01 8]# kubectl apply -f 1.pv.yaml 

[root@k8s-master01 8]# kubectl get pv
NAME      CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS      CLAIM   STORAGECLASS   REASON   AGE
nfspv1    1Gi        RWO            Retain           Available           nfs                     4s
nfspv10   1Gi        RWO            Retain           Available           nfs                     4s
nfspv2    1Gi        RWX            Retain           Available           nfs                     4s
nfspv3    1Gi        RWO            Retain           Available           mfs                     4s
nfspv4    2Gi        RWO            Retain           Available           nfs                     4s
nfspv5    1Gi        RWO            Retain           Available           nfs                     4s
nfspv6    1Gi        RWO            Retain           Available           nfs                     4s
nfspv7    1Gi        RWO            Retain           Available           nfs                     4s
nfspv8    1Gi        RWO            Retain           Available           nfs                     4s
nfspv9    1Gi        RWO            Retain           Available           nfs                     4s

1.pv.yaml 文件详细内容:

4、结合 statefulSet 控制器创建 PVC

  • 拓展:statefulSet 控制器(针对有状态服务部署的控制器)

​ 特性:1.有序创建;有序删除

​ 2.具备稳定的存储卷存储

​ 3.有稳定的网络访问(基于域名)

  • 结合 statefulSet 控制器。核心选项: VolumeClaimTemplates

ClusterIp: None:无头服务,不具备调度功能,可提供域名解析

  • pod命名:控制器名-数字(数字从0开始)

PVC 命名:卷名-PV名

  • 2.headless.yaml3.statefulset.yaml 文件详解:

headless.yaml.md

实验步骤
Ⅰ、创建无头服务的service
[root@k8s-master01 8]# vim 2.headless.yaml 
[root@k8s-master01 8]# kubectl apply -f 2.headless.yaml 
service/nginx created
[root@k8s-master01 8]# kubectl get svc
NAME         TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)   AGE
kubernetes   ClusterIP   10.96.0.1    <none>        443/TCP   24d
nginx        ClusterIP   None         <none>        80/TCP    3s


[root@k8s-master01 8]# vim 3.statefulSet.yaml 
Ⅱ、创建statefulSet控制器

创建完成以后,马上查看pod变化,验证 statefulSet控制器的有序创建

statefulSet控制器有序创建

删除statefulSet控制器,验证有序删除

statefulSet控制器有序删除

再次创建statefulSet控制器

[root@k8s-master01 8]# kubectl apply -f 3.statefulSet.yaml

5、查看 PV ,验证 PVC 与 PV 的绑定规则

​ 依据:容量、读写策略、类、回收策略

# 查看statefulset控制器信息(由此可以确定控制器中的pod命名)
[root@k8s-master01 8]# kubectl get statefulset
NAME   READY   AGE
web    3/3     4m31s


# 查看pv信息,由此可以验证:pv与pvc的绑定需要依据:  容量(可以超过、最好相等)
                                            读写策略(一 一匹配)
                                            类(一 一匹配)
[root@k8s-master01 8]# kubectl get pv
NAME      CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS      CLAIM               STORAGECLASS   REASON   AGE
nfspv1    1Gi        RWO            Retain           Available                       nfs                     49m
nfspv10   1Gi        RWO            Retain           Available                       nfs                     49m
nfspv2    1Gi        RWX            Retain           Available                       nfs                     49m
nfspv3    1Gi        RWO            Retain           Available                       mfs                     49m
nfspv4    2Gi        RWO            Retain           Available                       nfs                     49m
nfspv5    1Gi        RWO            Retain           Bound       default/www-web-0   nfs                     49m
nfspv6    1Gi        RWO            Retain           Available                       nfs                     49m
nfspv7    1Gi        RWO            Retain           Bound       default/www-web-1   nfs                     49m
nfspv8    1Gi        RWO            Retain           Bound       default/www-web-2   nfs                     49m
nfspv9    1Gi        RWO            Retain           Available                       nfs                     49m
[root@k8s-master01 8]# kubectl get pvc
NAME        STATUS   VOLUME   CAPACITY   ACCESS MODES   STORAGECLASS   AGE
www-web-0   Bound    nfspv5   1Gi        RWO            nfs            13m
www-web-1   Bound    nfspv7   1Gi        RWO            nfs            13m
www-web-2   Bound    nfspv8   1Gi        RWO            nfs            13m



# 扩容statefulset控制器的副本数量为10
[root@k8s-master01 8]# cp -a 3.statefulSet.yaml 4.statefulSet.yaml 
[root@k8s-master01 8]# vim 4.statefulSet.yaml 
[root@k8s-master01 8]# kubectl apply -f 4.statefulSet.yaml


# 查看pv和pvc绑定数量为8,剩下两个pv并没有和pvc绑定。进一步验证了绑定规则
[root@k8s-master01 8]# kubectl get pv |grep -i bound |wc -l
8

6、测试statefulSet控制器的稳定持久存储

​ 将控制器创建的pod删除后,虽然更改pod地址,但是仍然会创建同名的pod,并且存在稳定的持久存储。

# 删除pod,重建pod后,持久存储
[root@k8s-master01 8]# kubectl get pod -o wide |grep web-0
web-0   1/1     Running   0          27s   172.100.1.173   k8s-node01   <none>           <none>
[root@k8s-master01 8]# curl 172.100.1.173
yangqin---5
[root@k8s-master01 8]# kubectl delete pod web-0
pod "web-0" deleted
[root@k8s-master01 8]# kubectl get pod -o wide |grep web-0
web-0   1/1     Running   0          2s    172.100.1.174   k8s-node01   <none>           <none>
[root@k8s-master01 8]# curl 172.100.1.174
yangqin---5

# 进入pod的容器中,改变文件,再次删除pod,重建pod后,持久存储
[root@k8s-master01 8]# kubectl exec -it web-0 -- /bin/sh
/ # echo "yangqin" >> /usr/share/nginx/html/index.html 
/ # exit
[root@k8s-master01 8]# kubectl delete pod web-0
pod "web-0" deleted
[root@k8s-master01 8]# kubectl get pod -o wide |grep web-0
web-0   1/1     Running   0          7s    172.100.1.175   k8s-node01   <none>           <none>
[root@k8s-master01 8]# curl 172.100.1.175
yangqin---5
yangqin
[root@k8s-master01 8]# kubectl delete pod web-0
pod "web-0" deleted
[root@k8s-master01 8]# kubectl get pod -o wide |grep web-0
web-0   1/1     Running   0          6s    172.100.1.176   k8s-node01   <none>           <none>
[root@k8s-master01 8]# curl 172.100.1.176
yangqin---5
yangqin

(根据上一个实验的特性,结合service的无头服务,可以实现域名的持久访问)

7、测试 statefulSet 控制器的稳定地址访问

​ 当 web-0 删除后,会自动创建,仍能用域名访问

​ 测试1: dig 命令进行域名解析

dig -t A web-0.nginx.default.svc.cluster.local. @10.96.0.10

​ 测试2:新建一个其他pod,实现域名访问

  • 此处的域名

pod名.service名.名字空间名.svc.K8S集群域名.

podName.headlessServiceName.namespace.svc.domainName.
== 
statefulSetName-num(0).headlessServiceName.namespace.svc.domainName.
实验步骤

dns命令解析:

# 获取K8S中的dns地址
[root@k8s-master01 8]# ipvsadm -Ln |grep :53
TCP  10.96.0.10:53 rr
  -> 172.100.1.151:53             Masq    1      0          0         
  -> 172.100.1.152:53             Masq    1      0          0         
UDP  10.96.0.10:53 rr
  -> 172.100.1.151:53             Masq    1      0          0         
  -> 172.100.1.152:53             Masq    1      0          0 

# 进行dns解析(解析的地址都是pod中的web-0,若pod重建,dns解析会实时更改。从而实现了域名的稳定访问)
[root@k8s-master01 8]# dig -t A web-0.nginx.default.svc.cluster.local. @10.96.0.10|grep ^web-0
web-0.nginx.default.svc.cluster.local. 29 IN A  172.100.1.177
[root@k8s-master01 8]# kubectl delete pod web-0 
pod "web-0" deleted
[root@k8s-master01 8]# dig -t A web-0.nginx.default.svc.cluster.local. @10.96.0.10|grep ^web-0
web-0.nginx.default.svc.cluster.local. 30 IN A  172.100.1.178

新建一个pod,实现域名对web-0的持久访问:

[root@k8s-master01 8]# vim 5.pod.yaml 
[root@k8s-master01 8]# cat 5.pod.yaml 
apiVersion: v1
kind: Pod
metadata:
  name: test
spec:
  containers:
  - image: wangyanglinux/myapp:v1
    name: nginx
[root@k8s-master01 8]# kubectl apply -f 5.pod.yaml 



[root@k8s-master01 8]# kubectl exec -it test -- /bin/sh
/ # 
/ # wget web-0.nginx.default.svc.cluster.local./index.html && cat index.html && rm -rf index.html
Connecting to web-0.nginx.default.svc.cluster.local. (172.100.1.178:80)
index.html           100% |********************************************************|    20   0:00:00 ETA
yangqin---5
yangqin
/ # 
/ # exit


[root@k8s-master01 8]# kubectl delete pod web-0
pod "web-0" deleted
[root@k8s-master01 8]# kubectl exec -it test -- /bin/sh
/ # wget web-0.nginx.default.svc.cluster.local./index.html && cat index.html && rm -rf index.html
Connecting to web-0.nginx.default.svc.cluster.local. (172.100.1.180:80)
index.html           100% |********************************************************|    20   0:00:00 ETA
yangqin---5
yangqin
  • 注意:若删除 statefulSet 控制器,PVC 仍然存在,再次运行相同的yaml文件的控制器,仍然能够使用挂载

因为删除控制器后,pv和pvc仍然处于绑定状态

[root@k8s-master01 8]# kubectl delete statefulset --all

[root@k8s-master01 8]# kubectl apply -f 4.statefulSet.yaml 

[root@k8s-master01 8]# kubectl get pvc

[root@k8s-master01 8]# kubectl get pod -o wide |grep web-0
web-0   1/1     Running   0          52s     172.100.2.184   k8s-node02   <none>           <none>
[root@k8s-master01 8]# curl 172.100.2.184
yangqin---5
yangqin

​ 若删除pvc以后,pv处于释放状态(不可绑定状态,可以在存储位置进行数据备份)

​ 若备份完成,需要修复后才能处于可绑定状态

[root@k8s-master01 8]# kubectl delete pvc --all

[root@k8s-master01 8]# kubectl get pv
NAME      CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS      CLAIM               STORAGECLASS   REASON   AGE
nfspv1    1Gi        RWO            Retain           Released    default/www-web-5   nfs                     105m
nfspv10   1Gi        RWO            Retain           Released    default/www-web-6   nfs                     105m
nfspv2    1Gi        RWX            Retain           Available                       nfs                     105m
nfspv3    1Gi        RWO            Retain           Available                       mfs                     105m
nfspv4    2Gi        RWO            Retain           Released    default/www-web-7   nfs                     105m
nfspv5    1Gi        RWO            Retain           Released    default/www-web-0   nfs                     105m
nfspv6    1Gi        RWO            Retain           Released    default/www-web-3   nfs                     105m
nfspv7    1Gi        RWO            Retain           Released    default/www-web-1   nfs                     105m
nfspv8    1Gi        RWO            Retain           Released    default/www-web-2   nfs                     105m
nfspv9    1Gi        RWO            Retain           Released    default/www-web-4   nfs                     105m

8、已经释放后,修复 PV 为可用

​ 可以:删除pv,重新构建相同的pv

​ 推荐使用:删除 PV 中的 ClaimRef

[root@k8s-master01 8]# kubectl get pv |grep nfspv4
nfspv4    2Gi        RWO            Retain           Released    default/www-web-7   nfs                     113m
[root@k8s-master01 8]# kubectl edit pv nfspv4

image-20230203205554274

# 再次查看 nfspv4的状态为可绑定状态
[root@k8s-master01 8]# kubectl get pv |grep nfspv4
nfspv4    2Gi        RWO            Retain           Available                       nfs                     114m