概览

Secret是用来保存小片敏感数据的k8s资源,例如密码,token,或者秘钥。这类数据当然也可以存放在Pod或者镜像中,但是放在Secret中是为了更方便的控制如何使用数据,并减少暴露的风险。

用户可以创建自己的secret,系统也会有自己的secret。

Pod需要先引用才能使用某个secret,Pod有2种方式来使用secret:作为volume的一个域被一个或多个容器挂载;在拉取镜像的时候被kubelet引用。

內建的Secrets

由ServiceAccount创建的API证书附加的秘钥

k8s自动生成的用来访问apiserver的Secret,所有Pod会默认使用这个Secret与apiserver通信

创建自己的Secret

使用kubectl create secret命令创建Secret

假如mougePod要访问数据库,需要用户名密码,分别存放在2个文件中:username.txt,password.txt

# Create files needed for rest of example.
$ echo -n 'admin' > ./username.txt
$ echo -n '1f2d1e2e67df' > ./password.txt

kubectl create secret指令将用户名密码写到secret中,并在apiserver创建Secret

$ kubectl create secret generic db-user-pass --from-file=./username.txt --from-file=./password.txt
secret "db-user-pass" created

查看创建结果:

$ kubectl get secrets
NAME TYPE DATA AGE
db-user-pass Opaque 51s
$ kubectl describe secrets/db-user-pass
Name: db-user-pass
Namespace: default
Labels: <none>
Annotations: <none> Type: Opaque Data
====
password.txt: bytes
username.txt: bytes

get或describe指令都不会展示secret的实际内容,这是出于对数据的保护的考虑,如果想查看实际内容请继续往下看。

手动创建Secret

创建一个secret.yaml文件,内容用base64编码

$ echo -n 'admin' | base64
YWRtaW4=
$ echo -n '1f2d1e2e67df' | base64
MWYyZDFlMmU2N2Rm

yaml文件内容:

apiVersion: v1
kind: Secret
metadata:
name: mysecret
type: Opaque
data:
username: YWRtaW4=
password: MWYyZDFlMmU2N2Rm

创建:

$ kubectl create -f ./secret.yaml
secret "mysecret" created

解析Secret中内容

$ kubectl get secret mysecret -o yaml
apiVersion: v1
data:
username: YWRtaW4=
password: MWYyZDFlMmU2N2Rm
kind: Secret
metadata:
creationTimestamp: --22T18::56Z
name: mysecret
namespace: default
resourceVersion: ""
selfLink: /api/v1/namespaces/default/secrets/mysecret
uid: cfee02d6-c137-11e5-8d73-42010af00002
type: Opaque

base64解码:

$ echo 'MWYyZDFlMmU2N2Rm' | base64 --decode
1f2d1e2e67df

使用Secret

secret可以作为数据卷挂载或者作为环境变量暴露给Pod中的容器使用,也可以被系统中的其他资源使用。比如可以用secret导入与外部系统交互需要的证书文件等。

在Pod中以文件的形式使用secret

  1. 创建一个Secret,多个Pod可以引用同一个Secret
  2. 修改Pod的定义,在spec.volumes[]加一个volume,给这个volume起个名字,spec.volumes[].secret.secretName记录的是要引用的Secret名字
  3. 在每个需要使用Secret的容器中添加一项spec.containers[].volumeMounts[],指定spec.containers[].volumeMounts[].readOnly = truespec.containers[].volumeMounts[].mountPath要指向一个未被使用的系统路径。
  4. 修改镜像或者命令行使系统可以找到上一步指定的路径。此时Secret中data字段的每一个key都是指定路径下面的一个文件名

下面是一个Pod中引用Secret的列子:

apiVersion: v1
kind: Pod
metadata:
name: mypod
spec:
containers:
- name: mypod
image: redis
volumeMounts:
- name: foo
mountPath: "/etc/foo"
readOnly: true
volumes:
- name: foo
secret:
secretName: mysecret

每一个被引用的Secret都要在spec.volumes中定义

如果Pod中的多个容器都要引用这个Secret那么每一个容器定义中都要指定自己的volumeMounts,但是Pod定义中声明一次spec.volumes就好了。

映射secret key到指定的路径

可以控制secret key被映射到容器内的路径,利用spec.volumes[].secret.items来修改被映射的具体路径

apiVersion: v1
kind: Pod
metadata:
name: mypod
spec:
containers:
- name: mypod
image: redis
volumeMounts:
- name: foo
mountPath: "/etc/foo"
readOnly: true
volumes:
- name: foo
secret:
secretName: mysecret
items:
- key: username
path: my-group/my-username

发生了什么呢?

  • username被映射到了文件/etc/foo/my-group/my-username而不是/etc/foo/username
  • password没有变

Secret文件权限

可以指定secret文件的权限,类似linux系统文件权限,如果不指定默认权限是0644,等同于linux文件的-rw-r--r--权限

设置默认权限位

apiVersion: v1
kind: Pod
metadata:
name: mypod
spec:
containers:
- name: mypod
image: redis
volumeMounts:
- name: foo
mountPath: "/etc/foo"
volumes:
- name: foo
secret:
secretName: mysecret
defaultMode:

上述文件表示将secret挂载到容器的/etc/foo路径,每一个key衍生出的文件,权限位都将是0400

由于JSON不支持八进制数字,因此用十进制数256表示0400,如果用yaml格式的文件那么就很自然的使用八进制了

同理可以单独指定某个key的权限

apiVersion: v1
kind: Pod
metadata:
name: mypod
spec:
containers:
- name: mypod
image: redis
volumeMounts:
- name: foo
mountPath: "/etc/foo"
volumes:
- name: foo
secret:
secretName: mysecret
items:
- key: username
path: my-group/my-username
mode:

从volume中读取secret的值

值得注意的一点是,以文件的形式挂载到容器中的secret,他们的值已经是经过base64解码的了,可以直接读出来使用。

$ ls /etc/foo/
username
password
$ cat /etc/foo/username
admin
$ cat /etc/foo/password
1f2d1e2e67df

被挂载的secret内容自动更新

也就是如果修改一个Secret的内容,那么挂载了该Secret的容器中也将会取到更新后的值,但是这个时间间隔是由kubelet的同步时间决定的。最长的时间将是一个同步周期加上缓存生命周期(period+ttl)

特例:以subPath形式挂载到容器中的secret将不会自动更新

以环境变量的形式使用Secret

  1. 创建一个Secret,多个Pod可以引用同一个Secret
  2. 修改pod的定义,定义环境变量并使用env[].valueFrom.secretKeyRef指定secret和相应的key
  3. 修改镜像或命令行,让它们可以读到环境变量
apiVersion: v1
kind: Pod
metadata:
name: secret-env-pod
spec:
containers:
- name: mycontainer
image: redis
env:
- name: SECRET_USERNAME
valueFrom:
secretKeyRef:
name: mysecret
key: username
- name: SECRET_PASSWORD
valueFrom:
secretKeyRef:
name: mysecret
key: password
restartPolicy: Never

容器中读取环境变量,已经是base64解码后的值了:

$ echo $SECRET_USERNAME
admin
$ echo $SECRET_PASSWORD
1f2d1e2e67df

使用imagePullSecrets

创建一个专门用来访问镜像仓库的secret,当创建Pod的时候由kubelet访问镜像仓库并拉取镜像,具体描述文档在 这里

设置自动导入的imagePullSecrets

可以手动创建一个,然后在serviceAccount中引用它。所有经过这个serviceAccount创建的Pod都会默认使用关联的imagePullSecrets来拉取镜像,参考文档

自动挂载手动创建的Secret

参考文档

详情

限制

需要被挂载到Pod中的secret需要提前创建,否则会导致Pod创建失败

secret是有命名空间属性的,只有在相同namespace的Pod才能引用它

单个Secret容量限制的1Mb,这么做是为了防止创建超大的Secret导致apiserver或kubelet的内存耗尽。但是创建过多的小容量secret同样也会耗尽内存,这个问题在将来可能会有方案解决

kubelet只支持由API server创建出来的Pod中引用secret,使用特殊方式创建出来的Pod是不支持引用secret的,比如通过kubelet的--manifest-url参数创建的pod,或者--config参数创建的,或者REST API创建的。

通过secretKeyRef引用一个不存在你secret key会导致pod创建失败

用例

Pod中的ssh keys

创建一个包含ssh keys的secret

kubectl create secret generic ssh-key-secret --from-file=ssh-privatekey=/path/to/.ssh/id_rsa --from-file=ssh-publickey=/path/to/.ssh/id_rsa.pub

创建一个Pod,其中的容器可以用volume的形式使用ssh keys

kind: Pod
apiVersion: v1
metadata:
name: secret-test-pod
labels:
name: secret-test
spec:
volumes:
- name: secret-volume
secret:
secretName: ssh-key-secret
containers:
- name: ssh-test-container
image: mySshImage
volumeMounts:
- name: secret-volume
readOnly: true
mountPath: "/etc/secret-volume"

Pod中区分生产和测试证书

创建2种不同的证书,分别用在生产和测试环境

$ kubectl create secret generic prod-db-secret --from-literal=username=produser --from-literal=password=Y4nys7f11
secret "prod-db-secret" created
$ kubectl create secret generic test-db-secret --from-literal=username=testuser --from-literal=password=iluvtests
secret "test-db-secret" created

再创建2个不同的Pod

apiVersion: v1
kind: List
items:
- kind: Pod
apiVersion: v1
metadata:
name: prod-db-client-pod
labels:
name: prod-db-client
spec:
volumes:
- name: secret-volume
secret:
secretName: prod-db-secret
containers:
- name: db-client-container
image: myClientImage
volumeMounts:
- name: secret-volume
readOnly: true
mountPath: "/etc/secret-volume"
- kind: Pod
apiVersion: v1
metadata:
name: test-db-client-pod
labels:
name: test-db-client
spec:
volumes:
- name: secret-volume
secret:
secretName: test-db-secret
containers:
- name: db-client-container
image: myClientImage
volumeMounts:
- name: secret-volume
readOnly: true
mountPath: "/etc/secret-volume"

两个容器中都会有下列的文件

/etc/secret-volume/username
/etc/secret-volume/password

以“.”开头的key可以产生隐藏文件

kind: Secret
apiVersion: v1
metadata:
name: dotfile-secret
data:
.secret-file: dmFsdWUtMg0KDQo=
---
kind: Pod
apiVersion: v1
metadata:
name: secret-dotfiles-pod
spec:
volumes:
- name: secret-volume
secret:
secretName: dotfile-secret
containers:
- name: dotfile-test-container
image: k8s.gcr.io/busybox
command:
- ls
- "-l"
- "/etc/secret-volume"
volumeMounts:
- name: secret-volume
readOnly: true
mountPath: "/etc/secret-volume"

会在挂载目录下产生一个隐藏文件,/etc/secret-volume/.secret-file

最佳实践

风险

k8s中secret解析的更多相关文章

  1. 在k8s中搭建可解析hostname的DNS服务

    2016-01-25更新 上篇文章总结k8s中搭建hbase时,遇到Pod中hostname的DNS解析问题,本篇将通过修改kube2sky源码来解决这个问题. 1 前言 kube2sky在Githu ...

  2. k8s中pod内dns无法解析的问题

    用k8s创建了pod,然后进入pod后,发现在pod中无法解析www.baidu.com,也就是出现了无法解析外面的域名的问题.经过高人指点,做个小总结.操作如下. 一,将CoreDNS 的Confi ...

  3. k8s中yaml文常见语法

    在k8s中,所有的配置都是 json格式的.但为了读写方便,通常将这些配置写成yaml 格式,其运行的时候,还是会靠yaml引擎将其转化为json,apiserver 也仅接受json的数据类型. y ...

  4. 从harbor部署到在k8s中使用

    一.概述 harbor是什么呢?英文单词的意思是:港湾.港湾用来存放集装箱(货物的),而docker的由来正是借鉴了集装箱的原理,所以harbor是用于存放docker的镜像,作为镜像仓库使用.官方的 ...

  5. 在k8s中的基本概念

    在k8s中的基本概念 一.Pod1. podk8s下最重要也最基本的概念,由一个根容器Pause和许多用户业务容器组成,是容器的载体. 2. pod的yaml定义格式及字段 apiVersion: v ...

  6. [转帖]k8s 中的服务如何沟通

    k8s 中的服务如何沟通 https://www.jianshu.com/p/9fae09876eb7 本文将介绍 k8s 中的服务如何相互访问,例如后端服务访问数据库,不同类型的服务间的相互访问.并 ...

  7. [转帖]在 k8s 中通过 Ingress 配置域名访问

    在 k8s 中通过 Ingress 配置域名访问 https://juejin.im/post/5db8da4b6fb9a0204520b310 在上篇文章中我们已经使用 k8s 部署了第一个应用,此 ...

  8. [转帖]在 k8s 中自动为域名配置 https

    在 k8s 中自动为域名配置 https https://juejin.im/post/5db8d94be51d4529f73e2833 随着 web 的发展,https 对于现代网站来说是必不可少的 ...

  9. k8s中的网络(较详细汇总)

    目录 一.网络前提条件-网络模型 二.需要解决的网络问题 1.容器和容器之间的网络 2.pod与pod之间的网络 同一台node节点上pod和pod通信 不同node节点上pod和pod通信 3.po ...

随机推荐

  1. CDI Event解析

    CDI(Contexts And Dependency Injection)是JavaEE 6标准中一个规范,将依赖注入IOC/DI上升到容器级别, 它提供了Java EE平台上服务注入的组件管理核心 ...

  2. 关于createTextRange和createRange的一些用法【转】

    一.返回createTextRange的text和htmlText <mce:script language="javascript"><!--function ...

  3. you need to be root to perform this command

    在linux 终端执行某条命令时 提示一下错误 you need to be root to perform this command 是提示要获取root权限 输入su 回车输入密码 即可解决 参考 ...

  4. 用MVC5+EF6+WebApi 做一个小功能(一)开场挖坑,在线答题系统

    从哪开始说呢,这几年微软的技术一直在变,像是牟足了劲要累死所有的NET程序员,从WebForm到MVC到现在MPA.SPA .Razor单页,从net2.0一直走到现在.net4.6.2,后面还有一个 ...

  5. mongodb 连接失败

    需要加一个配置文件,mongo.config bind_ip = 127.0.0.1 dbpath = D:\MongoDB\data\db logpath = D:\MongoDB\data\mon ...

  6. Android Studion有用的快捷键

    注释:ctrl+/ 如果代码未添加注释,则添加注释上去:否则取消已经注释. 格式化代码:ctrl+alt+L l键不需要大写锁定,这里只是为了更清楚表示是L键.

  7. leetcode 56 合并区间 JAVA

    题目: 给出一个区间的集合,请合并所有重叠的区间. 示例 1: 输入: [[1,3],[2,6],[8,10],[15,18]] 输出: [[1,6],[8,10],[15,18]] 解释: 区间 [ ...

  8. NOIP2018滚粗祭(周记更新至11.25)

      还好吧, 好像回归之后 还是有时间去机房转一转的 一个特别生动的例子就是 体育会考就去机房呆了一上午. 这里又要吐槽一下信息技术会考 stm我拿到的第一道题就是 https://www.luogu ...

  9. [Objective-C语言教程]基础框架(34)

    如果您参考Apple文档,应该会看到Foundation框架的详细信息,如下所示. Foundation框架定义了Objective-C类的基础层. 除了提供一组有用的原始对象类之外,它还引入了几个定 ...

  10. tf入门-池化函数 tf.nn.max_pool 的介绍

    转载自此大神 http://blog.csdn.net/mao_xiao_feng/article/details/53453926 max pooling是CNN当中的最大值池化操作,其实用法和卷积 ...