专栏首页运维之美Kubernetes 官方出品调试工具上手指南(无需安装,开箱即用)

Kubernetes 官方出品调试工具上手指南(无需安装,开箱即用)

本文介绍了 Kubectl debug 和临时容器等调试方法。

作者:Martin Heinz 翻译:Bach (K8sMeetup) 校对:星空下的文仔

调试容器化工作负载和 Pod 是每位使用 Kubernetes 的开发人员和 DevOps 工程师的日常任务。通常情况下,我们简单地使用 kubectl logs 或者 kubectl describe pod 便足以找到问题所在,但有时候,一些问题会特别难查。这种情况下,大家可能会尝试使用 kubectl exec,但有时候这样也还不行,因为 Distroless 等容器甚至不允许通过 SSH 进入 shell。那么,如果以上所有方法都失败了,我们要怎么办?

更好的方法

其实我们只需要使用更合适的工具。如果在 Kubernetes 上调试工作负载,那么合适的工具就是 kubectl debug 这是不久前添加的一个新命令(v1.18),允许调试正在运行的 pod。它会将名为 EphemeralContainer(临时容器)的特殊容器注入到问题 Pod 中,让我们查看并排除故障。kubectl debug 看起来非常不错,但要使用它需要临时容器,临时容器到底是什么?

临时容器其实是 Pod 中的子资源,类似普通 container。但与普通容器不同的是,临时容器不用于构建应用程序,而是用于检查。 我们不会在创建 Pod 时定义它们,而使用特殊的 API 将其注入到运的行 Pod 中,来运行命令并检查 Pod 环境。除了这些不同,临时容器还缺少一些基本容器的字段,例如 portsresources

那么我们为什么不直接使用基本容器?这是因为我们不能向 Pod 添加基本容器,它们应该是一次性的(需要随时删除或重新创建),这会导致难以重现问题 Pod 的错误,排除故障也会很麻烦。这就是将临时容器添加到 API 的原因——它们允许我们将临时容器添加到现有 Pod,从而检查正在运行的 Pod。

虽然临时容器是作为 Kubernetes 核心的 Pod 规范的一部分,但很多人可能还没有听说过。这是因为临时容器处于早期 Alpha 阶段,这意味着默认情况下不启用。Alpha 阶段的资源和功能可能会出现重大变化,或者在 Kubernetes 的某个未来版本中被完全删除。因此,要使用它们必须在 kubelet 中使用Feature Gate(功能门)显式启用。

Configuring Feature Gates

现在如果确定要试用 kubectl debug,那么如何启用临时容器的功能门?这取决于集群设置。 例如,现在使用kubeadm启动创建集群,那么可以使用以下集群配置来启用临时容器:

apiVersion: kubeadm.k8s.io/v1beta2
kind: ClusterConfiguration
kubernetesVersion: v1.20.2
apiServer:
  extraArgs:
    feature-gates: EphemeralContainers=true

在以下示例中,为了简单和测试目的,我们使用 KinD(Docker 中的 Kubernetes)集群,这允许我们指定要启用的功能门。创建我们的测试集群:

# File: config.yaml
# Run:  kind create cluster --config ./config.yaml --name kind --image=kindest/node:v1.20.2
kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
featureGates:
  EphemeralContainers: true
nodes:
- role: control-plane

随着集群的运行,我们需要验证其有效性。最简单方法是检查 Pod API,它现在应该包含临时容器部分以及通常容器:

~ $ kubectl explain pod.spec.ephemeralContainers
KIND:     Pod
VERSION:  v1

RESOURCE: ephemeralContainers <[]Object>

DESCRIPTION:
     List of ephemeral containers run in this pod....
...

现在都有了,可以开始使用 kubectl debug。从简单的例子开始:

~ $ kubectl run some-app --image=k8s.gcr.io/pause:3.1 --restart=Never
~ $ kubectl debug -it some-app --image=busybox --target=some-app
Defaulting debug container name to debugger-tfqvh.
If you don't see a command prompt, try pressing enter.
/ #
# From other terminal...
~ $ kubectl describe pod some-app
...
Containers:
  some-app:
    Container ID:   containerd://60cc537eee843cb38a1ba295baaa172db8344eea59de4d75311400436d4a5083
    Image:          k8s.gcr.io/pause:3.1
    Image ID:       k8s.gcr.io/pause@sha256:f78411e19d84a252e53bff71a4407a5686c46983a2c2eeed83929b888179acea
...
Ephemeral Containers:
  debugger-tfqvh:
    Container ID:   containerd://12efbbf2e46bb523ae0546b2369801b51a61e1367dda839ce0e02f0e5c1a49d6
    Image:          busybox
    Image ID:       docker.io/library/busybox@sha256:ce2360d5189a033012fbad1635e037be86f23b65cfd676b436d0931af390a2ac
    Port:           <none>
    Host Port:      <none>
    State:          Running
      Started:      Mon, 15 Mar 2021 20:33:51 +0100
    Ready:          False
    Restart Count:  0
    Environment:    <none>
    Mounts:         <none>

我们首先启动一个名为 some-app 的 Pod 来进行“调试”。然后针对这个 Pod 运行 kubectl debug,指定 busybox 为临时容器的镜像,并作为原始容器的目标。此外,还需要包括 -it 参数,以便我们立即附加到容器获得 shell 会话。

在上面的代码中可以看到,如果我们在 Pod 上运行 kubectl debug 后对其进行描述,那么它的描述将包括具有之前指定为命令选项值的临时容器部分。

Process Namespace Sharing

kubectl debug 是非常强大的工具,但有时向 Pod 添加一个容器还不足以获取 Pod 的另一个容器中运行的应用程序相关信息。当故障容器不包括必要的调试工具甚至 shell 时,可能就是这种情况。在这种情况下,我们可以使用 Process Sharing(进程共享)来使用注入的临时容器检查 Pod 的原有容器。

进程共享的一个问题是它不能应用于现有的 Pod,因此我们必须创建一个新 Pod,将其 spec.shareProcessNamespace 设置为 true,并将一个临时容器注入其中。这样有点麻烦,尤其是需要调试多个 Pod 或容器,亦或者需要重复执行该操作时。幸运的是,kubectl debug 可以使用 --share-processes 做到:

~ $ kubectl run some-app --image=nginx --restart=Never
~ $ kubectl debug -it some-app --image=busybox --share-processes --copy-to=some-app-debug
Defaulting debug container name to debugger-tkwst.
If you don't see a command prompt, try pressing enter.
/ # ps ax
PID   USER     TIME  COMMAND
    1 root      0:00 /pause
    8 root      0:00 nginx: master process nginx -g daemon off;
   38 101       0:00 nginx: worker process
   39 root      0:00 sh
   46 root      0:00 ps ax
~ $ cat /proc/8/root/etc/nginx/conf.d/default.conf 
server {
    listen       80;
    listen  [::]:80;
    server_name  localhost;
...

上面的代码表明,通过进程共享,我们可以看到 Pod 中另一个容器内的所有内容,包括其进程和文件,这对于调试来说非常方便。另外,除了 --share-processes 还包括了 --copy-to=new-pod-name,这是因为我们需要创建一个新的 Pod,其名称由该 flag 指定。如果我们从另一个终端列出正在运行的 Pod,我们将看到以下内容:

# From other terminal:
~ $ kubectl get pods
NAME             READY   STATUS    RESTARTS   AGE
some-app         1/1     Running   0          23h
some-app-debug   2/2     Running   0          20s

这就是我们在原始应用程序 Pod 上的新调试 Pod。与原始容器相比,它有 2 个容器,因为它还包括临时容器。此外,如果想在任何时候验证 Pod 中是否允许进程共享,那么可以运行:

~ $ kubectl get pod some-app-debug -o json  | jq .spec.shareProcessNamespace
true

好好使用

既然我们已经启用了功能并且知道命令是如何工作的,那就试着使用它并调试一些应用程序。 想象这样一个场景——我们有一个问题应用程序,我们需要在它的容器中对网络相关的问题进行故障排除。该应用程序没有我们可以使用的必要的网络 CLI 工具。为了解决这个问题,我们通过以下方式使用 kubectl debug

~ $ kubectl run distroless-python --image=martinheinz/distroless-python --restart=Never
~ $ kubectl exec -it distroless-python -- /bin/sh
# id
/bin/sh: 1: id: not found
# ls
/bin/sh: 2: ls: not found
# env
/bin/sh: 3: env: not found
#
...

kubectl debug -it distroless-python --image=praqma/network-multitool --target=distroless-python -- sh
Defaulting debug container name to debugger-rvtd4.
If you don't see a command prompt, try pressing enter.
/ # ping localhost
PING localhost(localhost (::1)) 56 data bytes
64 bytes from localhost (::1): icmp_seq=1 ttl=64 time=0.025 ms
64 bytes from localhost (::1): icmp_seq=2 ttl=64 time=0.044 ms
64 bytes from localhost (::1): icmp_seq=3 ttl=64 time=0.027 ms

在启动一个 Pod 之后,我们首先尝试将 shell 会话放入它的容器中,这看起来有效,但是实际上我们尝试运行一些基本命令时,将看到那里什么都没有。所以,我们要使用 praqma/network-multitool 将临时容器注入到 Pod 中,该镜像包含了 curlpingtelnet 等工具,现在我们可以进行所有必要的故障排除。

在上面的例子中,我们进入 Pod 的另一个容器中就足够了。但有时可能需要直接查看有问题的容器。这种情况下,我们可以像这样使用进程共享:

~ $ kubectl run distroless-python --image=martinheinz/distroless-python --restart=Never
~ $ kubectl debug -it distroless-python --image=busybox --share-processes --copy-to=distroless-python-debug
Defaulting debug container name to debugger-l692h.
If you don't see a command prompt, try pressing enter.
/ # ps ax
PID   USER     TIME  COMMAND
    1 root      0:00 /pause
    8 root      0:00 /usr/bin/python3.5 sleep.py  # Original container is just sleeping forever
   14 root      0:00 sh
   20 root      0:00 ps ax
/ # cat /proc/8/root/app/sleep.py 
import time
print("sleeping for 1 hour")
time.sleep(3600)

在这里,我们再次运行使用 Distroless 镜像的容器。我们无法在它的 shell 中做任何事情。我们运行 kubectl debug 以及 --share-processes --copy-to=...,它创建了一个新的 Pod,带有额外的临时容器,可以访问所有进程。当我们列出正在运行的进程时,能看到应用程序容器的进程有 PID 8,可以用它来探索文件和环境。为此,我们需要通过 /proc/<PID>/... 目录,这个例子中是 /proc/8/root/app/...

另一种常见情况是应用程序在容器启动时不断崩溃,这让调试非常困难,因为没有足够的时间将 shell 会话导入容器并运行故障排除命令。在这种情况下,解决方案是创建具有不同入口点、命令的容器,这可以阻止应用程序立即崩溃并允许我们调试:

~ $ kubectl get pods
NAME                READY   STATUS             RESTARTS   AGE
crashing-app        0/1     CrashLoopBackOff   1          8s

~ $ kubectl debug crashing-app -it --copy-to=crashing-app-debug --container=crashing-app -- sh
If you don't see a command prompt, try pressing enter.
# id
uid=0(root) gid=0(root) groups=0(root)
#
...
# From another terminal
~ $ kubectl get pods
NAME                READY   STATUS             RESTARTS   AGE
crashing-app        0/1     CrashLoopBackOff   3          2m7s
crashing-app-debug  1/1     Running            0          16s

调试集群节点

本文主要关注 Pod 及其容器的调试,但任何集群管理员都知道常常需要调试的是节点而不是 Pod。幸运的是,kubectl debug 允许通过创建 Pod 来调试节点,该 Pod 将在指定节点上运行,节点的根文件系统安装在 /root 目录中。我们甚至可以用 chroot 访问主机二进制文件,这本质上充当了节点的 SSH 连接:

~ $ kubectl get nodes
NAME                 STATUS   ROLES                  AGE   VERSION
kind-control-plane   Ready    control-plane,master   25h   v1.20.2

~ $ kubectl debug node/kind-control-plane -it --image=ubuntu
Creating debugging pod node-debugger-kind-control-plane-hvljt with container debugger on node kind-control-plane.
If you don't see a command prompt, try pressing enter.
root@kind-control-plane:/# chroot /host
# head kind/kubeadm.conf
apiServer:
  certSANs:
  - localhost
  - 127.0.0.1
  extraArgs:
    feature-gates: EphemeralContainers=true
    runtime-config: ""
apiVersion: kubeadm.k8s.io/v1beta2
clusterName: kind
controlPlaneEndpoint: kind-control-plane:6443

在上面的代码中,我们首先确定了想要调试的节点,然后使用 node/... 作为参数显式运行 kubectl debug 以访问我们集群的节点。在那之后,当连接到Pod后,我们使用 chroot /host 突破 chroot,并完全进入主机。最后,为了验证是否真的可以看到主机上的所有内容,我们了查看一部分的 kubeadm.conf,最终看到我们在文章开头配置的内容 feature-gates: EphemeralContainers=true

小结

能够快速有效地调试应用程序和服务可以节省大量时间,但更重要的是,它能极大地帮助解决那些如果不立即解决可能最终会花费大量资金的问题。 这就是为什么 kubectl debug 之类的工具能随意使用非常重要,即使它们尚未正式发布或默认启用。如果启用临时容器不是一种选择,那么尝试替代调试方法可能是一个好主意,例如使用包含故障排除工具的应用程序镜像的调试版本;或临时更改 Pod 的容器命令以阻止其崩溃。

原文链接:https://towardsdatascience.com/the-easiest-way-to-debug-kubernetes-workloads-ff2ff5e3cc75

本文转载自:「 K8sMeetup社区 」,原文:https://tinyurl.com/5bp67tpm ,版权归原作者所有。欢迎投稿,投稿邮箱: editor@hi-linux.com。

本文分享自微信公众号 - 运维之美(Hi-Linux),作者:K8sMeetup

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2021-06-29

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 2020年Kubernetes中7个最佳日志管理工具

    Kubernetes在容器编排市场中占主导地位,通常用于托管微服务。但是,微服务的每个实例都会生成大量日志事件,这些日志事件很快就会变得难以管理。更糟糕的是,当...

    公众号: 云原生生态圈
  • 2021年需要关注的5个开源Kubernetes项目

    开源项目使Kubernetes更加强大。人们需要了解这些具有发展前途的开源项目,这些项目可以解决与Java、可观测性、持续集成(CI)/持续交付(CD)管道等相...

    静一
  • Kubernetes 的网络、存储和运行时该如何处理?

    技术的发展,总是解决了现有的问题,进而引入新的问题,继而继续解决,如此周而复始,Docker 公司在2013年成立,将容器的概念迅速扩散。正如当年集装箱点燃了全...

    CNCF
  • 面向 Kubernetes 开发者的设置指南

    本设置指南主要面向正在或将要参与 Kubernetes 开源项目以及为之做贡献的开发者、技术作家和测试人员。例如,它适用于以下各类人员:想要为 Kubernet...

    我是阳明
  • Kubernetes 是否值得学习吗?

    Original image by Myriam Zilles from Pixabay

    YP小站
  • 国内第一!腾讯云Serverless进入全球前三

    很荣幸,在Forrester最新发布的《The Forrester New WaveTM: Function-As-A- Service Platforms,...

    腾讯云serverless团队
  • 「运维之美」技术周刊 ( 第 4 期 )

    近日,谷歌副总裁巴提亚(Karan Bhatia)出席美国参议院司法委员会举行的听证会时确认谷歌已经终止了在中国推出审查搜索引擎的 “蜻蜓计划”,该计划原打算推...

    iMike
  • 当开源遇上云,Amazon EKS Distro 与 KubeSphere 能擦出怎样的火花?

    2021 年 1 月初,KubeSphere 社区也与亚马逊云科技联合宣布了 KubeSphere 正式登陆 Amazon Quick Starts,这些重大消...

    CNCF
  • 开发工具总结(7)之多年珍藏的Android开发必备网站和工具

    版权声明:本文为博主原创文章,未经博主允许不得转载。https://www.jianshu.com/p/781c1b56bc5b

    AWeiLoveAndroid
  • 开源项目介绍 |TKEStack-开源容器服务平台

    ‍‍ 滑至文末报名参与开源人才培养计划 提交项目Proposal ? TKEStack项目介绍  标签:容器,, Kubernetes  技术:golang ...

    腾讯开源
  • 1024程序员节献礼 | 精通Docker的50个必备教程、工具、资源

    ? 作者:Angela Stringfellow 译者:海松 原题:Master Docker: The Complete Toolkit Includi...

    yuanyi928
  • SAP Kyma on top of Kubernetes的会议台词

    版权声明:本文为博主汪子熙原创文章,未经博主允许不得转载。 https://jerry.blog....

    Jerry Wang
  • Docker,让数据库部署完成在弹指一挥间

    容器技术并非Docker的创新,容器技术所依赖的一些基础技术,如namespace、cgroup、chroot等等,也都不是Docker的首创。

    沃趣科技
  • Kubernetes VS Docker | 结局意想不到!

    Kubernetes vs Docker是云计算行业中多次提到的话题。无论您是否有技术背景,需要快速介绍,还是需要做出业务决策,我希望以下几点将一次性澄清这一问...

    xcbeyond
  • 推荐|50+有用的Kubernetes工具

    在短短两年的时间里,Kubernetes在集装箱管道战场上给其竞争对手带来了浪费。令人遗憾的是,Docker Swarm自2016年以来并未成为主要的竞争者,并...

    February
  • 阿里程序员常用的 15 款开发者工具

    这篇文章分享了 15 个阿里程序员常用的工具,其中很多我们都很熟悉比如Arthas(Java线上诊断工具) 、EasyExcel(高性能Excel处理)、Clo...

    王小婷
  • 10个最佳的Docker容器集群编排工具

    docker毫无疑问是一个优秀的开源工具。但是,仅靠docker引擎和容器就不能进行复杂的应用程序部署。对于部署复杂的应用程序体系结构的容器群集,必须进行适当的...

    DevOps云学堂
  • Kubernetes扩展容器架构的7 个工具

    Kubernetes是最初由Google开发的容器编排工具,已成为敏捷和DevOps团队的重要资源。作为一个开源工具,Kubernetes本身正在成为一个生态系...

    February
  • TF+K8s轻松上手|TF Carbide评估指南--准备篇

    Tungsten Fabric项目是一个开源项目协议,它基于标准协议开发,并且提供网络虚拟化和网络安全所必需的所有组件。项目的组件包括:SDN控制器,虚拟路由器...

    Tungsten Fabric

扫码关注云+社区

领取腾讯云代金券