k8s 挂载卷介绍(四)

kubernetes关于pod挂载卷的知识

首先要知道卷是pod资源的属性,pv,pvc是单独的资源。pod 资源的volumes属性有多种type,其中就包含有挂载pvc的类型。这也帮我理清了之间的关系。

pv一般是系统管理员做的

pvc 是一般k8s用户声明的,大概意思就是说我需要一个 什么权限的,多少存储空间的卷,然后k8s api收到这个请求就去找pv资源对象,如果两者相匹配,那么pv就和pvc绑定了。

从这里我们也想到了,pv如果是手动创建的话,那就麻烦大了。几个,几十个还好说,上万个,管理员该如何创建这么多。所以才有了动态创建pv的需求。这就引出另外一个资源 storageClass ,这个资源声明后端挂载什么样的存储服务,比如nfs,chef等,有了这个一般用户在定义pvc的时候,在提出存储空间和读写权限的同时声明用那个storageClass了,

如下:

apiVersion: v1
kind: PersistentVolumeClaim
metadata: mysql-pvc
spec:
  accessModes:
      - ReadWriteMany
  storageClassName: managed-nfs-storage  (注意这里)
  resources:
     requests:
        storage: 5Gi

以上便是pvc使用storageClass资源对象创建pv,pvc的绑定了

api收到对storageClass声明后,就会调用这个storageClass的生产者进行生产。

我们就会想到,在创建storageClass资源对象的时候肯定会指定生产者。

kind: StorageClass
apiVersion: storage.k8s.io/v1
metadata:
  name: example-nfs
provisioner: example.com/nfs  这里指定生产者,其中example.com/nfs只是一个标签,你在deploymend里定义什么这里就写什么。
mountOptions:
  - vers=4.1

那么问题又来了。在k8s中生产者组件不支持nfs,所以才会安装第三方组件。第三方组件的安装就需要创建相关的rbac的角色和账户。第三方组件是用deploymend的资源托管相关组件pod的。

那么通过deploy部署的pod怎么就是provisioner了?这个我不清楚,后面学习后在总结吧。

回到正题上。

volumes 的4种

1. emptyDir

2. gitRepo

3. hostpath

4.PersistentVolumeClaim

5.configMap,secret

6. 各种云平台的存储磁盘卷如google的gce,aws的ebs,azure的azureDisk

其实4只是一个概括,nfs,chef 这些网络存储通通可以单独来使用。但我觉得实际使用中还是讲这些网络存储转化成pv,pvc

从简单开始学习

emptyDir 两种应用场景: 1. 同一个pod中,各个容器间共享文件。 2. 当程序对大数据处理时内存空间不够时临时写入文件(当然也可以使用宿主主机的内存)

例子:

apiVersion: v1
kind: Pod
metadata:
    name: fortune
spec:
    containers:
    -   image: luksa/fortune
         name: html-generator
         volumeMounts:
         -   name: html
             mountPath: /var/htdocs
    -   image: nginx:alpine
         name: web-server
         volumeMounts:
         -   name: html
              mountPaht: /usr/share/nginx/html
              readOnly: true
         ports:
         -   containerPort: 80
              protocol: TCP
      volumes:
      -  name: html
          emptyDir: {}     (为{}表示使用节点服务器的文件系统)
      -  name: html-2
          emptyDir:
               medium: Memory   (使用节点服务器的内存)

以上就是emptyDir的用法。gitRepo其实是依赖于emptyDir的,你可以把它理解成,声明了一个emptyDir然后在把gitrepo下载填充到emptyDir

例子:

apiVersion: v1
kind: Pod
metadata:
    name: gitrepo-volume-pod
spec:
    containers:
    -   image: nginx: alpine
         name: web-nginx
         volumeMounts:
         -   name: html
              mountPath: /usr/share/nginx/html
              readOnly: true
          ports:
          -   containerPort: 80
               protocol: TCP
     volumes:
     -   name: html
          gitRepo:
              repository: https://github.com/luksa/kubia-website-example.git
              revision: master
              directory: .   (这个.很重要,表示在当前emptyDir目录下不然就会创建一个kubia-website-example目录)

以上就是gitRepo的用法,其中有个问题就是pod中的gitrepo并不会及时更新。如果想要及时更新需要用到sidecar ,加入到pod中,在Docker Hub搜索 “git ryc”获取相关镜像。

还有一个情况不得不使用sidecar container 。gitrepo 不支持连接私有库,也就是不能是ssh密钥连接,也不可以有用户名和密码。这时候就需要使用支持验证连接的sidecar container来实现了。具体怎么使用,用到的时候在研究吧.

至此gitRepo卷类型算是简单介绍了,下面学习hostpath

大多数时候pod应该忽略他们的主机节点,因此他们也不需要访问节点文件系统上的文件。但是某些系统级别的pod(通常由DaemonSet管理)确实需要读取节点的文件或使用节点文件系统来访问节设备,这时候就需要用到hostPath

hostPath 算是第一个持久化存储卷了,但是这个很少用到,因为这个卷只能在某一单一节点上,pod重启后很可能在另外一个节点上。当然可以使用NodeSelector但这样看起来也不高明。所以建议使用网络存储。hostPath过

接下来是网络存储和云平台提供的存储磁盘卷。这两种在用到的时候找相关的属性进行配置即可。也没什么要注意的,实际应用场景用到最多的持久存储是pv,pvc,storageClass

configmap

kubectl create configmap fortune-config --from-literal=sleep-interval=25

一般configmap包含多个映射条目所以创建时可以多次使用--from-literal参数

kubectl create conigmap fortune-config --from-literal=foo=bar --from-literal=bar=baz --from-literal=one=two

kubectl get configmap fortune-config -o yaml

configmap同样可以存储粗力度的配置数据,比如完整的配置文件。kubectl create configmap 命令支持从硬盘上读取文件,并将文件内容单独存储为ConfigMap中的条目:

kubectl create configmap my-config --from-file=config-file.conf

运行此命令,kubectl 会在当前目录下找config-file.conf文件,并将文件内容存储在configmap中以config-file.conf 为键名的条目下。当然也可以手动指定键名

kubectl create configmap my-config --from-file=customkey=config-file.conf

kubectl create configmap my-config --from-file=/path/to/dir

这时候,kubectl会为文件中每个文件单独创建条目,仅限文件名可作为合法ConfigMap键名的文件。

当让也可以将上面的参数混合使用

configmap设置完成了,如何将映射的值传递给pod的容器?三种方法

一,设置环境变量,例子如下:

apiVersion: v1
kind: Pod
metadata:
    name: fortune-env-from-configmap
spec:
    containers:
    -   image: luksa/fortune:env
        env:
        -   name: INTERVAL
             valueFrom:
                 configMapKeyRef:
                     name: fortune-config
                     key: sleep-interval

很好奇当pod 容器中引用不存在的configmap会发生什么?

pod会尝试运行所有容器,只有这个容器启动失败,其他正常(假如有多个容器),当你事后创建处这个configmap,无需重启pod,容器就会成功。当然也可以引用为可选的,设置configMapKeyRef.optional: true即可,这样即使ConfigMap不存在,容器也能正常启动。

如果configmap中条目很多,用env属性列出麻烦且容易出错。那么有没有办法一次导入呢。用envFrom, 例如configmap中有三个条目FOO、BAR和FOO-BAR

spec:
    containers:
    -   image: some-image
         envFrom:
         -   prefix: CONFIG_  所有环境变量均包含前缀CONFIG_  ,不设置就将引用configmap中的键名
              configMapRef:
                  name: my-config-map

如此,容器中多出两个变量 CONFIG_FOO 、CONFIG_BAR

为什么是两个,因为另外一个FOO-BAR包含破折号,不是一个合法的环境变量名称。被忽略了,所以我们应该注意创建configmap时 不要使用-

上面我们学习了如何将configmap中的条目以变量的形式传入到容器中

那么如何将configmap中的条目作为容器运行的参数args呢?例子:

apiVersion: v1
kind: Pod
metadata:
    name: fortune-env-from-configmap
spec:
    containers:
    -   image: luksa/fortune:env
        env:
        -   name: INTERVAL
             valueFrom:
                 configMapKeyRef:
                     name: fortune-config
                     key: sleep-interval
        args: ["$(INTERVAL)"]

环境变量和参数都适合于变量值较短的场景。configmap是可以包含完整配置文件内容的,当你想要将其暴露给容器时,可以使用上一章中提到的卷的类型。configmap卷会将ConfigMap中的每个条目均暴露成一个文件。运行在容器的进程通过读取文件内容获得对应的条目值。

configmap-files为一个目录

kubectl create configmap fortune-config --from-file=configmap-files

例子:

apiVersion: v1
kind: Pod
metadata:
    name: fortune-configmap-volume
spec:
    containers:
    - image: nginx:alpine
       name: web-server
       volumeMounts:
       ...
       - name: config
          mountPaht: /etc/nginx/config.d
          readOnly: true
       ....
   volumes:
   ...
   - name: config
      configMap:
           name: fortune-config
   ...

一种特殊情况,当你只想暴露configmap-files目录下的某一个配置文件,该如何做:

volumes:
-   name: config
     configmap:
         name: fortune-config
         items:
             - key: my-nginx-config.conf
                path: gzip.conf

这样配置后,挂载fortune-config 卷后,就只有my-nginx-config.conf 并且挂载后的名称为gzip.conf

另一种特殊情况,我们通过上述挂载configmap卷后会发现,被挂载的目录之前的文件都被隐藏掉了。那么如果你需求不想隐藏之前的文件,该如何做:

spec:
    containers:
    -   image: some/image
         volumeMounts:
         -   name: myvolume
              mountPath: /etc/someconfig.conf 挂载到指定的某一个文件,而不是某个文件夹
              subPath: myconfig.conf 挂载指定的条目,而不是完整的卷

为configMap卷中的文件设置权限

volumes:
-   name: config
    configmap:
        name: fortune-config
        defaultMode: "6600"

更新应用配置且不重启应用程序

使用环境变量或命令行参数作为配置源的弊端在于无法在进程运行时更新配置。将ConfigMap暴露为卷可以达到配置热更新的效果,无需重新创建pod或重启容器。

ConfigMap被更新后,卷中引用它的文件也会相应更新,进程发现文件被改变后进行重载。kubernetes同样支持文件更新后手动通知容器。但要注意的是,更新configmap之后对应文件的更新会相当耗时。

我们使用kubectl edit configmap fortune-config 来更改某一个值。

然后执行

kubectl exec fortune-configmap-volume -c web-server -- cat /etc/nginx/config.d/my-nginx-config.conf

查看文件是不是被修改了,如果没有稍等一会再查看。在确认更改后,我们来手动通知容器进行重载。

kubectl exec fortune-configmap-volume -c web-server -- nginx -s reload

你可能会疑惑 Kubernetes更新完configmap卷中的所有文件之前(所有的文件被更新而不是一部分),应用是否会监听到文件编号并主动进行重载。答案是不会,会在所有的文件更新后,一次性更新到pod容器中。kubernetes通过富豪链接做到这一点的。

kubectl exec -ti fortune-configmap-volume -c web-server -- ls -lA /etc/nginx/config.d

..4989_09_04_15_06.028485

..data -> ..4989_09_04_15_06.028485

my-nginx-config.conf -> ..data/my-nginx-config.conf

sleep-interval -> ..data/sleep-interval

可以看到,被挂载configMap卷中的文件是..data文件夹中文件的符号链接,而..data又是连接到 ..4989的符号链接,每当ConfigMap被更新后,Kubernetes 会创建一个这样的文件夹,卸任所有文件并重新将符号..data链接至新文件夹,通过这种方式可以一次性修改所有文件。

如果挂载configmap中的某一个文件,而不是文件夹,configmap更新之后对应的文件不会被更新。如果现在你需要挂载单个文件且在修改Configmap后想自动更新,可以将该卷挂载到其他文件夹,然后做一个软链接。

至于如何实现应用重载配置 ,需要应用自己实现了。

configmap都是以名文存储的,有些信息比较敏感,就需要用秘文存储了。

这就需要使用kubernetes 的secret资源了。

首先有一个情况我们需要了解

使用kubectl describe pod pod-id 查看任何一个pod你都会发现默认有挂载一个secret卷。

Volumes:
  default-token-ps7ff:
    Type:        Secret (a volume populated by a Secret)
    SecretName:  default-token-ps7ff
    Optional:    false
这个卷里的内容我们可以使用kubectl describe secrets查看
#  kubectl describe secrets default-token-ps7ff
Name:         default-token-ps7ff
Namespace:    default
Labels:       <none>
Annotations:  kubernetes.io/service-account.name: default
              kubernetes.io/service-account.uid: 6efa7f7c-6a61-11e9-bfdb-0a382f97318e

Type:  kubernetes.io/service-account-token

Data
====
ca.crt:     1359 bytes
namespace:  7 bytes
token:      eyJhbGciOiJSUzI1NiIsImtp...

可以看出这个Secret包含是哪个条目ca.crt 、namespace与token

包含了从pod内部安全访问Kubernetes API服务器所需的全部信息。尽管我们希望做到应用对kubernetes无感知,但是直连Kubernetes没有其他方法,你只能使用secret卷提供的文件来访问kubernetes API。

使用kubectl describe pod命令显示secret卷北挂载的位置:

mounts:

/var/run/secrets/kubernetes.io/serviceaccount from default-token-ps7ff (ro)

注意: default-token Secret默认会被挂载至每个容器。可以通过设置pod定义中的automountServiceAccountToken字段为false,或者设置pod使用的服务账户中的相同字段为false来关闭这种默认行为。

查看容器中挂载了哪些条目

# kubectl exec nginx-dnm9n -- ls /var/run/secrets/kubernetes.io/serviceaccount

ca.crt

namespace

token

创建Secret

openssl genrsa -out https.key 2048

openssl req -new -x509 -key https.key -out https.cert -days 3650 -subj /CN=www.kubia-example.com

# kubectl create secret generic fortune-https --from-file=https.key --from-file=https.cert --from-file=foo

secret/fortune-https created

也可以使用 --from-file=fortune-https 囊括这个歌文件夹中的文件

# kubectl get secret fortune-https -o yaml

# kubectl describe secret fortune-https

对比configmap与secret

secret与configMap有比较大的区别,这也是为何kubernetes开发者们在支持了Secret一段时间之后会选择创建ConfigMap。穿件的Secret的YAML格式定义显示

# kubectl get secret fortune-https -o yaml

apiVersion: v1
data:
  foo: YmFyCg==
  https.cert: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSURFekNDQWZ1Z0F3SUJBZ0lKQU96Y00rNzI3RWJHTUEwR0NTcUdTSWIzRFFFQkN3VUFNQ0F4SGpBY0JnTlYKQkF
  https.key: LS0tLS1CRUdJTiBSU0EgUFJJVkFURSBLRVktLS0tLQpNSUlFcFFJQkFBS0NBUUVBeFYvUVJiazJiRm8zRmdZdWpaTWxPVGg3MUxpY3AyUS9pL2pib2E1SExlUlpSTDBi
kind: Secret
. . .
将其与CoinfigMap的Yaml格式定义做对比
apiVersion: v1
data:
  bar: baz
  foo: bar
  one: two
kind: ConfigMap

注意到Secret条目的内容会被以Base64个市编译,而ConfigMap直接以纯文本展示。这种区别导致在处理YAML和JSON格式的Secret时会稍许有些麻烦,需要在设置和读取相关条目时对内容进行编解码。

这个具体使用中是这样的,

比如你现在想把一个配置文件加入到Secret中,那么你首先将配置文件中的内容通过BASE64进行编码后才能作为条目。

当然你会问难道kubernetes不提供base64编码?提供,只能对字符串,不能接受文件。如下:

kund: Secret
apiVersion: v1
stringData:
    foo: plain text
data:
    https.cert: lksjkaldjldasjladgjsjl...
    https.key: lsiodjsdlfjahcdo...

创建后使用kubectl get secret -o yaml会看到stringData字段中的所有条目会被Base64编码后展示在data字段下。所以stringData字段是只写不可读的。

如何在pod中使用Secret
apiVersion:  v1
kind: Pod
metadata:
    name: fortune-https
spec:
    containers:
    -   image: luksa/fortune:env
         name: html-generator
         env:
         -   name: INTERVAL
              valueFrom:
              configMapKeyRef:
                  name: fortune-config
                  key: sleep-interval
          volumeMounts:
          -   name: html
               mountPaht: /var/htdocs
    -   image: nginx:alpine
        name: web-server
        volumeMounts:
        -   name: html
             mountPath: /usr/share/nginx/html
             readOnly: true
        -   name: config
             mountPath: /etc/nginx/conf.d
             readOnly: true
        -   name: certs
             mountPath: /etc/nginx/certs/
             readOnly: true
        ports:
        - containerPort: 80
        - containerPort: 443
    volumes:
    -   name:  html
         emptyDir: {}
    -   name: config
         configmap:
             name: fortune-config
             items:
             -   key: my-nginx-config.conf
                  path: https.conf
    -   name: certs
         secret:
             secretname: fortune-https

简单点的实例:

apiVersion:  v1
kind: Pod
metadata:
    name: fortune-https
spec:
    containers:
    - image: nginx:alpine
      name: web-server
      volumeMounts:
      - name: certs
        mountPath: /etc/nginx/certs/
        readOnly: true
      ports:
      - containerPort: 80
      - containerPort: 443
    volumes:
    - name: certs
      secret:
        secretName: fortune-https

当然也可以将secret条目暴露为环境变量。但不建议这么做,应用通常会在错误报告时转储环境变量,或者是启动时打印在应用日志中,无意中就暴露Secret信息。另外,子进程会继承父进程的所有环境变量,如果是通过第三方二进制程序启动应用,你并不知道它使用敏感数据做了什么。所以不建议用环境变量,建议使用secret卷的形式挂载到pod.

env:
- name: FOO_SECRET
   valueFrom:
       secretKeyRef:
           name: fortune-https
           key: foo

学会了secret,接下来就有一个比较常用的secret实际应用,dockerhub

kubectl create secret docker-registry mydockerhubsecret --docker-username=myusername --docker-password=mypassword --docker-email=[email protected]

使用:

apiVersion: v1
kind: Pod
metadata:
    name: private-pod
spec:
    imagePullSecrets:
    - name: mydockerhubsecret
    containers:
    - image: username/private:tag
       name: main

假设系统通常运行大量Pod,你可能会好奇是否需要为每个Pod都添加相同的镜像拉取Secret.并不是,可以通过添加Secret至ServiceAccount 使所有pod都能自动添加上镜像拉取的Secret.

原文地址:https://www.cnblogs.com/zhming26/p/11719547.html

时间: 2024-11-13 09:11:59

k8s 挂载卷介绍(四)的相关文章

Android—— 4.2 Vold挂载管理_NetlinkManager (四)

在前文Android-- 4.2 Vold挂载管理_主体构建main (一)中有结构图表示,Vold是kernel与用户层的一个交互管理模块, Android-- 4.2 Vold挂载管理_VolumeManager (三)简单介绍了核心VolumeManager的构建,这篇分析从kernel进程沟通到VolumeManager进程的关键:NetlinkManager 撰写不易,转载请注明出处:http://blog.csdn.net/jscese/article/details/3858602

k8s存储卷

1.emptyDir存储卷 apiVersion: v1 kind: Pod metadata: name: cunchujuan spec: containers: - name: myapp #定义第一容器用于显示index.html文件内容 image: ikubernetes/myapp:v1 imagePullPolicy: IfNotPresent volumeMounts: #调用存储卷 - name: html #使用存储卷的名称要和下面定义的一样 mountPath: /usr

Lucene.Net 2.3.1开发介绍 —— 四、搜索(二)

原文:Lucene.Net 2.3.1开发介绍 -- 四.搜索(二) 4.3 表达式用户搜索,只会输入一个或几个词,也可能是一句话.输入的语句是如何变成搜索条件的上一篇已经略有提及. 4.3.1 观察表达式在研究表达式之前,一定要知道,任何一个Query都会对于一个表达式.不光可以通过Query构造表达式,还可以通过拼接字符串构造.这里说的观察表达式是指,用Query完成查询语句后,用ToString()方法输出Query的表达式.很简单是吧,呵呵. 4.3.2 表达式的与或非“与或非”让我想起

Lucene.Net 2.3.1开发介绍 —— 四、搜索(三)

原文:Lucene.Net 2.3.1开发介绍 -- 四.搜索(三) Lucene有表达式就有运算符,而运算符使用起来确实很方便,但另外一个问题来了. 代码 4.3.4.1 Analyzer analyzer = new StandardAnalyzer(); QueryParser parser = new QueryParser("title", analyzer); Query query = parser.Parse(@":"); Console.Write

Lucene.Net 2.3.1开发介绍 —— 四、搜索(一)

原文:Lucene.Net 2.3.1开发介绍 -- 四.搜索(一) 既然是内容筛选,或者说是搜索引擎,有索引,必然要有搜索.搜索虽然与索引有关,那也只是与索引后的文件有关,和索引的程序是无关的,因此,搜索和索引一般是分开部署.简单地说,就是一个应用程序(桌面程序)来索引,一个WEB程序来实现搜索.当然,为了测试的时候简单,这里还是使用NUnit的方式运行.搜索讲完后,将会简单介绍单机搜索引擎如何部署. 4.1 搜索与什么有关 搜索与什么有关呢?即使没有看过前面的文章,那么现在来随便猜一猜. 首

k8s基础学习-介绍持久卷和持久卷声明

在POD中使用PersistentVolume(持久卷,简称PV)要比使用常规的pod复杂一些. 当集群用户需要在其pod中使用持久化存储时,他们首先创建持久卷声明(PersistentVolumeClaim,简称PVC)清单,指定所需要的最低容量要求和访问模式,用户将持久卷声明清单提交给k8s API服务器,k8s将找到可匹配的持久卷并将其绑定到持久卷声明. 原文地址:https://www.cnblogs.com/normanlin/p/10852209.html

cinder挂载卷的过程原理

LVM名称介绍 PV:物理磁盘 VG:卷组,多个PV可以组成一个VG,一个VG可以划分成多个LV(逻辑卷). PP:物理区块,将一个VG逻辑的划分成连续的小块. LP:逻辑区块,若干个PP组成一个LP,多个PP组成一个LP,类似于raid0:一个LP映射多个PP镜像,类似于raid1. LV:由VG划分,若干连续LP组成一个LV(对应OS层的分区 LVM创建到挂载到物理机再到虚机实验 需要安装 lvm2 yum install lvm2 1.给虚拟机挂载三个云硬盘作为硬盘 2.创建pv pv c

Docker:网络及数据卷设置 [四]

一.Docker网络设置 默认情况下,docker会创建一个桥接网卡[docker 0],docker有2种映射方式,一种是随机映射,一种是指定映射 提示:生产场景一般不使用随机映射,但是随机映射的好处就是由docker分配,端口不会冲突 案例1:使用docker启动nginx随机映射配置 [[email protected] ~]# docker run -d -P nginx 63cbe30165c8fb2ce7789a8173db6f2060705028ce6c326d1f0cd467bd

K8s应用案例介绍——阿里云

原文链家:为什么 K8s 在阿里能成功?| 问底中国 IT 技术演进 着重描述了阿里巴巴基于 K8s 的云原生改造实践过程的三大能力升级,在对应能力升级过程中沉淀的技术解决方案,以及通过这些能力升级所取得的业务价值. 云原生技术也从原来的应用容器化发展出包括容器.Service Mesh.微服务.不可变基础设施.Serverless.FaaS 等众多技术方向,CFCF 旗下也囊括了越来多的开源项目. Kubernetes旨在帮助企业解决大规模 IT 基础设施的应用容器编排难题.Kubernete