在前面已经提到,容器的生命周期可能很短,会被频繁地创建和销毁。那么容器在销毁时,保存在容器中的数据也会被清除。这种结果对用户来说,在某些情况下是不乐意看到的。为了持久化保存容器的数据,kubernetes引入了Volume的概念。
Volume是Pod中能够被多个容器访问的共享目录,它被定义在Pod上,然后被一个Pod里的多个容器挂载到具体的文件目录下,kubernetes通过Volume实现同一个Pod中不同容器之间的数据共享以及数据的持久化存储。Volume的生命容器不与Pod中单个容器的生命周期相关,当容器终止或者重启时,Volume中的数据也不会丢失。
kubernetes的Volume支持多种类型,比较常见的有下面几个:
EmptyDir是最基础的Volume类型,一个EmptyDir就是Host上的一个空目录。
EmptyDir是在Pod被分配到Node时创建的,它的初始内容为空,并且无须指定宿主机上对应的目录文件,因为kubernetes会自动分配一个目录,当Pod销毁时, EmptyDir中的数据也会被永久删除。 EmptyDir用途如下:
接下来,通过一个容器之间文件共享的案例来使用一下EmptyDir。
在一个Pod中准备两个容器nginx和busybox,然后声明一个Volume分别挂在到两个容器的目录中,然后nginx容器负责向Volume中写日志,busybox中通过命令将日志内容读到控制台。

创建一个volume-emptydir.yaml
apiVersion: v1kind: Podmetadata: name: volume-emptydir namespace: devspec: containers: - name: nginx image: nginx:1.17.1 ports: - containerPort: 80 volumeMounts: # 将logs-volume挂在到nginx容器中,对应的目录为 /var/log/nginx - name: logs-volume mountPath: /var/log/nginx - name: busybox image: busybox:1.30 command: ["/bin/sh","-c","tail -f /logs/access.log"] # 初始命令,动态读取指定文件中内容 volumeMounts: # 将logs-volume 挂在到busybox容器中,对应的目录为 /logs - name: logs-volume mountPath: /logs volumes: # 声明volume, name为logs-volume,类型为emptyDir - name: logs-volume emptyDir: {}
# 创建Pod[root@k8s-master01 ~]# kubectl create -f volume-emptydir.yamlpod/volume-emptydir created # 查看pod[root@k8s-master01 ~]# kubectl get pods volume-emptydir -n dev -o wideNAME READY STATUS RESTARTS AGE IP NODE ...... volume-emptydir 2/2 Running 0 97s 10.42.2.9 node1 ...... # 通过podIp访问nginx[root@k8s-master01 ~]# curl 10.42.2.9...... # 通过kubectl logs命令查看指定容器的标准输出[root@k8s-master01 ~]# kubectl logs -f volume-emptydir -n dev -c busybox10.42.1.0 - - [27/Jun/2021:15:08:54 +0000] "GET / HTTP/1.1" 200 612 "-" "curl/7.29.0" "-"
上节课提到,EmptyDir中数据不会被持久化,它会随着Pod的结束而销毁,如果想简单的将数据持久化到主机中,可以选择HostPath。
HostPath就是将Node主机中一个实际目录挂在到Pod中,以供容器使用,这样的设计就可以保证Pod销毁了,但是数据依据可以存在于Node主机上。

创建一个volume-hostpath.yaml:
apiVersion: v1kind: Podmetadata: name: volume-hostpath namespace: devspec: containers: - name: nginx image: nginx:1.17.1 ports: - containerPort: 80 volumeMounts: - name: logs-volume mountPath: /var/log/nginx - name: busybox image: busybox:1.30 command: ["/bin/sh","-c","tail -f /logs/access.log"] volumeMounts: - name: logs-volume mountPath: /logs volumes: - name: logs-volume hostPath: path: /root/logs type: DirectoryOrCreate # 目录存在就使用,不存在就先创建后使用
关于type的值的一点说明: DirectoryOrCreate 目录存在就使用,不存在就先创建后使用 Directory 目录必须存在 FileOrCreate 文件存在就使用,不存在就先创建后使用 File 文件必须存在 Socket unix套接字必须存在 CharDevice 字符设备必须存在 BlockDevice 块设备必须存在
# 创建Pod[root@k8s-master01 ~]# kubectl create -f volume-hostpath.yamlpod/volume-hostpath created # 查看Pod[root@k8s-master01 ~]# kubectl get pods volume-hostpath -n dev -o wideNAME READY STATUS RESTARTS AGE IP NODE ......pod-volume-hostpath 2/2 Running 0 16s 10.42.2.10 node1 ...... #访问nginx[root@k8s-master01 ~]# curl 10.42.2.10 # 接下来就可以去host的/root/logs目录下查看存储的文件了### 注意: 下面的操作需要到Pod所在的节点运行(案例中是node1)[root@node1 ~]# ls /root/logs/access.log error.log # 同样的道理,如果在此目录下创建一个文件,到容器中也是可以看到的
HostPath可以解决数据持久化的问题,但是一旦Node节点故障了,Pod如果转移到了别的节点,又会出现问题了,此时需要准备单独的网络存储系统,比较常用的用NFS、CIFS。
NFS是一个网络文件存储系统,可以搭建一台NFS服务器,然后将Pod中的存储直接连接到NFS系统上,这样的话,无论Pod在节点上怎么转移,只要Node跟NFS的对接没问题,数据就可以成功访问。

1)首先要准备nfs的服务器,这里为了简单,直接是master节点做nfs服务器
# 在nfs上安装nfs服务[root@nfs ~]# yum install nfs-utils -y # 准备一个共享目录[root@nfs ~]# mkdir /root/data/nfs -pv # 将共享目录以读写权限暴露给192.168.5.0/24网段中的所有主机[root@nfs ~]# vim /etc/exports[root@nfs ~]# more /etc/exports/root/data/nfs 192.168.5.0/24(rw,no_root_squash) # 启动nfs服务[root@nfs ~]# systemctl restart nfs
2)接下来,要在的每个node节点上都安装下nfs,这样的目的是为了node节点可以驱动nfs设备
# 在node上安装nfs服务,注意不需要启动[root@k8s-master01 ~]# yum install nfs-utils -y
3)接下来,就可以编写pod的配置文件了,创建volume-nfs.yaml
apiVersion: v1kind: Podmetadata: name: volume-nfs namespace: devspec: containers: - name: nginx image: nginx:1.17.1 ports: - containerPort: 80 volumeMounts: - name: logs-volume mountPath: /var/log/nginx - name: busybox image: busybox:1.30 command: ["/bin/sh","-c","tail -f /logs/access.log"] volumeMounts: - name: logs-volume mountPath: /logs volumes: - name: logs-volume nfs: server: 192.168.5.6 #nfs服务器地址 path: /root/data/nfs #共享文件路径
4)最后,运行下pod,观察结果
# 创建pod[root@k8s-master01 ~]# kubectl create -f volume-nfs.yamlpod/volume-nfs created # 查看pod[root@k8s-master01 ~]# kubectl get pods volume-nfs -n devNAME READY STATUS RESTARTS AGEvolume-nfs 2/2 Running 0 2m9s # 查看nfs服务器上的共享目录,发现已经有文件了[root@k8s-master01 ~]# ls /root/data/access.log error.log
前面已经学习了使用NFS提供存储,此时就要求用户会搭建NFS系统,并且会在yaml配置nfs。由于kubernetes支持的存储系统有很多,要求客户全都掌握,显然不现实。为了能够屏蔽底层存储实现的细节,方便用户使用, kubernetes引入PV和PVC两种资源对象。
PV(Persistent Volume)是持久化卷的意思,是对底层的共享存储的一种抽象。一般情况下PV由kubernetes管理员进行创建和配置,它与底层具体的共享存储技术有关,并通过插件完成与共享存储的对接。
PVC(Persistent Volume Claim)是持久卷声明的意思,是用户对于存储需求的一种声明。换句话说,PVC其实就是用户向kubernetes系统发出的一种资源需求申请。

使用了PV和PVC之后,工作可以得到进一步的细分:
PV是存储资源的抽象,下面是资源清单文件:
apiVersion: v1 kind: PersistentVolumemetadata: name: pv2spec: nfs: # 存储类型,与底层真正存储对应 capacity: # 存储能力,目前只支持存储空间的设置 storage: 2Gi accessModes: # 访问模式 storageClassName: # 存储类别 persistentVolumeReclaimPolicy: # 回收策略
PV 的关键配置参数说明:
存储类型
底层实际存储的类型,kubernetes支持多种存储类型,每种存储类型的配置都有所差异
存储能力(capacity)
目前只支持存储空间的设置( storage=1Gi ),不过未来可能会加入IOPS、吞吐量等指标的配置
访问模式(accessModes)
用于描述用户应用对存储资源的访问权限,访问权限包括下面几种方式:
需要注意的是,底层不同的存储类型可能支持的访问模式不同
回收策略(persistentVolumeReclaimPolicy)
当PV不再被使用了之后,对其的处理方式。目前支持三种策略:
需要注意的是,底层不同的存储类型可能支持的回收策略不同
存储类别
PV可以通过storageClassName参数指定一个存储类别
状态(status)
一个 PV 的生命周期中,可能会处于4中不同的阶段:
实验
使用NFS作为存储,来演示PV的使用,创建3个PV,对应NFS中的3个暴露的路径。
# 创建目录[root@nfs ~]# mkdir /root/data/{pv1,pv2,pv3} -pv # 暴露服务[root@nfs ~]# more /etc/exports/root/data/pv1 192.168.5.0/24(rw,no_root_squash)/root/data/pv2 192.168.5.0/24(rw,no_root_squash)/root/data/pv3 192.168.5.0/24(rw,no_root_squash) # 重启服务[root@nfs ~]# systemctl restart nfs
apiVersion: v1kind: PersistentVolumemetadata: name: pv1spec: capacity: storage: 1Gi accessModes: - ReadWriteMany persistentVolumeReclaimPolicy: Retain nfs: path: /root/data/pv1 server: 192.168.5.6 --- apiVersion: v1kind: PersistentVolumemetadata: name: pv2spec: capacity: storage: 2Gi accessModes: - ReadWriteMany persistentVolumeReclaimPolicy: Retain nfs: path: /root/data/pv2 server: 192.168.5.6 --- apiVersion: v1kind: PersistentVolumemetadata: name: pv3spec: capacity: storage: 3Gi accessModes: - ReadWriteMany persistentVolumeReclaimPolicy: Retain nfs: path: /root/data/pv3 server: 192.168.5.6
# 创建 pv[root@k8s-master01 ~]# kubectl create -f pv.yamlpersistentvolume/pv1 createdpersistentvolume/pv2 createdpersistentvolume/pv3 created # 查看pv[root@k8s-master01 ~]# kubectl get pv -o wideNAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS AGE VOLUMEMODEpv1 1Gi RWX Retain Available 10s Filesystempv2 2Gi RWX Retain Available 10s Filesystempv3 3Gi RWX Retain Available 9s Filesystem
PVC是资源的申请,用来声明对存储空间、访问模式、存储类别需求信息。下面是资源清单文件:
apiVersion: v1kind: PersistentVolumeClaimmetadata: name: pvc namespace: devspec: accessModes: # 访问模式 selector: # 采用标签对PV选择 storageClassName: # 存储类别 resources: # 请求空间 requests: storage: 5Gi
PVC 的关键配置参数说明:
用于描述用户应用对存储资源的访问权限
选择条件(selector)
通过Label Selector的设置,可使PVC对于系统中己存在的PV进行筛选
存储类别(storageClassName)
PVC在定义时可以设定需要的后端存储的类别,只有设置了该class的pv才能被系统选出
资源请求(Resources )
描述对存储资源的请求
实验
apiVersion: v1kind: PersistentVolumeClaimmetadata: name: pvc1 namespace: devspec: accessModes: - ReadWriteMany resources: requests: storage: 1Gi---apiVersion: v1kind: PersistentVolumeClaimmetadata: name: pvc2 namespace: devspec: accessModes: - ReadWriteMany resources: requests: storage: 1Gi---apiVersion: v1kind: PersistentVolumeClaimmetadata: name: pvc3 namespace: devspec: accessModes: - ReadWriteMany resources: requests: storage: 1Gi
# 创建pvc[root@k8s-master01 ~]# kubectl create -f pvc.yamlpersistentvolumeclaim/pvc1 createdpersistentvolumeclaim/pvc2 createdpersistentvolumeclaim/pvc3 created # 查看pvc[root@k8s-master01 ~]# kubectl get pvc -n dev -o wideNAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE VOLUMEMODEpvc1 Bound pv1 1Gi RWX 15s Filesystempvc2 Bound pv2 2Gi RWX 15s Filesystempvc3 Bound pv3 3Gi RWX 15s Filesystem # 查看pv[root@k8s-master01 ~]# kubectl get pv -o wideNAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM AGE VOLUMEMODEpv1 1Gi RWx Retain Bound dev/pvc1 3h27m Filesystempv2 2Gi RWX Retain Bound dev/pvc2 3h27m Filesystempv3 3Gi RWX Retain Bound dev/pvc3 3h27m Filesystem
apiVersion: v1kind: Podmetadata: name: pod1 namespace: devspec: containers: - name: busybox image: busybox:1.30 command: ["/bin/sh","-c","while true;do echo pod1 >> /root/out.txt; sleep 10; done;"] volumeMounts: - name: volume mountPath: /root/ volumes: - name: volume persistentVolumeClaim: claimName: pvc1 readOnly: false---apiVersion: v1kind: Podmetadata: name: pod2 namespace: devspec: containers: - name: busybox image: busybox:1.30 command: ["/bin/sh","-c","while true;do echo pod2 >> /root/out.txt; sleep 10; done;"] volumeMounts: - name: volume mountPath: /root/ volumes: - name: volume persistentVolumeClaim: claimName: pvc2 readOnly: false
# 创建pod[root@k8s-master01 ~]# kubectl create -f pods.yamlpod/pod1 createdpod/pod2 created # 查看pod[root@k8s-master01 ~]# kubectl get pods -n dev -o wideNAME READY STATUS RESTARTS AGE IP NODE pod1 1/1 Running 0 14s 10.244.1.69 node1 pod2 1/1 Running 0 14s 10.244.1.70 node1 # 查看pvc[root@k8s-master01 ~]# kubectl get pvc -n dev -o wideNAME STATUS VOLUME CAPACITY ACCESS MODES AGE VOLUMEMODEpvc1 Bound pv1 1Gi RWX 94m Filesystempvc2 Bound pv2 2Gi RWX 94m Filesystempvc3 Bound pv3 3Gi RWX 94m Filesystem # 查看pv[root@k8s-master01 ~]# kubectl get pv -n dev -o wideNAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM AGE VOLUMEMODEpv1 1Gi RWX Retain Bound dev/pvc1 5h11m Filesystempv2 2Gi RWX Retain Bound dev/pvc2 5h11m Filesystempv3 3Gi RWX Retain Bound dev/pvc3 5h11m Filesystem # 查看nfs中的文件存储[root@nfs ~]# more /root/data/pv1/out.txtnode1node1[root@nfs ~]# more /root/data/pv2/out.txtnode2node2
PVC和PV是一一对应的,PV和PVC之间的相互作用遵循以下生命周期:
资源供应:管理员手动创建底层存储和PV
资源绑定:用户创建PVC,kubernetes负责根据PVC的声明去寻找PV,并绑定
在用户定义好PVC之后,系统将根据PVC对存储资源的请求在已存在的PV中选择一个满足条件的
PV一旦绑定到某个PVC上,就会被这个PVC独占,不能再与其他PVC进行绑定了
资源使用:用户可在pod中像volume一样使用pvc
Pod使用Volume的定义,将PVC挂载到容器内的某个路径进行使用。
资源释放:用户删除pvc来释放pv
当存储资源使用完毕后,用户可以删除PVC,与该PVC绑定的PV将会被标记为“已释放”,但还不能立刻与其他PVC进行绑定。通过之前PVC写入的数据可能还被留在存储设备上,只有在清除之后该PV才能再次使用。
资源回收:kubernetes根据pv设置的回收策略进行资源的回收
对于PV,管理员可以设定回收策略,用于设置与之绑定的PVC释放资源之后如何处理遗留数据的问题。只有PV的存储空间完成回收,才能供新的PVC绑定和使用

ConfigMap是一种比较特殊的存储卷,它的主要作用是用来存储配置信息的。
创建configmap.yaml,内容如下:
apiVersion: v1kind: ConfigMapmetadata: name: configmap namespace: devdata: info: | username:admin password:123456
接下来,使用此配置文件创建configmap
# 创建configmap[root@k8s-master01 ~]# kubectl create -f configmap.yamlconfigmap/configmap created # 查看configmap详情[root@k8s-master01 ~]# kubectl describe cm configmap -n devName: configmapNamespace: devLabels: <none>Annotations: <none> Data====info:----username:adminpassword:123456 Events: <none>
接下来创建一个pod-configmap.yaml,将上面创建的configmap挂载进去
apiVersion: v1kind: Podmetadata: name: pod-configmap namespace: devspec: containers: - name: nginx image: nginx:1.17.1 volumeMounts: # 将configmap挂载到目录 - name: config mountPath: /configmap/config volumes: # 引用configmap - name: config configMap: name: configmap
# 创建pod[root@k8s-master01 ~]# kubectl create -f pod-configmap.yamlpod/pod-configmap created # 查看pod[root@k8s-master01 ~]# kubectl get pod pod-configmap -n devNAME READY STATUS RESTARTS AGEpod-configmap 1/1 Running 0 6s #进入容器[root@k8s-master01 ~]# kubectl exec -it pod-configmap -n dev /bin/sh# cd /configmap/config/# lsinfo# more infousername:adminpassword:123456 # 可以看到映射已经成功,每个configmap都映射成了一个目录# key--->文件 value---->文件中的内容# 此时如果更新configmap的内容, 容器中的值也会动态更新
在kubernetes中,还存在一种和ConfigMap非常类似的对象,称为Secret对象。它主要用于存储敏感信息,例如密码、秘钥、证书等等。
[root@k8s-master01 ~]# echo -n 'admin' | base64 #准备usernameYWRtaW4=[root@k8s-master01 ~]# echo -n '123456' | base64 #准备passwordMTIzNDU2
apiVersion: v1kind: Secretmetadata: name: secret namespace: devtype: Opaquedata: username: YWRtaW4= password: MTIzNDU2
# 创建secret[root@k8s-master01 ~]# kubectl create -f secret.yamlsecret/secret created # 查看secret详情[root@k8s-master01 ~]# kubectl describe secret secret -n devName: secretNamespace: devLabels: <none>Annotations: <none>Type: OpaqueData====password: 6 bytesusername: 5 bytes
apiVersion: v1kind: Podmetadata: name: pod-secret namespace: devspec: containers: - name: nginx image: nginx:1.17.1 volumeMounts: # 将secret挂载到目录 - name: config mountPath: /secret/config volumes: - name: config secret: secretName: secret
# 创建pod[root@k8s-master01 ~]# kubectl create -f pod-secret.yamlpod/pod-secret created # 查看pod[root@k8s-master01 ~]# kubectl get pod pod-secret -n devNAME READY STATUS RESTARTS AGEpod-secret 1/1 Running 0 2m28s # 进入容器,查看secret信息,发现已经自动解码了[root@k8s-master01 ~]# kubectl exec -it pod-secret /bin/sh -n dev/ # ls /secret/config/password username/ # more /secret/config/usernameadmin/ # more /secret/config/password123456
至此,已经实现了利用secret实现了信息的编码。
Kubernetes作为一个分布式集群的管理工具,保证集群的安全性是其一个重要的任务。所谓的安全性其实就是保证对Kubernetes的各种客户端进行认证和鉴权操作。
客户端
在Kubernetes集群中,客户端通常有两类:

认证、授权与准入控制
ApiServer是访问及管理资源对象的唯一入口。任何一个请求访问ApiServer,都要经过下面三个流程:

Kubernetes集群安全的最关键点在于如何识别并认证客户端身份,它提供了3种客户端身份认证方式:
HTTP Base认证:通过用户名+密码的方式认证
这种认证方式是把“用户名:密码”用BASE64算法进行编码后的字符串放在HTTP请求中的Header Authorization域里发送给服务端。服务端收到后进行解码,获取用户名及密码,然后进行用户身份认证的过程。
HTTP Token认证:通过一个Token来识别合法用户
这种认证方式是用一个很长的难以被模仿的字符串--Token来表明客户身份的一种方式。每个Token对应一个用户名,当客户端发起API调用请求时,需要在HTTP Header里放入Token,API Server接到Token后会跟服务器中保存的token进行比对,然后进行用户身份认证的过程。
HTTPS证书认证:基于CA根证书签名的双向数字证书认证方式
这种认证方式是安全性最高的一种方式,但是同时也是操作起来最麻烦的一种方式。

HTTPS认证大体分为3个过程:
证书申请和下发
HTTPS通信双方的服务器向CA机构申请证书,CA机构下发根证书、服务端证书及私钥给申请者
客户端和服务端的双向认证
1> 客户端向服务器端发起请求,服务端下发自己的证书给客户端, 客户端接收到证书后,通过私钥解密证书,在证书中获得服务端的公钥, 客户端利用服务器端的公钥认证证书中的信息,如果一致,则认可这个服务器 2> 客户端发送自己的证书给服务器端,服务端接收到证书后,通过私钥解密证书, 在证书中获得客户端的公钥,并用该公钥认证证书信息,确认客户端是否合法
服务器端和客户端进行通信
服务器端和客户端协商好加密方案后,客户端会产生一个随机的秘钥并加密,然后发送到服务器端。 服务器端接收这个秘钥后,双方接下来通信的所有内容都通过该随机秘钥加密
注意: Kubernetes允许同时配置多种认证方式,只要其中任意一个方式认证通过即可
授权发生在认证成功之后,通过认证就可以知道请求用户是谁, 然后Kubernetes会根据事先定义的授权策略来决定用户是否有权限访问,这个过程就称为授权。
每个发送到ApiServer的请求都带上了用户和资源的信息:比如发送请求的用户、请求的路径、请求的动作等,授权就是根据这些信息和授权策略进行比较,如果符合策略,则认为授权通过,否则会返回错误。
API Server目前支持以下几种授权策略:
RBAC(Role-Based Access Control) 基于角色的访问控制,主要是在描述一件事情:给哪些对象授予了哪些权限
其中涉及到了下面几个概念:

RBAC引入了4个顶级资源对象:
Role、ClusterRole
一个角色就是一组权限的集合,这里的权限都是许可形式的(白名单)。
# Role只能对命名空间内的资源进行授权,需要指定nameapcekind: RoleapiVersion: rbac.authorization.k8s.io/v1beta1metadata: namespace: dev name: authorization-rolerules:- apiGroups: [""] # 支持的API组列表,"" 空字符串,表示核心API群 resources: ["pods"] # 支持的资源对象列表 verbs: ["get", "watch", "list"] # 允许的对资源对象的操作方法列表
# ClusterRole可以对集群范围内资源、跨namespaces的范围资源、非资源类型进行授权kind: ClusterRoleapiVersion: rbac.authorization.k8s.io/v1beta1metadata: name: authorization-clusterrolerules:- apiGroups: [""] resources: ["pods"] verbs: ["get", "watch", "list"]
需要详细说明的是,rules中的参数:
apiGroups: 支持的API组列表
"","apps", "autoscaling", "batch"
resources:支持的资源对象列表
"services", "endpoints", "pods","secrets","configmaps","crontabs","deployments","jobs","nodes","rolebindings","clusterroles","daemonsets","replicasets","statefulsets","horizontalpodautoscalers","replicationcontrollers","cronjobs"
verbs:对资源对象的操作方法列表
"get", "list", "watch", "create", "update", "patch", "delete", "exec"
RoleBinding、ClusterRoleBinding
角色绑定用来把一个角色绑定到一个目标对象上,绑定目标可以是User、Group或者ServiceAccount。
# RoleBinding可以将同一namespace中的subject绑定到某个Role下,则此subject即具有该Role定义的权限kind: RoleBindingapiVersion: rbac.authorization.k8s.io/v1beta1metadata: name: authorization-role-binding namespace: devsubjects:- kind: User name: heima apiGroup: rbac.authorization.k8s.ioroleRef: kind: Role name: authorization-role apiGroup: rbac.authorization.k8s.io
# ClusterRoleBinding在整个集群级别和所有namespaces将特定的subject与ClusterRole绑定,授予权限kind: ClusterRoleBindingapiVersion: rbac.authorization.k8s.io/v1beta1metadata: name: authorization-clusterrole-bindingsubjects:- kind: User name: heima apiGroup: rbac.authorization.k8s.ioroleRef: kind: ClusterRole name: authorization-clusterrole apiGroup: rbac.authorization.k8s.io
RoleBinding引用ClusterRole进行授权
RoleBinding可以引用ClusterRole,对属于同一命名空间内ClusterRole定义的资源主体进行授权。
一种很常用的做法就是,集群管理员为集群范围预定义好一组角色(ClusterRole),然后在多个命名空间中重复使用这些ClusterRole。这样可以大幅提高授权管理工作效率,也使得各个命名空间下的基础性授权规则与使用体验保持一致。
# 虽然authorization-clusterrole是一个集群角色,但是因为使用了RoleBinding# 所以heima只能读取dev命名空间中的资源kind: RoleBindingapiVersion: rbac.authorization.k8s.io/v1beta1metadata: name: authorization-role-binding-ns namespace: devsubjects:- kind: User name: heima apiGroup: rbac.authorization.k8s.ioroleRef: kind: ClusterRole name: authorization-clusterrole apiGroup: rbac.authorization.k8s.io
实战:创建一个只能管理dev空间下Pods资源的账号
# 1) 创建证书[root@k8s-master01 pki]# cd /etc/kubernetes/pki/[root@k8s-master01 pki]# (umask 077;openssl genrsa -out devman.key 2048) # 2) 用apiserver的证书去签署# 2-1) 签名申请,申请的用户是devman,组是devgroup[root@k8s-master01 pki]# openssl req -new -key devman.key -out devman.csr -subj "/CN=devman/O=devgroup" # 2-2) 签署证书[root@k8s-master01 pki]# openssl x509 -req -in devman.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out devman.crt -days 3650 # 3) 设置集群、用户、上下文信息[root@k8s-master01 pki]# kubectl config set-cluster kubernetes --embed-certs=true --certificate-authority=/etc/kubernetes/pki/ca.crt --server=https://192.168.109.100:6443 [root@k8s-master01 pki]# kubectl config set-credentials devman --embed-certs=true --client-certificate=/etc/kubernetes/pki/devman.crt --client-key=/etc/kubernetes/pki/devman.key [root@k8s-master01 pki]# kubectl config set-context devman@kubernetes --cluster=kubernetes --user=devman # 切换账户到devman[root@k8s-master01 pki]# kubectl config use-context devman@kubernetesSwitched to context "devman@kubernetes". # 查看dev下pod,发现没有权限[root@k8s-master01 pki]# kubectl get pods -n devError from server (Forbidden): pods is forbidden: User "devman" cannot list resource "pods" in API group "" in the namespace "dev" # 切换到admin账户[root@k8s-master01 pki]# kubectl config use-context kubernetes-admin@kubernetesSwitched to context "kubernetes-admin@kubernetes".
kind: RoleapiVersion: rbac.authorization.k8s.io/v1beta1metadata: namespace: dev name: dev-rolerules:- apiGroups: [""] resources: ["pods"] verbs: ["get", "watch", "list"] --- kind: RoleBindingapiVersion: rbac.authorization.k8s.io/v1beta1metadata: name: authorization-role-binding namespace: devsubjects:- kind: User name: devman apiGroup: rbac.authorization.k8s.ioroleRef: kind: Role name: dev-role apiGroup: rbac.authorization.k8s.io
[root@k8s-master01 pki]# kubectl create -f dev-role.yamlrole.rbac.authorization.k8s.io/dev-role createdrolebinding.rbac.authorization.k8s.io/authorization-role-binding created
# 切换账户到devman[root@k8s-master01 pki]# kubectl config use-context devman@kubernetesSwitched to context "devman@kubernetes". # 再次查看[root@k8s-master01 pki]# kubectl get pods -n devNAME READY STATUS RESTARTS AGEnginx-deployment-66cb59b984-8wp2k 1/1 Running 0 4d1hnginx-deployment-66cb59b984-dc46j 1/1 Running 0 4d1hnginx-deployment-66cb59b984-thfck 1/1 Running 0 4d1h # 为了不影响后面的学习,切回admin账户[root@k8s-master01 pki]# kubectl config use-context kubernetes-admin@kubernetesSwitched to context "kubernetes-admin@kubernetes".
通过了前面的认证和授权之后,还需要经过准入控制处理通过之后,apiserver才会处理这个请求。
准入控制是一个可配置的控制器列表,可以通过在Api-Server上通过命令行设置选择执行哪些准入控制器:
--admission-control=NamespaceLifecycle,LimitRanger,ServiceAccount,PersistentVolumeLabel, DefaultStorageClass,ResourceQuota,DefaultTolerationSeconds
只有当所有的准入控制器都检查通过之后,apiserver才执行该请求,否则返回拒绝。
当前可配置的Admission Control准入控制如下:
之前在kubernetes中完成的所有操作都是通过命令行工具kubectl完成的。其实,为了提供更丰富的用户体验,kubernetes还开发了一个基于web的用户界面(Dashboard)。用户可以使用Dashboard部署容器化的应用,还可以监控应用的状态,执行故障排查以及管理kubernetes中各种资源。
# 下载yaml
[root@k8s-master01 ~]# wget https://raw.githubusercontent.com/kubernetes/dashboard/v2.0.0/aio/deploy/recommended.yaml
# 修改kubernetes-dashboard的Service类型kind: ServiceapiVersion: v1metadata: labels: k8s-app: kubernetes-dashboard name: kubernetes-dashboard namespace: kubernetes-dashboardspec: type: NodePort
# 新增 ports: - port: 443 targetPort: 8443 nodePort: 30009
# 新增 selector: k8s-app: kubernetes-dashboard
# 部署
[root@k8s-master01 ~]# kubectl create -f recommended.yaml
# 查看namespace下的kubernetes-dashboard下的资源
[root@k8s-master01 ~]# kubectl get pod,svc -n kubernetes-dashboardNAME READY STATUS RESTARTS AGEpod/dashboard-metrics-scraper-c79c65bb7-zwfvw 1/1 Running 0 111spod/kubernetes-dashboard-56484d4c5-z95z5 1/1 Running 0 111s NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGEservice/dashboard-metrics-scraper ClusterIP 10.96.89.218 <none> 8000/TCP 111sservice/kubernetes-dashboard NodePort 10.104.178.171 <none> 443:30009/TCP 111s
2)创建访问账户,获取token
# 创建账号
[root@k8s-master01-1 ~]# kubectl create serviceaccount dashboard-admin -n kubernetes-dashboard
# 授权
[root@k8s-master01-1 ~]# kubectl create clusterrolebinding dashboard-admin-rb --clusterrole=cluster-admin --serviceaccount=kubernetes-dashboard:dashboard-admin
# 获取账号token
[root@k8s-master01 ~]# kubectl get secrets -n kubernetes-dashboard | grep dashboard-admindashboard-admin-token-xbqhh kubernetes.io/service-account-token 3 2m35s [root@k8s-master01 ~]# kubectl describe secrets dashboard-admin-token-xbqhh -n kubernetes-dashboardName: dashboard-admin-token-xbqhhNamespace: kubernetes-dashboardLabels: <none>Annotations: kubernetes.io/service-account.name: dashboard-admin kubernetes.io/service-account.uid: 95d84d80-be7a-4d10-a2e0-68f90222d039 Type: kubernetes.io/service-account-token Data====namespace: 20 bytestoken: eyJhbGciOiJSUzI1NiIsImtpZCI6ImJrYkF4bW5XcDhWcmNGUGJtek5NODFuSXl1aWptMmU2M3o4LTY5a2FKS2cifQ.eyJpc3MiOiJrdWJlcm5ldGVzL3NlcnZpY2VhY2NvdW50Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9uYW1lc3BhY2UiOiJrdWJlcm5ldGVzLWRhc2hib2FyZCIsImt1YmVybmV0ZXMuaW8vc2VydmljZWFjY291bnQvc2VjcmV0Lm5hbWUiOiJkYXNoYm9hcmQtYWRtaW4tdG9rZW4teGJxaGgiLCJrdWJlcm5ldGVzLmlvL3NlcnZpY2VhY2NvdW50L3NlcnZpY2UtYWNjb3VudC5uYW1lIjoiZGFzaGJvYXJkLWFkbWluIiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9zZXJ2aWNlLWFjY291bnQudWlkIjoiOTVkODRkODAtYmU3YS00ZDEwLWEyZTAtNjhmOTAyMjJkMDM5Iiwic3ViIjoic3lzdGVtOnNlcnZpY2VhY2NvdW50Omt1YmVybmV0ZXMtZGFzaGJvYXJkOmRhc2hib2FyZC1hZG1pbiJ9.NAl7e8ZfWWdDoPxkqzJzTB46sK9E8iuJYnUI9vnBaY3Jts7T1g1msjsBnbxzQSYgAG--cV0WYxjndzJY_UWCwaGPrQrt_GunxmOK9AUnzURqm55GR2RXIZtjsWVP2EBatsDgHRmuUbQvTFOvdJB4x3nXcYLN2opAaMqg3rnU2rr-A8zCrIuX_eca12wIp_QiuP3SF-tzpdLpsyRfegTJZl6YnSGyaVkC9id-cxZRb307qdCfXPfCHR_2rt5FVfxARgg_C0e3eFHaaYQO7CitxsnIoIXpOFNAR8aUrmopJyODQIPqBWUehb7FhlU1DCduHnIIXVC_UICZ-MKYewBDLwca.crt: 1025 bytes
3)通过浏览器访问Dashboard的UI
在登录页面上输入上面的token

出现下面的页面代表成功

本章节以Deployment为例演示DashBoard的使用
查看
选择指定的命名空间dev,然后点击Deployments,查看dev空间下的所有deployment

扩缩容
在Deployment上点击规模,然后指定目标副本数量,点击确定

编辑
在Deployment上点击编辑,然后修改yaml文件,点击确定

查看Pod
点击Pods, 查看pods列表

操作Pod
选中某个Pod,可以对其执行日志(logs)、进入执行(exec)、编辑、删除操作

Dashboard提供了kubectl的绝大部分功能,这里不再一一演示