<文章感谢 xingdian >
文章目录
kubernetes-pod-API
一:Pod API 对象
Pod是 k8s 项目中的最小编排单位。将这个设计落实到 API 对象上,容器(Container)就成了 Pod 属性里一个普通的字段。
问题:
到底哪些属性属于 Pod 对象,哪些属性属于 Container?
解决:
Pod 扮演的是传统环境里"虚拟机"的角色。是为了使用户从传统环境(虚拟机环境)向 k8s(容器环境)的迁移,更加平滑。
把 Pod 看成传统环境里的"机器"、把容器看作是运行在这个"机器"里的"用户程序",那么很多关于 Pod 对象的设计就非常容易理解了。
凡是调度、网络、存储,以及安全相关的属性,基本上是 Pod 级别的。
共同特征是,它们描述的是"机器"这个整体,而不是里面运行的"程序"。
比如:
配置这个"机器"的网卡(即:Pod 的网络定义)
配置这个"机器"的磁盘(即:Pod 的存储定义)
配置这个"机器"的防火墙(即:Pod 的安全定义)
这台"机器"运行在哪个服务器之上(即:Pod 的调度)
kind
指定了这个 API 对象的类型(Type),是一个 Pod,根据实际情况,此处资源类型可以是Deployment、Job、Ingress、Service等。
metadata
包含Pod的一些meta信息,比如名称、namespace、标签等信息。
spec
specification of the resource content 指定该资源的内容,包括一些container,storage,volume以及其他Kubernetes需要的参数,以及诸如是否在容器失败时重新启动容器的属性。可在特定Kubernetes API找到完整的Kubernetes Pod的属性。
容器可选的设置属性:
除了上述的基本属性外,还能够指定复杂的属性,包括容器启动运行的命令、使用的参数、工作目录以及每次实例化是否拉取新的副本。 还可以指定更深入的信息,例如容器的退出日志的位置。
容器可选的设置属性包括:
name、image、command、args、workingDir、ports、env、resource、volumeMounts、livenessProbe、readinessProbe、livecycle、terminationMessagePath、imagePullPolicy、securityContext、stdin、stdinOnce、tty
跟"机器"相关的配置
NodeSelector:
是一个供用户将 Pod 与 Node 进行绑定的字段,用法:
apiVersion: v1
kind: Pod
...
spec:
nodeSelector:
disktype: ssd
表示这个 Pod 永远只能运行在携带了"disktype: ssd"标签(Label)的节点上;否则,它将调度失败。
NodeName
一旦 Pod 的这个字段被赋值,k8s就会被认为这个 Pod 已经经过了调度,调度的结果就是赋值的节点名字。
这个字段一般由调度器负责设置,用户也可以设置它来"骗过"调度器,这个做法一般是在测试或者调试的时候才会用到。
HostAliases
定义 Pod 的 hosts 文件(比如 /etc/hosts)里的内容,用法:
apiVersion: v1
kind: Pod
...
spec:
hostAliases:
- ip: "10.1.2.3"
hostnames:
- "foo.remote"
- "bar.remote"
...
这里设置了一组 IP 和 hostname 的数据。
此Pod 启动后,/etc/hosts 的内容将如下所示:
# cat /etc/hosts
# Kubernetes-managed hosts file.
127.0.0.1 localhost
...
10.244.135.10 hostaliases-pod
10.1.2.3 foo.remote
10.1.2.3 bar.remote
注意:在 k8s 中,如果要设置 hosts 文件里的内容,一定要通过这种方法。否则,如果直接修改了 hosts 文件,在 Pod 被删除重建之后,kubelet 会自动覆盖掉被修改的内容。
凡是跟容器的 Linux Namespace 相关的属性,也一定是 Pod 级别的
原因:Pod 的设计,就是要让它里面的容器尽可能多地共享 Linux Namespace,仅保留必要的隔离和限制能力。这样,Pod 模拟出的效果,就跟虚拟机里程序间的关系非常类似了。
案例
一个 Pod 定义 yaml 文件如下:
apiVersion: v1
kind: Pod
metadata:
name: nginx
spec:
shareProcessNamespace: true
containers:
- name: nginx
image: nginx
- name: shell
image: busybox
stdin: true
tty: true
- 定义了 shareProcessNamespace=true
表示这个 Pod 里的容器要共享 PID Namespace
- 定义了两个容器:
一个 nginx 容器
一个开启了 tty 和 stdin 的 shell 容器
在 Pod 的 YAML 文件里声明开启它们俩,等同于设置了 docker run 里的 -it(-i 即 stdin,-t 即 tty)参数。
可以直接认为 tty 就是 Linux 给用户提供的一个常驻小程序,用于接收用户的标准输入,返回操作系统的标准输出。为了能够在 tty 中输入信息,需要同时开启 stdin(标准输入流)。
此 Pod 被创建后,就可以使用 shell 容器的 tty 跟这个容器进行交互了。
创建资源并连接到 shell 容器的 tty 上:
# kubectl attach -it nginx -c shell
在 shell 容器里执行 ps 指令,查看所有正在运行的进程:
# kubectl attach -it nginx -c shell
/ # ps ax
PID USER TIME COMMAND
1 root 0:00 /pause
8 root 0:00 nginx: master process nginx -g daemon off;
14 101 0:00 nginx: worker process
15 root 0:00 sh
21 root 0:00 ps ax
在容器里不仅可以看到它本身的 ps ax 指令,还可以看到 nginx 容器的进程,以及 Infra 容器的 /pause 进程。也就是说整个 Pod 里的每个容器的进程,对于所有容器来说都是可见的:它们共享了同一个 PID Namespace。
凡是 Pod 中的容器要共享宿主机的 Namespace,也一定是 Pod 级别的定义
比如:
apiVersion: v1
kind: Pod
metadata:
name: nginx
spec:
hostNetwork: true
hostIPC: true
hostPID: true
containers:
- name: nginx
image: nginx
- name: shell
image: busybox
stdin: true
tty: true
定义了共享宿主机的 Network、IPC 和 PID Namespace。这样,此 Pod 里的所有容器,会直接使用宿主机的网络、直接与宿主机进行 IPC 通信、看到宿主机里正在运行的所有进程。
容器属性:
Pod 里最重要的字段"Containers":
"Containers"和"Init Containers"这两个字段都属于 Pod 对容器的定义,内容也完全相同,只是 Init Containers 的生命周期,会先于所有的 Containers,并且严格按照定义的顺序执行。
k8s 对 Container 的定义,和 Docker 相比并没有什么太大区别。
Docker中Image(镜像)、Command(启动命令)、workingDir(容器的工作目录)、Ports(容器要开发的端口),以及 volumeMounts(容器要挂载的 Volume)都是构成container 的主要字段。
其他的容器属性:
ImagePullPolicy 字段:
定义镜像的拉取策略。之所以是一个 Container 级别的属性,是因为容器镜像本来就是 Container 定义中的一部分。
默认值: Always
表示每次创建 Pod 都重新拉取一次镜像。
当容器的镜像是类似于 nginx 或者 nginx:latest 这样的名字时,imagePullPolicy 也会被认为 Always。
值:Never 或者 IfNotPresent
表示 Pod 永远不会主动拉取这个镜像,或者只在宿主机上不存在这个镜像时才拉取。
Lifecycle 字段:
定义 Container Lifecycle Hooks。作用是在容器状态发生变化时触发一系列"钩子"。
例子:这是 k8s 官方文档的一个 Pod YAML 文件
在这个例子中,容器成功启动之后,在 /usr/share/message 里写入了一句"欢迎信息"(即 postStart 定义的操作)。而在这个容器被删除之前,我们则先调用了 nginx 的退出指令(即 preStop 定义的操作),从而实现了容器的"优雅退出"。
apiVersion: v1
kind: Pod
metadata:
name: lifecycle-demo
spec:
containers:
- name: lifecycle-demo-container
image: daocloud.io/library/nginx:latest
lifecycle:
postStart:
exec:
command: ["/bin/sh", "-c", "echo Hello from the postStart handler > /usr/share/message"]
preStop:
exec:
command: ["/usr/sbin/nginx","-s","quit"]
-
定义了一个 nginx 镜像的容器
-
设置了一个 postStart 和 preStop 参数
postStart:是在容器启动后,立刻执行一个指定的操作。
注意:
postStart 定义的操作,虽然是在 Docker 容器 ENTRYPOINT 执行之后,但它并不严格保证顺序。
也就是说,在 postStart 启动时,ENTRYPOINT 有可能还没有结束。
如果 postStart执行超时或者错误,k8s 会在该 Pod 的 Events 中报出该容器启动失败的错误信息,导致 Pod 也处于失败的状态。
preStop:
是容器被杀死之前(比如,收到了 SIGKILL 信号)。
注意:
preStop 操作的执行,是同步的。
所以,它会阻塞当前的容器杀死流程,直到这个 Hook 定义操作完成之后,才允许容器被杀死,这跟 postStart 不一样。
一个Pod 对象在 Kubernetes 中的生命周期
Pod 生命周期的变化,主要体现在 Pod API 对象的Status 部分,这是除了 Metadata 和 Spec 之外的第三个重要字段。其中,pod.status.phase,就是 Pod 的当前状态,有如下几种可能的情况:
Pending:
此状态表示Pod 的 YAML 文件已经提交给了 Kubernetes,API 对象已经被创建并保存在 Etcd 当中。
但这个 Pod 里有些容器因为某种原因而不能被顺利创建。比如,调度不成功。
Running:
此状态表示Pod 已经调度成功,跟一个具体的节点绑定。它包含的容器都已经创建成功,并且至少有一个正在运行中。
Succeeded:
此状态表示 Pod 里的所有容器都正常运行完毕,并且已经退出了。这种情况在运行一次性任务时最为常见。
Failed:
此状态表示 Pod 里至少有一个容器以不正常的状态(非 0 的返回码)退出。
这个状态的出现,意味着你得想办法 Debug 这个容器的应用,比如查看 Pod 的 Events 和日志。
Unknown:
这是一个异常状态,表示 Pod 的状态不能持续地被 kubelet 汇报给 kube-apiserver
这很有可能是主从节点(Master 和 Kubelet)间的通信出现了问题。
Pod 对象的 Status 字段,还可以再细分出一组 Conditions:
这些细分状态的值包括:PodScheduled、Ready、Initialized,以及 Unschedulable
它们主要用于描述造成当前 Status 的具体原因是什么。
比如, Pod 当前的 Status 是 Pending,对应的 Condition 是 Unschedulable,这表示它的调度出现了问题。
比如, Ready 这个细分状态表示 Pod 不仅已经正常启动(Running 状态),而且已经可以对外提供服务了。这两者之间(Running 和 Ready)是有区别的,仔细思考一下。
Pod 的这些状态信息,是判断应用运行情况的重要标准,尤其是 Pod 进入了非"Running"状态后,一定要能迅速做出反应,根据它所代表的异常情况开始跟踪和定位,而不是去手忙脚乱地查阅文档。
二:kubernetes-secret
secret
secret用来保存小片敏感数据的k8s资源,例如密码,token,或者秘钥。这类数据当然也可以存放在Pod或者镜像中,但是放在Secret中是为了更方便的控制如何使用数据,并减少暴露的风险。
用户可以创建自己的secret,系统也会有自己的secret。Pod需要先引用才能使用某个secret
Pod使用secret的方式
\1. 作为volume的一个域被一个或多个容器挂载
\2. 在拉取镜像的时候被kubelet引用
內建的Secrets
由ServiceAccount创建的API证书附加的秘钥,k8s自动生成的用来访问apiserver的Secret,所有Pod会默认使用这个Secret与apiserver通信.
创建自己的Secret
方式1:使用kubectl create secret命令
方式2:yaml文件创建Secret
命令方式创建secret:
假如某个Pod要访问数据库,需要用户名密码,分别存放在2个文件中:username.txt,password.txt
例子:
# 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 2 51s
# kubectl describe secret/db-user-pass
Name: db-user-pass
Namespace: default
Labels: <none>
Annotations: <none>
Type: Opaque
Data
====
password.txt: 12 bytes
username.txt: 5 bytes
get或describe指令都不会展示secret的实际内容,这是出于对数据的保护的考虑,如果想查看实际内容使用命令:
# kubectl get secret db-user-pass -o json
yaml方式创建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: 2016-01-22T18:41:56Z
name: mysecret
namespace: default
resourceVersion: "164619"
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
创建一个Secret,多个Pod可以引用同一个Secret
修改Pod的定义,在spec.volumes[]加一个volume,给这个volume起个名字,spec.volumes[].secret.secretName记录的是要引用的Secret名字,在每个需要使用Secret的容器中添加一项spec.containers[].volumeMounts[],指定spec.containers[].volumeMounts[].readOnly = true,spec.containers[].volumeMounts[].mountPath要指向一个未被使用的系统路径。
修改镜像或者命令行使系统可以找到上一步指定的路径。此时Secret中data字段的每一个key都是指定路径下面的一个文件名
Pod中引用Secret的列子
apiVersion: v1
kind: Pod
metadata:
name: mypod
spec:
containers:
- name: mypod
image: redis
volumeMounts:
- name: foo
mountPath: "/etc/foo" //这里是pod内部的目录
readOnly: true
volumes:
- name: foo
secret:
secretName: mysecret
去pod里面查看:
[root@k8s-master ~]# kubectl exec -it mypod /bin/bash
root@mypod:/# cd /etc/foo/
root@mypod:/etc/foo# ls
password username
每一个被引用的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: 256
上述文件表示将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: 511
从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
创建一个Secret,多个Pod可以引用同一个Secret
修改pod的定义,定义环境变量并使用env[].valueFrom.secretKeyRef指定secret和相应的key
修改镜像或命令行,让它们可以读到环境变量
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: daocloud.io/library/nginx
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: daocloud.io/library/nginx
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
实验案例
Secret:
作用是帮你把 Pod 想要访问的加密数据,存放到 Etcd 中。然后,就可以通过在 Pod 的容器里挂载 Volume 的方式,访问到这些 Secret 里保存的信息了。
Secret 典型的使用场景:
存放数据库的 Credential 信息
例子:
# cat test-projected-volume.yaml
apiVersion: v1
kind: Pod
metadata:
name: test-projected-volume
spec:
containers:
- name: test-secret-volume
image: busybox
args:
- sleep
- "86400"
volumeMounts:
- name: mysql-cred
mountPath: "/projected-volume"
readOnly: true
volumes:
- name: mysql-cred
projected:
sources:
- secret:
name: user
- secret:
name: pass
定义了一个容器,它声明挂载的 Volume是 projected 类型 , 并不是常见的 emptyDir 或者 hostPath 类型,而这个 Volume 的数据来源,则是名为 user 和 pass 的 Secret 对象,分别对应的是数据库的用户名和密码。
这里用到的数据库的用户名、密码,正是以 Secret 对象的方式交给 Kubernetes 保存的。
方法1. 使用 kubectl create secret 指令创建Secret对象
# cat ./username.txt
admin
# cat ./password.txt
c1oudc0w!
# kubectl create secret generic user --from-file=./username.txt
# kubectl create secret generic pass --from-file=./password.txt
username.txt 和 password.txt 文件里,存放的就是用户名和密码;而 user 和 pass,则是为 Secret 对象指定的名字。
查看Secret 对象:
# kubectl get secrets
NAME TYPE DATA AGE
user Opaque 1 51s
pass Opaque 1 51s
方法2. 通过编写 YAML 文件的方式来创建这个 Secret 对象
apiVersion: v1
kind: Secret
metadata:
name: mysecret
type: Opaque
data:
user: YWRtaW4=
pass: MWYyZDFlMmU2N2Rm
Secret 对象要求这些数据必须是经过 Base64 转码的,以免出现明文密码的安全隐患。转码操作:
# echo -n 'admin' | base64
YWRtaW4=
# echo -n '1f2d1e2e67df' | base64
MWYyZDFlMmU2N2Rm
注意:像这样创建的 Secret 对象,它里面的内容仅仅是经过了转码,并没有被加密。生产环境中,需要在 Kubernetes 中开启 Secret 的加密插件,增强数据的安全性。
用yaml方式创建的secret调用方法如下:
# cat test-projected-volume.yaml
apiVersion: v1
kind: Pod
metadata:
name: test-projected-volume1
spec:
containers:
- name: test-secret-volume1
image: busybox
args:
- sleep
- "86400"
volumeMounts:
- name: mysql-cred
mountPath: "/projected-volume"
readOnly: true
volumes:
- name: mysql-cred
secret:
secretName: mysecret
创建这个 Pod:
# kubectl create -f test-projected-volume.yaml
验证这些 Secret 对象是不是已经在容器里了:
# kubectl exec -it test-projected-volume -- /bin/sh
注意:
报错:上面这条命令会报错如下
# kubectl exec -it test-projected-volume /bin/sh
error: unable to upgrade connection: Forbidden (user=system:anonymous, verb=create, resource=nodes, subresource=proxy)
解决:绑定一个cluster-admin的权限
# kubectl create clusterrolebinding system:anonymous --clusterrole=cluster-admin --user=system:anonymous
clusterrolebinding.rbac.authorization.k8s.io/system:anonymous created
/ # ls /projected-volume/
user
pass
/ # cat /projected-volume/user
root
/ # cat /projected-volume/pass
1f2d1e2e67df
结果中看到,保存在 Etcd 里的用户名和密码信息,已经以文件的形式出现在了容器的 Volume 目录里。
而这个文件的名字,就是 kubectl create secret 指定的 Key,或者说是 Secret 对象的 data 字段指定的 Key。
同步更新:
通过挂载方式进入到容器里的 Secret,一旦其对应的 Etcd 里的数据被更新,这些 Volume 里的文件内容,同样也会被更新,kubelet 组件在定时维护这些 Volume。
\1. 生成新的密码数据:
# echo -n '111111' | base64
MTExMTEx
\2 . 修改数据:
# cat mysecret.yaml
apiVersion: v1
kind: Secret
metadata:
name: mysecret
type: Opaque
data:
user: YWRtaW4=
pass: MTExMTEx
\3. 更新数据:
# kubectl apply -f mysecret.yaml
Warning: kubectl apply should be used on resource created by either kubectl create --save-config or kubectl apply
secret/mysecret configured
\4. 查看对应pod里的数据是否更新:
# kubectl exec -it test-projected-volume1 /bin/sh
/ # cat projected-volume/pass
111111/ #
注:这个更新可能会有一定的延时。所以在编写应用程序时,在发起数据库连接的代码处写好重试和超时的逻辑,绝对是个好习惯。
查看secret具体的值:
# kubectl get secret mysecret -o json
{
"apiVersion": "v1",
"data": {
"pass": "MTExMTEx",
"user": "YWRtaW4="
},
"kind": "Secret",
"metadata": {
"annotations": {
"kubectl.kubernetes.io/last-applied-configuration": "{\"apiVersion\":\"v1\",\"data\":{\"pass\":\"MTExMTEx\",\"user\":\"YWRtaW4=\"},\"kind\":\"Secret\",\"metadata\":{\"annotations\":{},\"name\":\"mysecret\",\"namespace\":\"default\"},\"type\":\"Opaque\"}\n"
},
"creationTimestamp": "2019-01-21T07:31:05Z",
"name": "mysecret",
"namespace": "default",
"resourceVersion": "125857",
"selfLink": "/api/v1/namespaces/default/secrets/mysecret",
"uid": "82e20780-1d4e-11e9-baa8-000c29f01606"
},
"type": "Opaque"
}
k8s集群使用harbor私有仓库中的镜像
1.使用命令创建一个secret
注意:
–docker-server 是私有仓库地址
–docker-username 是私有仓库用户名
–docker-password 是私有仓库对用用户名的密码
[root@master ~]# kubectl create secret docker-registry regcred --docker-server=10.11.67.119 --docker-username=diange --docker-password=QianFeng@123
2.创建pod的yaml文件
[root@master ~]# cat nginx.yaml
apiVersion: v1
kind: Pod
metadata:
name: xingdian
labels:
app: xingdian
spec:
containers:
- name: diandian
image: 10.11.67.119/xingdian/nginx@sha256:2963fc49cc50883ba9af25f977a9997ff9af06b45c12d968b7985dc1e9254e4b
ports:
- containerPort: 80
imagePullSecrets:
- name: regcred
3.创建pod
[root@master ~]# kubectl create -f nginx.yaml
4.查看pod
[root@master ~]# kubectl get pods
NAME READY STATUS RESTARTS AGE
xingdian 1/1 Running 0 10m
三: kubernetes-ConfigMap
ConfigMap
用来存储配置文件的kubernetes资源对象,>所有的配置内容都存储在etcd中。ConfigMap与 Secret 类似.
ConfigMap与 Secret 的区别
ConfigMap 保存的是不需要加密的、应用所需的配置信息。
ConfigMap 的用法几乎与 Secret 完全相同:可以使用 kubectl create configmap 从文件或者目录创建 ConfigMap,也可以直接编写 ConfigMap 对象的 YAML 文件。
创建ConfigMap
创建ConfigMap的方式有4种
方式1:通过直接在命令行中指定configmap参数创建,即–from-literal
方式2:通过指定文件创建,即将一个配置文件创建为一个ConfigMap–from-file=<文件>
方式3:通过指定目录创建,即将一个目录下的所有配置文件创建为一个ConfigMap,–from-file=<目录>
方式4:事先写好标准的configmap的yaml文件,然后kubectl create -f 创建
通过命令行参数–from-literal创建
创建命令:
[root@master yaml]# kubectl create configmap test-config1 --from-literal=db.host=10.5.10.116 --from-literal=db.port='3306'
configmap/test-config1 created
结果如下面的data内容所示:
[root@master yaml]# kubectl get configmap test-config1 -o yaml
apiVersion: v1
data:
db.host: 10.5.10.116
db.port: "3306"
kind: ConfigMap
metadata:
creationTimestamp: "2019-02-14T08:22:34Z"
name: test-config1
namespace: default
resourceVersion: "7587"
selfLink: /api/v1/namespaces/default/configmaps/test-config1
uid: adfff64c-3031-11e9-abbe-000c290a5b8b
通过指定文件创建
编辑配置文件app.properties内容如下:
[root@master yaml]# cat app.properties
property.1 = value-1
property.2 = value-2
property.3 = value-3
property.4 = value-4
[mysqld]
!include /home/wing/mysql/etc/mysqld.cnf
port = 3306
socket = /home/wing/mysql/tmp/mysql.sock
pid-file = /wing/mysql/mysql/var/mysql.pid
basedir = /home/mysql/mysql
datadir = /wing/mysql/mysql/var
创建(可以有多个–from-file):
# kubectl create configmap test-config2 --from-file=./app.properties
结果如下面data内容所示:
[root@master yaml]# kubectl get configmap test-config2 -o yaml
apiVersion: v1
data:
app.properties: |
property.1 = value-1
property.2 = value-2
property.3 = value-3
property.4 = value-4
[mysqld]
!include /home/wing/mysql/etc/mysqld.cnf
port = 3306
socket = /home/wing/mysql/tmp/mysql.sock
pid-file = /wing/mysql/mysql/var/mysql.pid
basedir = /home/mysql/mysql
datadir = /wing/mysql/mysql/var
kind: ConfigMap
metadata:
creationTimestamp: "2019-02-14T08:29:33Z"
name: test-config2
namespace: default
resourceVersion: "8176"
selfLink: /api/v1/namespaces/default/configmaps/test-config2
uid: a8237769-3032-11e9-abbe-000c290a5b8b
通过指定文件创建时,configmap会创建一个key/value对,key是文件名,value是文件内容。如不想configmap中的key为默认的文件名,可以在创建时指定key名字:
# kubectl create configmap game-config-3 --from-file=<my-key-name>=<path-to-file>
指定目录创建
configs 目录下的config-1和config-2内容如下所示:
[root@master yaml]# tail configs/config-1
aaa
bbb
c=d
[root@master yaml]# tail configs/config-2
eee
fff
h=k
创建:
# kubectl create configmap test-config3 --from-file=./configs
结果下面data内容所示:
[root@master yaml]# kubectl get configmap test-config3 -o yaml
apiVersion: v1
data:
config-1: |
aaa
bbb
c=d
config-2: |
eee
fff
h=k
kind: ConfigMap
metadata:
creationTimestamp: "2019-02-14T08:37:05Z"
name: test-config3
namespace: default
resourceVersion: "8808"
selfLink: /api/v1/namespaces/default/configmaps/test-config3
uid: b55ffbeb-3033-11e9-abbe-000c290a5b8b
指定目录创建时,configmap内容中的各个文件会创建一个key/value对,key是文件名,value是文件内容。
假如目录中还包含子目录:
在上一步的configs目录下创建子目录subconfigs,并在subconfigs下面创建两个配置文件,指定目录configs创建名为test-config4的configmap:
# kubectl create configmap test-config4 --from-file=./configs
结果发现和上面没有子目录时一样,说明指定目录时只会识别其中的文件,忽略子目录
通过事先写好configmap的标准yaml文件创建
yaml文件内容如下: 注意其中一个key的value有多行内容时的写法
[root@master yaml]# cat configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: test-config4
namespace: default
data:
cache_host: memcached-gcxt
cache_port: "11211"
cache_prefix: gcxt
my.cnf: |
[mysqld]
log-bin = mysql-bin
haha = hehe
创建:
[root@master yaml]# kubectl apply -f configmap.yaml
configmap/test-config4 created
结果如下面data内容所示:
[root@master yaml]# kubectl get configmap test-config4 -o yaml
apiVersion: v1
data:
cache_host: memcached-gcxt
cache_port: "11211"
cache_prefix: gcxt
my.cnf: |
[mysqld]
log-bin = mysql-bin
haha = hehe
kind: ConfigMap
metadata:
annotations:
kubectl.kubernetes.io/last-applied-configuration: |
{"apiVersion":"v1","data":{"cache_host":"memcached-gcxt","cache_port":"11211","cache_prefix":"gcxt","my.cnf":"[mysqld]\nlog-bin = mysql-bin\nhaha = hehe\n"},"kind":"ConfigMap","metadata":{"annotations":{},"name":"test-config4","namespace":"default"}}
creationTimestamp: "2019-02-14T08:46:57Z"
name: test-config4
namespace: default
resourceVersion: "9639"
selfLink: /api/v1/namespaces/default/configmaps/test-config4
uid: 163fbe1e-3035-11e9-abbe-000c290a5b8b
查看configmap的详细信息:
# kubectl describe configmap
使用ConfigMap
使用ConfigMap有三种方式,一种是通过环境变量的方式,直接传递pod,另一种是通过在pod的命令行下运行的方式,第三种是使用volume的方式挂载入到pod内,示例ConfigMap文件:
apiVersion: v1
kind: ConfigMap
metadata:
name: special-config
namespace: default
data:
special.how: very
special.type: charm
通过环境变量使用
使用valueFrom、configMapKeyRef、name、key指定要用的key:
[root@master yaml]# cat testpod.yaml
apiVersion: v1
kind: Pod
metadata:
name: dapi-test-pod
spec:
containers:
- name: test-container
image: daocloud.io/library/nginx
env:
- name: SPECIAL_LEVEL_KEY //这里是容器里设置的新变量的名字
valueFrom:
configMapKeyRef:
name: special-config //这里是来源于哪个configMap
key: special.how //configMap里的key
- name: SPECIAL_TYPE_KEY
valueFrom:
configMapKeyRef:
name: special-config
key: special.type
restartPolicy: Never
测试:
[root@master yaml]# kubectl exec -it dapi-test-pod /bin/bash
root@dapi-test-pod:/# echo $SPECIAL_TYPE_KEY
charm
通过envFrom、configMapRef、name使得configmap中的所有key/value对都自动变成环境变量:
apiVersion: v1
kind: Pod
metadata:
name: dapi-test-pod
spec:
containers:
- name: test-container
image: daocloud.io/library/nginx
envFrom:
- configMapRef:
name: special-config
restartPolicy: Never
这样容器里的变量名称直接使用configMap里的key名:
[root@master yaml]# kubectl exec -it dapi-test-pod /bin/bash
root@dapi-test-pod:/# env
HOSTNAME=dapi-test-pod
NJS_VERSION=1.15.8.0.2.7-1~stretch
NGINX_VERSION=1.15.8-1~stretch
KUBERNETES_PORT_443_TCP_PROTO=tcp
KUBERNETES_PORT_443_TCP_ADDR=10.96.0.1
KUBERNETES_PORT=tcp://10.96.0.1:443
PWD=/
special.how=very
HOME=/root
KUBERNETES_SERVICE_PORT_HTTPS=443
KUBERNETES_PORT_443_TCP_PORT=443
KUBERNETES_PORT_443_TCP=tcp://10.96.0.1:443
TERM=xterm
SHLVL=1
KUBERNETES_SERVICE_PORT=443
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
special.type=charm
KUBERNETES_SERVICE_HOST=10.96.0.1
作为volume挂载使用
把1.4中test-config4所有key/value挂载进来:
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-configmap
spec:
replicas: 1
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx-configmap
image: daocloud.io/library/nginx:latest
ports:
- containerPort: 80
volumeMounts:
- name: config-volume3
mountPath: /tmp/config3
volumes:
- name: config-volume3
configMap:
name: test-config-3
进入容器中/tmp/config4查看:
[root@master yaml]# kubectl exec -it nginx-configmap-7447bf77d6-svj2t /bin/bash
root@nginx-configmap-7447bf77d6-svj2t:/# ls /tmp/config4/
cache_host cache_port cache_prefix my.cnf
root@nginx-configmap-7447bf77d6-svj2t:/# cat /tmp/config4/cache_host
memcached-gcxt
可以看到,在config4文件夹下以每一个key为文件名value为值创建了多个文件。
假如不想以key名作为配置文件名可以引入items 字段,在其中逐个指定要用相对路径path替换的key:
volumes:
- name: config-volume4
configMap:
name: test-config4
items:
- key: my.cnf //原来的key名
path: mysql-key
- key: cache_host //原来的key名
path: cache-host
备注:
删除configmap后原pod不受影响;然后再删除pod后,重启的pod的events会报找不到cofigmap的volume;
pod起来后再通过kubectl edit configmap …修改configmap,过一会pod内部的配置也会刷新。
在容器内部修改挂进去的配置文件后,过一会内容会再次被刷新为原始configmap内容
四:kubernetes- Downward API
用于在容器中获取 POD 的基本信息,kubernetes原生支持
Downward API提供了两种方式用于将 POD 的信息注入到容器内部:
环境变量:
用于单个变量,可以将 POD 信息和容器信息直接注入容器内部。
Volume挂载:
将 POD 信息生成为文件,直接挂载到容器内部中去。
环境变量的方式:
通过Downward API来将 POD 的 IP、名称以及所对应的 namespace 注入到容器的环境变量中去,然后在容器中打印全部的环境变量来进行验证,使用fieldRef获取 POD 的基本信息:
# vim test-env-pod.yaml
apiVersion: v1
kind: Pod
metadata:
name: test-env-pod
namespace: kube-system
spec:
containers:
- name: test-env-pod
image: daocloud.io/library/nginx:latest
command: ["/bin/sh", "-c", "env"]
env:
- name: POD_NAME
valueFrom: //使用valueFrom方式设置env的值
fieldRef:
fieldPath: metadata.name
- name: POD_NAMESPACE
valueFrom:
fieldRef:
fieldPath: metadata.namespace
- name: POD_IP
valueFrom:
fieldRef:
fieldPath: status.podIP
注意: POD 的 name 和 namespace 属于元数据,是在 POD 创建之前就已经定下来了的,所以使用 metata 获取就可以了,但是对于 POD 的 IP 则不一样,因为POD IP 是不固定的,POD 重建了就变了,它属于状态数据,所以使用 status 去获取。
创建上面的 POD:
# kubectl create -f test-env-pod.yaml
pod "test-env-pod" created
POD 创建成功后,查看:
[root@master yaml]# kubectl exec -it test-env-pod /bin/bash -n kube-system
root@test-env-pod:/# env | grep POD
POD_IP=172.30.19.24
POD_NAME=test-env-pod
POD_NAMESPACE=kube-system
Volume挂载
通过Downward API将 POD 的 Label、Annotation 等信息通过 Volume 挂载到容器的某个文件中去,然后在容器中打印出该文件的值来验证。 新建文件 yaml 文件:(test-volume-pod.yaml)
apiVersion: v1
kind: Pod
metadata:
name: test-volume-pod
namespace: kube-system
labels:
k8s-app: test-volume
node-env: test
annotations:
build: test
own: qikqiak
spec:
containers:
- name: test-volume-pod-container
image: daocloud.io/library/nginx:latest
volumeMounts:
- name: podinfo
mountPath: /etc/podinfo
volumes:
- name: podinfo
downwardAPI:
items:
- path: "labels"
fieldRef:
fieldPath: metadata.labels
- path: "annotations"
fieldRef:
fieldPath: metadata.annotations
将元数据 labels 和 annotaions 以文件的形式挂载到了/etc/podinfo目录下,创建上面的 POD :
# kubectl create -f test-volume-pod.yaml
pod "test-volume-pod" created
在实际应用中,如果你的应用有获取 POD 的基本信息的需求,就可以利用Downward API来获取基本信息,然后编写一个启动脚本或者利用initContainer将 POD 的信息注入到容器中去,然后在自己的应用中就可以正常的处理相关逻辑了。
目前 Downward API 支持的字段:
\1. 使用 fieldRef 可以声明使用:
spec.nodeName - 宿主机名字
status.hostIP - 宿主机 IP
metadata.name - Pod 的名字
metadata.namespace - Pod 的 Namespace
status.podIP - Pod 的 IP
spec.serviceAccountName - Pod 的 Service Account 的名字
metadata.uid - Pod 的 UID
metadata.labels['<KEY>'] - 指定 <KEY> 的 Label 值
metadata.annotations['<KEY>'] - 指定 <KEY> 的 Annotation 值
metadata.labels - Pod 的所有 Label
metadata.annotations - Pod 的所有 Annotation
\2. 使用 resourceFieldRef 可以声明使用:
容器的 CPU limit
容器的 CPU request
容器的 memory limit
容器的 memory request
上面这个列表的内容,随着 Kubernetes 项目的发展肯定还会不断增加。所以这里列出来的信息仅供参考,在使用 Downward API 时,还是要记得去查阅一下官方文档。
注意:Downward API 能够获取到的信息,一定是 Pod 里的容器进程启动之前就能够确定下来的信息。而如果你想要获取 Pod 容器运行后才会出现的信息,比如,容器进程的 PID,那就肯定不能使用 Downward API 了,而应该考虑在 Pod 里定义一个 sidecar 容器。
Secret、ConfigMap,以及 Downward API 这三种 Projected Volume 定义的信息,大多还可以通过环境变量的方式出现在容器里。但是,通过环境变量获取这些信息的方式,不具备自动更新的能力。一般情况下,建议使用 Volume 文件的方式获取这些信息。
五:kubernetes-ServiceAccount
本节是为理解ServiceAccount,不是要大家操作,后面部署dashboard应用的时候会用到,可以看一下dashboard是怎么使用ServiceAccount的
Kubernetes中提供了良好的多租户认证管理机制,如RBAC、ServiceAccount还有各种Policy等。
查看系统的config配置:
这里用到的token就是被授权过的SeviceAccount账户的token,集群利用token来使用ServiceAccount账户
[root@master yaml]# cat /root/.kube/config
什么是 Service Account ?
为Pod中的进程提供身份信息。
当用户访问集群(例如使用kubectl命令)时,apiserver 会将用户认证为一个特定的 User Account(目前通常是admin,除非系统管理员自定义了集群配置)。Pod 容器中的进程也可以与 apiserver 联系。 当它们在联系 apiserver 的时候,它们会被认证为一个特定的 Service Account(例如default)。
使用默认的 Service Account 访问 API server
当创建 pod 的时候,如果没有指定一个 service account,系统会自动在与该pod 相同的 namespace 下为其指派一个default service account。如果获取刚创建的 pod 的原始 json 或 yaml 信息(例如使用kubectl get pods podename -o yaml命令),将看到spec.serviceAccountName字段已经被设置为 default。
可以在 pod 中使用自动挂载的 service account 凭证来访问 API,如 Accessing the Cluster 中所描述。
Service account 是否能够取得访问 API 的许可取决于您使用的 授权插件和策略。
取消为 service account 自动挂载 API 凭证
在 1.6 以上版本中,可以选择取消为 service account 自动挂载 API 凭证,只需在 service account 中设置 automountServiceAccountToken: false:
apiVersion: v1
kind: ServiceAccount
metadata:
name: build-robot
automountServiceAccountToken: false
...
只取消单个 pod 的 API 凭证自动挂载:
apiVersion: v1
kind: Pod
metadata:
name: my-pod
spec:
serviceAccountName: build-robot
automountServiceAccountToken: false
...
pod 设置中的优先级更高:
如果在 pod 和 service account 中同时设置了 automountServiceAccountToken , pod 设置中的优先级更高。
使用 Service Account 作为用户权限管理配置 kubeconfig
创建服务账号(serviceAccount):
# kubectl create serviceaccount sample-sc
查看 serviceaccount 账号:
# kubectl get serviceaccount sample-sc -o yaml
apiVersion: v1
kind: ServiceAccount
metadata:
creationTimestamp: "2019-02-15T02:49:31Z"
name: sample-sc
namespace: default
resourceVersion: "37256"
selfLink: /api/v1/namespaces/default/serviceaccounts/sample-sc
uid: 518ad3d6-30cc-11e9-abbe-000c290a5b8b
secrets:
- name: sample-sc-token-4brlw
查看sample-sc帐号的token:
因为在使用 serviceaccount 账号配置 kubeconfig 的时候需要使用到 sample-sc 的 token, 该 token 保存在该 serviceaccount 保存的 secret 中;
# kubectl get secret sample-sc-token-4brlw -o yaml
apiVersion: v1
data:
ca.crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUN5RENDQWJDZ0F3SUJBZ0lCQURBTkJna3Foa2lHOXcwQkFRc0ZBREFWTVJNd0VRWURWUVFERXdwcmRXSmwKY201bGRHVnpNQjRYRFRFNU1ESXhOREEyTlRNME5Gb1hEVEk1TURJeE1UQTJOVE0wTkZvd0ZURVRNQkVHQTFVRQpBeE1LYTNWaVpYSnVaWFJsY3pDQ0FTSXdEUVlKS29aSWh2Y05BUUVCQlFBRGdnRVBBRENDQVFvQ2dnRUJBTHdmCjRIZEhod2hPRnVLNlVBRWcxekhzSGFBZS9VUUh5VGdPOG5LZ3FaK1BQQU9iOVc2dDZoeG1MKzBscGNFSS9xWFkKT3JFY2l5cVpnT0piV05jSUFYaCs3WmxDdk9BdzZpYmxmQy9oMUw1cWZGWkwvVXlNb3pUSWFVRUsweEV1bFNFMAp6SVJCN3R5aUNLSy9RODJEakk3NEVwQmxyUTE4UkYrQytrR3Fjb0d4a0FXZzZRU2x0cmJCTGRXQlc3NEdBVkI0ClZSRFk4S3c0Mm96WWZZRFErZ09BMjd4VnNaQWJRRDZUWmVTU0RHOVVyaU9NOVhmMVQ3ZytQY3hoMHZCL1ROcGgKdXJNL2tNUTM5eHNqazFEUms4L0tLQnlNZE9xd1lxZ3RwWUdvQnZVMDZnK1ZvL2tkWXJ2WnFoTy9oVmFBem00dwo1YmNsYUx5WDlBc1RZeFhYQXIwQ0F3RUFBYU1qTUNFd0RnWURWUjBQQVFIL0JBUURBZ0trTUE4R0ExVWRFd0VCCi93UUZNQU1CQWY4d0RRWUpLb1pJaHZjTkFRRUxCUUFEZ2dFQkFINW5YOXJBS2lDSGcvOWNVT1dXMWdRK2hZc1gKb2Flakt0TnAvbmJKTnJITGZrV3hWTFc4eU5Xem1BWnYzcDFZOENCMDF2OEtGNEdrVy9CSk81aVpXRTVvSVZuVQo2Nkp5Y1doTVV2RmFTQWN5MnJUVXpvcWh5YnVDaVJsSS9ScUVZNjQvbVZVdjFTK1dndzBaYSszK1FpSC9LNHVUCmVzcnhvQUdHRnBpd3JCQ0FGMjZxZHRuMTdjRTJRcHNHcFlyY1hOZ3BlSHpaK2ZLMkZuUzBiYkJMb082YlA4ZGYKQlVPZldvb1JteWUxdmtHWWlKcFZUajFDcDBKNkcxazc3NWZGMUlkQmNrelhyQmF2N0xkdml5S2dtRFN1ODFYegpuZ3AzMWx1bE9wdXVETHRiM0svVTZUTHNRVWlHN2hlOUg3eVMybk5tVnA0cWRIRC9MMzJiUU40dDEzRT0KLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQo=
namespace: ZGVmYXVsdA==
token: ZXlKaGJHY2lPaUpTVXpJMU5pSXNJbXRwWkNJNklpSjkuZXlKcGMzTWlPaUpyZFdKbGNtNWxkR1Z6TDNObGNuWnBZMlZoWTJOdmRXNTBJaXdpYTNWaVpYSnVaWFJsY3k1cGJ5OXpaWEoyYVdObFlXTmpiM1Z1ZEM5dVlXMWxjM0JoWTJVaU9pSmtaV1poZFd4MElpd2lhM1ZpWlhKdVpYUmxjeTVwYnk5elpYSjJhV05sWVdOamIzVnVkQzl6WldOeVpYUXVibUZ0WlNJNkluTmhiWEJzWlMxell5MTBiMnRsYmkwMFluSnNkeUlzSW10MVltVnlibVYwWlhNdWFXOHZjMlZ5ZG1salpXRmpZMjkxYm5RdmMyVnlkbWxqWlMxaFkyTnZkVzUwTG01aGJXVWlPaUp6WVcxd2JHVXRjMk1pTENKcmRXSmxjbTVsZEdWekxtbHZMM05sY25acFkyVmhZMk52ZFc1MEwzTmxjblpwWTJVdFlXTmpiM1Z1ZEM1MWFXUWlPaUkxTVRoaFpETmtOaTB6TUdOakxURXhaVGt0WVdKaVpTMHdNREJqTWprd1lUVmlPR0lpTENKemRXSWlPaUp6ZVhOMFpXMDZjMlZ5ZG1salpXRmpZMjkxYm5RNlpHVm1ZWFZzZERwellXMXdiR1V0YzJNaWZRLmRQdkJFQzV1djhlTHZfSFNfQjRLd3phYkx2TUdjZzVmU3dXX19GaXNYS3FSTmRuU0dFUjBFNE4zUDRCd0UyY0xJUWloRlNSNnhOc3ZpMU5qb0h0QTk1Qjd6UmNFRFUzaVBjdXN3cWJNN1BINWQxcnBmWHVjSkNlaWpZcnRzVXprWEJ0TGVHRDRYMlpDdGFzYjU1UjlaWE1ldXZmRllQdzhzejBWWmh4a1RabjVrRDA4V2VnZEFnTWIyR3ZzX0psMWVxZWd5WF9zUm9sSUFKa3o2QnQ5SW8tV0lfcDhxeFZ3SEFhZlpuazBnVW5penV0eGFHZ1RjaVRZNk9FTUxmNVhnZFp2U0taTUpVY0FKeENOUWNmYmRMckRtSXdYWDBoMHVjM2tQTi14OVNZMjFMZlNlQV9zeHRiSmkzSnhlMjV2cFg4YmhYWGl4Y25xRWgwR19ITjNOdw==
kind: Secret
metadata:
annotations:
kubernetes.io/service-account.name: sample-sc
kubernetes.io/service-account.uid: 518ad3d6-30cc-11e9-abbe-000c290a5b8b
creationTimestamp: "2019-02-15T02:49:31Z"
name: sample-sc-token-4brlw
namespace: default
resourceVersion: "37255"
selfLink: /api/v1/namespaces/default/secrets/sample-sc-token-4brlw
uid: 518d0a75-30cc-11e9-abbe-000c290a5b8b
type: kubernetes.io/service-account-token
其中 {data.token} 就是用户 token 的 base64 编码,之后配置 kubeconfig 的时候将会用到它;
创建角色
比如想创建一个只可以查看集群deployments,services,pods 相关的角色,使用如下配置
apiVersion: rbac.authorization.k8s.io/v1
## 这里也可以使用 Role
kind: ClusterRole
metadata:
name: mofang-viewer-role
labels:
from: mofang
rules:
- apiGroups:
- ""
resources:
- pods
- pods/status
- pods/log
- services
- services/status
- endpoints
- endpoints/status
- deployments
verbs:
- get
- list
- watch
创建角色绑定
apiVersion: rbac.authorization.k8s.io/v1
## 这里也可以使用 RoleBinding
kind: ClusterRoleBinding
metadata:
name: sample-role-binding
labels:
from: mofang
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: mofang-viewer-role #这里即绑定上面创建的clusterrole
subjects:
- kind: ServiceAccount #将clusterrole绑定到这个服务账户上
name: sample-sc
namespace: default
注意上面配置中的注意在复制的时候要删除干净,包括空格,否则出错
<文章感谢 xingdian >