16、深入学习Pod
1、概述
1.1、简介
Kubernetes是通过组合容器将应用放置到一个个的逻辑单元中,达到快速管理业务应用的效果,这个逻辑单元就是Pod。
Pod是Kubernetes中最重要也最基本的概念。
1.2、交付单元历史介绍
1、传统主机阶段 - 单台主机 2、容器环境阶段 - 单个容器 3、任务编排阶段 - Pod(容器集合)
2、Pod的特点解析比较
2.1、Pod vs 容器
1、一个Pod可以有多个容器,彼此间共享网络和存储资源。
2、每一个Pod中有一个Pause容器保存所有容器的状态,通过管理pause容器,达到管理pod中所有容器的效果。
3、只有紧密关系的容器才可以放到一个pod中,不同业务的容器分别放在不同的pod中
2.2、Pod vs 节点
1、同一Pod中的容器总会被调度到相同Node节点 2、不同节点间Pod的通信是基于虚拟二层网络技术实现的。
2.3、Pod vs Pod
普通的Pod和静态Pod(一般不用)
2.4、Pod vs 应用
1、每个Pod都是应用的一个(子应用)实例,有专用的ip,与容器暴露的端口组合为一个service的endpoint地址 2、每个service由kube-proxy转换为本地的ipvs或iptables规则
2.5、应用 vs 应用
1、每个service的enpoint地址由coredns组件解析为对应的服务名称, 2、其他service的pod通过访问该 名称 达到应用间通信的效果
2.6、外部 vs pod
外部流量通过节点网卡进入到k8s集群,基于ipvs或iptables规则找到对应的service,进而找到对应pod地址
3、pod通信
3.1、Pod内多容器通信
容器间通信(容器模型)
3.2、单节点内多Pod通信
主机间容器通信(host模型)
docker inspect host
3.3、多节点内多Pod通信
跨主机网络解决方案(overlay模型)
4、Pod核心思想
4.1、应用交付
Kubernetes是一个自动化的容器管理平台,存在的目的就是快速管理各种业务应用。所以它所面对的本
质上就是业务应用。
随着应用的进一步拆分和微服务架构的设计,一个应用被拆分成了多个独立的子模块应用。
虽然Kubernetes将这些应用的各个子模块单独部署在容器上,但是Kubernetes不再是对一个个子应用
容器进行管理,他是将这些子应用容器放在一个逻辑单元中,而这个逻辑单元针对的是应用或服务,通过对逻
辑单元的操作,达到对应用快速管理,从而实现业务的快速交付。
所以说Pod面向的是应用或服务,而不是具体的应用容器或者子应用容器。
一句话:
站得高,可大处着手
看得远,事随心所欲。
4.2、资源管理
kubernetes是一个分布式的资源管理平台,分布的特点就是资源分散,所以Kubernetes的应用,肯定会出
现业务应用的不同模块被分配到多个Node工作结点,那么随之而来,就会出现两种问题:
需要设计一个复杂的资源调度算法,根据业务需求,从不同Node上获取所有特定的数据
强耦合的业务应用,被分配到了不同节点,可能造成不可预测的功能缺失或潜在问题
所以,与其花费大力气解决上述两个问题,还不如把这些功能直接打包到一个逻辑单元pod中:
对内:
所有的子应用容器可以在Pod内部进行单独管理,即使pod在调度到其他Node节点,Pod内部的所
有子应用容器仍可以正常运行。
对外:
对于整个业务系统来说,面向的是一个个的应用或业务功能(即Pod),可以轻轻松松实现管理。
一句话:
精兵简政,高度自治。
4.3、实现细节
应用业务下放权力到Pod内部了,那么Pod如何管理子应用呢?我们从三个方面来学习:
通信机制:
Pod内有个Pause容器,它有独立的ip地址,其他子应用容器基于container网络模式实现统一的对外
服务,大大简化了关联业务容器之间的通信问题。
存储机制:
Pod内有专用的数据存储资源对象,其他子应用容器共享该数据卷,实现多容器数据信息的统一存储。
管理机制:
所有子应用容器的信息都保存在pause容器中,通过对pause容器的管理,达到管理所有容器效果。
5、pod管理
5.1、概述
k8s集群通过pod实现了大量业务应用容器的统一管理,而k8s也提供了大量的资源对象来对 pod进行管理:
通过控制器来确保 pod的运行和数量 符合用户的期望状态
通过网络资源来确保 pod的应用服务 可以被外部的服务来进行访问
5.2、pods流程图
5.3、pod关联资源对象图
1、工作负载型资源 Pod、Deployment、DaemonSet、Replica、StatefulSet、Job、Cronjob、Operator 2、服务发现和负载均衡资源 Service、Ingress 3、配置和存储 configMap、Secret、PersistentVolume、PersistentVolumeChain、DownwardAPI 4、动态调整资源 HPA、VPA 5、资源隔离权限控制资源 namespace、nodes、clusterroles、Roles
6、Pod简单实践
6.1、命令行方式
6.1.1、基本语法
命令行创建Pod对象,只需要在命令行中执行一条命令即可 语法:kubectl run NAME --image=image [--port=port] [--replicas=replicas] 参数详解 --dry-run=true 以模拟的方式来进行执行命令 --env=[] 执行的时候,向对象中传入一些变量 --image='' 指定容器要运行的镜像 --labels='' 设定pod对象的标签 --limits='cpu=200m,memory=512Mi' 设定容器启动后的资源配置 --replicas=n 设定pod的副本数量 --port='' 设定容器暴露的端口
6.1.2、运行nginx镜像
]# kubectl run nginx-1 --image=nginx pod/nginx-1 created ]# kubectl run nginx-2 --image=nginx --port=9999 pod/nginx-2 created
6.2、配置文件方式
6.2.1、布署Nginx-创建资源文件
# 创建nginx pod并且传入环境变量 cat >nginx_pod.yml<<'EOF' apiVersion: v1 kind: Pod metadata: name: nginx-test spec: containers: - name: nginx image: 192.168.10.33:80/k8s/my_nginx:v1 env: - name: HELLO value: "Hello kubernetes nginx" EOF 注意: 资源定义文件中可以同时写多个Pod对象,彼此间使用"---"隔开就可以了
6.2.2、应用资源文件
语法: kubectl create|apply -f nginx_pod.yml 子命令解析: create 仅仅是创建一个对象,如果对象已存在,则不会重复创建 apply 比较前后配置差异 而后作变更,如果不加限制此命令,会引起很大的隐患 命令示例: ]# kubectl create -f nginx_pod.yml pod "nginx-test" created
7、Pod管理
7.1、资源查看
7.1.1、语法
通过命令行工具,查看Pod对象的基本信息 语法: kubectl get pod/po <Pod_name> kubectl get pod/po <Pod_name> -o wide|yaml 注释: -o wide 获取更多详细的信息
7.1.2、查询pod
kubectl get pod kubectl get pod -o yaml [root@master1 ~]# kubectl get pod nginx-test -o custom-columns=NAME:metadata.name,STATUS:status.phase NAME STATUS nginx-test Running
7.2、资源描述
7.2.1、语法
通过命令行工具,查看Pod对象的全部信息 语法:kubectl describe pod/po <Pod_name> 示例: ]# kubectl describe po
7.2.2、描述查询
]# kubectl get pod NAME READY STATUS RESTARTS AGE nginx-deployment-6ff7d5db94-vdsqn 1/1 Running 0 19h nginx-test 1/1 Running 0 26m tomcat-deployment-774f9fdf7d-kw9x4 1/1 Running 0 20h ]# kubectl describe pod nginx-test
7.3、资源修改
7.3.1、语法
修改yaml文件里面的内容 value: "Hello nginx" 更改命令 kubectl replace -f FILENAME [options] 参数详解: --force 表示强制更新 注意: kubectl edit 是实时修改
7.3.2、执行修改
]# kubectl replace -f nginx_pod.yml --force ]# kubectl get pod nginx-test -o yaml | grep value value: Hello nginx
7.4、资源删除
7.4.1、语法
删除一个Pod对象有三种方式,如下: 语法一:kubectl delete pod --all/[pod_name] 语法二:kubectl delete deployment --all/[deployment_name] 语法三:kubectl delete -f pod_name.yaml 注意: 方法二要求有相应的deployment前提才可以。
7.4.2、执行删除
# 查询deployment和pod # deployment ]# kubectl get deployments.apps NAME READY UP-TO-DATE AVAILABLE AGE nginx-deployment 1/1 1 1 23h tomcat-deployment 1/1 1 1 20h # pod ]# kubectl get pods NAME READY STATUS RESTARTS AGE nginx-deployment-6ff7d5db94-vdsqn 1/1 Running 0 19h nginx-test 1/1 Running 0 3m53s tomcat-deployment-774f9fdf7d-kw9x4 1/1 Running 0 20h # 方法1:删除pod kubectl delete pod nginx-test # 方法2:删除deployments,对应的pods也会删除,但是service还需要手动删除“kubectl delete service tomcat-web-service” kubectl delete deployments.apps tomcat-deployment # 方法3:此方式删除是把deployment和service都删除的 kubectl delete -f nginx-proxy.yml
8、Pod流程解析
8.1、创建流程
8.1.1、Pod流程示意图
8.1.2、Pod流程解析
用户通过多种方式向master结点上的API-Server发起创建一个Pod的请求 apiserver 将该信息写入 etcd scheduluer 检测到api-Server上有建立Pod请求,开始调度该Pod到指定的Node,同时更新信息到etcd kubelet 检测到有新的 Pod 调度过来,通过Docker引擎运行该 Pod对象 kubelet 通过 container runtime 取到 Pod 状态,并同步信息到 apiserver,由它更新信息到etcd
8.2、Pod生命周期
8.2.1、简介
公司的业务应用项目是有生命周期的,Kubernetes是基于业务应用或服务进行统一管理的平台,每一个应用服务对应一个Pod,所以伴随着业务应用,Pod也有独立的生命周期。
8.2.2、生命周期流程图
三种模式: sideCar模式 - 为主容器提供辅助功能 Adapater模式 - 帮助主容器通信过程中的信息格式修正 Ambassador模式 - 利用pod内多容器共享数据的特性,代理后端容器和外部的其他应用进行交流
8.2.3、流程解析
顺序1:init容器 初始化容器,独立于主容器之外,pod可以拥有任意数量的init容器,init顺序执行。最后一个执行完 成后,才启动主容器。它主要是为了为主容器准备应用的功能,比如向主容器的存储卷写入数据,然后将存储 卷挂载到主容器上。 合理使用就绪探针(Readiness) 顺序2:生命周期钩子 启动后钩子 【与主进程并行运行】 运行中钩子 Liveiness - 判断当前容器是否处于存活状态 Readiness - 判断当前容器是否可以正常的对外提供服务 停止前钩子 先执行钩子,并在钩子执行完成后,向容器发送SIGTERM信号。如果没有优雅终止,则会被杀死。 不管执行成功与否,容器都会终止,如果未成功则告警。 顺序3:pod关闭 当API服务器接收到删除pod对象的命令后,按照下面流程进行: 执行停止前钩子,等待它执行完毕 向容器的主进程发送SIGTERM信号 等待容器优雅关闭或者等待终止宽限期超时 如果容器没有优雅关闭,使用SIGKILL信号强制终止进程 设置终止宽限期 spec.terminationGracePeriod,默认为30s 命令:kubectl delete pod mypod --grace-period=5 强制:kubectl delete pod mypod --grace-period=0 --force 根据我们对上面pod的启动流程的了解,我们发现当容器中的进程启动前或者容器中的进程终止之前都会 有一些额外的动作执行,这是由kubelet所设置的,在这里,我们称之为 pod hook。而Kubernetes 为我 们提供了两种钩子函数:PostStart和PreStop。 关于钩子函数的执行主要有两种方式: Exec - 用于执行一段特定的命令,不过要注意的是该命令消耗的资源会被计入容器。 HTTP - 对容器上的特定的端点执行HTTP请求。
8.3、Pod状态
8.3.1、状态解析
正常情况: 在Kubernetes集群中,真正工作的是Node节点,所以业务的子应用也就是Pod,肯定会被分配到相应 的Node节点上。Pod一旦绑定到Node节点,就永远不会移动,即便Node节点发生重启。 Pod作为一种资源对象,在整个业务生命周期中,会随着操作而出现五种状态: pending,running,succeeded,failed,Unknown 业务应用作为系统的一部分,会有相应的资源对象对它们进行统一管理,所以不建议手工单独创建一个 Pod 异常情况: 业务运行过程中不可避免会出现意外,这个时候有三种策略对Pod进行管理: OnFailure,Never和Always(默认) 参考资料: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle/
8.3.2、pod状态
状态 描述
Pending # APIserver已经创建该server,但pod内有一个或多个容器的镜像还未创建,可能在下载中
Running # Pod内所有的容器已创建,且至少有一个容器处于运行状态,正在启动或重启状态
Succeeded # 所有容器均成功执行退出,且不会再重启
Failed # Pod内所有容器都已退出,其中至少有一个容器退出失败。
Unknown # 由于某种原因无法获取Pod的状态比如网络不通
CrashLookBackOff # k8s曾经启动容器成功,但是后来异常情况下,重启次数过多导致异常终止容器退避算法:第1次0秒立刻重启,第二次10秒后重启,第三次20秒后重启, ...
第6次160秒后重启,第7次300秒后重启,如果仍然重启失败,则置为 CrashLookBackOff状态;其他的比如镜像获取,就无效了
Error # 因为集群配置、安全限制、资源等原因导致Pod 启动过程中发生了错误
Evicted # 集群节点 系统内存或硬盘资源不足 导致Pod出现异常
kubectl explain pods.status.phase
8.3.3、容器状态
容器状态 描述
Waiting # 容器处于 Running 和Terminated 状态之前的状态
Running # 容器能够正常的运行状态
Terminated # 容器已经被成功的关闭了
kubectl explain pods.status.containerStatuses.state
8.3.4、流程状态
流程状态 描述
PodScheduled # Pod被调度到某一个结点
Ready # 准备就绪,Pod可以处理请求
Initialized # Pod中所有初始init容器启动完毕
Unschedulable # 由于资源等限制,导致pod无法被调度
ContainersReady # Pod中所有的容器都启动完毕了
kubectl explain pods.status.conditions.status
8.3.5、重启策略
重启策略 描述
Always # 容器失效时,即重启
OnFailure # 容器终止运行,且退出码不为0 时重启
Never # Pod不重启
kubectl explain pods.spec.containers.imagePullPolicy
8.3.6、镜像拉取状态
拉取策略 描述
Always # 总是拉取新镜像,这是默认值
IfNotPresent # 如果本地仓库不存在的话,再拉取新镜像
Never # 不获取新镜像
kubectl explain pod.spec.containers.imagePullPolicy
9、流程实践
9.1、initContainers实践
9.1.1、简介
主容器启动之前要运行的容器,常用于执行一些预置操作
初始化容器必须运行完成至结束,每个初始化容器都必须按定义顺序串行运行
属性信息:kubectl explain pods.spec.initContainers
9.1.2、初始化等待10秒后,再创建容器
cat >pod_init_test.yml<<'EOF' apiVersion: v1 kind: Pod metadata: name: init-pod labels: app: init spec: containers: - name: nginx image: 192.168.10.33:80/k8s/my_nginx:v1 initContainers: - name: init-myservice image: 192.168.10.33:80/k8s/my_nginx:v1 command: ['sh', '-c', 'sleep 10;'] EOF # 创建pods kubectl apply -f pod_init_test.yml # 监控pods是否是10秒后创建 ]# kubectl get pods -w NAME READY STATUS RESTARTS AGE init-pod 0/1 Init:0/1 0 7s init-pod 0/1 PodInitializing 0 11s init-pod 1/1 Running 0 12s
9.2、poststart实践
9.2.1、简介
对于pod的流程启动,主要有两种钩子:
postStart,容器创建完成后立即运行,不保证一定会于容器中ENTRYPOINT之前运行
preStop,容器终止操作之前立即运行,在其完成前会阻塞删除容器的操作调用
钩子处理器实现方式:Exec 和 HTTP
Exec,在钩子事件触发时,直接在当前容器中运行由用户定义的命令
HTTP,在当前容器中向某Url发起HTTP请求
属性信息:kubectl explain pods.spec.initContainers.lifecycle
9.2.2、创建容器时写入html文件
cat >pod-poststart.yaml<<'EOF' apiVersion: v1 kind: Pod metadata: name: poststart spec: containers: - name: busybox image: busybox lifecycle: postStart: exec: command: ["/bin/sh","-c","echo 'lifecycle poststart' > /tmp/poststart.html"] command: ['sh', '-c', 'echo The app is running! && sleep 3600'] EOF
9.2.3、应用并且看效果
kubectl apply -f pod-poststart.yaml ]# kubectl get pods NAME READY STATUS RESTARTS AGE poststart 1/1 Running 0 2m51s ]# kubectl exec poststart -- ls /tmp/ poststart.html ]# kubectl exec poststart -- cat /tmp/poststart.html lifecycle poststart
9.3、prestop实践
9.3.1、简介
kubectl explain pods.spec.initContainers.lifecycle.preStop 功能:实现pod对象移除之前,我们需要做一些事情 实现方式: exec <Object> httpGet <Object> tcpSocket <Object> 钩子处理程序的日志不会在 Pod 事件中公开。 如果处理程序由于某种原因失败,它将播放一个事件。 对于 PostStart,这是 FailedPostStartHook 事件,对于 PreStop,这是 FailedPreStopHook 事件。 您可以通过运行 kubectl describe pod <pod_name> 命令来查看这些事件。
9.3.2、删除pods后往node节点写入文件【k8s系统自动调度到节点】
# 系统自动调度节点 cat >prestop-pod.yaml<<'EOF' apiVersion: v1 kind: Pod metadata: name: prestop-pod spec: volumes: - name: message hostPath: path: /tmp containers: - name: prestop-pod image: 192.168.10.33:80/k8s/my_nginx:v1 volumeMounts: - name: message mountPath: /prestop/ lifecycle: preStop: exec: command: ['/bin/sh', '-c', 'echo prestop Handler > /prestop/prestop'] EOF # 指定调度到node2节点 cat > node2_nginx_pod.yml <<'EOF' apiVersion: v1 kind: Pod metadata: name: prestop-pod spec: nodeName: node2 volumes: - name: message hostPath: path: /tmp containers: - name: prestop-pod image: 192.168.10.33:80/k8s/nginx:v1 volumeMounts: - name: message mountPath: /prestop/ lifecycle: preStop: exec: command: ['/bin/sh', '-c', 'echo prestop Handler > /prestop/prestop'] EOF
9.3.3、应用并且看效果
# 应用资源清单 kubectl apply -f prestop-pod.yaml # 查看pods是否正常运行 ]# kubectl get pods NAME READY STATUS RESTARTS AGE prestop-pod 1/1 Running 0 12s # 查看目录是否挂载正常 ]# kubectl exec prestop-pod -- df -h | grep prestop /dev/mapper/centos-root 18G 4.8G 13G 28% /prestop # 删除pods ]# kubectl delete pod prestop-pod # 在node查看是否存在这个文件 [root@node1 ~]# cat /tmp/prestop prestop Handler
10、静态Pod
10.1、简介
对于pod来说,基于控制的特性主要有两类:静态pod和动态pod。动态pod其实就是我们一直实践中用
到的pod,也就是可以直接被集群中的kubelet进行增删改查的pod,静态pod在本质上与动态pod没有区别,
只是在于静态pod只能在特定的节点上运行,由特定节点上的kubelet进程来管理,对于集群来说,只能看,不能动。
10.1.1、应用场景
常常用于某些结点上的一些隐私操作或者核心操作,而且这些操作往往受到特定结点的场景约束,比如某
些定向监控、特定操作。
10.2、属性解析
10.2.1、配置文件
所谓的配置文件的方式,其实就是在特定的目录下存放我们定制好的资源对象文件,然后结点上的 kubelet服务周期性的检查该目录下的所有内容,对静态pod进行增删改查。其配置方式主要有两步 1、定制kubelet服务定期检查配置目录 2、增删定制资源文件
10.2.2、http方式
1、准备http方式提供资源文件的web站点 2、工作结点的kubelet配置–manifest-url=<资源文件的url下载地址>
10.2.3、总结
这两种方式实现的原理基本上是一致的,只不过一个是在本地设置资源对象文件,一个是在别处设置,我们通过http的方式来获取。
10.3、kubelet配置文件位置介绍
10.3.1、查看kubelet服务配置位置
[root@master1 deplay]# rpm -ql kubelet /etc/kubernetes/manifests # 创建pod yaml的配置文件位置 /etc/sysconfig/kubelet # 启动kubelet额外增加的命令参数 /usr/bin/kubelet /usr/lib/systemd/system/kubelet.service # 开机自启动配置
10.3.2、配置文件的查找
]# systemctl status kubelet ● kubelet.service - kubelet: The Kubernetes Node Agent Loaded: loaded (/usr/lib/systemd/system/kubelet.service; enabled; vendor preset: disabled) Drop-In: /usr/lib/systemd/system/kubelet.service.d └─10-kubeadm.conf ]# cat /usr/lib/systemd/system/kubelet.service.d/10-kubeadm.conf # Note: This dropin only works with kubeadm and kubelet v1.11+ [Service] Environment="KUBELET_KUBECONFIG_ARGS=--bootstrap-kubeconfig=/etc/kubernetes/bootstrap-kubelet.conf --kubeconfig=/etc/kubernetes/kubelet.conf" Environment="KUBELET_CONFIG_ARGS=--config=/var/lib/kubelet/config.yaml" # This is a file that "kubeadm init" and "kubeadm join" generates at runtime, populating the KUBELET_KUBEADM_ARGS variable dynamically EnvironmentFile=-/var/lib/kubelet/kubeadm-flags.env # This is a file that the user can use for overrides of the kubelet args as a last resort. Preferably, the user should use # the .NodeRegistration.KubeletExtraArgs object in the configuration files instead. KUBELET_EXTRA_ARGS should be sourced from this file. EnvironmentFile=-/etc/sysconfig/kubelet ExecStart= ExecStart=/usr/bin/kubelet $KUBELET_KUBECONFIG_ARGS $KUBELET_CONFIG_ARGS $KUBELET_KUBEADM_ARGS $KUBELET_EXTRA_ARGS ]# grep static /var/lib/kubelet/config.yaml staticPodPath: /etc/kubernetes/manifests
10.4、/etc/kubernetes/manifests/文件查看
10.4.1、master
]# ls /etc/kubernetes/manifests/ etcd.yaml kube-apiserver.yaml kube-controller-manager.yaml kube-scheduler.yaml
# 只有master结点上才有默认启动的核心操作。
10.4.2、node
]# ls /etc/kubernetes/manifests/
10.5、静态pod实践
10.5.1、实现效果
接下来我们直接在 /etc/kubernetes/manifests 目录下创建资源对象文件即可
10.5.2、master查看集群当前效果
]# kubectl get pods No resources found in default namespace.
10.5.3、进入到node1结点的静态目录创建资源对象
cd /etc/kubernetes/manifests/ cat >static-pod.yml<<'EOF' apiVersion: v1 kind: Pod metadata: name: static-pod spec: containers: - name: web image: 192.168.10.33:80/k8s/my_nginx:v1 EOF
10.5.4、到master节点查看是否创建成功pod
]# kubectl get pods NAME READY STATUS RESTARTS AGE static-pod-node1 1/1 Running 0 69s
10.5.4、总结
1、无需应用资源清单,master自动获取创建pods。 2、master无法删除静态pod,删除后也会自动创建,需要删除的话,到node节点上,把资源清单删除掉。 3、master无法编辑静态pod。 4、master删除pod 对应的podIP地址是不会变的,还是原来的IP地址。
11、Pod策略
11.1、简介
11.1.1、隔离级别
Namespace 隔离内容
UTS 主机名与域名
IPC 信号量、消息队列和共享内存
PID 进程编号
Mount 挂载点(文件系统)
Network 网络设备、网络栈、端口等等
User 用户和用户组
11.1.2、约束的作用
根据约束的作用范围主要包括三个级别:
Pod级别:针对pod范围内的所有容器
容器级别:仅针对pod范围内的指定容器
PSP级别:PodSecurityPolicy,全局级别的Pod安全策略,涉及到准入控制相关知识
11.1.3、安全上下文属性
apiVersion: v1 kind: Pod metadata: {…} spec: securityContext: # Pod级别的安全上下文,对内部所有容器均有效 runAsUser <integer> # 以指定的用户身份运行容器进程,默认由镜像中的USER指定 runAsGroup <integer> # 以指定的用户组运行容器进程,默认使用的组随容器运行时 supplementalGroups <[]integer> # 为容器中1号进程的用户添加的附加组; fsGroup <integer> # 为容器中的1号进程附加的一个专用组,其功能类似于sgid runAsNonRoot <boolean> # 是否以非root身份运行 seLinuxOptions <Object> # SELinux的相关配置 sysctls <[]Object> # 应用到当前Pod上的名称或网络空间级别的sysctl参数设置列表 windowsOptions <Object> # Windows容器专用的设置 containers: - name: … image: … securityContext: # 容器级别的安全上下文,仅生效于当前容器 runAsUser <integer> # 以指定的用户身份运行容器进程 runAsGroup <integer> # 以指定的用户组运行容器进程 runAsNonRoot <boolean> # 是否以非root身份运行 allowPrivilegeEscalation <boolean> # 是否允许特权升级 capabilities <Object> # 于当前容器上添加(add)或删除(drop)的操作内核某些资源的能力 add <[]string> # 添加由列表格式定义的各内核能力 drop <[]string> # 移除由列表格式定义的各内核能力 privileged <boolean> # 是否运行为特权容器 procMount <string> # 设置容器的procMount类型,默认为DefaultProcMount; readOnlyRootFilesystem <boolean> # 是否将根文件系统设置为只读模式 seLinuxOptions <Object> # SELinux的相关配置 windowsOptions <Object> # windows容器专用的设置
注意: 上面的属性,仅仅是最常用的属性,而不是所有的属性
11.2、资源策略-用户级别
11.2.1、简介
相关的属性
runAsUser、runAsGroup
11.2.1、默认用户级别
cat >pod-test.yml<<'EOF' apiVersion: v1 kind: Pod metadata: name: nginx-test spec: nodeName: node2 containers: - name: nginx image: 192.168.10.33:80/k8s/my_nginx:v1 env: - name: HELLO value: "Hello kubernetes nginx" EOF ]# kubectl apply -f pod-test.yml ]# kubectl get pods NAME READY STATUS RESTARTS AGE nginx-test 1/1 Running 0 10s # 默认是以root用户运行 ]# kubectl exec -it nginx-test -- id uid=0(root) gid=0(root) groups=0(root) ]# kubectl delete pod nginx-test pod "nginx-test" deleted 注意:因为默认情况下,一旦pod创建好后,是不允许对用户归属权限进行任意修改的,所以需要修改的话,必须先关闭,再开启
11.2.2、添加安全属性的资源策略
# 所有NODE节点,创建运行的用户 ]# useradd k8s_test ]# id k8s_test uid=1000(k8s_test) gid=1000(k8s_test) groups=1000(k8s_test) cat >pod-securityContext.yml<<'EOF' apiVersion: v1 kind: Pod metadata: name: security-context-demo spec: securityContext: runAsUser: 1001 runAsGroup: 1001 containers: - name: sec-ctx-demo image: busybox command: [ "sh", "-c", "sleep 1h" ] securityContext: allowPrivilegeEscalation: false EO ]# kubectl apply -f pod-securityContext.yml ]# kubectl get pods NAME READY STATUS RESTARTS AGE security-context-demo 1/1 Running 0 5s ]# kubectl exec -it security-context-demo -- id uid=1001 gid=1001 groups=1001
11.3、资源策略-安全上下文
11.3.1、简介
相关的安全上下文 CAP_CHOWN:改变UID和GID; CAP_MKNOD:mknod(),创建设备文件; CAP_NET_ADMIN:网络管理权限; CAP_SYS_ADMIN:大部分的管理权限; CAP_SYS_TIME:更改系统的时钟 CAP_SYS_MODULE:装载卸载内核模块 CAP_NET_BIND_SERVER:允许普通用户绑定1024以内的特权端口
11.3.2、默认安全上下文
cat > pod-capabilities.yml <<'EOF' apiVersion: v1 kind: Pod metadata: name: pod-capabilities spec: containers: - name: pod-capabilities image: 192.168.10.33:80/k8s/pod_test:v0.1 command: ['/bin/sh', '-c'] args: ["/sbin/iptables -t nat -A PREROUTING -p tcp --dport 8080 -j REDIRECT --to-port 80 && /usr/bin/python3 /usr/local/bin/demo.py"] EOF ]# kubectl apply -f pod-capabilities.yml ]# kubectl get pods NAME READY STATUS RESTARTS AGE pod-capabilities 0/1 Error 0 3s # 报没有权限错误 ]# kubectl logs pod-capabilities getsockopt failed strangely: Operation not permitted
结果提示:
我们知道容器在启动的时候,默认是以linux系统普通用户启动的,所以普通用户是没有权限更改系统级
别的内容的,所以导致我们更改命令权限失败
11.3.3、安全上下文add
cat > pod-capabilities-add.yml <<'EOF' apiVersion: v1 kind: Pod metadata: name: pod-capabilities spec: containers: - name: pod-capabilities image: 192.168.10.33:80/k8s/pod_test:v0.1 command: ['/bin/sh', '-c'] args: ["/sbin/iptables -t nat -A PREROUTING -p tcp --dport 8080 -j REDIRECT --to-port 80 && /usr/bin/python3 /usr/local/bin/demo.py"] securityContext: capabilities: add: ["NET_ADMIN"] EOF ]# kubectl apply -f pod-capabilities-add.yml pod/pod-capabilities created # 运行成功 ]# kubectl get pods NAME READY STATUS RESTARTS AGE pod-capabilities 1/1 Running 0 4s
11.3.4、安全上下文drop
# 默认是可以支持授权限 ]# kubectl exec -it pod-capabilities -- chown 1001.1001 /etc/hosts # 禁用授权限的功能 cat > pod-capabilities-drop.yml <<'EOF' apiVersion: v1 kind: Pod metadata: name: pod-capabilities spec: containers: - name: pod-capabilities image: 192.168.10.33:80/k8s/pod_test:v0.1 command: ['/bin/sh', '-c'] args: ["/sbin/iptables -t nat -A PREROUTING -p tcp --dport 8080 -j REDIRECT --to-port 80 && /usr/bin/python3 /usr/local/bin/demo.py"] securityContext: capabilities: add: ["NET_ADMIN"] drop: ["CHOWN"] EOF 注意: add后面的权限能力必须使用双引号(""),不要使用单引号('') ]# kubectl apply -f pod-capabilities-drop.yml pod/pod-capabilities created ]# kubectl get pods NAME READY STATUS RESTARTS AGE pod-capabilities 1/1 Running 0 4s # 文件权限不能随意的更改了 ]# kubectl exec -it pod-capabilities -- chown 1001.1001 /etc/hosts chown: /etc/hosts: Operation not permitted command terminated with exit code 1
11.4、特权模式-sysctls
11.4.1、简介
默认情况下,pod的容器在启动的时候是具备了特权用户权限的。比如我们知道 kubeproxy 会将pod 启动时候的一些规则转换成对应的iptable或者ipvs规则 -- 这就涉及到宿主机内核级别的操作。 对于pod内部的容器名称空间的内核级别(不是系统级别)的参数调整,pod支持三个: kernel.shm_rmid_forced net.ipv4.ip_local_port_range net.ipv4.tcp_syncookies, 而对于这些内核参数的修改,必须要所有的node节点上让 kubelet服务支持 --allowed-unsafesysctls=net.core.somaxconn,net.ipv4.ip_unprivileged_port_start等相关内核参数才行,否则无法更改容器的内核参数。
11.4.2、默认报错
cat >pod-sysctl.yml<<'EOF' apiVersion: v1 kind: Pod metadata: name: pod-sysctl spec: securityContext: sysctls: - name: net.core.somaxconn value: "6666" - name: net.ipv4.ip_local_port_range value: "1024 65535" - name: kernel.shm_rmid_forced value: "0" containers: - name: pod-sysctl image: 192.168.10.33:80/k8s/pod_test:v0.1 EOF ]# kubectl apply -f pod-sysctl.yml pod/pod-sysctl created ]# kubectl get pods NAME READY STATUS RESTARTS AGE pod-sysctl 0/1 SysctlForbidden 0 4s # 默认情况下,普通用户是不允许修改命名空间里相关内核参数的 ]# kubectl logs pod-sysctl Error from server (BadRequest): container "pod-sysctl" in pod "pod-sysctl" is not available
11.4.3、针对普通用户是不允许修改命名空间里相关内核参数解决方法
# 所有Node都需要修改为如下 ]# cat /etc/sysconfig/kubelet KUBELET_EXTRA_ARGS="--allowed-unsafe-sysctls net.core.somaxconn,net.ipv4.ip_local_port_range" # 参数解析: net.core.somaxconn 网卡入栈的最大连接数 net.ipv4.ip_local_port_range 非特权用户可以使用的端口起始值,默认是1024 # 在所有的node角色节点上配置该文件,然后重启该服务 systemctl restart kubelet