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= my.email@provider.com
 
使用:
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.
相关文章
相关标签/搜索