
为什么永远不应该直接在 Kubernetes 中运行容器
以为 Kubernetes 只是用来运行容器的?再想想。如果我告诉你,直接在 Kubernetes 中运行容器是最糟糕的做法之一,你会怎么想?
等等,我们不是可以直接在 Kubernetes 中运行容器吗?
技术上来说,是的。你可以使用 kubectl run
命令直接运行容器,像这样:
kubectl run my-nginx --image=nginx --restart=Never
这会在 Kubernetes 集群中启动一个一次性容器——类似于运行 docker run nginx
。但问题是:
仅仅因为 Kubernetes 允许这样做,并不意味着你应该这样做。
让我们分析为什么这种做法不仅不推荐,而且在现实系统中可能是灾难性的——以及你通过避免使用 Pod、Deployment 和 ReplicaSet 等抽象而错过了哪些神奇的功能。
丑陋的真相:为什么直接在 Kubernetes 中运行容器是个坏主意
1. 你绕过了 Kubernetes 的核心抽象——Pod
Kubernetes 并不真正管理单个容器——它管理的是 Pod。
Pod 是 Kubernetes 中最小的可部署单元,可以包含一个或多个紧密耦合的容器。直接运行容器会创建一个 临时 Pod,但没有 Kubernetes 所需的清单或元数据来正确监控、修复或扩展它。
你跳过了:
健康检查 通过 sidecar 收集日志和指标 临时存储定义 资源分配和隔离设置
简而言之:你把 Kubernetes 当作一个愚蠢的 Docker 主机,这是极大的浪费。
2. 没有重启策略 = 没有容错能力
让我们回到那个 kubectl run
命令:
kubectl run my-nginx --image=nginx --restart=Never
--restart=Never
标志告诉 Kubernetes 在容器崩溃时不要重启它。在一个生产级的自愈系统中,你为什么会想要这样?
相比之下,使用:
kubectl run my-nginx --image=nginx --restart=Always
会在内部创建一个 Deployment,为你提供:
失败时自动重启 声明式状态管理 与 ReplicaSet 集成以实现扩展
3. 你错过了声明式管理
直接运行容器是 命令式 的——即发即忘。无法描述期望状态。
与 Deployment YAML 相比:
apiVersion:apps/v1
kind:Deployment
metadata:
name:my-nginx
spec:
replicas:3
selector:
matchLabels:
app:nginx
template:
metadata:
labels:
app:nginx
spec:
containers:
-name:nginx
image:nginx:1.21
resources:
limits:
memory:"128Mi"
cpu:"500m"
livenessProbe:
httpGet:
path:/
port:80
initialDelaySeconds:5
periodSeconds:10
这会给你:
滚动更新和回滚 受控升级 存活和就绪探针 CPU 和内存限制
所有这些在直接运行容器时都是不可能的。
4. 没有标签、选择器或服务
直接运行容器意味着你跳过了关键功能:
标签和选择器:无法与服务或监控工具关联。 **没有 Horizontal Pod Autoscaler (HPA)**:无法基于 CPU/内存或自定义指标自动扩展。 没有网络策略:无法强制执行细粒度的安全规则。
使用适当的 Deployment 或 StatefulSet,你可以在集群中获得 逻辑分组、版本控制 和 身份。
5. 没有卷挂载或存储类
使用临时容器直接运行?
你错过了:
PersistentVolumeClaims (PVCs) StorageClass 支持 访问模式如 ReadWriteOnce
或ReadOnlyMany
卷类型: emptyDir
、hostPath
、configMap
、secret
相比之下,Pod 定义允许你声明式地管理所有这些:
volumeMounts:
-mountPath:"/usr/share/nginx/html"
name:html
volumes:
-name:html
persistentVolumeClaim:
claimName:html-pvc
跳过 Pod 和控制器时错过的隐藏宝藏
Init 容器
在主容器启动之前运行设置逻辑——适用于数据库模式迁移、权限检查等。
initContainers:
-name:init-myservice
image:busybox
command:['sh','-c','until nslookup mydb; do echo waiting for mydb; sleep 2; done;']
零停机滚动更新
在 Deployment YAML 上使用 kubectl apply
?你可以无缝进行滚动更新。Kubernetes 会排空旧 Pod 并启动新 Pod,而不会造成中断。
Secrets 和 ConfigMaps 注入
你无法将 secrets 或配置安全地注入一次性容器。
使用 Pod,你可以:
envFrom:
-configMapRef:
name:app-config
-secretRef:
name:app-secrets
这可以保持敏感数据的安全并与代码分离。
直接运行容器的现实后果
没有审计跟踪——命令式命令不会保存在 Git 或 CI/CD 流水线中。 调试噩梦——没有元数据,你会失去可见性,日志在 Pod 死亡时丢失。 零弹性——如果你的节点死亡,你的应用也会永久死亡。 破坏 GitOps——因为没有可以版本化或回滚的内容。
正确的方式:使用控制器,而不是容器
Kubernetes 是为编排而构建的,而不是为了运行。这种编排依赖于以下控制器:
Deployments(用于无状态应用) StatefulSets(用于数据库、队列等) DaemonSets(用于后台作业或节点级代理) Jobs/CronJobs(用于批处理或计划任务)
每个控制器都提供了自愈、声明式状态和操作成熟度,这是直接运行容器永远无法提供的。
总结:跳过正确方式时你错过了什么

最后的思考
如果你仍然直接在 Kubernetes 中运行容器,你并没有真正使用 Kubernetes。
你只是把它当作一个花哨的 docker run
,这样做你错过了 90% 让 Kubernetes 强大的功能。当你不再把 Pod 和控制器视为可选时,你才能真正解锁编排的力量。
所以下次你准备使用 kubectl run
时,问问自己:
“我是在编排,还是在瞎搞?”
(版权归原作者所有,侵删)
免责声明:本文内容来源于网络,所载内容仅供参考。转载仅为学习和交流之目的,如无意中侵犯您的合法权益,请及时联系Docker中文社区!

温馨提示:文章内容系作者个人观点,不代表Docker 中文对观点赞同或支持。
版权声明:本文为转载文章,来源于 互联网 ,版权归原作者所有,欢迎分享本文,转载请保留出处!
发表评论