16、深入学习Pod

Kubernetes学习目录

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

 

posted @ 2023-03-19 08:30  小粉优化大师  阅读(172)  评论(0编辑  收藏  举报