k8s在生产中需要注意的各种事项和便捷方法
上下文切换 https://github.com/ahmetb/kubectx
https://github.com/junegunn/fzf
https://github.com/sbstp/kubie
kubectx 是一个在 kubectl 上更快地在上下文(集群)之间切换的工具。kubens 是一个可以轻松在 Kubernetes 命名空间之间切换(并为 kubectl 配置它们)的工具。
合并多集群kubeconfig 1 2 3 4 5 6 7 8 9 10 export KUBECONFIG =$(find $PWD -maxdepth 1 -type f | grep -v all-in-one | tr '\n' ':' | sed 's/.$//' )echo $KUBECONFIG kubectl config view --flatten > all-in-one .yaml kubectl config get-contexts --kubeconfig=all-in-one.yaml
安装 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 choco install kubens kubectx choco install fzf sudo git clone https://gi thub.com/ahmetb/ kubectx /opt/ kubectx sudo ln -s /opt/ kubectx/kubectx /u sr/local/ bin/kubectx sudo ln -s /opt/ kubectx/kubens /u sr/local/ bin/kubens apt install fzf Completion scripts for bash git clone https://gi thub.com/ahmetb/ kubectx.git ~/.kubectx COMPDIR=$(pkg-config --variable=completionsdir bash-completion) ln -sf ~/.kubectx/ completion/kubens.bash $COMPDIR/ kubens ln -sf ~/.kubectx/ completion/kubectx.bash $COMPDIR/ kubectx source <(kubectl completion bash) cat << EOF >> ~/.bashrc export PATH=~/.kubectx:\$PATH EOF 如果您已fzf安装,但想选择不使用此功能,请设置环境变量KUBECTX_IGNORE_FZF=1
使用 1 2 kubectx 直接切换集群kubens 切换命名空间
pod亲和性 podAffinity
亲和性
podAntiAffinity
反亲和性
差异:
requiredDuringSchedulingIgnoredDuringExecution
: #硬策略
preferredDuringSchedulingIgnoredDuringExecution
: #软策略
In:label 的值在某个列表中
NotIn:label 的值不在某个列表中
Gt:label 的值大于某个值
Lt:label 的值小于某个值
Exists:某个 label 存在
DoesNotExist:某个 label 不存在
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 apiVersion: v1 kind: Pod metadata: name: pod-anti-affinity labels: anti-affinity-demo: anti-affinity-demo-yahaha spec: affinity: podAntiAffinity: requiredDuringSchedulingIgnoredDuringExecution: - labelSelector: matchExpressions: - key: label_key_135 operator: In values: - label_value_135 topologyKey: kubernetes.io/hostname containers: - name: pod-anti-affinity image: nginx imagePullPolicy: IfNotPresent
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 apiVersion: v1 kind: Pod metadata: name: pod-anti-affinity labels: anti-affinity-demo: anti-affinity-demo-yahaha spec: affinity: podAntiAffinity: preferredDuringSchedulingIgnoredDuringExecution: - weight: 100 podAffinityTerm: topologyKey: "kubernetes.io/hostname" labelSelector: matchExpressions: - key: "label_key_135" operator: In values: - "label_value_135" containers: - name: pod-anti-affinity image: nginx imagePullPolicy: IfNotPresent
ingress apisix 开启gzip 1 2 3 4 5 6 7 8 9 10 11 12 13 14 { "comp_level" : 9 , "disable" : false , "types" : [ "text/plain" , "text/css" , "application/json" , "application/javascript" , "text/xml" , "application/xml" , "application/xml+rss" , "text/javascript" ] }
nginx-ingress 开启gzip 1 2 use -gzip: 'true' gzip-level: '5'
配置gzip的时候,若更改好ingress controler 的configmap, 默认情况下所有域名都开了gzip,若需要关闭指定的域名,那么直接在 annotations 中设置 nginx.ingress.kubernetes.io/server-snippet: gzip off;
上传文件大小: cm: nginx-configuration
1 2 proxy-body-size: 500 m client-body-buffer-size: 100 m
超时时间 出于某种原因,nginx进程不断重新加载 - 每30秒 . 每次重新加载时,所有连接都被删除 .
解决方案是设置:
在nginx-ingress config-map
中 .
1 worker-shutdown-timeout : "900s"
配置了nginx-ingress超时:
1 2 3 4 5 nginx.ingress .kubernetes .io/proxy-send-timeout: "300" nginx.ingress .kubernetes .io/proxy-read-timeout: "300" nginx.ingress .kubernetes .io/proxy-connect-timeout: "300" nginx.ingress .kubernetes .io/proxy-body-size: "1024m" proxy-next-upstream-timeout
proxy_connect_timeout :后端服务器连接的超时时间_发起握手等候响应超时时间(默认60秒)
proxy_read_timeout:连接成功后_等候后端服务器响应时间_其实已经进入后端的排队之中等候处理(也可以说是后端服务器处理请求的时间)
proxy_send_timeout :后端服务器数据回传时间_就是在规定时间之内后端服务器必须传完所有的数据
代理k8s api-server 1 2 3 4 尝试连接如果报x509 ip 认证失败没查证书可信域名 https:// www.jianshu.com/p/ 35 ac252b5045 后添加hosts即可连接
负载不均问题 对于长连接的服务,可能会存在负载不均的问题,下面介绍两种场景。
滚动更新负载不均 滚动更新时,旧 Pod 上的连接逐渐断掉,重连到新启动的 Pod 上,越先启动的 Pod在连接数比较固定或波动不大的情况下,所接收到的连接数越多,造成负载不均
rr 策略负载不均 假如长连接服务的不同连接的保持时长差异很大,而 ipvs 转发时默认是r 策略转发,如果某些后端 Pod”运气较差”,它们上面的连接保持时间比较较长,而由于是r 转发,它们身上累计的连接数就可能较多,节点上通过 pvsadm -Ln -t CLUSTER-IP:PORT 查看某个 service 的转发情况
扩容失效问题 在连接数比较固定或波动不大的情况下,工作负载在 HPA 自动扩容时,由于是场链接,连接数又比较固定,所有连接都“固化”在之前的 Pod 上,新扩出的 Pod 几乎没有连接,造成之前的 Pod 高负载,而扩出来的 Pd 又无法分担压力,导致扩容失丝
最佳实践
业务层面自动重连,避免连接“固化”到某个后端 Po上。比如周期性定时重连,或者一个连接中处理的请求数达到阙值后自动重连
不直接请求后端,通过七层代理访问。比如 gRPC 协议,可以使用 nginxingress 转发 gRPC,也可以使用istio 转发gRPC,这样对于 gRPC 这样多个请求复用同一个长连接的场景,经过七层代理后,可以自动拆分请求,在请求级别负载均衡。
kube-proxy 的ipvs 转发策略设置为 sh(–ipvs-scheduler=sh)。如果用的腾讯云 EKS 弹性集群,没有节点,看不到kube-proxy,可以通过 eks.tke.cloud.tencent.com/ipvs-scheduler:sh 这样的注解来设置,另外还支持将端口号也加入到 hash 的 key,更利于负载均衡,需再设置下eks.tke.cloud.tencent.com/ipvs-sh-port: “true’
容器3个探针 Readiness-就绪探针 就绪探针的目的是让Kubernetes知道该应用是否已经准备好为流量服务。Kubernetes将始终确保准备就绪探针通过之后开始分配服务,将流量发送到Pod。
Liveness-存活探针 你怎么知道你的应用程序是活的还是死的?存活探针可以让你做到这一点。如果你的应用死了,Kubernetes会移除旧的Pod并用新Pod替换它。
startup-启动探针 指示容器中的应用是否已经启动。如果提供了启动探针(startup probe),则禁用所有其他探针,直到它成功为止。如果启动探针失败,kubelet 将杀死容器,容器服从其重启策略进行重启。如果容器没有提供启动探针,则默认状态为成功Success。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 readinessProbe: httpGet: port: 20011 path: /actuator/health scheme: HTTP httpHeaders: - name: Content-Type value: application/json initialDelaySeconds: 95 periodSeconds: 2 timeoutSeconds: 15 livenessProbe: httpGet: port: 20011 path: /actuator/health scheme: HTTP httpHeaders: - name: Content-Type value: application/json initialDelaySeconds: 95 periodSeconds: 10 timeoutSeconds: 15
限制 CPU 和内存资源 1 2 3 4 5 6 7 resources: requests: cpu: "0.5" memory: 2Gi limits: cpu: "2" memory: 2Gi
kubectl patch 1 2 3 4 5 6 7 8 9 10 11 #!/bin/bash APP_LIST=`kubectl get deployments.apps -n suosi-prod | egrep -v 'NAME|nacos|redis|artemis|rocket' | grep 'suosi-' |awk '{print $1}' ` for deploy in $APP_LIST do echo $deploy kubectl patch deploy -n suosi-prod $deploy -p '{"spec":{"template":{"spec":{"containers":[{"name":"' ${deploy} '","env":[{"name":"aliyun_logs_suosi-app-logs","value":"stdout"},{"name":"aliyun_logs_logtag_tags","value":"app=' ${deploy} '"},{"name":"TZ","value":"Asia/Shanghai"}]}]}}}}' sleep 20 done {"spec" :{"template" :{"spec" :{"containers" :[{"name" :"'${deploy} '" ,"env" :[{"name" :"TZ" ,"value" :"Asia/Shanghai" }]}]}}}} kubectl set env -n suosi-dev deployment/fe-manager-container -c fe-manager-container TZ=Asia/Shanghai
启用RBAC 人数少可使用permission-manager
插件,多了就直接用rancher
配置网络策略 网络策略只不过是一个对象,它使你能够明确地声明和决定哪些流量是允许的,哪些是不允许的。这样,Kubernetes将能够阻止所有其他不想要的和不符合规则的流量。在我们的集群中定义和限制网络流量是强烈推荐的基本且必要的安全措施之一。
日志记录 标准输出只输出warn,后端程序直接推送至logstore,或写文件后抓取
磁盘(日志)清理 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 docker image prune -a -f docker container prune -f find /var/ lib/docker/ overlay2/ -name "info-log.log" -exec cp / dev/null {} \; find /var/ lib/docker/ overlay2/ -name "ons.log.*" -exec rm -rf {} \; find /var/ lib/docker/ overlay2/ -name "ons.log" -exec cp / dev/null {} \; find /var/ lib/docker/ containers/ -name "*-json.log.*" -exec rm -rf {} \; find /var/ lib/docker/ overlay2/*/ diff/data/ applogs/xxl-job/ jobhandler/ -name "*.log" -mtime +1 -exec rm -rf {} \; vim /etc/ crictl.yaml runtime-endpoint: unix:// /run/ containerd/containerd.sock image-endpoint: unix:// /run/ containerd/containerd.sock crictl 要下载k8s对应版本 https://gi t.xfj0.cn/https:/ /github.com/ kubernetes-sigs/cri-tools/ releases/download/ v1.20.0 /crictl-v1.20.0 -linux-amd64.tar.gz wget https:// kgithub.com/kubernetes-sigs/ cri-tools/releases/ download/v1.20.0/ crictl-v1.20.0 -linux-amd64.tar.gz tar xf crictl-v1.20.0 -linux-amd64.tar.gz mv crictl /usr/ local/bin/ crictl rmi --prune find /var/ lib/container/ containerd/io.containerd.snapshotter.v1.overlayfs/ snapshots/ -name "info-log.log" -exec cp / dev/null {} \;
1 2 forfiles -p "C:\comchatlog" -s -m *.log -d -5 -c "cmd /c del @path " forfiles -p "C:\comchatlog" -s -m *.log -d -5 -c "cmd /c echo @path "
监控 spring-cloud-prometheus插件,钉钉告警
无状态,不可变 镜像里只有运行代码
自动扩缩容 水平pod自动伸缩(HPA)、垂直pod自动伸缩(VPA)和集群自动伸缩。
控制镜像拉取来源 控制在集群中运行所有容器的镜像源。如果您允许您的Pod从公共资源中拉取镜像,您就不知道其中真正运行的是什么。
如果从受信任的注册表中提取它们,则可以在注册表上应用策略以提取安全和经过认证的镜像。
持续学习 不断评估应用程序的状态和设置,以学习和改进。例如,回顾容器的历史内存使用情况可以得出这样的结论:我们可以分配更少的内存,在长期内节省成本。
零停机时间 通过在HA中运行所有服务,支持集群和服务的零停机升级。这也将保证您的客户获得更高的可用性。
使用pod反亲和性来确保在不同的节点上调度一个pod的多个副本,从而通过计划中的和计划外的集群节点停机来确保服务可用性。
使用pod Disruptions策略,不惜一切代价确保您有最低的Pod副本数量!
1 2 3 4 5 6 7 8 lifecycle: preStop: exec: command: - "sh" - "-c" - | curl -X "PUT" http://eureka:20001/eureka/apps/<APP-NAME>/${HOSTNAME}/status?value=DOWN;sleep 90
为容器配置 Security Context 大部分情况下容器不需要太多的权限,我们可以通过 Security Context
限定容器的权限和访问控制,只需加上 SecurityContext 字段:
1 2 3 4 5 6 7 8 9 apiVersion: v1 kind: Pod metadata: name: <Pod name> spec: containers: - name: <container name> image: <image> + securityContext:
禁用 allowPrivilegeEscalation allowPrivilegeEscalation=true
表示容器的任何子进程都可以获得比父进程更多的权限。最好将其设置为 false,以确保 RunAsUser
命令不能绕过其现有的权限集。
1 2 3 4 5 6 7 8 9 10 apiVersion: v1 kind: Pod metadata: name: <Pod name> spec: containers: - name: <container name> image: <image> securityContext: + allowPrivilegeEscalation: false
不要使用 root 用户 为了防止来自容器内的提权攻击,最好不要使用 root 用户运行容器内的应用。UID 设置大一点,尽量大于 3000
。
1 2 3 4 5 6 7 8 apiVersion: v1 kind: Pod metadata: name: <name> spec: securityContext: + runAsUser: <UID higher than 1000 > + runAsGroup: <UID higher than 3000 >
不必挂载 Service Account Token ServiceAccount 为 Pod 中运行的进程提供身份标识,怎么标识呢?当然是通过 Token 啦,有了 Token,就防止假冒伪劣进程。如果你的应用不需要这个身份标识,可以不必挂载:
1 2 3 4 5 6 apiVersion: v1 kind: Pod metadata: name: <name> spec: + automountServiceAccountToken: false
确保 seccomp 设置正确 对于 Linux 来说,用户层一切资源相关操作都需要通过系统调用来完成,那么只要对系统调用进行某种操作,用户层的程序就翻不起什么风浪,即使是恶意程序也就只能在自己进程内存空间那一分田地晃悠,进程一终止它也如风消散了。seccomp(secure computing mode)就是一种限制系统调用的安全机制,可以可以指定允许那些系统调用。
对于 Kubernetes 来说,大多数容器运行时都提供一组允许或不允许的默认系统调用。通过使用 runtime/default
注释或将 Pod 或容器的安全上下文中的 seccomp 类型设置为 RuntimeDefault
,可以轻松地在 Kubernetes 中应用默认值。
1 2 3 4 5 6 apiVersion: v1 kind: Pod metadata: name: <name> annotations: + seccomp.security.alpha.kubernetes.io/pod: "runtime/default"
默认的 seccomp 配置文件应该为大多数工作负载提供足够的权限。如果你有更多的需求,可以自定义配置文件。
限制容器的 capabilities 容器依赖于传统的Unix安全模型,通过控制资源所属用户和组的权限,来达到对资源的权限控制。以 root 身份运行的容器拥有的权限远远超过其工作负载的要求,一旦发生泄露,攻击者可以利用这些权限进一步对网络进行攻击。
默认情况下,使用 Docker 作为容器运行时,会启用 NET_RAW
capability,这可能会被恶意攻击者进行滥用。因此,建议至少定义一个PodSecurityPolicy
(PSP),以防止具有 NET_RAW 功能的容器启动。
通过限制容器的 capabilities,可以确保受攻击的容器无法为攻击者提供横向攻击的有效路径,从而缩小攻击范围。
1 2 3 4 5 6 7 8 9 10 11 12 apiVersion: v1 kind: Pod metadata: name: <name> spec: securityContext: + runAsNonRoot: true + runAsUser: <specific user> capabilities: drop: + -NET_RAW + -ALL
如果你对 Linux capabilities 这个词一脸懵逼,建议去看看脑残入门系列:
只读 如果容器不需要对根文件系统进行写入操作,最好以只读方式加载容器的根文件系统,可以进一步限制攻击者的手脚。
1 2 3 4 5 6 7 8 9 10 apiVersion: v1 kind: Pod metadata: name: <Pod name> spec: containers: - name: <container name> image: <image> securityContext: + readOnlyRootFilesystem: true
node污点 1 kubectl taint node cn-hangzhou .10.10 .198.18 schedule_type= true :PreferNoSchedule
NoSchedule:只有拥有和这个 taint 相匹配的 toleration 的 pod 才能够被分配到这个节点。
PreferNoSchedule:系统会尽量避免将 pod 调度到存在其不能容忍 taint 的节点上,但这不是强制的。
NoExecute :任何不能忍受这个 taint 的 pod 都会马上被驱逐,任何可以忍受这个 taint 的 pod 都不会被驱逐。
node预留资源 https://kubernetes.io/zh/docs/tasks/administer-cluster/out-of-resource/#
K8S 把计算节点资源分为 4 个部分:
Kube Reserved:预留给 K8S 管理进程的资源,如 Kubelet,Docker Daemon 等
System Reserved:预留给系统资源,如 kernel,sshd,udev 等
Eviction Thresholds:驱逐(Eviction)的阈值,只支持 memory 和 storage。
Allocatable(available for pods):pods 可以使用的资源
为了简化管理,建议不对 kube-reserved/system-reserved 做区分,直接使用 --system-reserved
做系统预留。
1 --system-reserved=memory=4Gi,storage=5Gi \
node驱逐阈值 1 2 3 4 5 6 7 --eviction-soft=memory.available<4Gi,nodefs.available<15Gi,imagefs.available<20Gi \ --eviction-soft-grace-period=memory.available=2m,nodefs.available=2m,imagefs.available=2m \ --eviction-max-pod-grace-period=30 \ --eviction-hard=memory.available<1Gi,nodefs.available<10Gi,imagefs.available<15Gi \ --eviction-minimum-reclaim=memory.available=500Mi,nodefs.available=500Mi,imagefs.available=2Gi \
驱逐监控时间间隔 kubelet
根据其配置的整理时间间隔计算驱逐阈值。
housekeeping-interval
是容器管理时间间隔。
增大内核选项配置 /etc/sysctl.conf
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 fs.file-max=52706963 fs.nr_open = 52706963 vm.max_map_count = 262144 net.nf_conntrack_max = 10485760 net.netfilter.nf_conntrack_max=10485760 vm.panic_on_oom=0 vm.overcommit_memory=1 net.ipv4.neigh.default.gc_thresh1=1024 net.ipv4.neigh.default.gc_thresh2=4096 net.ipv4.neigh.default.gc_thresh3=8192 net.ipv4.tcp_max_orphans = 32768 net.ipv4.tcp_max_tw_buckets = 32768 net.ipv4.tcp_max_syn_backlog = 8096 net.netfilter.nf_conntrack_tcp_timeout_established=300 net.netfilter.nf_conntrack_buckets = 65536 fs.inotify.max_user_instances=524288 fs.inotify.max_user_watches=524288 net.core.netdev_max_backlog = 10000 net.core.somaxconn = 32768 kernel.pid_max=655350 kernel.threads-max=655350 net.netfilter.nf_conntrack_max=10485760 net.nf_conntrack_max = 10485760 net.netfilter.nf_conntrack_tcp_timeout_fin_wait = 60 net.netfilter.nf_conntrack_tcp_timeout_time_wait = 60 net.netfilter.nf_conntrack_tcp_timeout_close_wait = 360 net.netfilter.nf_conntrack_tcp_timeout_established = 8640
/etc/security/limits.conf
1 2 3 4 root soft nofile 655350 root hard nofile 655350 * soft nofile 655350* hard nofile 655350
SLB实例压测请求超时
登录后端服务器,排查发现Nginx日志没有异常,但是messages日志存在“nf_conntrack: table full, dropping packet”错误。该信息是因为Linux系统为每个经过内核网络栈的数据包,都生成一个新的连接记录项,当服务器处理的连接过多时,连接跟踪表无法记录新的连接记录项,服务器会丢弃新建连接的数据包。所以导致SLB和后端服务器TCP三次握手失败,出现504状态码。
解决方案
建议调整nf_conntrack参数,调整命令如下所示,参数值请以实际情况为准。
说明 :该方法会临时修改参数,重启实例后配置会不生效。
1 2 3 sysctl -w net.netfilter.nf_conntrack_max =1048576 sysctl -w net.netfilter.nf_conntrack_buckets =262144 sysctl -w net.netfilter.nf_conntrack_tcp_timeout_established =3600
在init-container做信号量限制放开 1 sysctl -w kernel.sem= "1034 32000 100 1000"
Pod 时区同步(PodPreset) 往往都会遇到修改 Pod 时区的需求,更多的需求是要求所有的 Pod 都在同一个时区,比如我们所在的东8区,一般我们可以通过环境变量或者挂载主机的时区文件到 Pod 中来实现同步,但是这样需要我们对每一个 Pod 手动做这样的操作,一个更好的方式就是利用 PodPreset 来预设。
首先启用 PodPreset:在 kube-apiserver 启动参数 -runtime-config 增加 settings.k8s.io/v1alpha1=true
;
然后在 –admission-control 增加 PodPreset 启用。最后重启 kube-apiserver 即表示启用成功。可以通过如下命令查看是否启用成功:
1 $ kubectl get podpresets
然后创建一个 PodPresents 资源对象:
1 2 3 4 5 6 7 8 9 10 apiVersion: settings.k8s.io/v1alpha1 kind: PodPreset metadata: name: tz-env spec: selector: matchLabels: env: - name: TZ values: Asia/Shanghai
这里需要注意的地方是,一定需要写 selector...matchLabels
,但是 matchLabels 为空,表示应用于所有容器,这个就是我们想要的,创建上面这个资源对象,然后我们去创建一个普通的 Pod 可以查看下是否注入了上面的 TZ 这个环境变量。需要注意的是,PodPreset 是 namespace 级别的对象,其作用范围只能是同一个命名空间下的容器。
限制日志大小和emptydir v1.7 + 支持对基于本地存储(如 hostPath, emptyDir, gitRepo 等)的容量进行调度限额。为了支持这个特性,Kubernetes 将本地存储分为两类:
storage.kubernetes.io/overlay
,即 /var/lib/docker
的大小
storage.kubernetes.io/scratch
,即 /var/lib/kubelet
的大小
Kubernetes 根据 storage.kubernetes.io/scratch
的大小来调度本地存储空间,而根据 storage.kubernetes.io/overlay
来调度容器的存储。比如为容器请求 64MB 的可写层存储空间:
1 2 3 4 5 6 7 8 9 10 11 12 13 apiVersion: v1 kind: Pod metadata: name: ls1 spec: restartPolicy: Never containers: - name: hello image: busybox command: ["df" ] resources: requests: storage.kubernetes.io/overlay: 64Mi
为 emptyDir 请求 64MB 的存储空间:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 apiVersion: v1 kind: Pod metadata: name: ls1 spec: restartPolicy: Never containers: - name: hello image: busybox command: ["df" ] volumeMounts: - name: data mountPath: /data volumes: - name: data emptyDir: sizeLimit: 64Mi
lxcfs让pod正确的意识到给自己分配的资源 1 2 3 4 $ git clone https://gitclone.com/github.com/denverdino/lxcfs-admission-webhook.git $ kubectl apply -f lxcfs-admission-webhook/deployment/lxcfs-daemonset.yaml $ cd lxcfs-admission-webhook && deployment/install.sh$ kubectl label namespace default lxcfs-admission-webhook=enabled
不支持alpine镜像
DEBUG 如何摘下某个Pod进行Debug 使用label机制,对Pod进行标记。在Service定义中,我们添加 status: serving字段。当需要摘下某个Pod做Debug,而又不影响整个服务,可以:
1 2 $ kubectl get pods --selector="status=serving" $ kubectl label pods webserver-rc-lxag2 --overwrite status=debuging
此时kubelet就会把这个Pod从Service的后端列表中删掉。等到Debug完,想恢复?再改回去就好了:
1 $ kubectl label pods webserver-rc-lxag2 --overwrite status=serving
Pod重启了,如何看重启之前的日志? 下面的命令只能看到当前Pod的日志:
1 $ kubectl logs zookeeper-1
通过 --previous
参数可以看之前Pod的日志
1 $ kubectl logs zookeeper-1
kubectl debug https://github.com/aylei/kubectl-debug/blob/master/docs/zh-cn.md
kubectl-debug 包含两部分: kubectl-debug:命令行工具; debug-agent:部署在K8s的node上,用于启动关联排错工具容器
1.20版本之前的k8s都需要安装插件后kubectl就能自动识别插件(1.15之前都需要使用kubect-debug二进制命令)
containerd 支持要安装pre最新分支
kubectl-debug –agentless=false -n suosi-prod xxl-job-78dfcbdcff-58nql # 最新分支无法使用配置文件
https://github.com/aylei/kubectl-debug/issues/140
客户端安装 1 2 3 4 curl -Lo debug_0.1.1_linux_amd64.tar.gz https://ghproxy.com/https://github.com/aylei/kubectl-debug/releases/download/v0.1.1/kubectl-debug_0.1.1_linux_amd64.tar.gz tar xf debug_0.1.1_linux_amd64.tar.gz mv kubectl-debug /usr/local/bin/kubectl debug -h
服务端安装 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 kubectl apply -f https://raw.githubusercontent.com/aylei/kubectl-debug/master/scripts/agent_daemonset.yml apiVersion: apps/v1 kind: DaemonSet metadata: labels: app: debug-agent name: debug-agent spec: selector: matchLabels: app: debug-agent template: metadata: labels: app: debug-agent spec: hostPID: true tolerations: - key: node-role.kubernetes.io/master effect: NoSchedule containers: - name: debug-agent image: aylei/debug-agent:v0.1.1 imagePullPolicy: Always securityContext: privileged: true livenessProbe: failureThreshold: 3 httpGet: path: /healthz port: 10027 scheme: HTTP initialDelaySeconds: 10 periodSeconds: 10 successThreshold: 1 timeoutSeconds: 1 ports: - containerPort: 10027 hostPort: 10027 name: http protocol: TCP volumeMounts: - name: cgroup mountPath: /sys/fs/cgroup - name: lxcfs mountPath: /var/lib/lxc mountPropagation: Bidirectional - name: docker mountPath: "/var/run/docker.sock" - name: runcontainerd mountPath: "/run/containerd" - name: runrunc mountPath: "/run/runc" - name: vardata mountPath: "/var/data" hostNetwork: true volumes: - name: cgroup hostPath: path: /sys/fs/cgroup - name: lxcfs hostPath: path: /var/lib/lxc type: DirectoryOrCreate - name: docker hostPath: path: /var/run/docker.sock - name: vardata hostPath: path: /var/data - name: runcontainerd hostPath: path: /run/containerd - name: runrunc hostPath: path: /run/runc updateStrategy: rollingUpdate: maxUnavailable: 5 type: RollingUpdate
debug-agent 两种运行方式: daemon-set模式,agent pod预先部署在所有node上,会始终占用资源,对于排错调试频率不高的环境造成资源浪费; agentless模式,kubectl-debug执行命令后,才创建agent pod和排错工具容器,并在退出后删除工具容器和agent pod。由于每次执行都要重新拉起agent,启动会比daemon-set模式稍慢。 使用-a, –agentless开启agentless模式:
需要配置文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 cat .kube/debug-config # debug-agent 映射到宿主机的端口 # 默认 10027 # agentPort: 10027 # 是否开启ageless模式 # 默认 true agentless: false # agentPod 的 namespace, agentless模式可用 # 默认 default # agentPodNamespace: default # agentPod 的名称前缀,后缀是目的主机名, agentless模式可用 # 默认 debug-agent-pod # agentPodNamePrefix: debug-agent-pod # agentPod 的镜像, agentless模式可用 # 默认 aylei/debug-agent:latest # agentImage: aylei/debug-agent:latest # debug-agent DaemonSet 的名字, port-forward 模式时会用到 # 默认 'debug-agent' # debugAgentDaemonset: debug-agent # debug-agent DaemonSet 的 namespace, port-forward 模式会用到 # 默认 'default' # debugAgentNamespace: devops # 是否开启 port-forward 模式 # 默认 true portForward: false # image of the debug container # default as showed image: registry-vpc.cn-hangzhou.aliyuncs.com/nbugs-share/share:debug_imagev1 # start command of the debug container # default ['bash' ] # command :# - '/bin/bash' # - '-l' # private docker registry auth kuberntes secret, default is kubectl-debug-registry-secret # 使用私有仓库镜像,并设置私有仓库使用的kubernetes secret # secret data原文请设置为 {Username: <username>, Password: <password>} # 默认RegistrySecretName为kubectl-debug-registry-secret,默认RegistrySecretNamespace为default # RegistrySecretName: qh-docker-registry # RegistrySecretNamespace: default # 在默认的agentless模式下可以设置agent pod的resource资源限制 # 若不设置,默认为空 # agentCpuRequests: "" # agentCpuLimits: "" # agentMemoryRequests: "" # agentMemoryLimits: "" # 当使用fork mode时,如果需要复制出来的pod保留原pod的labels,可以设置需要保留的labels列表 # 格式为[]string # 默认为空(既不保留任何原POD的labels,新fork出pod的labels) # forkPodRetainLabels: []
建议使用daemon-set模式
1 2 3 进阶使用: 排错init-container: kubectl debug demo-pod --container =init-pod
1 2 排错crash pod: kubectl debug POD_NAME