为什么在Kubernetes上开发很糟糕? | Tilt博客


Kubernetes改变了我运行软件的方式,但是,当我编写软件时,Kuberentes会让事情变得更难。在这篇文章中,我想叙述我自己在Kubernetes上开发软件时遇到的所有问题。完全披露:虽然我在Tilt工作是我工作的一部分,我们的目的是解决其中的一些问题,但我的另一部分工作是编写在Kubernetes上运行的软件。当有另一种工具比Tilt更好地解决问题时,我会使用它。

无数的开发环境
MinikubeMicroK8s适用于Mac的DockerKIND,所有这些都是本地的Kubernetes环境。换句话说:它们是Kubernetes,只是在你的笔记本电脑上。您无需前往网络与大型Kubernetes集群(可能与生产数据交互)进行通信,您可以在笔记本电脑上启动一个小型集群来检查问题。
当你想在这些集群中的多个集群上运行代码/ Kubernetes配置时会出现问题,因为它们各自拥有自己的......怪癖。它们的行为彼此不同,或者与真正的Kubernetes集群完全相同。我不会在这里列举这些差异,但在讨论网络和身份验证等棘手问题时,我会在整篇博客文章中提到这个问题。
除了在云中真正的Kubernetes集群中进行开发之外,没有任何我知道的工具可以解决这些问题,这是我最近工作的方式。如果您在本地开发群集的市场中,我们最近发布了一个选择开发群集指南,以帮助理解所有选项。

权限/验证
如果您正在使用Kubernetes开发软件,那么您可能正在使用Kubernetes进行生产。如果您在生产中使用Kubernetes,则可能已锁定身份验证设置。例如,常见的设置是只允许开发人员访问在一个命名空间中创建/编辑对象。要做到这一点,你需要设置一些东西:

  • 一名角色
  • 一个角色绑定
  • 一个secret

如果您正在使用“真正的”Kubernetes集群,这非常有用,但只要您开始使用本地Kuberentes设置,事情就会变得奇怪。还记得那些本地开发环境吗?事实证明,其中一些处理RBAC的方式与您预期的完全不同。我遇到了一个问题,kubeadm有访问控制设置允许一切。结果,我有一种虚假的信心会刺激我的设置实际上限制了权限,而事实上他们没有起效。当然,kubeadm-dind-cluster已被弃用,但它表明并非所有Kubernetes集群都是相同的。我还遇到了另一个问题,试图在Docker for Mac的Kubernetes集群中重现该问题,其中没有强制执行RBAC规则
像NetworkPolicies这样的测试也很充实。NetworkPolicies在Docker for Mac或microk8s上根本不起作用,并且需要Minikube的特殊标志

网络调试
网络入口是Kubernetes最重要的事情之一。不幸的是,入口由不同的云提供商以不同的方式实现,因此很难测试。不同的实现还支持不同的扩展,通常配置标签,这些扩展在环境之间绝对不可移植。我很幸运能够访问一个临时集群来测试入口更改,但即使这样,更改也可能需要30分钟才能生效,并且可能导致不可思议的错误消息。如果你在当地的Kubernetes环境中,你几乎没有运气。
网络是我最不喜欢在Kubernetes工作的东西,而且我认为这个领域仍然需要最多的爱。但是,有一些工具可以提供帮助。
至少可以看到您的服务如何连接的一个很好的工具是Octant。Octant为您提供所有pod的视觉概览以及它们所属的服务。至少在Octant中,我可以轻松地从一段代码转到连接到互联网的方式。
对于复杂的Kubernetes对象,如在不同云平台上表现不同的入口Kubespy是一个非常宝贵的工具。Kubespy向您展示创建对象时引擎盖下发生的事情。例如,如果我创建一个服务,它会显示哪些IP地址Kubespy将为其提供流量的Pod:

> kubespy trace svc test-frontend
[ADDED v1/Service] default/test-frontend

[ADDED v1/Endpoints] default/test-frontend
   Directs traffic to the following live Pods:
    - [Ready] test-frontend-f6d6ff44-b7jzd @ 192.168.1.1

登录到容器并做事情
每个开发人员都会遇到的一个常见问题是SSH。也许在将来,SSH将像软盘图标一样不合时宜,但是现在,我想登录到一个容器,四处寻找,看看状态是什么,并且可能运行一些命令,如strace或tcpdump。
Kubernetes并不容易。工作流程如下所示: kubectl get pods 查找我的pod名称 kubectl exec -it $podname -- /bin/bash
事情变得很烦人。

> kubectl exec -it dan-test-75d7b88d8f-4p45c -- /bin/bash
OCI runtime exec failed: exec failed: container_linux.go:345: starting container process caused "exec: \"/bin/bash\": stat /bin/bash: no such file or directory": unknown
command terminated with exit code 126

这到底是什么?我知道在制作中我希望我的容器镜像很小(考虑镜像推送性能和安全性),但这些信息有点多。

我最喜欢的解决这个问题的工具之一是Kubebox。Kubebox可让您轻松查看所有pod,只需按“r”即可将远程shell添加到其中一个。
无论如何,大镜像在本地集群上应该不是问题,对吗?

推/拉镜像
在你的笔记本电脑上推镜像应该超级快,因为没有必要去网络。不幸的是,无数本地Kubernetes设置再一次暴露了丑陋。
让我们来谈谈快乐的道路:Minikube和Docker for Mac。这两个设置都运行一个Docker守护程序,您可以从本地笔记本电脑和Kubernetes集群内部进行通信。这意味着你需要做的就是将镜像放入Kubernetes中来构建它; 您的pod可以直接从本地注册表“拉”它,而不需要处理通过网络移动数据。
MicroK8s默认情况下不附带群集内注册表,但可以使用标志轻松启用。
相比之下,KIND是另一头野兽。它有一个特殊的命令,用于将镜像加载到集群中kind load。不幸的是,这是无法忍受的缓慢。

$ time kind load docker-image golang:1.12

real    0m39.225s
user    0m0.438s
sys    0m2.159s

这是因为KIND会复制镜像的每一层,并且只进行非常原始的内容协商。这意味着如果您只更改1.5 GB镜像的最后15 KB图层中的一个文件,KIND可以复制整个1.5 GB镜像。
幸运的是,那些致力于KIND项目的人们最近对镜像加载做了很多改进。我们还发布了在KIND中运行注册表的概念证明,这有助于进一步提高速度。
如果我要使用本地开发环境,我倾向于使用Docker for Mac或MicroK8s,尽管如前所述,这些天我更喜欢在真正的云Kubernetes集群中进行开发。这个领域也出现了很好的工具。Garden在远程注册表中缓存镜像层,减少每个开发人员需要重建的内容。使用live_update可以帮助我完全不需要推送和拉取镜像,这就是我用来解决这个问题的方法。

安装/文件同步
即使您在推送镜像时可以避免上网,只需构建镜像也会很长时间。特别是如果您不使用多阶段构建,特别是如果您使用具有额外依赖性的特殊开发镜像。与热重新加载本地JavaScript设置相比,即使是最快的镜像构建也可能太慢。
我想要做的只是将文件同步到我的pod。手工完成这个过程相对简单,但很乏味:

kubectl cp <file-spec-src> <file-spec-dest>

此外,如果您的容器因任何原因重新启动,例如,如果您的进程崩溃或pod被驱逐,您将丢失所有更改。
有像ksyncskaffold和Tilt这样的工具可以帮助解决这个问题,尽管他们需要投入一些资金来设置。

日志/观测/活动
在开发中,我想tail相关的日志,这样我就可以看到我在做什么。Kubernetes并不那么容易。每个Kubernetes pod都有自己的日志,我必须单独查询,每个日志都有很多容器。真地,很容易看到只有一个pod(kubectl logs podname)的日志。但是,要查看聚合视图,您需要了解很多关于pod的组织方式,比如哪些标签适用于应用程序的哪些部分,以便您可以运行命令kubectl logs -l app=myapp。
然后是Kubernetes事件,您可以通过完全独立的命令观察。这很糟糕,因为它在事件日志中我会找到重要的开发信息,比如我的pod无法安排或者我推出的新镜像无法执行。
我可以使用一组很好的可观察性工具来帮助生成这些工具,但我不想在本地运行它们。有时我买不起资源 - 我的笔记本电脑相当受限制。虽然这些工具在各自的利基中都非常出色,但我宁愿使用一种工具来轻松完成常见任务。换句话说,我应该始终能够在一个窗口中开始调试。有些问题可能是如此独特或特殊,以至于我最终会使用其他工具来解决这些问题,但我不能通过十二个窗口来检查一个问题。
我在另一篇博客文章中探讨了这个问题,我认为Tilt解决了这个问题,特别是现在它包括Kubernetes事件和pod日志。前面提到的Kubebox花园是另外两个很棒的选择。

结论
虽然在Kubernetes上的开发仍然很糟糕,但在过去的一年里我们已经走了很长的路。其最大漏洞是网络。如果我们想让开发人员能够创建端到端的完整堆栈微服务架构,我们需要提供一些方法来解决网络问题。在此之前,最后一次推向生产将始终揭示隐藏的网络问题。