大约在 2012-2013 年间,我开始在系统管理员社区中听到大量关于一种名为“Borg”的技术的讨论。它似乎是谷歌内部的一种 Linux 容器系统,用于运行他们所有的服务。相关术语让人有些困惑,比如集群中的“Borglet”和“细胞”,但基本概念逐渐浮出水面。其中包含“服务”和“任务”的概念,应用程序可通过服务响应用户请求,再借助任务完成运行时间更长的批处理任务。
2014年6月7日,我们迎来了Kubernetes的首次提交。这个源自希腊语的“舵手”一词,在头三年里几乎没人能正确发音。(是koo-ber-NET-ees?还是koo-ber-NEET-ees?干脆放弃,和我们一样叫它k8s吧。)
微软、红帽、IBM、Docker等公司很快加入了Kubernetes社区,这使得Kubernetes从一个有趣的谷歌项目转变为“也许这是一个真正的产品?”2015年7月21日,我们迎来了v1.0版本的发布,同时成立了CNCF。
在最初的提交后的十年里,Kubernetes已成为我职业生活中不可或缺的一部分。我在家中、工作中、副项目中——任何有意义的地方都使用它。这是一个学习曲线陡峭的工具,但它也是一个巨大的生产力倍增器。我们不再在服务器级别“管理基础设施”;一切都是声明式的、可扩展的、可恢复的,(如果你幸运的话)还是自愈的。
但这段旅程并非一帆风顺。一些常见趋势浮现出来,其中错误或配置问题往往源于 Kubernetes 在某些方面不够明确。即使十年过去了,我们仍然看到生态系统内部大量变动,以及人们踩中已知地雷的情况。那么,基于我们目前的认知,我们还能做些什么来让这个伟大的工具更适用于更多人和更多问题?
Kubernetes做对了什么?
让我们从积极的一面开始。为什么我们现在还在讨论这个平台?
大规模容器化
容器作为软件开发工具具有完美逻辑。摒弃个人笔记本配置的混乱,采用一个标准、可抛弃的概念,贯穿整个技术栈。虽然像 Docker Compose 这样的工具允许部署容器,但它们操作笨拙,仍需要管理员手动处理大量步骤。我曾设置一个 Compose 堆栈,通过部署脚本将实例从负载均衡器中移除、拉取新容器、确保其启动后再重新添加到 LB,许多人也是如此操作。
K8s使这一概念得以扩展,意味着可以将笔记本电脑上的容器部署到成千上万台服务器上。这种灵活性使组织能够重新审视其整体设计策略,放弃单体架构,采用更灵活(也往往更复杂)的微服务设计。
低维护
如果将运维的历史视为一种“从宠物到牲畜的命名时间线”,我们最初处于我亲切称之为“辛普森时代”的阶段。服务器是团队搭建的裸金属设备,它们通常拥有团队内部流行的专属名称,且每个服务器都是独一无二的。服务器运行时间越长,积累的冗余代码越多,以至于重启它们都变得令人望而生畏,更不用说尝试重建它们了。我称之为“辛普森时代”,因为当时我参与的项目中,用《辛普森一家》角色命名服务器的情况出奇地普遍。没有任何东西能自动修复,一切都需要手动操作。
随后我们进入“01时代”。Puppet和Ansible等工具已普遍应用,服务器变得更易替换,堡垒主机和其他访问控制系统也成为常态。服务器不再直接面对互联网,而是位于负载均衡器之后,我们也放弃了“app01”或“vpn02”这类可爱的名称。组织设计时已考虑过部分服务器可能在某些时间点失效。然而故障仍无法自动修复,仍需有人通过SSH登录排查问题、在工具中编写修复方案并部署到整个机群。操作系统升级仍是一项复杂任务。
我们现在进入了“UUID时代”。服务器存在的目的就是运行容器,它们是完全可抛弃的概念。没有人关心特定版本的操作系统支持多久,你只需创建一个新的AMI并替换整个机器。K8s并不是唯一实现这一目标的技术,但它是加速这一进程的关键。如今,通过SSH密钥连接到底层服务器进行故障修复的堡垒服务器概念,更多被视为“紧急备用方案”。几乎所有解决方案都是“销毁该节点,让K8s按需重新组织资源,创建新节点”。
许多对我职业生涯至关重要的 Linux 技能,如今大多已成为可有可无的附加技能,而非必需技能。对此你可以感到高兴或沮丧,我本人也经常在两种情绪之间切换,但这就是事实。
任务执行
K8s 的任务系统并非完美无缺,但它比多年来在工作中常见的“雪花 cron01 服务器”要好得多。无论是通过 cron 计划还是消息队列执行任务,现在都可以可靠地将任务放入队列、执行任务、在任务失败时重启,然后继续处理其他事务。
这不仅解放了人类免于重复枯燥的任务,更是对资源的更高效利用。虽然每个队列项仍需启动一个 pod,但团队在“pod”概念内拥有极大的灵活性,可自由定义需要运行的内容及运行方式。这对于许多人(包括我自己在内)来说,确实是一项提升工作质量的改进,因为我们只需要能够轻松地将任务置于后台运行,而无需再过多关注它们。
服务发现与负载均衡
多年来,应用程序中硬编码的 IP 地址作为请求路由模板,一直是我头疼的问题。如果你足够幸运,这些依赖关系并非基于IP地址,而是基于DNS条目,这样你就可以在不协调部署数百万个应用程序的情况下更改DNS条目背后的内容。
K8s允许使用简单的DNS名称调用其他服务。它消除了整个类别的错误和麻烦,并简化了整个过程。借助服务 API,你可以获得一个稳定、长期有效的 IP 地址和主机名,只需将请求指向该地址即可,无需关心底层实现细节。甚至还有 ExternalName 这样的概念,允许你将外部服务视为集群内部的服务。
如果要设计 Kubernetes 2.0,我会加入什么?
放弃 YAML,采用 HCL
YAML 的吸引力在于它不是 JSON 或 XML,这就像说你的新车很棒,因为它既不是马也不是单轮车。它在 k8s 中的演示效果更好,放在仓库中看起来更美观,并且给人一种简单文件格式的错觉。但实际上。YAML对于我们试图在k8s中实现的目标来说过于复杂,且不够安全。缩进容易出错,文件扩展性不佳(你真的不希望有一个超长的YAML文件),调试也可能令人头疼。YAML规范中描述了如此多的微妙行为。
我至今仍记得第一次看到“挪威问题”时的不敢置信。对于那些幸运地未曾遭遇此问题的人来说,YAML中的“挪威问题”是指“NO”会被解释为false。想象一下向挪威同事解释他们的整个国家在配置文件中被评估为false。再加上因缺少引号导致的意外数字,问题清单可以无限延长。关于为何YAML如此疯狂,已有比我更擅长阐述的优质文章:
为什么选择HCL?
HCL已经是Terraform的格式,所以至少我们只需要讨厌一种配置语言,而不是两种。它具有强类型和显式类型。已经有了良好的验证机制。它专门设计用于完成我们要求YAML完成的任务,而且阅读起来并不困难。它内置了人们已经使用的函数,这将使我们能够从 YAML 工作流中移除一些第三方工具。
我敢打赌,今天有 30% 的 Kubernetes 集群已经通过 Terraform 使用 HCL 进行管理。我们不需要 Terraform 部分就能获得更优配置语言的大部分好处。
唯一的缺点是 HCL 比 YAML 稍显冗长,且其 Mozilla Public License 2.0 (MPL-2.0) 许可证在集成到 Apache 2.0 项目(如 Kubernetes)时需要进行仔细的法律审查。然而,考虑到它带来的生活质量提升,这些障碍是值得克服的。
为什么 HCL 更好
让我们来看一个简单的 YAML 文件。
# YAML doesn't enforce types
replicas: "3" # String instead of integer
resources:
limits:
memory: 512 # Missing unit suffix
requests:
cpu: 0.5m # Typo in CPU unit (should be 500m)
即使在最基本的示例中,也到处都是潜在的错误。HCL 和类型系统会捕获所有这些问题。
replicas = 3 # Explicitly an integer
resources {
limits {
memory = "512Mi" # String for memory values
}
requests {
cpu = 0.5 # Number for CPU values
}
}
假设你有一个类似这样的 YAML 文件,而你的 k8s 仓库中可能有 6000 个这样的文件。现在看看 HCL,无需外部工具。
# Need external tools or templating for dynamic values
apiVersion: v1
kind: ConfigMap
metadata:
name: app-config
data:
# Can't easily generate or transform values
DATABASE_URL: "postgres://user:password@db:5432/mydb"
API_KEY: "static-key-value"
TIMESTAMP: "2023-06-18T00:00:00Z" # Hard-coded timestamp
resource "kubernetes_config_map" "app_config" {
metadata {
name = "app-config"
}
data = {
DATABASE_URL = "postgres://${var.db_user}:${var.db_password}@${var.db_host}:${var.db_port}/${var.db_name}"
API_KEY = var.api_key != "" ? var.api_key : random_string.api_key.result
TIMESTAMP = timestamp()
}
}
resource "random_string" "api_key" {
length = 32
special = false
}
以下是采用此方案的所有优势。
- 类型安全:在部署前防止类型相关错误
- 变量与引用:减少重复并提升可维护性
- 函数与表达式:支持动态配置生成
- 条件逻辑:支持环境特定配置
- 循环与迭代:简化重复配置
- 更好的注释:提升文档和可读性
- 错误处理:使错误更易于识别和修复
- 模块化:支持配置组件的复用
- 验证:防止无效配置
- 数据转换:支持复杂数据操作
允许 etcd 替换
我知道,我是第 10,000 个写下这句话的人。etcd 表现出色,但它作为唯一工具的情况有点离谱。对于较小的集群或较小的硬件配置,它在集群类型中占用大量资源,而这种集群类型永远不会达到节点数量的临界点,使其投入有所回报。目前k8s与etcd之间的关系也有些奇怪,k8s基本上是etcd唯一的客户了。
我建议将kine的工作正式化。为了项目的长期健康发展,能够支持更多后端接口是必要的。添加这一抽象层意味着未来更换新后端将更加容易,同时也能根据硬件配置进行更精细的调优。
我推测最终实现的效果将类似于以下场景: . 基于Raft共识的分布式SQLite内存数据库,几乎无需升级工作,这将使集群管理员在K8s部署的持久层方面拥有更多灵活性。如果你在数据中心有传统的服务器架构且etcd资源使用不是问题,那很好!但这将使低端K8s部署体验更佳,并(希望)减少对etcd项目的依赖。
超越 Helm:原生包管理器
Helm 是临时解决方案演变为永久依赖的典型案例。我感谢 Helm 维护者们付出的辛勤努力,将最初的黑客马拉松项目发展成为在 k8s 集群中安装软件的事实标准。它在不深入集成 k8s 的情况下,已尽可能好地履行了这一角色。
尽管如此,Helm 的使用体验堪称噩梦。Go 模板难以调试,常包含复杂逻辑,导致令人困惑的错误场景。这些场景产生的错误信息往往毫无意义。Helm 并非优秀的包管理系统,因为它在包系统应具备的基本任务上存在缺陷,例如处理传递依赖和解决依赖冲突。
我的意思是什么?
告诉我这个条件逻辑试图做什么:
# Helm 中复杂条件逻辑的真实世界示例
{{- if or (and .Values.rbac.create .Values.serviceAccount.create) (and .Values.rbac.create (not .Values.serviceAccount.create) .Values.serviceAccount.name) }}
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: {{ template “myapp.fullname” . }}
labels:
{{- include “myapp.labels” . | nindent 4 }}
{{- end }}
或者如果我向我的图表提供多个值文件,哪个会生效:
helm install myapp ./mychart -f values-dev.yaml -f values-override.yaml --set service.type=NodePort
好,如果我想用 Helm 图表来管理我的应用程序及其所有依赖项,这很有意义。因为我的应用程序本身依赖于其他组件,所以我希望将它们全部打包在一起。因此,我在 Chart.yaml 中定义了子图表或伞形图表。
dependencies:
- name: nginx
version: “1.2.3”
repository: “”
- name: memcached
version: “1.2.3”
repository: “”
但假设我有多个应用程序,完全有可能出现两个服务都依赖于 nginx 或类似组件的情况,例如:
Helm 无法优雅地处理这种情况,因为模板名称是全局的,且模板按字母顺序加载。基本上你需要:
- 不要多次声明对同一图表的依赖(对于许多微服务来说很难做到)
- 如果确实有多次声明同一图表,必须使用完全相同的版本
问题列表还在继续。
- 跨命名空间安装很糟糕
- 图表验证过程很麻烦,而且没人使用它
让我们直接查看 artifacthub 的首页:
我将选择 elasticsearch,因为它似乎很重要。
官方 Elastic Helm 图表看起来 相当糟糕。当然,
ingress-nginx
是正确的,它是整个行业中绝对关键的依赖项。
不,也不对。而且,该图表的维护者是“Kubernetes”,但它仍然没有被标记为“经过验证的发布者”。天啊,还能更验证吗。
- 图表搜索中没有元数据。你只能通过名称和描述进行搜索,而不能通过功能、能力或其他元数据进行搜索。
– Helm 并不严格执行语义化版本控制
# 包含非语义化版本的 Chart.yaml
apiVersion: v2
name: myapp
version: “v1.2-alpha”
- 如果卸载并重新安装包含 CRD 的图表,可能会删除由这些 CRD 创建的资源。这个问题已经让我吃过多次亏,而且极其不安全。
我还可以再写 5000 字,但仍然无法列出所有问题。目前没有办法让 Helm 足够好,以承担“管理地球上所有关键基础设施的包管理器”这一任务。
Kubernetes 的包管理系统会是什么样子?
让我们将这个假设的包管理系统命名为 KubePkg,因为如果 Kubernetes 生态系统需要一件事,那就是另一个以 ‘K’ 开头的缩写名称。我们会尽量复制Linux生态系统中已有的工作,同时利用k8s的CRD功能。我的想法大致如下:
包就像Linux包一样是打包的:
有一个定义文件,涵盖了你在安装软件时实际遇到的各种真实场景。
apiVersion: kubepkg.io/v1
kind: Package
metadata:
name: postgresql
version: 14.5.2
spec:
maintainer:
name: "PostgreSQL Team"
email: "maintainers@postgresql.example.com"
description: "PostgreSQL database server"
website: "https://postgresql.org"
license: "PostgreSQL"
# Dependencies with semantic versioning
dependencies:
- name: storage-provisioner
versionConstraint: ">=1.0.0"
- name: metrics-collector
versionConstraint: "^2.0.0"
optional: true
# Security context and requirements
security:
requiredCapabilities: ["CHOWN", "SETGID", "SETUID"]
securityContextConstraints:
runAsUser: 999
fsGroup: 999
networkPolicies:
- ports:
- port: 5432
protocol: TCP
# Resources to be created (embedded or referenced)
resources:
- apiVersion: v1
kind: Service
metadata:
name: postgresql
spec:
ports:
- port: 5432
- apiVersion: apps/v1
kind: StatefulSet
metadata:
name: postgresql
spec:
# StatefulSet definition
# Configuration schema using JSON Schema
configurationSchema:
type: object
properties:
replicas:
type: integer
minimum: 1
default: 1
persistence:
type: object
properties:
size:
type: string
pattern: "^[0-9]+[GMK]i$"
default: "10Gi"
# Lifecycle hooks with proper sequencing
hooks:
preInstall:
- name: database-prerequisites
job:
spec:
template:
spec:
containers:
- name: init
image: postgres:14.5
postInstall:
- name: database-init
job:
spec:
# Job definition
preUpgrade:
- name: backup
job:
spec:
# Backup job definition
postUpgrade:
- name: verify
job:
spec:
# Verification job definition
preRemove:
- name: final-backup
job:
spec:
# Final backup job definition
# State management for stateful applications
stateManagement:
backupStrategy:
type: "snapshot" # or "dump"
schedule: "0 2 * * *" # Daily at 2 AM
retention:
count: 7
recoveryStrategy:
type: "pointInTime"
verificationJob:
spec:
# Job to verify recovery success
dataLocations:
- path: "/var/lib/postgresql/data"
volumeMount: "data"
upgradeStrategies:
- fromVersion: "*"
toVersion: "*"
strategy: "backup-restore"
- fromVersion: "14.*.*"
toVersion: "14.*.*"
strategy: "in-place"
存在一个真正的签名流程,这将要求你对流程有更多控制权。
apiVersion: kubepkg.io/v1
kind: Repository
metadata:
name: official-repo
spec:
url: "https://repo.kubepkg.io/official"
type: "OCI" # or "HTTP"
# Verification settings
verification:
publicKeys:
- name: "KubePkg Official"
keyData: |
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvF4+...
-----END PUBLIC KEY-----
trustPolicy:
type: "AllowList" # or "KeyRing"
allowedSigners:
- "KubePkg Official"
- "Trusted Partner"
verificationLevel: "Strict" # or "Warn", "None"
想象一下,如果能自动更新包而无需手动操作,那该多好。
apiVersion: kubepkg.io/v1
kind: Installation
metadata:
name: postgresql-main
namespace: database
spec:
packageRef:
name: postgresql
version: "14.5.2"
# Configuration values (validated against schema)
configuration:
replicas: 3
persistence:
size: "100Gi"
resources:
limits:
memory: "4Gi"
cpu: "2"
# Update policy
updatePolicy:
automatic: false
allowedVersions: "14.x.x"
schedule: "0 2 * * 0" # Weekly on Sunday at 2am
approvalRequired: true
# State management reference
stateRef:
name: postgresql-main-state
# Service account to use
serviceAccountName: postgresql-installer
k8s 需要一个满足以下要求的系统:
- 真正的 Kubernetes 原生:所有内容都是带有正确状态和事件的 Kubernetes 资源
- 一流的状态管理:内置对有状态应用程序的支持
- 增强的安全性:强大的签名、验证和安全扫描
- 声明式配置:无需模板,仅需基于模式的结构化配置
- 生命周期管理:全面的生命周期钩子和升级策略
- 依赖项解析:类似 Linux 的依赖项管理,支持语义版本控制
- 审计日志:完整记录更改历史,包括执行者、内容和时间,而 Helm 目前无法提供此功能。
- 策略执行:支持组织策略和合规性管理。
- 简化用户体验:提供类似 Linux 的包管理命令。令人惊讶的是,我们正试图与使用数十年的包管理系统采取不同方向。
IPv6 默认启用
试想一下,在全球范围内,为了解决以下三个问题中的任何一个,已经投入了多少时间和精力。
- 我需要让这个集群中的这个 Pod 与那个集群中的那个 Pod 进行通信。
- NAT 穿透过程中出现了问题,我需要解决它。
- 我的集群用完了 IP 地址,因为我没有考虑到会用掉多少。记住:一家公司从一个 /20 子网(4,096 个地址)开始,部署了 40 个节点,每个节点有 30 个 pod,突然发现他们快要达到 IP 限制了。这并不是很多节点!
我并非建议整个互联网立即切换到IPv6,目前K8s已支持纯IPv6模式或双栈方案。但我认为现在正是将默认设置切换为IPv6的时机。此举可一举消除大量问题。
- 集群内部更扁平、更简单的网络拓扑结构。
- 组织可以选择忽略多个集群之间的区别,如果他们希望获得公共IP地址。
- 更容易理解堆栈内部的流量流动。
- 内置 IPSec
这与在全球范围内推动 IPv6 采用无关,只是承认我们不再生活在一个必须接受 IPv4 奇怪限制的世界中,尤其是在可能需要在短时间内突然获取 10,000 个 IP 地址的情况下。
对于拥有公共IPv6地址的组织而言,其优势显而易见,但云服务提供商和用户从中获得的价值足以让企业高层也支持这一方案。AWS无需在VPC内拼凑更多私有IPv4地址空间。这无疑具有重要价值。
结论
对这些观点的常见反驳是:“Kubernetes是一个开放平台,因此社区可以构建这些解决方案。”虽然这没错,但这一论点忽略了一个关键点:默认设置是技术领域最强大的力量。核心项目定义的“理想路径”决定了90%的用户将如何与之交互。如果系统默认要求使用签名包,并提供强大且原生的管理方式,那么生态系统就会采用这种方式。
这是一份雄心勃勃的清单,我明白。但既然我们要梦想,就该梦想得更大胆。毕竟,我们是那个认为将一项技术命名为“Kubernetes”会流行起来的行业,而它确实流行起来了!
我们在移动开发和网页开发等其他领域也经常看到这种情况,平台会评估自身状况并做出激进的突破性进展。并非所有这些项目都是维护者或公司会接手的,但我认为这些都是值得有人重新审视并思考“在我们已成为全球数据中心运营中不可忽视的占比时,现在是否值得去做”的理念。
Kubernetes 的最大问题在于它并非“开箱即用”。能够在 Kubernetes 上部署服务且不会在生产环境中崩溃的工程师寥寥无几——更不用说在自己的虚拟机上自行运行并维护 Kubernetes 集群了。
为此,涌现出一波“无服务器”初创公司,因为自行运行任何服务已被视为(a)耗时耗力、(b)极易出错,以及(c)极有可能在生产环境中失败。
我认为Kubernetes 2.0应考虑构建一个工程师可轻松采用并自信自行运行的部署平台——同时仍保持其作为小型核心调度器的角色,并具备强大的基础功能。
我花了很多时间构建Rivet,以满足自己对一个可自行托管并轻松扩展的调度器与部署平台的需求:
我们目前定位为“开源无服务器平台”,但我常将问题视为“Kubernetes 2.0应呈现何种形态”。人们已开始采用它来突破传统Kubernetes擅长领域的边界。我们发现,它最大的优点是,你可以轻松地构建一个与 Kubernetes 控制器大致相当的控制器。这解锁了更复杂的工作负载协调(游戏服务器、每个租户的部署)、多租户(每个租户的后端 vibe 编码、大语言模型(LLM) 代码解释器)、每个租户的计量计费、更强大的操作员等功能。
我非常不喜欢这种观点,而且我经常看到这种情况。我年纪大了,也变得世故了,所以事情就是这样……
有人认为X技术过于笨重,只想在笔记本电脑上简单地运行东西,因为“我不需要所有这些冗余”。他们花时间和资源发明技术Y来满足自己的需求。技术Y变得流行,人们对其进行扩展以实现可扩展性,因为没有人会在生产环境中用笔记本电脑运行系统。另一个人出现并说:“该死,技术Y太臃肿了,我不用这些冗余功能……”
“时间之轮既无始也无终。但这是一个开始。”
我希望这里的情况不是这样。我真心认为Kubernetes在容器编排方面做得很好,但需要进行演进。
如果你能听我讲一下我的观点:
设计这类系统的人的任务是决定哪些是正确的原始组件,并围绕这些组件构建一个简单且灵活的平台。
最初的云原始组件是虚拟机(VMs)、块设备、负载均衡器(LB)和虚拟私有云(VPC)。
Kubernetes之所以流行,是因为它标准化了容器化应用程序所需的原始组件(如Pod、PVC、服务和RBAC)。
Rivet 采取了不同的方法,基于大多数组织当前部署应用程序的方式,投资于三种不同的基本组件:
– 无状态函数(类似于 Fluid Compute)
– 有状态工作者(类似于 Cloudflare Durable Objects)
– 容器(类似于 Fly.io)
我预计会有人对此提出异议,认为这些是现代应用程序的“新基本组件”,但我们的经验表明,这些组件正在解决当前实际应用程序的实际问题。
编辑:澄清“原始云基本组件”
事物也可能过于复杂。
仅仅因为某件事物复杂,并不意味着它必须如此复杂。
依我之见,这句话的后半部分是“对某些受众而言过于复杂”
我可以向你保证,试图用大量shell脚本、自动缩放组、CloudWatch指标和祈祷来复现Kubernetes,对我而言对那些了解Kubernetes的受众来说过于复杂
或者过于通用。很多复杂性来自于试图支持所有用例。对于每个新功能,都有一个明确的案例:“我们有X个满意的用户,以及Y个用户,如果我们添加Z,他们就会开始使用它。”但重复这个过程足够多次,整个系统就会变得如此复杂和抽象,以至于你失去了那些满意的用户。
我最喜欢的工具(包括部署工具)是那些有明确目标群体和愿景的工具,以及那些拒绝任何偏离目标太远的领导层。是的,它通常没有我想要的所有功能,但它也没有我不需要的众多功能
由于以促销和简历为导向的文化,工程师们不断创造复杂性。没有人会因为减少功能而获得晋升。
只需为当前情境编写所需的功能。
我们这种对通用平台的愚蠢需求,将终结该行业的进步。
只需根据当前情况编写所需内容。不要使用Kubernetes和Helm,而是使用专门为解决你当前问题而编写的小型工具;不是为可能不会出现的问题,也不是为他人问题。而是你当前面临的问题。
所需的代码量远比你想象的要少,而且在你重复操作几次后,其他解决方案都会显得像巨大的鲁布·戈德堡装置(因为它们本质上就是这样)。
自行编写并维护一个小工具的复杂度,仅为在Kubernetes中运行并维护那个庞然大物的百分之一。
我不是在说要重新编写单体应用。我指的是只编写你真正需要的那部分Kubernetes代码,然后部署到那里。
参见:JavaScript框架
Rivet可能是两全其美的选择,因为它不仅是一个旨在简化复杂任务的复杂项目,你还需要用TypeScript编写所有管理代码。
Kubernetes 解决的问题是“如何部署这个”……所以我查看了 Rivet(看起来确实很酷)的文档,可选方案包括:
* 单个容器
* Docker Compose
* 手动部署(使用 Docker run 命令)
但坦白说,这种方式在实际规模下部署“无服务器基础设施平台”真的可行吗?
我的直觉反应是……如何在Kubernetes上部署Rivet,无论是通过容器还是类似kube-virt的方案,来在多台物理/虚拟机上运行这个无服务器平台?Docker Compose 为何能成为比 Kubernetes 更可靠、更可扩展的替代方案?那么,你也可以提供云服务,但……这并非 Kubernetes 2.0。如果我要自行部署 Rivet,我会修改你的文档以便在 Kubernetes 上运行。
我们的自托管文档目前非常粗糙——我深知这与我的评论形成鲜明对比。我们计划在未来几周内完善这些文档。
如果你对细节感兴趣,我们投入了大量工作以确保系统尽可能简化:
我们拥有与Rivet核心平台集成的自有云VM级自动缩放器——中间不涉及Kubernetes或其他编排工具。你可以在这里查看核心实现:[https://github.com/rivet-gg/rivet/blob/335088d0e7b38be5d029d…] (https://github.com/rivet-gg/rivet/blob/335088d0e7b38be5d029d52556aa8ad8e101b344/packages/core/services/cluster/src/lib.rs)
例如,Rivet 提供了一个 API,可按需动态创建集群:[https://github.com/rivet-gg/rivet/blob/335088d0e7b38be5d029d…] (https://github.com/rivet-gg/rivet/blob/335088d0e7b38be5d029d52556aa8ad8e101b344/packages/core/services/cluster/src/workflows/datacenter/mod.rs#L13)
一旦您使用 API 密钥启动 Rivet 的“种子”过程,后续所有操作均自动完成。
因此,自托管部署通常采用以下其中一种方式:
– 将云 API 令牌插入 Rivet 以实现自动缩放(推荐)
– 固定数量的服务器(手动配置的业余部署、简单的 Terraform 部署或裸金属部署)
– 在 Kubernetes 中运行(通常因为依赖于现有服务)
根据我的经验,基础设施和运维中没有任何东西会“直接工作”。即使像Heroku这样的平台也会遇到扩展问题,以及你愿意为此支付多少费用。
如果人们的担忧是希望有一个易于采用和使用的部署平台,那么最好将Kubernetes视为构建人们想要的PaaS的基础。
尽管如此,Rivet看起来很有趣。我认出其中一些想法来自BEAM生态系统。对我来说,它的吸引力更多在于弹性和本地优先,而非大规模部署。
作为一名工程师,我正在开发一个标准的简单单体应用,我希望系统不能做一切事情。首先要能够以尽可能简单的方式托管几个服务。我希望这里的复杂度能达到 Heroku/Render 的水平。启动一个数据库、带有简单扩展规则的 Web 工作者、后台工作者等。一旦设计完善,再看看是否能添加其他功能来扩展能力。如果这样做会让系统变得高维护且难以理解,那就不要做。它将永远被视为托管简单应用的最佳方式。
“低维护”,嗯。
我猜这在某种程度上是正确的——因为我大量使用EKS,自己并不维护集群健康(除了我找到的所有创意方式来搞砸一个节点)。或许在另一种意义上:它会尽最大努力运行一些容器,无论我让它自杀多少次。
但是,Kubernetes 在现实中几乎就是纯粹的维护工作。别误会我的意思,能够通过提交一些 YAML 文件就将软件部署到生产环境中确实很棒。但这种便利的代价就是纯粹的维护工作。
搭建集群的工作流程、决定为了让 ArgoCD 运行而需要做出哪些鸡生蛋还是蛋生鸡的权衡、如果采用 hub-and-spoke 模型则需要注册其他集群……这些步骤就像马戏团中的一个单一表演环节。
然后还有安装所有选定的操作员。我的意思是,那页内容已经成了梗,但有多少人运行K8s集群时,至少有30个Pod在运行“辅助”工具?(“辅助”这个词用得对吗?这些是我们需要的工具,但不是我们的主要工作负载。)
另一个重复的马戏团是花数小时调整 values.yaml 的正确值。(或者更可能的是,花数小时模板化它,因为我们正在使用 ArgoCD 进行部署,对吧?)
> 作为一个插曲,我曾经花了大量时间试图(错误地)将 Secrets Manager 中的 Secret 中的布尔值传递到 k8s Secret(通过 External Secrets,另一个操作员!),再到 ArgoCD ApplicationSet 定义,最后到另一个 values.yaml 文件。
然后你必须将集群的更新操作化——以及你安装/精心配置的所有操作器。考虑到发布速度,这简直就是纯粹的维护工作,而且始终存在。
最后,如果你在进行自动缩放(我们的案例中是Karpenter),那么在不造成停机的情况下“频繁”替换节点,这在Kubernetes中运行有状态应用时,会以各种有趣的方式变得“有趣”(运行有状态应用在Kubernetes中确实很有趣!)
总之,这就是我的抱怨。低维护!
“低维护”是相对于其他方案而言的。根据我的经验,每次使用K8s时,我需要的维护工作量远低于不使用它时,就能获得相同的服务质量(从自动缩放、故障转移、部署、回滚、灾难恢复、DevOps,到轻松创建完全独立的集群)。你的情况可能不同。
这又是一个类似于许多反对Kubernetes的论点,本质上归结为“Kubernetes太复杂了!”
不,分布式系统的部署本身就是复杂的,无论你使用什么平台进行部署。Kubernetes之所以被认为“复杂”,是因为它能够以标准方式完成部署软件所需的所有操作。你可以通过不使用Kubernetes来简化流程,但这样你就必须手动实现Kubernetes提供的所有功能。如果你不需要其中大部分功能,那么你可能不需要Kubernetes。
我认为人们(正确地)指出Kubernetes复杂的原因是,大多数人实际上并不需要分布式系统。人们选择K8s是因为它很流行,但事实上,许多用户使用配置好的虚拟机(通过Chef等工具)以传统方式运行软件会更好。
完全正确,很多比较并不公平。如果你将Kubernetes与一个固定大小的资源池运行固定应用程序(每个应用程序都有固定资源)进行比较,那有什么意义?这并非当今大多数部署的方式。
有人可能会认为,今天需要K8s的部署过于复杂,我认为这里有一个更具说服力的论点,但我的前公司对架构非常保守(没有基于简历的开发),最终转向了K8s,而我目前公司的系统往往比任何人预期的都要简单得多,但在规模上,没有K8s等价物的协调工作将过于繁重。
在选择分布式系统平台时,K8s与自研编排工具的对比并非核心决策点。真正的抉择在于K8s与那些以解决问题为名索要费用的云服务商之间。
诚实地说,自行搭建控制平面并不比使用EKS或GKE难多少。祖辈所说的真正复杂性在于控制平面之外的所有调优和配置工作。例如,基于Kubernetes构建的基础设施和部署,以及围绕这些部署的所有相关配置。换句话说,无论你使用EKS还是自行搭建Kubernetes,你仍然需要解决节点自动缩放、负载均衡、指标/可观察性、DNS和网络、Ingress等一系列问题。
但你讨论的不是维护Kubernetes,而是维护CI/CD系统、密钥管理系统、数据库操作自动化等。
与编辑一些 YAML 文件不同,在“旧时代”,这些软件供应商会要求你维护 cron 任务、Ansible 剧本、systemd 单元、Bash 脚本……
我已经在 Hetzner 上运行 k3s 超过两年,实现 100% 的正常运行时间。
事实上,它的维护成本如此之低,以至于我弄丢了主节点的SSH密钥,不得不重新部署整个集群。整个过程大约花了90分钟,其中包括更新文档的时间。如果情况紧急,我最多可以在15分钟内完成。
每月20欧元,使用k3s搭建K8s集群,仅支持ARM架构,包含3个节点(1个主节点)、部分存储空间以及配备Cloudflare自动DNS的负载均衡器。
是的,只要你有了Helm图表和节点安装程序。
安装速度非常快。
我们不备份集群(除了数据库等),而是直接重新 provision 整个集群。
你们多久进行一次版本升级?节点或控制平面的操作系统补丁更新等?如果应用程序的可用性至关重要,事情会很快变得复杂。
那些抱怨运行 Kubernetes 维护痛苦的人都有实际客户,且不会将整个基础设施部署在每月 20 欧元的环境中。
此类轶事毫无帮助。
我正在 ~10^5 个主机上运行数千个服务,且需遵守各种合规性和合同要求来维护系统。维护痛苦对我们这类人而言是不可避免的现实议题。
你的评论在我们这个领域里就像纯粹的噪音。
听起来像是自找麻烦。别安装那么多垃圾。你添加的每一项都是技术债务,都有相应的成本,即使产品是免费的。
如果自动缩放节省的$$少于技术债务/维护负担,那就关掉它。
我同意你的观点。
但我认为很多人处于一种状态,他们需要以当前方式运行系统,因为“直接关闭”行不通。
比如在K8s上运行多年且与K8s特性紧密耦合的系统。人们不知道如何在没有K8s的情况下设置和运行系统。
相比之下,运行一套大致相当的服务时,维护成本低到可以“设置后忘记”。
你必须知道自己在做什么,不要陷入“安装酷炫小工具”的陷阱。
首先,K8S 并不强制要求使用 YAML。虽然它可能更符合惯例,但绝非强制要求。据我所知,
kubectl apply
从一开始就支持 JSON。端点本身支持 JSON 和 gRPC。你可以从任何你喜欢的语言中生成 JSON 或 YAML。例如,Jsonnet 就非常不错。其次,我很好奇为什么 Helm 图表中存在依赖关系,以及为什么倡导依赖关系顺序,仿佛我们仍然生活在一个依赖关系顺序和 Linux 或 Windows 上的服务启动阻塞的世界中。Kubernetes 的主要模式之一是循环:如果依赖项不可用,你的应用程序应该将其视为可恢复的错误并继续尝试,直到依赖项可用。或者,应用程序崩溃,此时 ReplicaSet 控制器会为你重启应用程序。
如果你没有依赖关系(此处可插入“想想看”的梗),并且单独安装每个图表,那么图表中就不会出现依赖冲突。Helm 确实允许你安装多个版本的图表,但如果你在同一个命名空间中这样做,那就自求多福吧。
如果一个应用程序真正依赖于另一个应用程序,一个选项是将依赖项包含在同一个 Helm 图表中!Helm 图表一直允许你拥有多个应用程序和服务资源。
对依赖项失败应可恢复的观点表示强烈支持。
我曾参与过一次由依赖项的失败关闭行为引发的停机事件,而该依赖项实际上并未被使用且正在被关闭。
服务器之间的依赖关系几乎总是软依赖。如果无法与下游依赖项通信,只需返回 500 状态码。让负载均衡器绕过不健康的服务器。
你说应该这样做。这在内部构建自己的软件堆栈时很棒,但有多少软件可以在 Kubernetes 上运行,而这些软件是在 Kubernetes 出现之前创建的。但有人发现它可以在Docker中运行,后来有人意识到让它在Kubernetes中运行并不难,因为它已经在Docker中运行了。
你可以创建一个有自己观点的平台,按照你认为最好的方式做事,但人们还是会按照自己的方式去做,结果可能不好。或者你可以添加功能,让它以多种方式工作,让人们选择如何使用它。
反驳的观点是,自掘坟墓和诱人的麻烦与弹性相悖。人们会错误地使用他们可能从未需要过的功能;而每个新功能都是引入 bug 和模糊行为的新机会。
> Kubernetes 的主要模式之一是循环。
确实,在使用Kubernetes的过程中,我认为Kubernetes的主要架构特征是“协调循环”。观察当前状态,与期望状态进行差异比较,应用差异。反复进行。不存在“失败”或“成功”状态,只有我们能够观察到的状态和我们希望观察到的状态。两者之间的任何差异都会通过迭代消除。
我认为,机械控制中占主导地位的“足够好的技术”——PID反馈循环——与Kubernetes的核心组件有着惊人的相似性。
PID反馈循环、OODA循环和黑板系统(AI设计模型)都是K8s所体现的有效比喻,前两者足够知名,以至于在K8s 1.0版本的演示和演讲中经常被提及。
我几年前开发过类似系统(你所说的“协调循环”)。确实存在失败状态(出于多种原因)。但作为“循环”的一部分,你可以添加逻辑来修复它,以使其达到预期状态。
我们集成了监控/日志分析,以将故障与“发生的事情”相关联
强烈反对用HCL替换YAML。开发者认为HCL非常令人困惑。它可能难以阅读。现在支持导入吗?错误可能难以调试。
为什么不使用Protobuf或其他接口定义语言?然后让用户使用他们熟悉的语言指定配置。
让我提出一个挑衅性的观点:
在人工智能时代,关于配置语言的争论已无意义。没有人会再手动编写部署配置了。人工智能可以生成底层K8s机制所需的任何奇怪语法,并且比人类更可靠。如果不是今天,那可能在三个月后。
如果你想为K8s 2.0畅想未来,让人工智能解析人类意图来生成部署和集群管理。暂且称之为“氛围配置”或类似名称。用自然语言描述你的需求。优秀的模型会考虑边界情况并提出问题以求澄清,随后生成配置供你审核。若你是追求极致的运维人员,也可直接自动应用。
坦白说,现代代码生成技术已大多朝此方向发展。你正通过与人工智能互动来实现脑海中构想的应用程序。你仍然需要引导它避免做出愚蠢的选择,但你不会手动编写每个函数。告诉人工智能“我需要4个具有反亲和性的Pod,滚动部署,连接到现有的Postgres Pod,并根据CPU使用情况进行自动缩放。仔细考虑我可能遗漏的任何边界情况。”然后继续你的生活。这就是我们正在走向的方向。
我已做好心理准备承受这条评论引发的批评,请畅所欲言。我真心希望听到正反两方面的论点。
同意HCL很糟糕。K8s YAML没问题。我尚未遇到无法通过其类型解决的用例。如果你做得太多,或许配置映射(ConfigMap)不是正确选择。
没有适当的类型支持(或强制执行)时,使用 YAML 更容易自掘坟墓。我见过 Kubernetes 更新失败,因为版本字段设置为 1.30,被解释为浮点数 1.3。当然,有人犯了错误,但配置语言本应阻止你犯这样的错误。
那用 JSON 呢?
是的,但这是应用程序模式的问题。如果版本是字符串,为什么接受浮点数?
你可以非常轻松地在客户端本身(例如 kubectl)之外构建并序列化/反序列化 HCL、JSON、YAML 或任何你能想到的格式。这实际上与 Kubernetes 本身毫无关系。
HCL序列化/反序列化工具并不多。尤其是如果你不使用Go语言的话。
也许你已经知道,Kubernetes接口定义本身就是protobufs(除了CRDs)
某种程度上是这样。手动编写的 Go 类型才是真实的来源,而 proto 定义是从那里生成的,仅用于为手动编写的 Go 类型生成 protobuf 序列化器。proto 定义更多地作为中间表示形式,而非“API 规范”。虽然有用,但生态系统仍以 Go 类型及其相关工具为核心。
既然我可以直接将生成的.proto文件导入软件,然后序列化任何内置类型并通过标准K8s API应用,为什么还需要apimachinery的所有冗余代码?现有的REST语义已足够,完整GRPC实现则过于复杂
我对HCL的主要不满在于它实现for循环的方式。
我认为这种语法绝对令人讨厌
这个问题在另一个线程中被提得很深,但这简直就是对用户不友好的设计。
变量 “my_list” { 默认值 = [‘a’, “b”] } 资源 whatever something { for_each = var.my_list } 给定的 “for_each” 参数值不合适: “for_each” 参数必须是映射或字符串集合,而您提供的值是元组类型。
我建议大家尽量避免在 Terraform 中编写循环。如果必须迭代,请确保使用键值对字典而非数组/列表等数据结构
> 开发人员认为 HCL 非常令人困惑。它可能难以阅读。现在支持导入吗?错误可能难以调试。
这听起来更像是“我讨厌学习新事物”,而不是关于 HCL 的问题,或者可能是同时学习 HCL 和复杂配置语言的问题,而不是配置的领域本身的问题。
问题在于你不希望开发人员学习HCL。就像你不希望你的SRE团队被迫学习Next和React一样。
理想的解决方案是提供一个易于使用的抽象层,无需学习全新概念(尤其是像HCL这样丑陋的概念)。学习HCL只是冰山一角,还需深入理解组件间的依赖关系以及从多个工作区读取的输出等。让开发人员跟上SRE团队管理的Terraform堆栈及其持续演进,纯属浪费时间。这部分开发时间应更好地用于创建新功能。
为什么?如果他们无法学习HCL,就无法成为成功的开发者。
如果你认为他们不应该学习基础设施,那么这个论点是站不住脚的,因为这同样适用于每个选择(知道如何缩进YAML并不意味着他们知道该写什么)。这种绝对立场也是错误的,但原因不同。
你没有理解我的观点。理想的解决方案应该是开发人员和基础设施团队都能轻松学习的东西,而无需在一方或另一方上大费周章。上面提到的protobuf就是一个更好的想法,我认为比HCL更好。
我理解但不同意你的观点。我认为有两件事被混为一谈:学习HCL本身的难度,以及几乎所有人学习HCL所针对的领域复杂性。我见过有人放弃Terraform,并长篇大论地抱怨HCL难以掌握,转而用自己偏好的“真实编程语言™”编写数千行代码,最终才意识到问题在于他们以为自己在学习一件事(基础设施即代码),却实际上同时在学习两件事(基础设施即代码和AWS/GCP等云平台),却没有花时间系统化地理解两者。
我对protobufs没有异议,但我认为一旦你超越了YAML的基本改进(真正的类型系统、没有魔法、良好的验证和不破坏数据的格式化器),这比管理领域复杂性更不重要。YAML对于除人类阅读的文本文档以外的任何用途都是糟糕的选择,因为它要求你了解其魔法如何运作,以避免正确输入产生意外输出(如挪威、字符串/浮点数混淆、字符串值中的标点符号等),而且每个工具都必须为模板化、流程控制等发明约定。我认为HCL在各方面都更优,但并不固执己见——我只是希望避免让人们浪费更多时间在那些他们意识到自己刚花了两小时追踪一个多余空格,或未对列表中必须引用的某个值进行引号处理以避免误解的场景上。
HCL 可以表示为 JSON,因此也可以表示为 YAML。为什么我们需要另一种配置语言,而我可以在任何严肃使用的层面上用一种合适的编程语言来处理它?
博客文章中的示例展示了完整的逻辑结构(如果这样,那么那样,否则这样),这……不,谢谢。
我认为无法将 JSON 或 YAML 文档导出为包含此类逻辑的 HCL,但同时我认为我们也不应这样做。我非常不希望配置文件产生副作用或根据环境不同而行为不一。“这个随机字符串是从哪里来的?”“它是配置文件动态生成的,因为这个环境变量没有设置”听起来像是噩梦般的调试场景。
YAML有太多缺点,我同意作者应该淘汰它,但HCL在这个用例中同样糟糕——它做的事情太多了。遗憾的是,我不确定是否存在另一种在这种使用场景下真正合理且不充满噩梦般冗余的配置语言。
> 强烈反对用 HCL 替换 YAML。
我倒是看到了一些价值。最近我一直在用Terraform代码搭建一个完整的平台,只需半天时间(包括AWS子账户、EKS集群、用于Karpenter的托管节点组、Karpenter部署、Ingress控制器、LGTM堆栈、公共/私有DNS区域、Cert-Manager以及更多内容),而且我所有操作都通过Terraform完成,包括Kubernetes资源。
我喜欢在HCL中创建Kubernetes资源(以及Helm部署)的原因是,它具有类型和模式,因此任何能够与LSP(语言服务器协议 ——我使用 GNU Emacs 搭配 terraform-ls)都能提供有意义的自动补全功能以及正确的语法检查(我无需实际应用代码就能发现错误,Emacs 通过语言服务器已能告知我所写内容存在问题)。
我真的不再需要在 IDE 和 Kubernetes API 参考文档之间切换,以确保每个字段填写正确。
我做类似的事情,只是使用Pulumi,因此我无需学习HCL,可以依赖TypeScript或Python等优秀的语言服务器。
但是……YAML和JSON文档也是这样吗?
困惑?我在基础设施方面工作时,以为自己在使用一种专为不会编程的初学者设计的简易配置语言,当我使用HCL/Terraform时。
我很难想象一个整天与JavaScript打交道的人会觉得HCL令人困惑。
需要明确的是,我指的是HCL的语法和数据类型,而非Terraform处理HCL的方式,后者确实可能令人困惑或沮丧。但Kubernetes不会有这些陷阱。
矛盾的是,这种简单性本身可能就是混淆的来源:贫血的“for循环”语法、为了绕过缺乏“if”语句而设计的疯狂条件表达式,再加上“count”功能,可能会产生一些奇怪的结果。这形成了一种独特的风格。
真的,这代表了什么结构?
outer { example { foo = “bar” } example { foo = “baz” } }
这让我想起了 TOML 的疯狂
[lol] [[whut]] foo = “bar” [[whut]] foo = “baz”
至少使用 TOML 时,我可以通过 $(python3.13 -c ‘import tomllib, sys; print(tomllib.loads(sys.stdin.read()))’) 来查看,但 HCL 就没这么方便了888/3/XorNot
哦,谢天谢地我不是唯一一个这么看的人。
人们抱怨 YAML,然后去使用 TOML。
我仍然认为 Kubernetes 极其复杂,尽管它做了这么多事情。它现在看起来不那么复杂,因为它无处不在,但它仍然复杂。
我希望 v2 能更注重最常见操作的用户体验,比如部署应用程序并将其公开,然后进行服务帐户或映像更改等操作,而无需进入 kubectl edit。
鉴于目前大语言模型(LLMs) 非常流行,这可能不会发生,但梦想一下也没什么坏处,对吗?
Kubernetes 本身包含许多抽象层。有 Pod,这是核心的新概念,非常棒。但现在又有部署、重复集和命名空间……这让我希望我们能直接使用 Docker Swarm。
即使 Terraform 似乎也只存在于单一层级,学习起来相对直观。
是的,我正在学习 K8s,所以我深知学习曲线有多陡峭。
核心概念并非 Pod。核心概念是协调循环:你有一个期望状态——资源应呈现的理想状态——以及一些控制器循环,这些循环会无限期地将期望状态与实际状态进行比较,并更新实际状态。
大部分复杂性源于海量的资源类型,包括所有自定义类型。但基本概念其实非常简单。
我发现 Terraform 更加令人困惑——有一个规范,有一个真实世界,然后是一个我无法理解的模糊实体,Terraform 将其存储在 S3 或文件系统中,然后……大概类似于一个一次性协调器,每次计划和应用时将所有内容连接起来?
有人说“这很复杂,但我认为我抓住了核心概念”,而另一个人回应“那根本不是核心概念”,这既好笑又令人悲伤。但讽刺的是,你刚才描述的Terraform工作原理完全相同——只是你通过CI/CD手动触发循环,而不是等待新配置加载。你提到的状态文件只是当前状态的缓存,TF会将旧状态与新状态进行同步。
我一直认为Terraform的执行过程类似于使用三向差异进行合并。
其中包括状态文件(基础提交,即Terraform上次成功执行时系统的状态)、当前系统(主分支,可能在你“分支”后已发生变化)以及Terraform文件(你的分支)。
运行Terraform时,它会将你的分支合并到主分支中。
现在我写下这些,才意识到我从未真正核实过这是否准确,但tf apply无论如何都会生效。
然后猫头鹰的其余部分正在处理合并冲突 😀
我不知道如何用一个可爱的Git比喻来解释“但首先,Git会删除你的生产数据库,然后重新创建它,因为某个属性发生了变化,这让提供商不高兴了”
> 一个一次性调解器,每次计划和应用时将所有内容连接在一起?
你跳过了 { while true; do tofu plan; tofu apply; echo “well shit”; patch; done; } 部分,因为提供商实际上什么都不做,说真的,他们不会告诉你计划是否能成功
对我来说,K8s的核心是节点上的Pod调度、网络入口(如NodePort服务)、Pod之间的网络通信(所有地址均可直接访问)以及Pod内共置的容器。
声明式协调非常不错,但并非不可替代(实际上也不是强制要求的,例如kubectl run xyz)
我们仍然缺少一些这些功能,但这是我们在Rivet上构建的最终目标:
这一切都始于我想要一个我可以自信地部署并忘记的调度器。
作为运维人员,在查看Rivet后,我开始像《办公室》里那样大喊“天啊,不要,求求你不要”
大多数人都在寻找带有HTTP(S)前端的容器管理运行时,能够自动处理Let's Encrypt的证书。
我不想使用函数/角色,也不需要这个庞大的套件:
FoundationDB:角色状态
CockroachDB:OLTP
ClickHouse:面向开发者的监控
Valkey:缓存
NATS:发布/订阅
Traefik:负载均衡器和隧道
这只是将Kubernetes云锁定与KEDA和其他一些更晦涩的操作员切换为Rivet云锁定。至少Kubernetes比这稍微更具可移植性。
哦对了,我不清楚ClickHouse在监控方面做了什么,但Prometheus/Grafana套件已经联系过,表示他们很乐意让你回归。
我承认我存在偏见,但你需要认真考虑是否能让你的受众达到成功,与(例如)https://kubernetes.io/docs/reference/generated/kubernetes-ap…
在设计空间中,它相对于谷歌内部集群管理经过多年发展、数万名工程师在严苛环境下打磨后的成熟方案,处于何种位置?
我逐渐意识到,这涉及“计算机程序类型之间的区别是人类构建的”这一问题。
我从人性角度认同你的观点。操作器和控制器让我联想到COM和CORBA。它们是高度抽象的概念,其内在灵活性允许设计中做出判断(也可能导致误判)。
对于简单实现,我希望使用k8s-lite,它更具意见性且灵活性较低。这样可以避免太多自掘坟墓的情况。然而,对于非常复杂的实现,我感到现有抽象层存在局限性。这就是为什么在细胞架构中,单个集群有时会被用作细胞边界的基础。
我时常思考,是否存在一个单一系统——无论是Kubernetes 2.0还是其他方案——能够涵盖问题空间的全部复杂性,同时又便于人类架构师和程序员进行操作。
> 我希望有一个更具意见性且更不灵活的 k8s-lite
你似乎想要类似于(仍与 k8s manifests 兼容)的东西。
或者甚至类似于
或者如果你仍然想要真正的认证 Kubernetes,但规模较小,那么有
啊,原来如此:https://github.com/skateco/skate#:~:text=leverages%20podman%…
我们已经开始开发一种类似于Kubernetes 2.0的系统——目前仍处于预Alpha阶段
我们计划改进的方面:
* 全球分布式* 轻量级,可以在笔记本电脑上作为单一二进制文件运行,同时仍能扩展到云端数千个节点。* Tailnet作为默认网络栈 * Bittorrent作为默认存储栈 * 从底层设计的多租户架构 * 实时迁移作为核心功能
这些需求大多源于构建现代机器学习产品,以及随之而来的GPU短缺问题。随着机器学习的普及,这可能很快成为常态。
哇……很酷的功能,实时迁移非常有趣。我们目前基于价格在跨云集群中进行自动缩放,但实际的实时迁移是完全不同的概念
这不是 Kubernetes,这是一个专为运行 GPU 设计的定制解决方案。
由于它仍然可以处理Kubernetes配置文件,因此对Kubernetes从业者具有吸引力。
由于Kubernetes配置文件是一种“语言”,因此可以有多种实现方式,并且必然会出现多种方言。
这是未来的一切,而Kubernetes在这方面做得非常糟糕。
你停止了输入;Kubernetes 在处理声明需要至少 1 个 GPU 资源但应限制在每个节点不超过 4 个 GPU 资源的工作负载调度方面表现不佳?[https://kubernetes.io/docs/tasks/manage-gpus/scheduling-gpus…] (https://kubernetes.io/docs/tasks/manage-gpus/scheduling-gpus/#:~:text=you%20can%20consume%20these%20gpus%20from%20your%20containers%20by%20requesting%20the%20custom%20gpu%20resource)
> * 全球分布式
非必要?
> * Tailnet 作为默认网络堆栈
如果我使用该功能,这可能是第一个要移除的组件。
假设底层主机仅有一个网络接口卡(NIC)的 Kubernetes 设计,已成为行业的一大弊端,使技术发展倒退约 20 年,并惩罚了所有未在云端运行的用户。幸好有多个 CNI 实现方案。
直到最近,随着 Multus () 的出现,该基础设施部分似乎才开始恢复一些合理性。
> * 从底层开始的多租户支持
这与 Kubernetes 有何不同?
> * Bittorrent 作为默认存储堆栈
这可能很有趣,除非你也指的是分发公共容器镜像。出站流量极其昂贵。
>> * 全球分布式 >非必要条件?
这是必需的,因为你无法在单一区域可靠地找到 GPU,而 Kubernetes 无法在多个区域运行。
>> * Tailnet 作为默认网络堆栈
> 这是我如果使用该方案时首先会考虑移除的部分。
这很合理,我们发现它非常有用,因为它可以轻松跨云扩展,甚至在本地桥接它们。这是我们能够实现这些特性的最简单解决方案,但我们绝不会对它产生依赖。
>> * 从底层开始的多租户
> 这与Kubernetes有什么不同?
Kubernetes 本质上不支持多租户,任何尝试在 Kubernetes 上构建多租户解决方案的人都遇到过这个问题。我在多家公司都做过,那是一团糟。
>> * Bittorrent 作为默认存储堆栈
> 可能很有趣,除非你也指的是分发公共容器镜像。出站流量极其昂贵。
是的,出站成本确实是个问题,但它很懒惰,所以你只有在需要时才需要付费。这似乎是跨云进行实时迁移时同步数据的最轻量级解决方案。例如,我需要将我的数据集和机器学习模型迁移到另一个云,或者只是在另一个云中复制它。
> Kubernetes 无法在多个区域运行
为什么?你当然可以在节点上使用注解并将其部署在不同区域。
除了用于硬件故障的绑定外,多个网卡的用例是什么?
每次我在服务器上使用多个具有不同 IP 的网卡时,我都后悔了。
我猜是管理访问,或者老派的 vLAN 实现方式。Kubernetes 提供了网络策略来解决集群中不受信任的工作负载访问其不应访问的 pod 和 pod 端口的问题 https://kubernetes.io/docs/concepts/services-networking/netw…
网络策略还具有深度防御特性,因为另一个 Pod 需要知道其兄弟 Pod 的名称或 IP 才能直接访问它。因此,正确的边界是不要在工作负载的服务中暴露管理工具,而是创建一个单独的服务,仅暴露这些管理端口
类似于:
interface Awesome { String getFavoriteColor(); } interface Management { void setFavoriteColor(String value); } class MyPod implements Awesome, Management {}
但仅向每个行为的消费者提供Awesome或Management中的一个。888/3/znpy
例如,专用于SAN流量的网络接口卡(NIC)。认真对待网络存储的人不会在同一NIC上同时处理存储网络I/O和流量服务。
> 非必要条件
> 我首先要移除的内容
这仅表明行业需求的多样性。一刀切的方案无法满足所有需求,因此多种实质上不同的解决方案应运而生。这正是好事。
> 一刀切的方案并不适用,因此出现了多种实质上不同的解决方案。
所以……就像Kubernetes今天所做的那样?
嘿,我觉得你没看懂这个目录 https://github.com/agentsea/nebulous/blob/v0.1.88/deploy/cha…
另外,天啊,千万不要这样做,千万不要这样做,天啊 [https://github.com/agentsea/nebulous/blob/v0.1.88/deploy/cha…] (https://github.com/agentsea/nebulous/blob/v0.1.88/deploy/charts/nebulous/templates/provider_aws.yaml#L12-L13)
为什么不呢?我们可以运行在Kube上,并在需要时扩展到多区域,或者我们可以运行在任何虚拟机上作为单一二进制文件,或者只是你的笔记本电脑。
如果你指的是Helm,是的,我讨厌它,但它是目前最常见的标准。另外,我不确定你所说的“秘密”是什么意思,那是很安全的。
安全指的是什么,朋友?这相当于一个等待发生的凭证泄露,更不用说现在还需要管理AWS中的IAM用户。这是2000年代与AWS进行身份验证的方式,让我想起那些仍然使用密码进行SSH的人。当然,它目前运行良好,直到某位员工离职并带走根密码。
对于2.0版本来说,这并不是一个非常雄心勃勃的愿望清单。我接触的每个人都抱怨k8s在生产环境中的复杂性,所以我认为关键问题是,是否能实现足够的向后兼容性,使2.0版本能够逐步采用并简化流程。向后兼容性几乎总是意味着复杂性增加,因为新系统既要处理新功能,又要兼容旧功能。
问题总是出在哪些复杂性可以被消除。我迄今为止看到的每个“k8s抽象层”要么只适用于非常小的子集(例如类似Heroku的封装),要么最终会发展出一个与k8s同样复杂的完整DSL(而现在你必须学习这个特定任务的DSL)
相关:Show HN:Canine——基于Kubernetes的Heroku替代方案 – 2025年6月(125条评论)
没错,这是此类项目悠久历史中的最新版本(其中一个项目我曾亲自参与)。其他类似项目包括kubero、dokku、porter、kr0等。2019年曾有一段时期,每家大型科技公司都试图推出自己的K8s DSL(我了解的包括Twitter、Airbnb、WeWork等)。
对我来说,唯一真正改变的是大语言模型(LLMs)——chatgpt 在理解和生成有效的 k8s 配置方面非常出色(比编码更准确)。它仍然很复杂,但感觉我现在有了第二个大脑来处理它。
或许这正是K8s 2.0的未来方向。与其大刀阔斧地改造核心架构,不如通过微调消除令人烦躁的限制,并将资源投入到前端部署强大的AI系统,从而减少人类的重复劳动。
未来某天,或许无需专门的运维团队。我认为参与这场讨论的许多人并未意识到这一趋势的走向。
我认为应添加“合理默认值”,即除非用户主动选择其他配置,否则系统应默认提供足够优秀的负载均衡器、网络、持久存储等组件。
我同意 YAML 并非理想选择,但 HCL 同样不佳。试过阅读 Terraform 配置文件吗?那同样糟糕。本质上,我们需要一种更好的方式来配置 Kubernetes 集群,而仅仅更换语言只能做到有限的改进。
IPv6,绝对支持。所有 Docker、容器和 Kubernetes 从一开始就应该仅使用 IPv6 内部网络。想要 IPv4?那应该由一个特殊的 ingress 控制器来处理。
合理的默认设置与“让你成为云服务提供商管理服务的客户”相冲突。
我越是研究k8s,就越发现它在存储、网络等方面是“不包含电池”,结果是这些电池会附带来自AWS、GCP等云服务提供商的账单。K8s 更像是一种鼓励依赖云服务提供商这些极具利润的填补空白服务的手段,而非单纯的开源项目。
但你完全可以在车库里的旧硬件上安装 Calico、Istio 和 Ceph,使用完全免费的开源软件,获得与所有超大规模云服务商几乎相同的体验。
基于本地部署的K8s项目,确实可以实现这一点。但要达到生产级别的稳定性,与车库级别的概念验证有天壤之别。
我认为楼主想表达的是:生产级别的困境有多少是Kubernetes本身的责任,而非从头搭建PaaS平台本身就难如登天。我认为K8s的可插拔设计也模糊了大多数人脑海中的界限。我记不清上一次控制平面出问题是什么时候了,而每个人及其亲戚都有关于安装在K8s上的组件控制器CLBO的故事。
CLBO?
崩溃循环后退
我发现阅读 Terraform/HCL 比 YAML 更容易,仅仅是因为它不需要我处理不可见的字符。
从前端世界转到Kubernetes后,我发现它异常直观。我过去习惯于编写接收数据并让UI做出响应的代码——现在我编写的是控制面板用于将资源与配置进行同步的代码。
他们描述的理想包管理系统听起来很像Carvel的kapp-controller()。Carvel生态系统包含其自有的YAML模板工具'ytt',但在我看来,它并不是最用户友好的,而且感觉有点过度设计。不过,它在使用CRDs实现Kubernetes原生包管理方面基本上做对了。
我认为YAML/HCL与包系统存在重叠。
我不会选择 HCL,而是更倾向于 JSONnet、Pkl、Dhall,甚至(仅供参考而非推荐)Nix——我们需要一种能够为 LSP 提供模式的语言,具备足够的表达力以避免使用 Helm 的模板化怪兽,并且理想情况下允许用户覆盖库/包作者未明确提供的钩子。
这样的东西已经存在了吗?可能还没有,但上述语言正在朝这个方向发展。
k8s 可以提供一个强类型的 DSL,比如 cdk8s+
在基础层可以是声明式的,但人们通常以操作的方式思考(部署这个、安装那个、升级这个、分配一些虚拟主机、过滤那个等)
即使对于声明式内容,构建器模式也效果良好,它可以非常方便、足够简洁、类型化,并且易于组合(通过普通语言而非模板进行组装)…
嗯。不管怎样。也许等到 k8s2 发布时,Go 至少会拥有正常的错误处理。
》放弃 YAML 转用 HCL
我维护 borgcfg 2015-2019
k8s 从 borg 汲取的最大教训是将 bcl(borgcfg 配置语言)替换为 yaml(由 Brian Grant 创建)
然后这篇文章建议反转
没错,没有经验的知识只是幻想
我认为K8s 2.0需要:1. 基于gRPC/Proto3的API,以便使用任何编程语言(而不仅仅是目前几乎仅限于Go语言)更轻松地控制K8s集群,这甚至可以使处理K8s控制器更加轻松和可管理,尽管坦率地说,这可能会在API服务器端处理CRD时实际上增加复杂性。2. 默认使用 PostgreSQL 或可插拔存储后端,而非 etcd。 3. 基于身份的、L7 感知型 ABAC 访问控制接口,可由 CNIs 等实现。 4. 默认应用用户名。 5. 更易于实现的可插拔 pod 级 CRI 系统,使微虚拟机和基于容器的运行时可根据工作负载类型轻松共存。
所有 API(包括 CRDs)均已具备描述清晰且可内省的 OpenAPI 模式,可用于生成客户端。我使用由 Kubernetes 组织维护的 TypeScript 客户端。我看不出来添加二进制序列化传输格式有什么优势。我认为 gRPC 在存在延迟、复用、流等方面的节省时有意义,但像 Kubernetes 这样的控制平面组件似乎不需要它。
我本人已经几年没有使用 CRD 了(大概是从 2021 年开始),但我仍然记得开发 CRD 是一件非常糟糕且棘手的事情,部分原因是 Golang 本身存在缺陷(例如没有像 Rust 这样的 traits、没有宏、没有枚举等)。使用Protobuf,你可以轻松地将定义编译为任何语言,并实现清晰的枚举、oneof等功能。你可以使用标准的Protobuf库来进行深拷贝、合并等操作,还可以在Protobuf定义中添加基本验证等功能。gRPC/Protobuf基本上允许你用任何语言轻松开发K8s控制器。
CRDs 与 Go 语言没有任何关联; <https://www.redhat.com/en/blog/writing-custom-controller-pyt…> 和 <[https://metacontroller.github.io/metacontroller/guide/create…] (https://metacontroller.github.io/metacontroller/guide/create.html)> 是两个具体的反例,其中后者是最极端的“微服务”实现。如果你想登上Hacker News的首页,几乎可以肯定能用Bash实现它们
我从未说过CRDs与Go语言绑定,我只是指出,过去使用gen-controller或其他当前流行的工具将CRDs编译为Go语言类型时,体验非常糟糕,这部分原因在于Go语言本身存在的缺陷。我的意思是,gRPC 可以标准化将 k8s 自身资源定义以及 CRDs 编译为 Golang 类型的过程,从而使使用任何语言开发 k8s 控制器变得简单得多。然而,这可能会使 API 服务器在理解和解码基于二进制的 protobuf 资源序列化表示时比当前基于文本的 JSON 表示更加复杂。
我认为基于 OpenAPI 规范的 HTTP API 是 Kubernetes 如此出色的一部分,也是其成功的原因之一。
> 拥有一个描述清晰且可内省的 OpenAPI 规范,你可以用它来生成客户端。
上次我在工作笔记本电脑上尝试在Swagger UI中加载OpenAPI规范时(大约3-4年前,当时我使用的是第八代酷睿i7处理器,配备16GB内存),浏览器卡死并导致标签页崩溃。
在什么环境下加载的?我直接将1.8MB的OpenAPI.json(版本1.31)导入Mockroon,它立即正常运行。
4,5 可能不需要 2.0——可以通过现有 API 通过 KEP 轻松添加(cri-o 已经根据注解实现用户配置)。
[0] –
除了 1 和 3 之外,如果负责的人有决心去做,其他内容今天就可以添加,这假设我是对的,这些点确实重要到需要标准化。然而,Kubernetes 中的大型企业级收入主要来自简化官方 k8s 接口,尤其是与访问控制相关的接口(例如 k8s 自身的 NetworkPolicy 与 Istio 的访问控制相关资源相比)。
我感觉自己已经生活在 Kubernetes 2.0 世界中,因为我使用 Terraform 管理集群及其应用程序。
– 我可以免费获得HCL、类型、资源依赖关系和数据结构操作
– 我使用单个
tf apply
命令来创建集群、其底层计算节点、相关的云资源(如S3桶)等,以及集群上运行的所有内容– 我们使用Terraform模块实现复用和去重,包括与非K8s基础设施的集成。例如,我们有一个模块可为K8s服务配置Cloudflare ZeroTrust隧道,只需5行代码即可为K8s中运行的任意服务获取受SSO保护的唯一公共HTTPS端点。该模块会创建运行cloudflared的Deployment,并通过Cloudflare API配置隧道。
– 许多基础设施提供商提供经过签名且文档完善的 Terraform 模块,而 Terraform 通过锁定文件对模块及提供商本身进行合理的依赖管理。
– 若有必要,我可通过 Helm Terraform 提供商轻松组合 Helm 图表。我经常看到 Helm 图表仅包含“创建命名空间、创建 foo-operator 部署、从图表值创建自定义资源”(如 Datadog)。对于这类场景,我选择直接通过 Terraform 安装操作员并管理 CRD,或通过一个简单的 Helm 传递图表,该图表仅回显从 Terraform 值中输入的 HCL/YAML 内容。
Terraform 的主要弱点在于协调应用过程本身,类似于 Kubernetes 中的 YAML 操作或其他方式。我们使用 Spacelift 解决此问题。
从某种意义上说,在Kubernetes本身和Terraform状态中重复存储状态是多余的。这在通过突变webhook或其他方式修改资源时可能导致问题。此时需要将属性标记为“计算字段”等。因此我不太喜欢通过TF管理应用程序。管理集群可能还行。
与之相关,MetalLB开发者在2020年对该主题的看法:
关于《从头开始构建更好的Kubernetes》的152条评论:
在我们进行推测时:
我不同意 YAML 如此糟糕的观点。我也不特别喜欢 HCL。但我使用的工具并不在意——只要我还能用 JSON 指定内容,就能生成(而非模板化)所需的结构。生成 HCL 则会更困难。
我对 Helm 并不感冒,但它已是事实上的包管理器。我不喜欢 Helm 的主要原因与其模板系统有关。与使用完整的语言平台生成可转换为 JSON 的数据结构相比,模板化的 YAML 非常局限。你可以用这种方式做一些有趣的事情。(cdk8s 就是这样,但它并不是生成器能做的事情的好例子。)
另一方面,如果 HCL 允许我们使用模块、作用域和组合,那么也许它并不那么糟糕。
我完全支持 HCL 的请求。说实话,我对 GitHub 仍然感到愤怒,因为他们最初在 GitHub Actions 中使用 HCL,然后在稳定版本中放弃它转而使用 YAML。
我讨厌 HCL,它的模块系统简直糟糕透顶。它完全不具备组合性,你不得不做各种花哨的操作来确保所有内容在计划阶段就被定义(比如用列表代替字典),以及其他反模式。
我使用Terranix来生成config.tf.json,这意味着我拥有NixOS模块系统,它足够可组合,可以随时构建一个Linux发行版,从而构建一个出色的Terraform“状态”/项目/等等。
能够运行一些Python代码来获取一些数据,将其导出为JSON,使用Terranix读取它,生成config.tf.json,然后应用它,真是太棒了 🙂
Terraform 中列表与字典的问题是什么?我经常使用字典(在 Terraform 中称为映射),而 Terraform 的某些功能(如 for_each)期望接收字典,若传入列表则会抛出错误。
内部许多模块会将字典转换为相同长度的列表,因为字典的键在计划阶段可能未知或其他原因。Terraform AWS VPC 模块在内部对许多操作都进行了此类转换。
我无法确切说明,但模块总是会出现暴露不足或暴露过多的情况。如果我使用 Terranix 编写模块,我可以轻松地通过 “resource.type.name.parameter = lib.mkForce ‘overridenValue’;” 替换从导入模块中获取的任何资源的任何值,而无需在模块的 “API” 中暴露该参数。
值得一提的是,它会生成 Terraform 配置文件(config.tf.json),因此强大的状态引擎和提供程序中绑定的所有 API 领域知识都能正常工作,我无需使用像 Pulumi 这样复杂的工具。
您甚至可以将Terranix与普通HCL混合使用,因为config.tf.json与HCL在同一项目中是有效的。一个很好的入门方式是生成您的提供程序配置和其他您会使用Terragrunt/friends的地方。然后您可以开始以自己的节奏创建生成资源的选项。
遗憾的是,Terraform LSP 目前还无法读取 config.tf.json,因此你会收到关于未声明局部变量等警告,但对我来说这值得一试。我通常在编写 tf/tfnix 时会打开提供商文档,而 Nix 和 HCL 语言本身足够简单,无需完整 LSP 也能轻松编写。
它比我表达得更好,但通过使用 Nix,你可以获得对世界上最大的包库的程序化访问权限,可以随心所欲地使用(编写脚本从奇怪的地方获取值,运行带有 null_resource 或其替代品的不纯脚本),以及一种表达力强的函数式编程语言,你可以进行递归等操作,你可以使用派生来运行任何语言来使用任何工具转换字符串。
这就像 Terraform 的“解锁版” 🙂 忘掉“动态”块、糟糕的模块 API 和 hack(同时仍可使用现有模块,如果你有此需求)。
内部……在什么地方?不是 HCL 本身,我猜?我也没看到太多暗示 HCL 有“计划时间”的内容。
我对 HCL 不太熟悉,所以很难在这里找到有说服力的内容,但这个帖子的大部分内容听起来像是“HCL 的一些功能是 YAML 没有的,但这些功能不够好,不足以让我只使用 HCL”,而……嗯,你通常也不能用 YAML 那样做,所以我不知道这有什么大不了的?
我一直在闲暇时探索配置语言,个人倾向于使用 JSON5,因为注释是绝对必要的……但支持程度远不及 YAML 那么好或自动化 :/ HCL 已经在我感兴趣的列表中有一段时间了,但我还没有深入研究到足以形成任何真实的看法。
我认为Pulumi处于类似的位置,你可以使用自己选择的编程语言,并利用现有的提供商生态系统。你可以利用编程语言的组合功能绕过计划系统,尽管他们的计划允许比Terraform更动态的内容。
Terranix 的设置听起来很不错!我本人对构建系统类的东西非常感兴趣,最近我也编写了一个计划/应用系统,用于管理 SQL 迁移。
我想学习 nix,但我认为它和 Rust 一样,对我来说范围太广、深度太深,如果没有导师/同事或工作项目这样的推动力,我无法在业余时间克服初期的障碍。
没错,原理类似,但Nix会将所有依赖项一并带入,而非通过特定语言的包管理器。
建议先使用devenv.sh之类的工具,以跨发行版兼容且大致兼容MacOS的方式将工具添加到$PATH环境变量中(这样可确保所有人使用相同版本的全部构建依赖)。
在它为你带来价值后再学习语言基础,然后了解衍生关系,最后学习模块系统——这是一个基于Nix实现的疯狂可组合多层递归魔法合并类型系统,不要害怕克隆nixpkgs并查看内部。
Nix 衍生本质上是强化版的 Dockerfile,但 Nix 语言会将 /nix/store 路径引入容器,为你设置环境变量并运行一些脚本,所有这些内容都会被哈希,因此任何输入变化都会触发自动级联重建,同时这也意味着你可以使用二进制缓存作为一种“备忘录”缓存机制,这很方便。
这是一个非常有用的工具,它对你的系统几乎没有侵入性(除了磁盘空间,如果你没有管理垃圾回收的话),而且你可以将其与其他工具结合使用。
这使得确保您的 DevOps 脚本能够精确运行所有 CLI 工具和构建系统的特定版本变得非常容易,即使最终结果并非通过 Nix 实现。
查看 “pgroll” 用于 Postgres 迁移 🙂
pgroll看起来不错,但我最终还是自己编写了工具,因为我需要进行一些独特的操作,比如在Materialize.com(自托管)中测试不同的分片和资源分配方案。我拥有480个源输入模式(如果您感兴趣,Postgres输入模式的描述在此,而Materialize的相关内容是全新的),并管理基于这些模式构建的多个视图和索引; 创建多个视图/索引的副本并分布在计算节点上,例如目前我正在测试每个 AWS 实例节点分配 20 个模式,与每个四分之一 AWS 节点分配 4 个模式的方案,M/N×Y 模式下 N 和 Y 的不同组合。借助计划/应用模型,我只需修改几行 TypeScript 代码,即可获得所有下游依赖项所需的最小更改以进行部署。
这听起来像是 Kustomize 的思维模型:对你可能无法控制的代码应用补丁,直到其行为符合你的预期,然后应用
如果 Kustomize 的文档和 IDE 支持更好,我将成为其最大的拥护者
你可以通过 Nix 导出运行 Kustomize,使用 Nix 作为输入,并通过 Terranix 和 kubectl 提供程序应用输出,这为你提供了一种非常可重复的方式来应用 Kubernetes 资源,同时利用 Terraform 的状态引擎。我喜欢 Terraform 如何管理 CRUD 生命周期,通过级联更改和替换来实现,这通常至少是相当优化的。
而且,由于它是 Terraform,你可以使用注册表中的任何提供程序来创建资源,以根据你的 Kubernetes 对象创建资源,它可以技术上替换像 external-dns 和类似的控制器,这些控制器在其他云中创建东西,但以一种更“静态配置”的方式。
编辑:这与 Gitlab Terraform 状态托管功能配合得很好。
> 允许 etcd 替换
从你的嘴到上帝的耳朵。正如他们正确指出的,这项工作已经完成,所以我真的不明白为什么会拖延。人们可以继续使用 etcd 作为他们的首选,但强制要求使用它就有点奇怪了。我已经能预见“但如果……”的质疑,但CNCF已有认证流程和专门用于测试Kubernetes本身的子项目,他们到底是否相信这些测试?
> Go模板难以调试,常包含复杂逻辑导致极具迷惑性的错误场景。这些场景产生的错误信息往往是乱码
他们还忽略了使用一种文本模板语言来处理一种空格敏感、结构化的文件格式是多么荒谬。但就像其他抱怨一样,我们已经有了替代方案,但网络效应非常真实且难以克服
这种“我们有更好的东西,但惯性是真实的”障碍适用于许多领域,只是 Helm 影响的受众范围更大
> 放弃 YAML,改用 HCL
坚决反对。DSL 的一个主要缺点在于它是语言层面的而非程序层面的。它依赖人类学习一种语言并弄清楚如何正确应用它。
我用 HCL 编写了大量 Terraform 代码。然而即使是我,也难以扭曲大脑去思考如何在 Terraform 的限制性逻辑和数据结构下实现我想要的功能。我几乎完全依赖保存的代码片段示例、Stackoverflow,以及现在的ChatGPT,只是为了弄清楚如何在多维数据结构中部署正确的资源并保持DRY配置。
YAML不是配置格式(它是数据编码格式),但它在不是DSL方面做得相当不错,这让事情变得容易得多。无需学习语言,只需填写带有属性的数据结构。任何人都可以轻松按照文档操作,无需学习语言,任何程序也能轻松生成或解析它。(不过,K8s 的特定配置模式确实糟糕透顶,但这与 YAML 无关)
> 我至今仍记得第一次看到“挪威问题”时的不敢置信
这并不是“挪威问题”。这是 PEBKAC 问题。所谓的“问题”实际上是用户没有阅读 YAML 规范,因此他们不知道自己在做什么,然后做了错误的事情,并责怪 YAML。这就像在夜间走进森林,绊倒在一棵树桩上,然后责怪树桩。阅读文档。YAML并不复杂,它是一个相当简单的数据格式。
> Helm就是一个典型的例子,一个临时解决方案演变成了永久依赖。
没有人会永远依赖Helm。很多大型公司根本不使用它。这就是你证明自己根本不懂自己在说什么的地方。(更不用说Helm相比直接使用YAML或HCL要好用得多)
关于验证发布流程的混淆,这是CNCF鼓励 artifact 作者及其项目设置的内容。以下是验证 artifact 的操作指南:
你几乎可以对任何与K8s相关的 artifact 进行同样的操作。我们始终鼓励项目完成该流程,但有时他们需要帮助来理解该流程的存在。
Artifacthub本身是CNCF的孵化项目,任何关于如何让这一过程对所有人更友好的想法都欢迎提出,感谢!
(免责声明:CNCF员工)
> 我们始终鼓励项目完成这一流程,但有时他们需要帮助来理解这一流程的存在。
包括 ingress-nginx?根据原帖,它尚未被标记为已验证。如果连官方组件都不在意,就很难推荐给第三方。
不如发布 2.0 版本,然后很长时间内不发布 2.1 版本。
我明白在早期阶段,如此快速的发布/生命周期结束(EOL)计划是有道理的。但现在,运行在如此底层的组件不应每三个月就进行非安全升级,并且每年至少进行一次破坏性API更改。
YAML和Helm是我在k8s中遇到的两大痛点,我希望看到它们被其他东西取代。用CUE替代YAML会非常不错。至于替换 Helm,我其实不太确定。或许在 YAML 被 CUE 取代后,可以基于 CUE 发展出更强大且易于理解的工具?
我原本以为这会像一个大型语言模型(LLM)分析你的代码——生成一个 Railway 文件。然后对于一些无法轻松推断的手动依赖项,使用 TF 等工具。
& 实现开箱即用的自动扩展等功能,流程更加简化,而非手动处理 YAML 或 HCL。
简而言之,想象一下如果 Kubernetes 是一个最多 5 行、类似 Docker Compose 的文件。
确保有一种合理的方式来安装它,并且这种方法在仅在单个节点或笔记本电脑上运行的单个虚拟机上尝试时也能正常工作。
我的日常工作要求我的团队这样做,但当试图将这种逻辑应用于容器和云原生控制平面时,细节中隐藏着更多问题。即使有 NLB 可用,也要使用 MetalLB 吗?即使有 EBS 可用,也要使用 Ceph 进行存储吗?绝对不要在某人的 8GB 笔记本电脑上使用 Ceph。我可以继续列出“是的,但”的项目,这些项目使得此类操作无法排查故障,因为没有一个消费者
因此,回到你的原点:rke2(Apache 2)是一个出色的、支持空气隔离、经情报界批准的发行版,与Rancher Desktop(同样是Apache 2)搭配使用效果极佳。困难的不是Kubernetes部分,而是乐高搭建中的“是的,但是”部分
– https://github.com/rancher/rke2/tree/v1.33.1%2Brke2r1#quick-…
–
我同意作者的观点,即 YAML 作为配置格式存在错误风险,但请为了你所珍视的任何神明或理想,不要将 HCL 作为 k8s 的首选配置语言。
虽然我承认HCL的类型安全性能优于YAML(这是一个较低的标准),但它仍然有很大的改进空间。既然你们已经考虑使用不同的配置语言,不如顺便考虑一下CUE[1]或Starlark[2]等语言,它们要么提供更好的类型安全性能,要么提供更丰富的组合方法。
1. https://cuelang.org/docs/introduction/#philosophy-and-princi…
2. https://github.com/bazelbuild/starlark?tab=readme-ov-file#de…
我反复看到“YAML 不是类型安全的”这一说法,但完全不清楚它从何而来,因为所有 Kubernetes API 都是 OpenAPI,因此是 JSON 模式,而 YAML 作为 JSON 的超集,必然是类型安全的
宇宙中所有支持 JSON 模式的工具都会立即识别出这个 PodSpec 是错误的:
kind: 123 metadata: [ {you: wish} ]
我认为很可能的情况是,人们——完全有理由!——对使用一种文本模板语言来尝试生成结构化文件感到愤怒。如果他们选择 jinja2,也会遇到同样的问题——它不认为任何文本输出是“无效的”,因此 jinja2 认为这是完全正常的
jinja2.Template(“kind: {{ youbet }}”).render(youbet=True)
我清楚 Helm 会对 YAML 进行基本校验,因此无法随意输出任意格式混乱的 YAML 文件,但它并未进一步提示“你的 JSON 模式有问题,朋友”888/0/nikisweeting
它应该原生支持运行 docker-compose.yml 配置文件,本质上将它们视为 Swarm 配置,并“自动”使用合理的默认值进行部署,包括存储和网络设置。目前,Compose 和完整的 Kubernetes 之间的差距太大。
所以,我听到的意思是,它应该与一家商业公司绑定,而这家商业公司现在需要向私募股权公司汇报,而不是由基金会运营的开源技术。
此外,这个帖子中有一半的内容都在抱怨 Helm,而 Docker Compose 对 Helm 没有任何解决方案。不存在 $(docker compose run oci://example.com/awesome –version 1.2.3 –set-string root-user=admin)
> 目前,Compose 与完整的 Kubernetes 之间的差距太大。
这是 Hashicorp,所以你必须小心,但 Nomad 填补了这个空白
我不明白为什么大家这么讨厌 etcd。在简单环境中,你可以运行单节点 etcd。你无法轻松替换它,因为 Kubernetes API 的大部分都是对 etcd API(如 watch)的薄层封装,这些 API 对编写控制器至关重要,且无法干净地映射到大多数其他数据库,更不用说 sqlite 或 DynamoDB 这样的无摩擦托管数据库了。
实际上,让 Kubernetes 难以自行部署的因素包括:a) CNI(网络插件),尤其是当你既想避免使用云提供商专属的 CNI,又想支持所有网络(及安全!)功能,同时保持高性能时;b) 集群 PKI 中的所有证书,这些证书适用于不同组件,而 Kubernetes 将其作为绝对必要条件,因为这关乎生产级别的安全性。
因此,如果你认为可以打造一个“更简单”的 Kubernetes,那意味着你正在回避所有已有的经验教训,以及我们为何走到今天这一步。CNI 绝非解决问题的幼稚方法。
抱怨 YAML 和 Helm 是愚蠢的。Kubernetes 并未强制要求使用这两者。API 服务器最终仍期望接收 JSON 格式。你可以使用任何你喜欢的工具。
> 我不明白为什么大家这么讨厌 etcd。
我敢打赌你之前只用过托管的 Kubernetes。一个兄弟评论提到他们需要自定义工具来管理 etcd,我的经历也类似。
如果你在运行单节点 etcd,这也解释了为什么你无法理解:你非常、非常、非常、非常幸运,从未遇到过该节点故障的情况,也从未需要解决仅剩两个 etcd 节点运行的实际问题
让我困扰的是:
– 在小型机器(1GB 内存)上运行需要太多内存。我希望从小规模开始,但不需要担心可扩展性。Docker Swarm 在这方面做得很好。
– 使用 KCL 语言或 CUE 语言来管理模板
嗯,我认为这是错误的。
Kubernetes最缺乏的是10年的简单性和稳定性记录。它要蓬勃发展最需要的是一个更好的声誉,即不会轻易让自己陷入困境。
说“看看你能用 Kubernetes 做什么,你只需要一支由 3 名工程师组成的全职团队,每年花费 100 万美元,就能实现价值 $40k 的 bin-packing”,这并不是一个有说服力的商业案例。
尽管存在大量混乱的插件和自定义配置,它们以组合爆炸的方式相互作用,带来复杂性、风险和开销的激增,但Kubernetes正逐渐成为通用语言。如果我试图终结Kubernetes,我会提议推出2.0版本。
Kubernetes是当你需要在核心平台上支持每个人的需求和愿望时所发生的事情。抽象层破裂,最终暴露了所有底层组件,因为有人需要功能X。Kubernetes的大部分复杂性对大多数用户来说都是YAGNI(你不需要它)。
Kubernetes 2.0 应该是一个无聊的 pod 调度器,周围有一些 RBAC。让人们在需要时替换抽象层,而不是让一切在核心平台中如此紧密地耦合。
> 让人们在需要时替换抽象层,而不是让一切在核心平台中如此紧密地耦合。
当然,但随后某个第三方产品(例如 X)会赶上, everyone 开始使用它。然后招聘广告会开始要求“X 的 10 年经验”。然后 X 会用自己的实现取代核心调度器(K8s)。然后我们会在 HN 上看到诸如“X 是一个极其复杂、臃肿的平台,本应只是一个无聊的调度器”的评论。
Kubernetes就是当你想要出售复杂性时,因为复杂性能赚钱,而且自然会让你陷入供应商锁定,即使表面上声称是供应商中立。不要打断客户在自掘坟墓的过程中。
瑞士军刀式马车鞭,人人有份!
其实不然。Kubernetes 相比之前的解决方案仍然简单得多,尤其是考虑到其功能的提升。
没错。从 Puppet + 自定义脚本环境和 Terraform + 自定义脚本迁移过来后,K8S 确实让人耳目一新。
我明白它并非适合所有人,我也不会推荐给所有人。但一旦你开始构建一个多样化的服务生态系统,K8S 就能以相对低廉的成本解决很多问题。
存储是个大问题,而且确实需要解决。我通常建议需要持久化存储的人不要使用 K8S。
> 存储是个大问题,而且确实需要解决。我通常建议需要持久化存储的人不要使用Kubernetes。
我开始怀疑这实际上是AWS的问题,而不是Kubernetes的问题。我提到这一点是因为CSI控制器似乎行为正常,但它们的性能取决于IaaS控制平面满足请求的能力。我私下怀疑EBS根本没有为这种热插拔环境设计
我提出这一观点是因为我从未在Azure或GCP上运行过集群,无法验证我的理论是否成立
我想反向实验可能是放弃AWS存储层,尝试使用Ceph或Longhorn,但在我工作过的公司中,没有一家愿意在这一领域开辟新路,因此他们只是积累了关于如何小心翼翼地处理PVC的机构性经验
说实话,这感觉就像Kubernetes只解决简单问题而忽视复杂部分。在观察新软件开发一段时间后,你会频繁注意到这种模式。
抱歉,但Kubernetes对AWS处理EBS的挂载与卸载行为有何影响?
还是说你的观点是Kubernetes应该成为独立的存储提供商,而EBS可以被淘汰?
我有点跑题了,但确实,Kubernetes不提供存储系统导致了大量烦人的第三方解决方案
> 没错。我曾从Puppet + 自定义脚本环境迁移到Terraform + 自定义脚本环境。K8S 是一股清新的空气。
在大型科技公司中,我既经历过前者也经历过后者,后来还自己编写控制器并处理底层网络和覆盖网络问题,我不确定是否同意。
到 2025 年,工程师需要处理持久化存储,需要存储,需要高性能网络,需要 HVM 隔离,还需要 GPU。当一种理念开始阻碍解决实际问题,而你的业务因此落后时,这种理念终将被抛弃。依我之见,它注定会像 OpenStack 一样,当有人构建出更简单、更干净的抽象层时,它就会被淘汰,届时许多人的自尊心也会随之受挫。
> 更简单、更干净的抽象层
我到目前为止的生活经验是,“更简单、更干净”通常是通过忽略实际处理现实世界中更困难的部分来实现的。
我曾在其他地方以Kubernetes对存储的支持不足为例,这是同样的情况,如果你忽略了问题空间中实际困难的10%,你看起来会非常聪明和优雅。
这是什么鬼。
问题是K8s既是编排系统又是服务提供商。
Grid/batch/tractor/cube在规模化运行时都简单得多。此外它们还能支持复杂依赖关系。(但映射存储更难)
但K8s在DNS和网络上搞鬼,禁用交换分区。
进行简单的部署相对简单。
但如果你想要任何类型的 CI/CD,你需要 Flux;任何类型的配置管理,你需要 Helm。
> 但如果你想要任何类型的 CI/CD,你需要 Flux;任何类型的配置管理,你需要 Helm。
两者都荒谬地错误。
K8s现在支持交换分区。我正在管理一个由每个节点配备12TB NVMe交换分区的节点集群。每个容器的交换分区限制为(内存限制 / 节点内存)×(总交换分区)。目前无法在Pod规范中指定交换分区需求,因此需要通过污点或其他关联方式手动管理。
交换空间能带来什么?说实话,我一直认为它有点过时。
你回复的评论提到了 12TB 的 NVMe,我可以向你保证,12TB 的 ECC 内存比 NVMe 昂贵得多。
Kubernetes不需要什么包管理器或图表。它只需要做好一件事:工作负载调度。
Kubernetes集群不应该因为添加了不同类型的插件而变得定制化且行为异常。这与您试图管理的 workload 的原则相悖。您应该能够轻松地对整个系统进行管理。
服务发现只是许多应该独立于其他层面的功能之一。
> 服务发现只是许多应该独立于其他层面的功能之一。
我完全同意。这就像Jenkins一样,是个好主意,但它不够便携。
> 这就像Jenkins
在遗憾地使用过K8s和Jenkins之后,我完全同意这一点,它们在某些核心设计上有着深厚的共通性。
与其使用 YAML、JSON 或 HCL,不如尝试 Starlark?它是一种精简版的 Python,已被 Bazel 在生产环境中采用,因此已具备 Go 语言的库支持。
正如兄弟评论所指出的,我认为这可以作为 Helm 的完美替代方案,但我绝不会直接将 Starlark 输入到 K8s API 中
kube-apiserver 使用 JSON REST API。你可以使用任何能序列化为 JSON 的格式。YAML 是最常见的,并且已经可以直接与 kubectl 配合使用。
我个人使用 TypeScript,因为它支持联合类型和结构化类型,并且原生支持 JSON,但实际上任何格式都可以工作。
有趣的是,在研究兄弟评论中对 OpenAPI 规范的抱怨时,我了解到它实际上支持多种内容类型:
application/json application/json;stream=watch application/vnd.kubernetes.protobuf application/vnd.kubernetes.protobuf;stream=watch application/yaml
我推测这些内容类型在实际解析前都会被强制转换为protobuf格式888/0/Dedime
作为最近被指派“添加服务网格”任务的人,我希望让服务网格变得多余。我不想安装服务网格。pod之间应自动实现mTLS或其他形式的加密。我不想在 pod 定义中注入像 linkerd 这样的破旧 sidecar,现在有人抱怨 cilium 的 god mode 太过宽松。请直接内置相关功能。
支持 pod 间 mTLS 的各种组件正逐步被纳入 Kubernetes 主项目。
请查看https://github.com/kubernetes/enhancements/tree/master/keps/…,该功能有望在Kubernetes 1.34中以alpha版本发布。它允许你运行一个控制器来签发证书,这些证书会自动分发到 pod 的文件系统中,并且证书的刷新也会自动处理。
结合 ClusterTrustBundles(KEP 3257),这些都是构建一个控制器所需的组件,该控制器可以将证书和信任锚点分发到集群中的每个 pod。
出于好奇,mTLS 和 pod 间加密技术针对的威胁模型是什么?您是否在集群中运行不受信任的工作负载,并担心它们会泄露您的……比如,集群内 Postgres 的 SQL 登录凭证?
作为一个有过你描述的经历的人,即不稳定的sidecar导致正常工作负载崩溃,我对服务网格持强烈反对态度。但是,证书过期和subjectAltName管理已经够难的了,你希望这发生在每个pod上?更不用说每个连接的TLS握手了?
说实话,应该让一些标准更易于使用和维护。
目前,在云提供商和玩具(k3s/minikube)之外运行K8S,除非你是经验丰富的基础设施工程师,否则就是一场灾难。
存储/状态管理绝非已解决的问题,调试 Longhorn/Ceph 部署中的性能问题简直是噩梦。
此外,我不认为我们应该移除 YAML,而是应该更好地将其用作中间语言表示(ILR),并生成我们需要的 YAML,而不是尝试进行一些奇怪的就地生成(如 Argo/Helm 模板化)。- Kubernetes为了与 manifests 保持最终一致性而牺牲了大量简洁性,而我们的应对方式是尽量减少使用 manifests,这感觉非常奇怪。
此外,k8s 网络设计似乎非常适合 IPv6,但不知为何似乎没人注意到这一点。
我喜欢 YAML,因为任何工具都可以用来读写它。使用 Python/JS/yq 在管道中动态生成和修补 YAML 非常方便。
我的主要痛点一直是 Helm 模板。它不了解 YAML 或 Kubernetes 模式,将管理空格和语法的责任推给了图表开发者。这简直是疯狂。
有一段时间我使用本地 Ansible 剧本进行模板化。效果很好:它可以将资源模板 YAML 加载到字典中,读取单独定义的资源配置,然后在这些模板中设置嵌套较深的键,并输出为有效的 YAML。无需 Helm
indent
命令。如果需要管理大量应用程序(例如中型企业或更大规模的组织),YAML 根本无法维护。升级过程将变得手动且痛苦。
秘诀是永远不要手动编辑 YAML。
这只是在“紧急情况下打破玻璃”的备选方案,而非主要机制。
使用编程语言、专用领域特定语言(DSL),甚至自定义的持续集成/持续部署(CI/CD)流程来生成 JSON 配置文件。花一点时间学习 JSONNET,你就能获得一个模板,即使从未使用过 JSONNET(甚至几乎从未接触过 Kubernetes 配置文件)的人,也能快速设置新应用程序或修改现有应用程序。
k3s 并非玩具。
* 使用 Flannel 双向 NAT 实现 SDN
* 默认使用本地存储提供商管理 PVC
* 要求整个集群由 k3s 管理,这意味着不支持 FreeBSD/macOS/Windows 节点
* 主 TLS/SSL 证书未轮换(且未提及)。
k3s 确实是一个玩具——但它是一个很棒的玩具,玩起来非常有趣。
这些都不是让它成为玩具的原因。事实上,当你想要在小型环境中运行 Kubernetes 时,它是一个有用的工具。
微虚拟机(MicroVM)
让我再补充一点:为控制器/操作员定义明确的执行顺序。不要让更改双向流动。提供更好的方式来构建不会与他人冲突的系统。让取代 Helm 的工具真正维护系统,而非只是简单地部署。
这对我来说是绝对不可行的。这就是整个协调循环的问题。你可以将内容推送到 API/etcd,最终当所有依赖项存在时,它就会准备就绪。现在,因为 CRD 还不存在而拒绝 manifests 是一个不同的讨论。我支持建立一个待部署 manifests 的缓存,但如果 CRD 未部署,则类似垃圾回收的工具应将其从缓存中移除。这在某种程度上是 fluxcd 和 argocd 已经实现的,但我希望它能原生支持。
systemd,但分布式。并且从头重新编写配置文件(理想情况下不使用 YAML)
我希望:
1. 避免使用 CNI 重新创建“粘稠的内部网络”反模式,而是为服务间调用提供强零信任认证。
2. 与公共网络集成。有了 IPv6,就没有必要使用覆盖网络。
3. 几个 K8s 集群之间的互操作性。我想在我的机器上运行一个本地 k3s 控制器来开发一个服务,但这个服务仍然需要调用一个生产端点来获取依赖服务。
据我所知,目前没有任何因素阻止你实现上述任何功能。包括颇具讽刺意味的 pod 间调用认证,因为这就是当前服务账户的工作原理。这甚至跨越了 Kubernetes API 边界,得益于 IRSA,而如果使用任何符合 OIDC 标准的提供商,只要该提供商信任 Kubernetes 中的 OIDC 发行者,也能实现。eks-anywhere 发行版甚至展示了如何从您的工作站通过将 JWKS 发布到 S3 或其他可公开解析的 HTTPS 端点来实现这一操作
我不知道有什么理由阻止您从工作站直接连接到任何 Pod,这必然包括 kube-apiserver 的 Pod,除非是您公司自身的网络政策
服务账户与我想要的非常接近,但还不够。它们在服务间调用时不够无缝。
> 我不认为有任何理由不能从工作站直接连接到任何 Pod,这必然包括 kube-apiserver 的 Pod,除非是您公司自身的网络政策限制
我认为无法在EKS中创建不包含私有网络的Pod?
除了兄弟评论中提到的这是EKS的特性外,我确信VPC-CNI会从子网定义中分配Pod IP地址,其中包括公共IP地址。我们利用这一点绕过了NAT网关的限制,因为所有Pod都能够访问互联网,而它们自身并不直接暴露在互联网中。据我所知,由于某些未知原因,无法在公共子网中运行Fargate工作负载,但这是我所了解的关于公共/私有网络划分的唯一强制要求。
此外,如果还不明显:VPC-CNI 并非唯一的 CNI,甚至不是最好的 CNI,因为可以连接到节点的 ENI 数量会根据其实例类型而有所不同,这在我看来简直是愚蠢至极。使用覆盖网络可以让所有能够容纳在节点上的 Pod 在那里运行
这是 EKS 的问题,不是 k8s 的问题。
K8s 允许你使用主机网络运行 Pod,甚至原始的 “kubenet” 网络实现也允许直接调用 Pod,只要你的网络没有比多次中风加上头部炮击坦克炮(即我经验中大多数企业网络)更糟糕
请让它看起来像旧版的 Heroku,这样我们这些普通用户也能用
我想补充我的观点:
1. Helm:正式采用,放弃文本模板化。Helm的工作流程尚可,但文本模板化既繁琐又易出错。我们应该做的是修补对象。我不知道具体如何实现,但应该设置字段,而不是确保我的值包含正确缩进的文本(多少个空格?8?12?16?)
2. 我们能尽快获得一个无根 Kubernetes 吗,作为一等公民?这将打开一个全新的可能性世界。我希望在家中拥有一台物理机器,仅分配一个无特权用户给它。它会有一些限制,但我可以接受。也许可以使用一些 setuid 二进制文件来处理一些有限的特权任务。
> 目前K8s基本上是ETCD的唯一客户。
这是真的吗?没有人真的在使用它吗?
我认为K8s需要为状态化系统(大规模部署,而非初创公司中的MySQL)提供明确的解决方案。我认为有一些方法可以实现?在我工作的公司,基本上所有东西都运行在 k8s 上,然后所有数据库都运行在他们自己那些奇怪的专用系统上,他们坚持认为这样做不可能且成本太高。我现在正处于最糟糕的境地,不得不支持这种情况。
关于 k8s 应该只负责调度 pod 的评论。Mesos 搭配 Aurora 或 Marathon 基本上就是这样。如果人们想要这样做,那些方案本可以做得更好。Mesos 的最大用户已经转向 k8s
几年前我不得不深入研究 etcd 的细节。我遇到的主要问题:
2. 当时etcd有8GB的硬性限制。不确定此限制是否仍存在。
3. 原生etcd对多数节点故障时的处理过于谨慎。我最终编写了一个包装程序,在大部分情况下自动从这种情况中恢复,实践中效果良好。
综上所述,我从未遇到过使用 etcd 的场景,让我不希望使用高可用性 SQL 数据库。事实上,k3s 在小型部署中使用 sqlite 就是正确的选择。
对于 (1),我确实希望生产环境的高可用性数据库在每次写入时都进行 fsync。
当然,可配置性是好的(例如,对于自动化的快速测试,你不需要它),但安全是一个好的默认设置,如果有人设置了一个Kubernetes集群,他们可以并且应该负担得起企业级SSD,其中小数据的fsync是快速和可靠的(例如,每秒1000次fsync)。
> 我肯定希望我的生产高可用性数据库在每次写入时都进行fsync。
我没有!我们的业务灾难恢复计划仅要求我们恢复到较旧版本并保持较短停机时间,因此在每个节点上每次写入都进行fsync会降低性能,而没有实际的业务目的或好处。据我所记得,我们修改了数据库以在ramdisk上运行并每隔几分钟进行快照,这运行得更好且对我们的生产恢复策略没有影响。
> 如果有人搭建 Kubernetes 集群,他们应该能够负担得起企业级 SSD,因为对小数据的 fsync 操作既快速又可靠。
当时我遇到的问题之一是,东南亚的公共云区域使用的 SSD 性能显著较差,无法跟上需求。这发生在三大云服务提供商之一。
每秒1000次fsync仅占实际生产负载的极小部分。一个每秒仅接受1000次写入的API非常缓慢!
此外,许多人会在通用硬件上运行K8s集群。我曾在地下室用一台旧游戏PC和廉价SSD运行过一段时间。这是k3s的绝佳用例。
1和2可以通过标志覆盖。3几乎是整个软件的核心目的
我所说的3是指,在存在明确正确的恢复方式的情况下,etcd并未自动恢复。我的封装程序会始终从这些情况中恢复。(这已经过去好几年了,具体细节现在有些模糊了。)
如果多数投票权确实不可用,那么系统就会不可用。这是设计使然。在这种情况下,没有好的方法可以恢复而不丢失状态,因此系统正确地什么都不做。当然,你可以通过外部干预强行让系统进入工作状态,但这取决于你。
如我所说,我对细节已记不清,这是很久以前做的小事。但我记得值班人员需要手动修复etcd的多数决,而修复手册中没有需要人工决策的步骤,所以我编写了这个封装程序来自动化恢复过程。它也不复杂,据我所记得,大概是一两页代码,大部分是日志记录。
那绝对不是事实。许多大型公司直接使用 etcd 满足各种需求。
更像是Wasm?
据我所知,目前可以实现这一点,因为wasmedge(Apache 2)暴露了一个CRI接口https://wasmedge.org/docs/develop/deploy/oci-runtime/crun#pr…(等)
关于 kustomize 和 kpt 呢?我正在使用它们(而不是 Helm),但:
* kpt 尚未达到 1.0 版本
* 无论是 kustomize 还是 kpt,都需要复杂的配置来程序化生成配置文件(即使是像 replicas = replicasx2 这样简单的事情)
有多少地方在不使用 OpenShift 包裹和管理复杂性的情况下运行 k8s?
OpenShift,如果 IBM 和 Red Hat 想要通过许可证和支持合同获利。还有其他供应商销售 k8s:例如 Rancher。SuSe 收购了 Rancher。
我从未使用过OpenShift,也不认识现实生活中使用它的人。以旧金山为例,我认识的大多数人都使用AWS或GCP。
OpenShift作为本地部署Kubernetes的交钥匙解决方案还算受欢迎,前提是你能接受Red Hat的定价。
你可以选择双管齐下,在 AWS 上运行 ROSA:Red Hat OpenShift on AWS
[删除]
需要的时候,施瓦茨在哪里?
当然是
Kubernetes 2.0:通过试图消除复杂性来追求更多复杂性。
Bluecobra 引用了《太空球》的台词。
一个词:更简单。
既然可以使用 wasmCloud 上的 Wasm 组件,为什么还要使用容器呢?:-)