05.Kubernetes Volume和Kubernetes ConfigMap

2026-04-22

复习和预习

昨天课堂内容

  1. yaml 格式
  2. Pod 管理
  3. Volume

课前复习

  1. kubernetes 中 pod 和 容器区别?
  2. kubernetes 为什么直接管理 pod 而不是容器?
  3. 解释 pod 中 pause 容器作用。
  4. 解释 container 属性 ImagePullPolicy 作用。有哪些可用配置?
  5. 解释 pod 属性 restartPolicy 作用。有哪些可用配置?
  6. 解释kubectl api-resources 作用。
  7. 解释kubectl explain 作用。
  8. Kubernetes 集群master组件是以pod方式运行的,这写pod是如何启动的?

今天课堂内容

  1. Volume
  2. Configure
  3. 部署一个自己网站。

Kubernetes Volume

学习参考:

环境准备

bash 复制代码
[root@master30 ~]# kubectl create ns storage
[root@master30 ~]# kubectl config set-context --current --namespace storage

Volume 类型

Kubernetes支持Volume类型有:

  • emptyDir
  • hostPath
  • gcePersistentDisk
  • awsElasticBlockStore
  • nfs
  • iscsi
  • fc (fibre channel)
  • flocker
  • glusterfs
  • rbd
  • cephfs
  • gitRepo
  • secret
  • persistentVolumeClaim
  • downwardAPI
  • projected
  • azureFileVolume
  • azureDisk
  • vsphereVolume
  • Quobyte
  • PortworxVolume
  • ScaleIO
  • StorageOS
  • local

emptyDir

默认情况下,当Pod分配到Node上时,将会创建emptyDir,只要Node上的Pod一直运行,Volume就会一直存。当Pod(不管任何原因)从Node上被删除时,emptyDir也同时会删除,存储的数据也将永久删除。

**实验:**准备一个包含2个容器的pod,使用emptyDir。

bash 复制代码
[root@master30 ~]# vim pod-emptyDir.yaml
yaml 复制代码
apiVersion: v1
kind: Pod
metadata:
  name: busybox
  labels:
    app: busybox
spec:
  volumes:
  - name: datavolume
    emptyDir: {} 
  containers:
  - name: busybox1
    image: docker.io/library/busybox
    imagePullPolicy: IfNotPresent
    command: ['sh', '-c', 'echo Hello Kubernetes! && sleep 3600']
    volumeMounts:
    - mountPath: /data
      name: datavolume
  - name: busybox2
    image: docker.io/library/busybox
    imagePullPolicy: IfNotPresent
    command: ['sh', '-c', 'echo Hello Kubernetes! && sleep 3600']
    volumeMounts:
    - mountPath: /data
      name: datavolume

配置说明:

  • spec.volumes:定义卷,是默认卷类型。

  • spec.containers.volumeMounts:引用卷

bash 复制代码
# 创建pod
[root@master30 ~]# kubectl apply -f pod-emptyDir.yaml
pod/busybox created

# 获取容器ID
[root@master30 ~]# kubectl describe pod busybox |egrep -o 'Container ID.*//.{12}'
Container ID:  containerd://07d189383321
Container ID:  containerd://bb02c680ca8a

# 获取容器所在节点
[root@master30 ~]# kubectl describe pod busybox |grep Node:
Node:             worker32.laoma.cloud/10.1.8.32

# 登录到node查看容器挂载情况
[root@worker32 ~]# crictl inspect 07d189383321|grep datavolume
        "hostPath": "/var/lib/kubelet/pods/8417656f-4b6c-4b2a-a2f3-f4a248c4c043/volumes/kubernetes.io~empty-dir/datavolume",
          "host_path": "/var/lib/kubelet/pods/8417656f-4b6c-4b2a-a2f3-f4a248c4c043/volumes/kubernetes.io~empty-dir/datavolume"
          "source": "/var/lib/kubelet/pods/8417656f-4b6c-4b2a-a2f3-f4a248c4c043/volumes/kubernetes.io~empty-dir/datavolume",

# 创建数据
[root@master30 ~]# kubectl exec busybox -c busybox1 -- touch /data/b1-f1
[root@master30 ~]# kubectl exec busybox -c busybox2 -- ls /data
b1-f1

# node上查看数据
[root@worker32 ~]# ls /var/lib/kubelet/pods/8417656f-4b6c-4b2a-a2f3-f4a248c4c043/volumes/kubernetes.io~empty-dir/datavolume
b1-f1

# 删除pod,验证emptyDir
[root@master30 ~]# kubectl delete pod busybox --force
[root@worker32 ~]# ls /var/lib/kubelet/pods/8417656f-4b6c-4b2a-a2f3-f4a248c4c043/volumes/kubernetes.io~empty-dir/datavolume
ls: cannot access '/var/lib/kubelet/pods/8417656f-4b6c-4b2a-a2f3-f4a248c4c043/volumes/kubernetes.io~empty-dir/datavolume': No such file or directory

# 容器删除后,需要等待一些时间,临时卷数据等待才会删除。

hostPath

hostPath允许Pod将Node的文件系统中某个目录挂载到Pod内部。pod删除后,hostPath卷数据保留。

**实验:**准备一个pod,使用hostPath。

bash 复制代码
[root@master30 ~]# vim pod-hostPath.yaml
yaml 复制代码
apiVersion: v1
kind: Pod
metadata:
  name: busybox
  labels:
    app: busybox
spec:
  volumes:
  - name: datavolume
    hostPath:
      path: /busyboxdir 
  containers:
  - name: busybox1
    image: docker.io/library/busybox
    imagePullPolicy: IfNotPresent
    command: ['sh', '-c', 'echo Hello Kubernetes! && sleep 3600']
    volumeMounts:
    - mountPath: /data
      name: datavolume
  - name: busybox2
    image: docker.io/library/busybox
    imagePullPolicy: IfNotPresent
    command: ['sh', '-c', 'echo Hello Kubernetes! && sleep 3600']
    volumeMounts:
    - mountPath: /data
      name: datavolume
      # 设置readOnly,控制读写,默认值是false,也就是读写访问。
      readOnly: false
bash 复制代码
# 创建pod
[root@master30 ~]# kubectl apply -f pod-hostPath.yaml
pod/busybox created

# 获取容器ID
[root@master30 ~]# kubectl describe pod busybox |egrep -o 'Container ID.*//.{12}'
Container ID:  containerd://318922d0c666
Container ID:  containerd://0688146babe5

# 获取容器所在节点
[root@master30 ~]# kubectl describe pod busybox |grep Node:
Node:             worker32.laoma.cloud/10.1.8.32

# 登录到worker31查看容器挂载情况
[root@worker32 ~]# crictl inspect 318922d0c666|grep busyboxdir
        "hostPath": "/busyboxdir",
          "host_path": "/busyboxdir"
          "source": "/busyboxdir",

# 创建数据
[root@master30 ~]# kubectl exec busybox -c busybox1 -- touch /data/b1-f1
[root@master30 ~]# kubectl exec busybox -c busybox2 -- ls /data
b1-f1

# node上查看数据
[root@worker32 ~]# ls /busyboxdir/
b1-f1

# 删除pod,验证hostPath
[root@master30 ~]# kubectl delete pod busybox --force
[root@worker32 ~]# ls /busyboxdir/
b1-f1
# pod 删除后,hostPath卷数据保留。

NFS 存储

NFS卷,将数据存储在NFS共享中。

准备NFS共享

bash 复制代码
# 安装 NFS server
[root@master30 ~]# apt install -y nfs-kernel-server

# 安创建NFS目录 修改创建文件夹的权限
[root@master30 ~]# mkdir -m 777 /nfsshares
[root@master30 ~]# echo hello laoma > /nfsshares/index.html

# 配置共享,允许所有客户端访问
[root@master30 ~]# cat << EOF > /etc/exports
/nfsshares *(rw)
EOF

# 重启 nfs server
[root@master30 ~]# systemctl restart nfs-server.service

# 客户端安装
[root@worker31 ~]# apt install -y nfs-common
[root@worker32 ~]# apt install -y nfs-common

准备 pod

bash 复制代码
[root@master30 ~]# vim pod-nfs.yaml 
yaml 复制代码
apiVersion: v1
kind: Pod
metadata:
  labels:
    run: nginx
  name: nginx
spec:
  volumes:
  - name: nfs
    nfs:
      server: 10.1.8.30 
      path: "/nfsshares"
  containers:
  - image: docker.io/library/nginx
    name: nginx
    volumeMounts:
    - name: nfs
      mountPath: "/usr/share/nginx/html"
bash 复制代码
# 创建pod
[root@master30 ~]# kubectl apply -f pod-nfs.yaml 
pod/nginx created

# 获取容器ID
[root@master30 ~]# kubectl describe pod nginx |egrep -o 'Container ID.*//.{12}'
Container ID:   containerd://c5e734dab9b5

# 获取容器所在节点
[root@master30 ~]# kubectl describe pod nginx |grep Node:
Node:             worker32.laoma.cloud/10.1.8.32

# 登录到worker31查看容器挂载情况
[root@worker32 ~]# crictl inspect c5e734dab9b5|grep /usr/share/nginx/html
        "containerPath": "/usr/share/nginx/html",
          "container_path": "/usr/share/nginx/html",
          "destination": "/usr/share/nginx/html",

# 访问容器
[root@master30 ~]# kubectl get pod -o wide
NAME    READY   STATUS    RESTARTS   AGE     IP              NODE               NOMINATED NODE   READINESS GATES
nginx   1/1     Running   0          5m19s   10.224.51.171   worker32.laoma.cloud   <none>           <none>
[root@master30 ~]# curl 10.224.51.171
hello laoma

# 创建数据
[root@master30 ~]# kubectl exec nginx -- ls /usr/share/nginx/html
index.html
[root@master30 ~]# kubectl exec nginx -- touch /usr/share/nginx/html/test.html
[root@master30 ~]# ls /nfsshares
index.html  test.html

# 删除pod,验证nfs卷数据
[root@master30 ~]# kubectl delete pod nginx --force
pod "nginx" deleted
[root@master30 ~]# ls /nfsshares
index.html  test.html
# pod 删除后,nfs卷数据保留。

持久性存储

学习参考:持久卷

Kubernetes 使用 persistent volume(PV)架构为集群提供永久存储。

Kubernetes中用户:

  1. 集群管理员,提供集群的计算资源。
  2. 集群的使用者。使用者只需要用就可以了,不需要太多的管理技能。

PV 和 PVC 架构

开发人员不知道特定云环境的细节的情况下,只需要使用persistentVolumeClaim(PVC)请求PV资源,实现持久化存储。

  • Persistent Volume ,由PersistentVolume API对象定义,代表集群中现有存储。PV的生命周期与使用其的pod无关。Persistent Volume 是集群级别资源。

  • Persistent Volume Claim ,由PersistentVolumeClaim API对象定义,代表开发人员请求PV。Persistent Volume Claim 是 namespace 级别资源。

创建 PV 和 PVC

创建 PV

集群管理员可以创建任意数量PV,取决于后端存储。

为了方便演示,我们这里使用NFS后端存储。

pv文件示例:

bash 复制代码
[root@master30 ~]# vim pv.yaml
yaml 复制代码
apiVersion: v1
kind: PersistentVolume
metadata:
  name: web
spec:
  capacity:
    storage: 5Gi
  volumeMode: Filesystem
  accessModes:
    - ReadWriteOnce
  nfs:
    path: /nfsshares
    server: 10.1.8.30
bash 复制代码
[root@master30 ~]# kubectl apply -f pv.yaml 
[root@master30 ~]# kubectl get pv
NAME   CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS      CLAIM   STORAGECLASS   REASON   AGE
web    5Gi        RWO            Recycle          Available                                   3s
创建 PVC

用户创建PVC,pod使用PVC申请特定容量、特定modes和特定存储类别的存储。master监控PVCs,查找匹配的PV或者等待后端存储创建相应PV,然后绑定PV和PVC。

pvc示例:

bash 复制代码
[root@master30 ~]# vim pvc.yaml
yaml 复制代码
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: webclaim
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 5Gi
bash 复制代码
[root@master30 ~]# kubectl apply -f pvc.yaml 
[root@master30 ~]# kubectl get pvc
NAME       STATUS   VOLUME   CAPACITY   ACCESS MODES   STORAGECLASS   AGE
webclaim   Bound    web      5Gi        RWO                           4s
创建 Pod
bash 复制代码
[root@master30 ~]# vim pod-web.yaml
yaml 复制代码
apiVersion: v1
kind: Pod
metadata:
  name: web
  labels:
    name: web
spec:
  containers:
    - image: docker.io/library/httpd
      name: web
      ports:
        - containerPort: 80
          name: web-port
      volumeMounts:
        - name: web-persistent-storage
          mountPath: /usr/local/apache2/htdocs
  volumes:
    - name: web-persistent-storage
      persistentVolumeClaim:
        claimName: webclaim
bash 复制代码
[root@master30 ~]# kubectl apply -f pod-web.yaml 
pod/web created
[root@master30 ~]# kubectl get pod -o wide
NAME   READY   STATUS    RESTARTS   AGE   IP              NODE                  NOMINATED NODE   READINESS GATES
web    1/1     Running   0          35s   10.224.193.69   worker32.laoma.cloud   <none>           <none>

# 测试:访问pod web页面
[root@master30 ~]# curl http://10.224.193.69
hello laoma
[root@master30 ~]# echo test > /nfsshares/test.html
[root@master30 ~]# curl http://10.224.193.69/test.html
test

# 删除pod
[root@master30 ~]# kubectl delete pod web --force

PV accessModes

PersistentVolume 卷访问模式有:

  • ReadWriteOnce ,卷可以被一个节点以读写方式挂载,也允许同一节点上的多个 Pod 读写访问卷。

  • ReadOnlyMany ,卷可以被多个节点以只读方式挂载。

  • ReadWriteMany ,卷可以被多个节点以读写方式挂载。

  • ReadWriteOncePod ,卷可以被单个 Pod 以读写方式挂载。 如果你想确保整个集群中只有一个 Pod 可以读取或写入该 PVC, 请使用 ReadWriteOncePod 访问模式。这只支持 CSI 卷以及需要 Kubernetes 1.22 以上版本。

这篇博客文章 Introducing Single Pod Access Mode for PersistentVolumes 描述了更详细的内容。

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

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

不同存储后端支持不同的模式:

卷插件 ReadWriteOnce ReadOnlyMany ReadWriteMany ReadWriteOncePod
AzureFile -
CephFS -
CSI 取决于驱动 取决于驱动 取决于驱动 取决于驱动
FC - -
FlexVolume 取决于驱动 -
GCEPersistentDisk - -
Glusterfs -
HostPath - - -
iSCSI - -
NFS -
RBD - -
VsphereVolume - -(Pod 运行于同一节点上时可行) -
PortworxVolume - -

重要: 每个卷同一时刻只能以一种访问模式挂载,即使该卷能够支持多种访问模式。 例如,一个 GCEPersistentDisk 卷可以被某节点以 ReadWriteOnce 模式挂载,或者被多个节点以 ReadOnlyMany 模式挂载,但不可以同时以两种模式挂载。

常见的NAS存储都支持三种存储模式:ReadWriteOnce、ReadOnlyMany、ReadWriteMany。

PV volumeModes

特性状态: Kubernetes v1.18 [stable]

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

  • Filesystem 卷 ,会被 Pod 挂载(Mount) 到某个目录。 如果卷的存储来自某块设备而该设备目前为空,Kuberneretes 会在第一次挂载卷之前在设备上创建文件系统。

  • Block 卷 ,会被作为原始块设备来使用。 这类卷以块设备的方式交给 Pod 使用,其上没有任何文件系统。 这种模式对于为 Pod 提供一种使用最快可能方式来访问卷而言很有帮助, Pod 和卷之间不存在文件系统层。另外,Pod 中运行的应用必须知道如何处理原始块设备。 关于如何在 Pod 中使用 volumeMode: Block 的卷, 可参阅原始块卷支持

PVC与PV匹配规则

  • PV的mode必须高于PVC申请的最低要求:mode 优先级,可简单理解为ROX<RWO<RWX。例如,用户请求RWO模式PV,但是目前只有NFS PV(RWO+ROX+RWX),PVC将匹配NFS。

  • 容量满足最低要求:具有相同modes卷会被分组,然后根据size分类(由小到大)。

  • pv storage classes用于对pv进行分类,pvc可以根据storageClassName参数申请特定类型pv。如果pv设置了storageClassName,那么 pvc 申请资源的时候也要指定storageClassName。例如,storageClassName指定为 ns1-storage,ns1中pvc申请也指定storageClassName为ns1-storage。

PV 回收策略

当用户不再使用其存储卷时,他们可以从 API 中将 PVC 对象删除, 从而允许该资源被回收再利用。PersistentVolume 对象的回收策略告诉集群, 当其被从申领中释放时如何处理该数据卷。

PersistentVolume 回收策略支持:Retain(保留)、Recycle(回收)、Delete(删除)。

Retain(保留)

回收策略 Retain 使得用户可以手动回收资源。当 PersistentVolumeClaim 对象被删除时,PersistentVolume 卷仍然存在,对应的数据卷被视为"已释放(released)"。 由于卷上仍然保留上一次关联的pvc信息,清理掉上一次关联的pvc信息才可分配给其他pvc。Retain(保留)策略是默认策略

示例:

bash 复制代码
[root@master30 ~]# vim pv-pvc-Retain.yaml
yaml 复制代码
---
apiVersion: v1
kind: PersistentVolume
metadata:
  name: web
spec:
  capacity:
    storage: 5Gi
  #persistentVolumeReclaimPolicy: Retain
  volumeMode: Filesystem
  accessModes:
    - ReadWriteOnce
  nfs:
    path: /nfsshares
    server: 10.1.8.30
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: webclaim
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 5Gi
bash 复制代码
[root@master30 ~]# kubectl apply -f pv-pvc-Retain.yaml
[root@master30 ~]# kubectl get pv
NAME   CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS   CLAIM              STORAGECLASS   REASON   AGE
web    5Gi        RWO            Retain           Bound    default/webclaim                           22s
[root@master30 ~]# kubectl get pvc
NAME       STATUS   VOLUME   CAPACITY   ACCESS MODES   STORAGECLASS   AGE
webclaim   Bound    web      5Gi        RWO                           23s

删除 pvc 验证

bash 复制代码
[root@master30 ~]# kubectl delete pvc webclaim 
[root@master30 ~]# kubectl get pv
NAME   CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS     CLAIM              STORAGECLASS   REASON   AGE
web    5Gi        RWO            Retain           Released   default/webclaim                           3m4s

# 创建新pvc,无法绑定
[root@master30 ~]# vim pvc-db.yaml
yaml 复制代码
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: dbclaim
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 5Gi
bash 复制代码
[root@master30 ~]# kubectl apply -f pvc-db.yaml 
[root@master30 ~]# kubectl get pvc dbclaim 
NAME      STATUS    VOLUME   CAPACITY   ACCESS MODES   STORAGECLASS   AGE
dbclaim   Pending                                                     11s

# 手动清理卷上claimRef信息,删除claimRef部分
[root@master30 ~]# kubectl edit pv web
yaml 复制代码
......
spec:
  accessModes:
  - ReadWriteOnce
  capacity:
    storage: 5Gi
  # 删除claimRef部分
  # claimRef:
  #   apiVersion: v1
  #   kind: PersistentVolumeClaim
  #   name: webclaim
  #   namespace: test
  #   resourceVersion: "112157"
  #   uid: 0839cdc1-81bb-11e9-9ca8-52540000fa0a
  # 删除claimRef部分
  nfs:
    path: /web
    server: 10.1.8.30
......
bash 复制代码
# dbclaim 绑定成功
[root@master30 ~]# kubectl get pvc dbclaim 
NAME      STATUS   VOLUME   CAPACITY   ACCESS MODES   STORAGECLASS   AGE
dbclaim   Bound    web      5Gi        RWO                           3m49s

清理环境

bash 复制代码
[root@master30 ~]# kubectl delete pvc dbclaim
[root@master30 ~]# kubectl delete pv web
[root@master30 ~]# ls /nfsshares/
index.html  test.html

**注意:**删除pv,并不会删除后端存储中数据。

思考

问题:如何创建一个只能绑定给特定pvc的pv?

答案:在定义pv的时候,指定claimRef属性。

yaml 复制代码
---
apiVersion: v1
kind: PersistentVolume
metadata:
  name: web
spec:
  capacity:
    storage: 5Gi
  volumeMode: Filesystem
  accessModes:
    - ReadWriteOnce
  nfs:
    path: /nfsshares
    server: 10.1.8.30
  claimRef:
    name: webclaim
    namespace: test

PV 卷的类型

PV 持久卷是用插件的形式来实现的。Kubernetes 目前支持以下插件:

  • csi - 容器存储接口 (CSI)
  • fc - Fibre Channel (FC) 存储
  • hostPath - HostPath 卷 (仅供单节点测试使用;不适用于多节点集群;请尝试使用 local 卷作为替代)
  • iscsi - iSCSI (SCSI over IP) 存储
  • local - 节点上挂载的本地存储设备
  • nfs - 网络文件系统 (NFS) 存储

环境清理

bash 复制代码
[root@master30 ~]# kubectl delete ns storage

Kubernetes ConfigMap

环境准备

bash 复制代码
[root@master30 ~]# kubectl create ns ConfigMap
[root@master30 ~]# kubectl config set-context --current --namespace ConfigMap

ConfigMap

学习参考:ConfigMap

ConfigMap 介绍

ConfigMap 是一个存储其他对象所需要使用的配置的 API 对象。 ConfigMap 使用 databinaryData 字段,保存键值对数据。

  • data 字段,用来保存 UTF-8 字符串。
  • binaryData 字段,用来保存二进制数据(base64 编码的字串) 。

ConfigMap 的名字必须是一个合法的 DNS 子域名databinaryData 字段下面的每个键的名称都必须由字母、数字或者 -_. 组成。在 data 下保存的键名不可以与在 binaryData 下出现的键名有重叠。

从 v1.19 开始,你可以添加一个 immutable 字段到 ConfigMap 定义中, 创建不可变更的 ConfigMap

ConfigMap 使用建议

  • 使用 ConfigMap 存储配置数据,与应用程序代码分开。

  • **ConfigMap 在设计上不是用来保存大量数据的。**如果你需要保存大量数据,考虑使用挂载存储卷或者使用独立的数据库或者文件服务。

ConfigMap 创建

使用帮助

bash 复制代码
kubectl create configmap NAME [--from-file=[key=]source]
[--from-literal=key1=value1] [--dry-run=server|client|none] [options]
键值对类型
bash 复制代码
[root@master30 ~]# kubectl create configmap mysql --from-literal=password=redhat 
[root@master30 ~]# kubectl get configmaps mysql -o yaml |grep ^data -A1
data:
  password: redhat
文件类型
bash 复制代码
[root@master30 ~]# echo Hello World > index.html 
[root@master30 ~]# kubectl create configmap web1 --from-file=./index.html
[root@master30 ~]# kubectl get configmaps web1 -o yaml |grep ^data -A2
data:
  index.html: |
    Hello World
目录类型
bash 复制代码
[root@master30 ~]# echo error > error.html
[root@master30 ~]# mkdir web2
[root@master30 ~]# mv index.html error.html web2
[root@master30 ~]# kubectl create configmap web2 --from-file=./web2
[root@master30 ~]# kubectl get configmaps web2 -o yaml |grep ^data -A4
data:
  error.html: |
    error
  index.html: |
    Hello World

ConfigMap 引用

环境变量方式引用

**注意:**环境变量属于特定容器级别。

bash 复制代码
[root@master30 ~]# vim pod-cm-env.yaml
yaml 复制代码
---
apiVersion: v1
kind: Pod
metadata:
  name: mysql
  labels:
    name: mysql
spec:
  containers:
  - image: docker.io/library/mysql:latest
    imagePullPolicy: IfNotPresent
    name: mysql
    ports:
    - containerPort: 3306
      name: mysql
    env:
    - name: MYSQL_ROOT_PASSWORD
      # 原先通过value设置环境变量值
      valueFrom:
        configMapKeyRef:
          name: mysql
          key: password

验证

bash 复制代码
[root@master30 ~]# kubectl apply -f pod-cm-env.yaml
[root@master30 ~]# kubectl get pods -o wide
NAME    READY   STATUS    RESTARTS   AGE     IP              NODE                  NOMINATED NODE   READINESS GATES
mysql   1/1     Running   0          4m33s   10.224.193.70   worker32.laoma.cloud   <none>

[root@master30 ~]# kubectl exec -it mysql -- bash -c 'echo $MYSQL_ROOT_PASSWORD'
redhat

[root@master30 ~]# apt install -y mysql-client
[root@master30 ~]# mysql -u root -predhat -h 10.224.193.70
mysql: [Warning] Using a password on the command line interface can be insecure.
......

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql> quit
Bye

# 删除 pod
[root@master30 ~]# kubectl delete pod mysql --force
以 volume 方式引用

**注意:**volumes属于pod级别,通过volumeMounts挂载。

引用整体
bash 复制代码
[root@master30 ~]# vim pod-cm-volume-all.yaml
yaml 复制代码
---
apiVersion: v1
kind: Pod
metadata:
  labels:
    run: web
  name: web
spec:
  containers:
  - image: docker.io/library/nginx:latest
    imagePullPolicy: IfNotPresent
    name: web
    volumeMounts:
    - name: webcontent
      # mountPath值是一个挂载点,将secrete中所有键值对挂载过来
      mountPath: "/usr/share/nginx/html"
  volumes:
  - name: webcontent
    configMap:
      name: web2

验证

bash 复制代码
[root@master30 ~]# kubectl apply -f pod-cm-volume-all.yaml
[root@master30 ~]# kubectl get pods -o wide
NAME   READY   STATUS    RESTARTS   AGE   IP              NODE                  NOMINATED NODE   READINESS GATES
web    1/1     Running   0          66s   10.224.193.69   worker32.laoma.cloud   <none>           <none>

[root@master30 ~]# kubectl exec web -- ls /usr/share/nginx/html
error.html
index.html

[root@master30 ~]# curl http://10.224.193.69
Hello World
[root@master30 ~]# curl http://10.224.193.69/error.html
error
引用特定key
bash 复制代码
[root@master30 ~]# vim pod-cm-volume-single.yaml
yaml 复制代码
---
apiVersion: v1
kind: Pod
metadata:
  labels:
    run: web
  name: web
spec:
  containers:
  - image: docker.io/library/nginx:latest
    imagePullPolicy: IfNotPresent
    name: web
    volumeMounts:
    - name: webcontent
      mountPath: "/usr/share/nginx/html"
  volumes:
  - name: webcontent
    configMap:
      name: web2
      items:
        - key: index.html
          path: index.html

等同于

yaml 复制代码
apiVersion: v1
kind: Pod
metadata:
  labels:
    run: web
  name: web
spec:
  containers:
  - image: docker.io/library/nginx:latest
    imagePullPolicy: IfNotPresent
    name: web
    volumeMounts:
    - name: webcontent
      mountPath: "/usr/share/nginx/html/index.html"
      subPath: index.html
  volumes:
  - name: webcontent
    configMap:
      name: web2

**被挂载的 ConfigMap 内容会被自动更新。**当卷中使用的 ConfigMap 被更新时,所投射的键最终也会被更新。 kubelet 组件会在每次周期性同步时检查所挂载的 ConfigMap 是否为最新。

k8s 中 ConfigMap

以 kube-proxy 为例

bash 复制代码
[root@master30 ~]# kubectl get configmaps -n kube-system 
NAME                                                   DATA   AGE
calico-config                                          4      37h
coredns                                                1      37h
extension-apiserver-authentication                     6      37h
kube-apiserver-legacy-service-account-token-tracking   1      37h
kube-proxy                                             2      37h
kube-root-ca.crt                                       1      37h
kubeadm-config                                         1      37h
kubelet-config                                         1      37h

[root@master30 ~]# kubectl get configmaps kube-proxy -n kube-system -o yaml
apiVersion: v1
data:
  config.conf: |-
    apiVersion: kubeproxy.config.k8s.io/v1alpha1
    bindAddress: 0.0.0.0
    bindAddressHardFail: false
    clientConnection:
      acceptContentTypes: ""
      burst: 0
      contentType: ""
      kubeconfig: /var/lib/kube-proxy/kubeconfig.conf
      qps: 0
    clusterCIDR: 10.224.0.0/16
    configSyncPeriod: 0s
    conntrack:
      maxPerCore: null
      min: null
      tcpCloseWaitTimeout: null
      tcpEstablishedTimeout: null
    detectLocalMode: ""
    enableProfiling: false
    healthzBindAddress: ""
    hostnameOverride: ""
    iptables:
      masqueradeAll: false
      masqueradeBit: null
      minSyncPeriod: 0s
      syncPeriod: 0s
    ipvs:
      excludeCIDRs: null
      minSyncPeriod: 0s
      scheduler: ""
      strictARP: false
      syncPeriod: 0s
      tcpFinTimeout: 0s
      tcpTimeout: 0s
      udpTimeout: 0s
    kind: KubeProxyConfiguration
    metricsBindAddress: ""
    mode: ""
    nodePortAddresses: null
    oomScoreAdj: null
    portRange: ""
    showHiddenMetricsForVersion: ""
    udpIdleTimeout: 0s
    winkernel:
      enableDSR: false
      networkName: ""
      sourceVip: ""
  kubeconfig.conf: |-
    apiVersion: v1
    kind: Config
    clusters:
    - cluster:
        certificate-authority: /var/run/secrets/kubernetes.io/serviceaccount/ca.crt
        server: https://10.1.8.30:6443
      name: default
    contexts:
    - context:
        cluster: default
        namespace: default
        user: default
      name: default
    current-context: default
    users:
    - name: default
      user:
        tokenFile: /var/run/secrets/kubernetes.io/serviceaccount/token
kind: ConfigMap
metadata:
  annotations:
    kubeadm.kubernetes.io/component-config.hash: sha256:77333136e4f6883a76e786187738706eb9a60efd1f8641f2489dbd1e085726d9
  creationTimestamp: "2021-07-03T03:07:55Z"
  labels:
    app: kube-proxy
  managedFields:
  - apiVersion: v1
    fieldsType: FieldsV1
    fieldsV1:
      f:data:
        .: {}
        f:config.conf: {}
        f:kubeconfig.conf: {}
      f:metadata:
        f:annotations:
          .: {}
          f:kubeadm.kubernetes.io/component-config.hash: {}
        f:labels:
          .: {}
          f:app: {}
    manager: kubeadm
    operation: Update
    time: "2021-07-03T03:07:55Z"
  name: kube-proxy
  namespace: kube-system
  resourceVersion: "193"
  selfLink: /api/v1/namespaces/kube-system/configmaps/kube-proxy
  uid: 2b6168fd-29c8-49c4-a465-08720e9f48db

# kube-proxy有两种工作模式ipvs和iptables
# 这里 mode 值为空,查看日志发现默认使用iptables。
[root@master30 ~]# kubectl logs -n kube-system kube-proxy-8kp8w 
I1019 02:26:00.975333       1 server_others.go:69] "Using iptables proxy"
I1019 02:26:01.037589       1 node.go:141] Successfully retrieved node IP: 10.1.8.31
I1019 02:26:01.040909       1 conntrack.go:100] "Set sysctl" entry="net/netfilter/nf_conntrack_max" value=131072
I1019 02:26:01.041412       1 conntrack.go:52] "Setting nf_conntrack_max" nfConntrackMax=131072
I1019 02:26:01.041902       1 conntrack.go:100] "Set sysctl" entry="net/netfilter/nf_conntrack_tcp_timeout_close_wait" value=3600
......

# 更改模式为ipvs
[root@master30 ~]# kubectl edit cm -n kube-system kube-proxy 
......
    mode: "ipvs"
......

# 删除pod,等待控制器重新创建
[root@master30 ~]# kubectl get pod -n kube-system |grep kube-proxy
kube-proxy-8kp8w                            1/1     Running   1          37d
kube-proxy-ghgxw                            1/1     Running   1          37d
kube-proxy-p6qnk                            1/1     Running   1          37d

[root@master30 ~]# kubectl delete pod -n kube-system kube-proxy-{8kp8w,ghgxw,p6qnk}
pod "kube-proxy-8kp8w" deleted
pod "kube-proxy-ghgxw" deleted
pod "kube-proxy-p6qnk" deleted

# 再次查看日志
[root@master30 ~]# kubectl get pod -n kube-system |grep kube-proxy
kube-proxy-8swmx                            1/1     Running   0          18s
kube-proxy-948cw                            1/1     Running   0          29s
kube-proxy-xlh7b                            1/1     Running   0          24s
[root@master30 ~]# kubectl logs -n kube-system kube-proxy-8swmx
I1019 03:41:12.288952       1 node.go:141] Successfully retrieved node IP: 10.1.8.31
I1019 03:41:12.290902       1 conntrack.go:52] "Setting nf_conntrack_max" nfConntrackMax=131072
I1019 03:41:12.325988       1 server.go:632] "kube-proxy running in dual-stack mode" primary ipFamily="IPv4"
I1019 03:41:12.364416       1 server_others.go:218] "Using ipvs Proxier"
......

# 实验完成后,模式更改回来

综合案例:haproxy+web

需求

  1. 创建一个名称为 haproxy 的pod,使用镜像 haproxy ,pod haproxy 的配置文件保存在 configmap 中,通过 volume 方式挂载到 /usr/local/etc/haproxy/haproxy.cfg 。将流量转发到pod webapp-1webapp-2

    haproxy 的配置文件模板内容如下:

    ini 复制代码
    global
        daemon
        maxconn 256
    
    defaults
        mode http
        timeout connect 5000ms
        timeout client 50000ms
        timeout server 50000ms
    
    frontend http-in
        bind *:8080
        default_backend servers
    
    backend servers
        server  app1 10.224.84.80:80 check
        server  app2 10.224.149.25:80 check
  2. 创建第一个pod,名称为webapp-1 ,使用镜像nginx 。为该pod创建一个cm,名称为webapp-1,该cm保存两个值:

    • index.html="hello webapp-1"
    • error.html="sorry, error."

    这个两个值通过volume方式挂载到**/usr/share/nginx/html**目录。

  3. 创建第二个pod,名称为webapp-2 ,使用镜像nginx 。为该pod创建一个cm,名称为webapp-2,该cm保存两个值:

    • index.html="hello webapp-2"
    • error.html="sorry, error."

    这个两个值通过volume方式挂载到**/usr/share/nginx/html**目录。

解答:

  1. 创建第一个cm和pod

    bash 复制代码
    [root@master30 ~]# mkdir web && cd web
    root@master30:~/web# kubectl create cm webapp-1 --from-literal=index.html="hello webapp-1" --from-literal=error.html="sorry, error."
    root@master30:~/web# vim pod-webapp-1.yaml
    yaml 复制代码
    apiVersion: v1
    kind: Pod
    metadata:
      name: webapp-1
    spec:
      containers:
      - name: nginx
        image: docker.io/library/nginx:latest
        imagePullPolicy: IfNotPresent
        volumeMounts:
        - name: config
          mountPath: "/usr/share/nginx/html"
          readOnly: true
      volumes:
      - name: config
        configMap:
          name: webapp-1
    bash 复制代码
    root@master30:~/web# kubectl apply -f pod-webapp-1.yaml
  2. 创建第二个cm和pod

    bash 复制代码
    root@master30:~/web# kubectl create cm webapp-2 --from-literal=index.html="hello webapp-2" --from-literal=error.html="sorry, error."
    root@master30:~/web# vim pod-webapp-2.yaml
    yaml 复制代码
    apiVersion: v1
    kind: Pod
    metadata:
      name: webapp-2
    spec:
      containers:
      - name: nginx
        image: docker.io/library/nginx:latest
        imagePullPolicy: IfNotPresent
        volumeMounts:
        - name: config
          mountPath: "/usr/share/nginx/html"
          readOnly: true
      volumes:
      - name: config
        configMap:
          name: webapp-2
    bash 复制代码
    root@master30:~/web# kubectl apply -f pod-webapp-2.yaml
  3. 创建haproxy配置文件。

    bash 复制代码
    # 获取pod ip地址
    root@master30:~/web# kubectl get pods -o wide
    NAME	   READY   STATUS    RESTARTS   AGE   IP              NODE                NOMINATED NODE   READINESS GATES
    webapp-1   1/1     Running   0          63m   10.224.84.80    worker1.laoma.fun   <none>           <none>
    webapp-2   1/1     Running   0          63m   10.224.149.25   worker2.laoma.fun   <none>           <none>
    
    # haproxy内容如下:
    root@master30:~/web# vim haproxy.cfg
    ini 复制代码
    global
        daemon
        maxconn 256
    
    defaults
        mode http
        timeout connect 5000ms
        timeout client 50000ms
        timeout server 50000ms
    
    frontend http-in
        bind *:8080
        default_backend servers
    
    backend servers
        server  app1 10.224.84.80:80 check
        server  app2 10.224.149.25:80 check
    bash 复制代码
    # 创建haproxy.cfg configmap
    root@master30:~/web# kubectl create cm haproxy.cfg --from-file=haproxy.cfg=./haproxy.cfg
    
    # 创建pod haproxy
    root@master30:~/web# vim haproxy.yaml
    yaml 复制代码
    ---
    apiVersion: v1
    kind: Pod
    metadata:
      name: haproxy
    spec:
      containers:
      - name: haproxy
        image: docker.io/library/haproxy
        imagePullPolicy: IfNotPresent
        securityContext:
          allowPrivilegeEscalation: true
        volumeMounts:
        - name: config
          mountPath: "/usr/local/etc/haproxy"
          readOnly: true
      volumes:
      - name: config
        configMap:
          name: haproxy.cfg
    bash 复制代码
    root@master30:~/web# kubectl apply -f haproxy.yaml
    
    # 验证
    root@master30:~/web# kubectl get pods haproxy -o wide
    NAME      READY   STATUS    RESTARTS   AGE   IP              NODE                  NOMINATED NODE   READINESS GATES
    haproxy   1/1     Running   0          33s   10.224.149.35   worker32.laoma.cloud   <none>           <none>
    
    
    [root@master30 ~]# curl http://10.224.149.35:8080
    hello webapp-1
    [root@master30 ~]# curl http://10.224.149.35:8080
    hello webapp-2

环境清理

bash 复制代码
[root@master30 ~]# kubectl delete ns ConfigMap

开发一个网站

搭建服务器

CentOS 7.9 + Nginx + PHP(js)

额外:

  1. 域名
  2. 公网 IP
  3. httpd 证书
  4. 开发站点内容

开发站点内容

借助AI完成。

第 1 次问

我是一名云原生运维工程师,毕业一年,现在在找工作。为了展示我的技术栈能力,现打算开发一个网站,用于面试,展示我的能力。这个网站要提供写博客的功能。

请你帮我设计一下这个网站。

第 2 次问

按照你的设计,请帮我设计网站首页,并提供可以直接复制的源代码。

学习参考:https://learn.lianglianglee.com/

菜鸟俱乐部:https://www.runoob.com/

相关推荐
MAVER1CK8 小时前
Install VNC in Docker container
运维·docker·容器
眷蓝天11 小时前
kubectl 管理工具
kubernetes·kubectl
亚空间仓鼠11 小时前
Kubernetes技术入门与实践(二):常用命令
云原生·容器·kubernetes
LSL666_11 小时前
3 安装docker
运维·docker·容器
小江的记录本11 小时前
【微服务与云原生架构】DevOps、CI/CD流水线、GitOps 系统性知识体系
分布式·后端·ci/cd·微服务·云原生·架构·devops
LSL666_12 小时前
4 Docker 镜像安装与容器启动
运维·docker·容器
wuxinyan12313 小时前
Java面试题51:一文深入了解K8s 环境下企业级 CI/CD 流水线搭建
java·ci/cd·kubernetes·面试题
安逸sgr13 小时前
Hermes Agent + Obsidian 打造第二大脑(三):Docker 部署详解——从零到生产环境的完整实战指南!
运维·docker·容器·obsidian·hermes·hermesagent
小夏子_riotous14 小时前
Docker学习路径——9、Docker 网络深度解析:从默认网络到自定义网络实战
linux·运维·网络·docker·容器·centos·云计算