9. kubernetes 存储卷

9. kubernetes 存储卷

[TOC]

本文基于马哥的docker和k8s视频总结, 在此致谢马哥.

k8s上可以用的三种存储卷类型

emptyDir

  • (1) emptyDir 只在节点本地使用, 且pod删除时存储卷会随之被删除, 用于当临时目录或缓存, 此存储卷可使用节点的内存

    一个存储卷可以在同一个pod内的多个容器间共享:

apiVersion: v1
kind: Pod
metadata:
    name: pod-demo
    namespace: default
    labels:
        app: myapp
        tier: frontend
    annotations:
        magedu.com/create-by: "cluster admin"
spec:
    containers:
    - name: myapp
        image: nginx
        ports:
        - name: http
            containerPort: 80
        volumeMounts:
        - name: html # 挂载名为html的存储卷 (需要使用下面存在的volumes)
            mountPath: /usr/share/nginx/html/ # 挂载点路径
            # 其他参数: readOnly, subPath, mountPropagation
    - name: busybox
        image: busybox:latest
        imagePullPolicy: IfNotPresent
        volumeMounts: # 挂载是容器级别的, 哪个容器使用, 哪个容器就要挂载, 不挂载时访问不到数据
        - name: html
            mountPath: /data/ # 注意两个容器的挂载路径可以不同
        command:
        - "/bin/sh"
        - "-c"
        - "while true; done echo $(date) >> /data/index.html; sleep 10; done"
    volumes:
    - name: html
        emptyDir: {} # 可以指定为空, 表示使用默认值(使用硬盘空间, 不限制使用大小)
            # medium 指定使用的存储卷设备, 空字符串代表使用硬盘, Memory代表使用内存
            # sizeLimit 指定使用的存储卷大小
kubectl apply -f vol-demo1.yml
kubectl exec -it pod-demo -c busybox -- /bin/sh
/ # echo $(date) >> /data/index.html
kubectl exec -it pod-demo -c myapp -- /bin/sh
/ # cat /data/web/html/index.html # 可以在另一个容器中看到共享的数据

kubect get pods -o wide # 查看pod的IP
curl pod_IP

hostPath

  • (2) hostPath 宿主机路径, 将pod上的存储卷与宿主机的目录做映射
hostPath支持的type类型.png
apiVersion: v1
kind: Pod
metadata:
    name: pod-hostpath-vol
    namespace: default
spec:
    containers:
    - name: myapp
        image: nginx:1.14:alpine
        volumeMounts:
        - name: html
            mountPath: /usr/share/nginx/html/  
        volumes:
        - name: html
            hostPath:
                path: /data/pod/volume1/
                type: DirectoryOrCreate # 目录不存在时自动创建
mkdir -p /data/pod/volume1/
echo "test hostPath" >> /data/pod/volume1/index.html # 只要节点上有相同内容, 则pod宕了也没关系
kubectl apply -f pod-hostpath-vol.yml

nfs为例

  • (3) 共享存储, 支持awsElasticBlockStore, azureDisk, cephfs, glusterfs, gitRepo, nfs, iscsi, rbd
# node1(ip为192.168.200.200)作为nfs服务的提供者
yum -y install nfs-utils # 作为nfs共享存储的节点需要安装此包
mkdir /data/volumes -pv
vi /etc/exports
/data/volumes  192.168.0.0/16(rw,no_root_squash)
systemctl start nfs

# node2(ip为192.168.200.201)作为nfs服务的使用者
yum -y install nfs-utils
mount -t nfs 192.168.200.200:/data/volumes /mnt # 一定要进行挂载测试
umount /mnt
vi pod-nfs-vol.yml
apiVersion: v1
kind: Pod
metadata:
    name: pod-nfs-vol
    namespace: default
spec:
    containers:
    - name: myapp
        image: nginx:1.14:alpine
        volumeMounts:
        - name: html
            mountPath: /usr/share/nginx/html/  
        volumes:
        - name: html
            nfs:
                path: /data/pod/volumes
                server:
                    192.168.200.201
                readOnly: false # 默认就是false, 即rw
kubectl apply -f pod-nfs-vol.yml

注: nfs支持多客户端同时挂载, 支持多客户端的多路读写访问

pvc和pv

pvcpv也是标准的k8s资源

定义存储模型.png
kubectl explain pods.spec.volumes.persistentVolumeClaim
    claimName # 必要选项, 指明已创建好的pvc名称
    readOnly # default false

kubectl explain pvc.spec
    accessModes <[]string># 访问模型, 这里不可随便定义, 有些设备可能不支持某种模型
        ReadWriteOnce # 单路读写, 可简写为RWO
        ReadOnlyMany # 多路只读, 可简写为ROM
        ReadWriteMany # 多路读写, 可简写为RWM
    resources # 资源限制, 对应的存储空间至少需要的大小
    selecotr # pv可以有标签, pvc上使用selector时表示必须使用哪个pv建立关联关系, 不加selector时自动选择最佳匹配
    volumeMode # 后端存储卷的模式, 可以不指定
    volumeName # 卷名称, 绑定某个pv, 可以不指定

kubectl explain pv.spec
    accessModes <[]string># 访问模型, 这里不可随便定义, 有些设备可能不支持某种模型
        ReadWriteOnce # 单路读写, 可简写为RWO
        ReadOnlyMany # 多路只读, 可简写为ROM
        ReadWriteMany # 多路读写, 可简写为RWM
    capacity  # 定义存储空间大小, 支持E, P, T, G, M, K, m和Ei, Pi, Ti, Gi, Mi, Ki, mi
        stroage
  • 创建pvc后会去找系统上合适的pv进行绑定, 如果没有则挂起(pending), 例如pvc需要使用30G, 而pv现在最大创建的容量只有20G, 不满足条件, 操作被挂起, 直到满足条件

  • pvpvc是一一对应的关系, 如果某个pvpvc占用了, 则这个pv不能再被其他pvc占用, 但一个pvc可以被多个pod访问

# node1(ip为192.168.200.200)作为nfs服务的提供者
yum -y install nfs-utils # 作为nfs共享存储的节点需要安装此包
mkdir /data/volumes -pv
vi /etc/exports
/data/volumes/v1  192.168.0.0/16(rw,no_root_squash)
/data/volumes/v2  192.168.0.0/16(rw,no_root_squash)
/data/volumes/v3  192.168.0.0/16(rw,no_root_squash)
/data/volumes/v4  192.168.0.0/16(rw,no_root_squash)
/data/volumes/v5  192.168.0.0/16(rw,no_root_squash)
exportfs -arv
showmount -e

# node2(ip为192.168.200.201)作为nfs服务的使用者
yum -y install nfs-utils
mount -t nfs 192.168.200.200:/data/volumes /mnt # 一定要进行挂载测试
umount /mnt
vi pod-pv.yml
apiVersion: v1
kind: PersistentVolume
metadata:
    name: pv001 # 定义pv时千万不要定义namespace, 因为pv是集群级别的, 不属于namespace
    labels:
        name: pv001
spec:
    nfs:
        path: /data/volumes/v1
        server: 192.168.200.200
    accessModes: ["ReadWriteMany", "ReadWriteOnce"]
    capacity:
        storage: 2Gi

---
apiVersion: v1
kind: PersistentVolume
metadata:
    name: pv002
    labels:
        name: pv002
spec:
    nfs:
        path: /data/volumes/v2
        server: 192.168.200.200
    accessModes: ["ReadWriteMany"]
    capacity:
        storage: 5Gi

---
apiVersion: v1
kind: PersistentVolume
metadata:
    name: pv003
    labels:
        name: pv003
spec:
    nfs:
        path: /data/volumes/v3
        server: 192.168.200.200
    accessModes: ["ReadWriteMany", "ReadWriteOnce"]
    capacity:
        storage: 20Gi

---
apiVersion: v1
kind: PersistentVolume
metadata:
    name: pv004
    labels:
        name: pv004
spec:
    nfs:
        path: /data/volumes/v4
        server: 192.168.200.200
    accessModes: ["ReadWriteMany", "ReadWriteOnce"]
    capacity:
        storage: 10Gi

---
apiVersion: v1
kind: PersistentVolume
metadata:
    name: pv005
    labels:
        name: pv005
spec:
    nfs:
        path: /data/volumes/v5
        server: 192.168.200.200
    accessModes: ["ReadWriteMany", "ReadWriteOnce"]
    capacity:
        storage: 10Gi

---
kubectl apply -f pod-pv.yml
kubectl get pv
    # RECLAIM POLICY 回收策略, 某个pvc绑定了pv, 当pvc被删除后pv内还有数据, 该如何处理?
        # Retain 保留数据
        # Recycle 回收
        # Delete 删除

vi pod-pvc.yml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
    name: mypvc
    namespace: default
spec:
    accessModes: ["ReadWriteMany"] # pvc的accessModes必须是pv的子集
    resources:
        requests: # 要求有多大的存储空间
            storage: 6Gi

---
apiVersion: v1
kind: Pod
metadata:
    name: pod-vol-pvc
    namespace: default
spec:
    containers:
    - name: myapp
        image: nginx:1.14:alpine
        volumeMounts:
        - name: html
            mountPath: /usr/share/nginx/html/  
        volumes:
        - name: html
            persistentVolumeClaim:
                claimName: mypvc
kubeclt apply -f pod-pvc.yml
kubectl get pv # 可查看STATUS, 是否被Bound
kubectl get pvc

特殊类型的存储卷: 用于制作数据中心

配置容器化应用的方式有以下几种:

  • (1) 自定义命令行参数
    • command
    • args: []
  • (2) 把配置文件直接放入基本镜像并重构
  • (3) 环境变量
    • (3.1) Could Native的应用程序一般可直接通过环境变量加载配置
    • 通过entrypoint脚本来预处理变量为配置文件中配置信息
  • (4) 存储卷
    • (4.1) configmap: 明文
    • (4.2) secret: 密文

configmap

# 创建configmap的方式:
# 第一种: 直接直接用命令行的方式给定
kubectl create configmap nginx-config --from-literal=nginx_port=80 --from-ilteral=server_name=myapp.magedu.com
    # --from-literal=key=value 直接用命令行的方式给定
kubectl get cm
kubectl describe cm nginx-config
    # 可在显示信息中看到Data (定义的key和value)

# 第二种: 配置文件给定
mkdir configmap
vi www.conf
server {
    server_name myapp.magedu.com;
    listen 80;
    root /data/web/html/;
}

kubectl create configmap nginx-www --from-file=www=./www.conf
    # 按这种方式指定, key=www, value=www.conf的文件内容
kubectl create configmap nginx-www --from-file=./www.conf
    # 按照这种方式指定, key=文件名(此例中为www.conf), value=www.conf的文件内容
kubectl descirbe cm nginx-www

vi pod-configmap.yml
  • 通过环境变量的方式向pod传数据:
apiVersion: v1
kind: Pod
metadata:
    name: pod-demo-1
    namespace: default
    labels:
        app: myapp
        tier: frontend 
    annotations:
        alexti/created-by: "cluster admin"
spec:
    containers: 
    - name: myapp 
        image: nginx:1.14-alpine 
        ports: 
        - name: http
            containerPort: 80
        env:
        - name: NGINX_SERVER_PORT # 变量最好使用下划线
            valueFrom: 
                configMapKeyRef: # 引用configmap获取数据
                    name: nginx-config
                    key: nginx_port # nginx_port的值会传递给变量NGINX_SERVER_PORT
                    optional: true # 如果configmap不存在或者configmap中定义的变量没有你需要使用的key, pod将无法被启动, 可以将这一项的值设置为true, 表示此configmap可以在定义完之后再创建
        - name: NGINX_SERVER_NAME
            valueFrom:
                configMapKeyRef:
                    name: nginx-conf
                    key: server_name
                    optional: true
kubectl apply -f pod-configmap.yml
kubectl exec -it pod pod-demo-1 -- /bin/sh
/ # printenv # 可查看到自定义的变量: NGINX_SERVER_PORT和NGINX_SERVER_NAME

kubectl edit cm nginx-config # 支持编辑
  • 通过存储卷的方式向pod传数据:

方法一, 使用命令行创建的configmap:

vi pod-configmap2.yml
apiVersion: v1
kind: Pod
metadata:
    name: pod-demo-2
    namespace: default
    labels:
        app: myapp
        tier: frontend 
    annotations:
        alexti/created-by: "cluster admin"
spec:
    containers: 
    - name: myapp 
        image: nginx:1.14-alpine 
        ports: 
        - name: http
            containerPort: 80
        volumeMounts:
        - name: nginxconf
            mountPath: /etc/nginx/config.d/
            readOnly: true # 不允许容器修改配置文件
        volumes:
        - name: nginxconf
            configMap: # 存储卷类型为configMap
                name: nginx-config
kubectl apply -f pod-configmap2.yml
kubectl exec -it pod pod-demo-2 -- /bin/sh
/ # cd /etc/nginx/config.d/
/ # ls # 可以查看到两个文件, 文件名为nginx_port和server_name

kubectl edit cm nginx-config
    # 将nginx_port从80改为8080

kubectl exec -it pod pod-demo-2 -- /bin/sh
/ # cat /etc/nginx/config/nginx_port # 此时可以查看到结果为修改后的8080

方法二, 使用创建的配置文件:

vi pod-configmap3.yml
apiVersion: v1
kind: Pod
metadata:
    name: pod-demo-3
    namespace: default
    labels:
        app: myapp
        tier: frontend 
    annotations:
        alexti/created-by: "cluster admin"
spec:
    containers: 
    - name: myapp 
        image: nginx:1.14-alpine 
        ports: 
        - name: http
            containerPort: 80
        volumeMounts:
        - name: nginxconf
            mountPath: /etc/nginx/conf.d/
            readOnly: true # 不允许容器修改配置文件
        volumes:
        - name: nginxconf
            configMap: # 存储卷类型为configMap
                name: nginx-www
                # 指定items可以只挂载部分键值而不是全部
kubecgtl apply -f pod-configmap3.yml
kubectl get pods
kuebctl exec -it pod-demo-3 -- /bin/sh
/ # cat /etc/nginx/conf.d/www.conf # 可看到使用配置文件定义的配置
/ # nginx -T # 查看nginx加载的配置

kubectl edit cm nginx-www
    # 将某个参数修改, 例如listen的值改为8080, 等待一段时间后会发现pod内的配置会随之修改为8080, 但此时配置还未生效, 需要重载配置文件
/ # nginx -s reload

secret

kubectl create secret --help
    # 有三种类型
    generic # 通用的secret, 一般用于保存密码
    tls # 保存私钥和证书
    docker-registry # 保存docker-registry认证信息, 连接私有仓库时拉取镜像时使用

kubectl create secret generic mysql-root-password --form-literal=password=MyP@ss123
kubectl get secret
kubectl descirbe secret mysql-root-password # 会发现值不显示
kubectl get secret mysql-root-password -o yaml
echo "经base加密后的密码" | base64 -d # 解码, 可看到密码源码, 说明密码安全性不佳

vi pod-secret-1.yml
apiVersion: v1
kind: Pod
metadata:
    name: pod-demo-4
    namespace: default
    labels:
        app: myapp
        tier: frontend 
    annotations:
        alexti/created-by: "cluster admin"
spec:
    containers: 
    - name: myapp 
        image: nginx:1.14-alpine 
        ports: 
        - name: http
            containerPort: 80
        env:
        - name: MYSQL_ROOT_PASSWORD
            valueFrom: 
                secretKeyRef:
                    name: mysql-root-password
                    key: password
                    optional: true
kubectl apply -f pod-secret-1.yml
kubectl exec -it pod-demo-4 -- printenv # 会发现传入的MYSQL_ROOT_PASSWORD在会解密后通过环境变量的方式注入pod

你可能感兴趣的:(9. kubernetes 存储卷)