10-kubernetes-pod-API

<文章感谢 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
  1. 定义了 shareProcessNamespace=true

表示这个 Pod 里的容器要共享 PID Namespace

  1. 定义了两个容器:

一个 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"]
  1. 定义了一个 nginx 镜像的容器

  2. 设置了一个 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 >

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值