上个月接了一个内网交付,客户要求把研发团队的 PaaS 环境整体搬到隔离网络里,公网不碰,半天之内要能跑业务。以前遇到这种需求,我第一反应是 OpenStack,或者老老实实手动拉 K8s 集群。但这次我直接用 Sealos 做私有化部署,从执行安装命令到集群可以正常调度业务,只花了 15 分钟左右。这篇文章就把整个过程摊开讲:为什么选 Sealos、内网环境要提前准备什么、怎么在裸机上把 K8s 云平台拉起来、以及那些只有在内网环境才容易踩的坑。如果你也在评估内网私有化方案,或者被“离线安装 K8s”折磨过,这篇应该能给你一个可以抄作业的路径。
1. 为什么这次内网交付,我选了 Sealos 而不是 OpenStack
先说结论:不是 OpenStack 不好,而是这次需求根本不需要那么重。客户要的是一个能给团队提供容器服务、数据库、GPU 调度能力的云平台底座,不是一套完整 IaaS。OpenStack 那套网络、虚拟机、镜像体系在这种场景下太重了,维护成本也高。而 Sealos 给我的感觉更像一个“交钥匙”方案:它把 Kubernetes 集群的安装、组件适配、后期扩展都做成了可以复用和离线搬运的东西。
1.1 内网私有化的真实痛点:不是装不上,是收不了尾
很多人觉得内网部署 K8s 最难的是“没有公网镜像”,其实这只是第一层。真正麻烦的是后面这些连锁问题:节点间版本不一致、CNI 选型要重新评估、containerd 和 kubelet 的参数对不上、证书不信任内部镜像仓库、存储方案没想好导致业务跑起来后蛋疼。我见过不少团队在公网环境下照着教程半小时装好集群,一到内网就卡在某个镜像拉不下来,然后整个下午都在手工传包、改配置。
另一个痛点是“可复现性”。传统安装脚本是一连串步骤,每台机器执行一遍,中途出错的概率相当高。节点越多,越难保证每一步结果都一样。Sealos 用集群镜像的方式把最终状态固化下来,相当于把“怎么装出来”变成了“我要什么状态”,这个概念上的转变解决了内网交付里最头疼的标准化问题。
1.2 Sealos 的“集群镜像”思路,和传统安装脚本的差别
Sealos 的核心概念是 Cluster Image,也就是集群镜像。你可以把它类比成 Docker 镜像:Docker 镜像里面是一个应用的完整运行环境,Sealos 集群镜像里面则是一套 K8s 集群的组件和配置。包括 kubelet、containerd、etcd、CNI、Helm 等等,都被打成可以被sealos拉取和运行的对象。
传统安装方式里,你要自己处理顺序:先装容器运行时,再装 kubeadm,再初始化 etcd,再装 CNI,最后还要处理证书和 kubeconfig。Sealos 把这些步骤收敛成一条命令,sealos run指定集群镜像,它会在你指定的机器上自动分发、初始化和完成组件安装。对我这种要交付给客户、后续还要升级维护的人来说,这种设计最大的价值是:集群的预期状态是明确的,交付物是干净的,回滚和重建也相对容易。
1.3 它适合哪些场景,又不适合哪些场景
我的判断标准分两类。适合 Sealos 的场景包括:中小规模的私有化交付,比如几十台到几百台节点的企业内部平台;边缘机房和隔离网络,因为镜像可以提前准备、离线导入;企业内部研发测试环境,需要快速给多个团队提供云平台;还有深度学习和大模型私有化部署,需要快速把 GPU 调度能力建立起来。
不适合的场景也有,比如数千节点的大规模生产集群,或者已经有深度定制过的 K8s 体系,团队对底层安装细节有强掌控需求。这种场景下一味依赖封装工具反而会增加排障难度。另外,如果你现有的 K8s 平台已经稳定运行很长时间,也没有必要为了“换工具”而迁移。工具永远是服务交付目标的,不是用来集邮的。
2. 动手前先把账算清:节点规划、网络设计与离线物料
内网部署最忌讳拿到机器就开始敲命令。因为内网环境没有公网下载兜底,后面如果发现方案选错,纠错成本很高。我每次都会花小半天把节点、网络、离线物料认真盘一遍。
2.1 节点怎么划分:先想清楚要交付什么
部署前先把角色定清楚,避免后面资源打架。下面是我常用的最小划分方式:
| 节点角色 | 数量建议 | 配置建议 | 主要职责 |
|---|---|---|---|
| 控制面节点 | 1-3 台 | 4C8G 起步,SSD | etcd、API Server、调度器、控制器 |
| 计算节点 | 按业务评估 | 16C64G 起步,视业务而定 | 跑业务 Pod、数据库、推理服务 |
| GPU 计算节点 | 按模型需求 | 加装 NVIDIA GPU,显存要大 | 大模型推理、深度学习训练 |
| 存储节点 | 按容量评估 | 大容量 HDD/SSD | 为分布式存储提供底层盘 |
如果只有三台物理机,我建议单控制面加两个计算节点的组合,先跑起来,后续再扩展。如果目标是高可用生产环境,控制面至少三台,并且给每台 master 用独立的 SSD,因为 etcd 对磁盘延迟特别敏感。主节点上不要让业务 Pod 随便调度,毕竟控制面和数据面混跑,一旦资源争抢,整个集群稳定性都会受影响。
2.2 内网环境的基础设施准备:DNS、时间同步、端口放行
内网部署最关键的三件小事:
- 主机名要唯一,建议按统一规则命名,比如
region-dc-project-role-01,后面维护时看到主机名就大概知道位置和用途。 - 时间同步必须做,用 chrony 指向内网 NTP 服务器。证书校验强依赖节点间时间一致,时间偏差大时会出现莫名其妙的 x509 错误。
- SSH 免密登录要在所有节点间配好。后面 Sealos 分发组件会用到 SSH,配置好免密能省很多事。
端口方面,至少确认这些主要端口能互通:
| 用途 | 端口 |
|---|---|
| SSH | 22 |
| Kubernetes API | 6443 |
| etcd 客户端/集群 | 2379 / 2380 |
| kubelet 指标 | 10250 |
| NodePort 服务段 | 30000-32767 |
| CNI 网络(根据类型) | 8472 / 4789 等 |
内网通常没有严格防火墙,但如果你在带安全策略的网络里,这些端口要提前找网络管理员确认放行。
2.3 在有网机器上准备好离线物料
这一步是整个内网交付的“弹药库”。Sealos 的好处是物料可以提前准备好,我一般准备四类东西:sealos 二进制文件、基础集群镜像、常用组件镜像、以及可能需要用到的业务镜像。
在有外网的准备机上执行拉取和导出:
# 示例:拉取基础集群镜像 sealos pull labring/kubernetes:v1.27.0 sealos pull labring/calico:v3.25.0 sealos pull labring/helm:v3.12.0 # 导出为离线包 sealos save -o kubernetes.tar labring/kubernetes:v1.27.0 sealos save -o calico.tar labring/calico:v3.25.0 sealos save -o helm.tar labring/helm:v3.12.0然后把这些 tar 包拷贝到内网节点上,再用对应的 load 命令导入。不同版本的 sealos 子命令可能有差异,拿不准就敲sealos save --help或sealos load --help看一眼。原理其实不复杂:所有组件镜像都落到本地,后续安装就不再需要访问公网。
2.4 决定要默认部署哪些组件
不要一口气把网上看到的所有组件都塞进去。我的经验是分两阶段。第一阶段跑最小集:Kubernetes 核心、Calico 网络、Helm。第二阶段按需加:MetalLB、Ingress-nginx、OpenEBS 或 Longhorn、Metrics Server、Kubernetes Dashboard。为什么这样分?因为最小集越单纯,出问题越容易排查。如果一开始就装十几个组件,集群起不来的时候你根本分不清是 CNI 的问题还是存储的问题。
3. 实操记录:从裸机到可用 K8s 集群的一条龙命令
下面这段是我这次交付的真实执行路径。这里以当前稳定版为参考,具体镜像 tag 要看你用的时候官方仓库里有什么。
3.1 安装 sealos 二进制,并确认版本
在目标机器上把 sealos 放到/usr/local/bin,然后执行sealos version确认。如果是新版本,一般命令格式都是sealos run,但一些参数细节可能有变化,第一次使用建议先跑一下sealos run --help。
3.2 单命令拉起基础集群
如果是单机环境,命令最简单:
sealos run labring/kubernetes:v1.27.0 \ labring/calico:v3.25.0 \ labring/helm:v3.12.0多节点环境则指定 master 和 node:
sealos run labring/kubernetes:v1.27.0 \ labring/calico:v3.25.0 \ labring/helm:v3.12.0 \ --masters 192.168.10.10,192.168.10.11,192.168.10.12 \ --nodes 192.168.10.20,192.168.10.21 \ --passwd '你的SSH密码'如果已经配好免密,可以把--passwd参数去掉。Sealos 本质上会 SSH 到目标机器,把镜像和组件推上去,然后执行集群初始化。这一步执行完,K8s 集群的基础骨架就立起来了。
3.3 把集群配置导出,确认组件状态
集群起来后,在控制面节点上查看状态:
kubectl get nodes kubectl get pods -A kubectl get sc正常情况下节点状态是Ready,需要的 Pod 都是Running或Completed。如果你想在自用的管理机上操作集群,把控制面节点的/root/.kube/config拷贝到管理机,然后设置好KUBECONFIG环境变量就行。这一步写进文档里,方便团队成员连接。
3.4 安装内网镜像仓库和默认存储
集群跑通只是第一步。内网环境要长期用,镜像仓库和存储是刚需。镜像仓库我一般选 Harbor 或者轻量一点的 Docker Registry。如果 Sealos 官方镜像仓库里刚好有打包好的应用,可以直接用sealos run装;没有就 Helm 手动装。装完把私有仓库地址配到 containerd 的信任列表里,这个细节下一章单独讲。
存储方面,不建议裸奔 hostPath。我在内网小规模环境里推荐 OpenEBS 或者 Longhorn,一个轻量一个功能全。命令大致是:
# 示例:通过 helm 安装 openebs helm repo add openebs https://openebs.github.io/charts helm install openebs openebs/openebs --namespace openebs --create-namespace装完确认一下默认 StorageClass 有没有出现:
kubectl get sc只要有一个默认 StorageClass,后面 Redis、数据库、大模型推理服务才能放心申请持久化存储。
3.5 想上 Sealos Cloud 控制台怎么办
这里要说明白:上面搭建出来的 K8s 集群本身已经是一个云平台底座,能跑容器、数据库、GPU 任务。如果你还需要像公有云那样的 Web 控制台、应用商店、多人工作空间,那可以在集群上部署 Sealos Cloud,常见做法是找官方仓库里对应的 cluster image,然后sealos run labring/sealos-cloud:<版本>。因为版本迭代快,我不在这里写死 tag,用之前先到官方镜像仓库确认。这个控制台对内网团队使用很友好,尤其适合不想整天碰 kubectl 的同事。
4. 内网环境下最容易踩的坑:镜像、证书、存储和 LoadBalancer
这次部署踩得最多的坑,不是 Sealos 本身,而是内网环境特有的系统性问题。把这些坑提前避开,能省下一整天时间。
4.1 离线镜像的导入顺序和 Namespace 管理
离线环境里,镜像导入顺序很重要。原则是:先导入基础集群镜像,再导入组件镜像,最后导入业务镜像。因为 Sealos 安装时需要先完成集群初始化,才能给后续业务组件提供运行环境。如果顺序反了,业务镜像导入了也暂时用不上。
另一个容易被忽略的是镜像命名空间。“命名空间”在 K8s 里是资源隔离单位,但镜像仓库里也有“namespace”的概念,比如labring/kubernetes:v1.27.0中的labring就是仓库里的项目/命名空间。内网私有仓库上,我建议统一规划前缀,比如harbor.internal/base/...、harbor.internal/app/...,避免所有人把镜像随便推到同一个项目里,后面找都找不到。
维护一份镜像清单非常有必要。我已经吃过亏了,离线环境里没有公网可以临时搜索,所有镜像都要靠清单找。用脚本把镜像列表导出、备份,甚至纳入版本管理,都很值得。
4.2 自建 CA 证书在 containerd/kubelet 里的信任问题
内网镜像仓库如果用的是自签名证书或者私有 CA,节点上的 containerd 默认不信任。你会在创建 Pod 时看到一堆x509: certificate signed by unknown authority错误。
解决办法有两类。一类是把私有 CA 加入到系统的信任链,同时让 containerd 重新加载配置并重启。另一类是给 containerd 单独配置仓库的 certs,常见路径是/etc/containerd/certs.d/<仓库域名>/hosts.toml,在里面指定 CA 证书路径。不管哪种方式,配完一定要在节点上验证:
crictl pull <你的私有仓库地址>/some-image:tag能拉下来才算真的通。这个验证动作别省,否则后面部署应用时才开始报错,排查成本高很多。
4.3 没有公有云盘,存储方案别将就
公网上你敢用云厂商提供的块存储和对象存储,内网就没人替你兜底了。纯靠节点本地磁盘时,存储方案直接决定业务稳定性和维护难度。我的选择逻辑是:
| 方案 | 类型 | 适合场景 | 注意事项 |
|---|---|---|---|
| hostPath / local-path | 本地目录 | 临时测试、无状态应用 | 不支持跨节点迁移,Pod 重建后数据可能丢失 |
| OpenEBS LocalPV | 本地持久卷 | 中小规模、对性能敏感 | 数据仍绑定单节点,需要应用层副本 |
| Longhorn | 分布式块存储 | 需要跨节点副本、方便迁移 | 占用部分系统资源做管理和副本同步 |
| Rook-Ceph | 分布式存储 | 大容量、需要块/对象存储 | 运维成本较高,不建议小团队起步 |
如果业务里已经有数据库类应用,至少用 Longhorn,它对故障迁移的支持比 OpenEBS LocalPV 强。如果只是跑无状态 Web 服务,hostPath 都行,但长期维护起来容易失控。
4.4 内网服务怎么暴露:MetalLB + Ingress 组合
裸金属 K8s 环境里,Service 的LoadBalancer类型默认是空的,因为它依赖云厂商的负载均衡器。内网环境要暴露服务,最常见做法是 MetalLB 加 Ingress-nginx。
MetalLB 支持二层广播和 BGP 两种模式。小规模内网用二层广播最省事,但你要预留一段和内网业务网段同网段的空闲 IP 池,并且不要和 DHCP 冲突。安装完之后,可以通过 ConfigMap 配置 IP 池范围。然后 Ingress-nginx 的 Service 会拿到一个 MetalLB 分配的 IP,后续 HTTP 服务统一走这个入口。
我建议的方案是:内部服务走 ClusterIP,跨节点或给外部团队访问的走 Ingress,只有极少数需要固定 IP 的走 LoadBalancer 直连。
5. 平台不只是跑通:Redis 集群、GPU 推理与多团队 Namespace
一个内网云平台能跑起来不算交付完成,真正有价值的是业务能稳定跑在上面。这次我在平台上做了三件事:Redis 集群、GPU 推理资源就绪、多团队 Namespace 隔离。
5.1 用 Helm 在内网拉起 Redis 集群
我用了 redis-cluster 模式,这样即使某个节点挂了,Redis 还能继续读写。内网安装时最关键的是把 Chart 提前拉到本地,然后把镜像地址改成内网仓库地址,否则 Pod 创建时会去公网拉镜像。
Helm 安装的大致思路:
helm repo add bitnami https://charts.bitnami.com/bitnami helm pull bitnami/redis-cluster helm install redis-cluster bitnami/redis-cluster \ --set persistence.storageClass=<你的默认存储类> \ --set cluster.nodes=3 \ --set cluster.replicas=1如果想确保镜像来自内网私有仓库,用 values 里对应的image.registry参数把仓库地址替换掉。部署完验证:
kubectl run redis-cli --image=<内网镜像仓库>/redis:7.0 --rm -it -- redis-cli -h redis-cluster能正常PONG就说明没问题。这个使用 PostgreSQL 一类数据库的思路也一样,关键是先解决镜像和存储两个前置条件。
5.2 深度学习与大模型私有化部署的 GPU 调度
内网私有化部署大模型的企业现在越来越多。底座要做的事其实不复杂:让 K8s 能识别 GPU 资源,并把推理服务调上去。
第一步,在各 GPU 节点安装 NVIDIA 驱动和 container toolkit,确保裸机上nvidia-smi能正常输出。第二步,部署 NVIDIA device plugin,让 Kubelet 感知 GPU 设备。第三步,给 GPU 节点打标签,参与资源调度规划:
kubectl label node gpu-node-01 nvidia.com/gpu=true验证 GPU 调度用一个小 Pod 即可:
apiVersion: v1 kind: Pod metadata: name: gpu-test spec: restartPolicy: Never containers: - name: cuda image: <内网镜像仓库>/nvidia/cuda:12.2.0-base-ubuntu22.04 command: ["nvidia-smi"] resources: limits: nvidia.com/gpu: 1如果 Pod 能正常显示 GPU 信息,说明调度链路已经通了。再往上就是具体的大模型推理服务,比如用 vLLM 或 Triton 部署推理实例,模型文件放到 PersistentVolume 里,通过 Ingress 暴露兼容接口。这样对外看起来就是一个“大模型私有化部署平台”。
5.3 多团队共用平台的隔离:Namespace、配额与权限
内网平台如果多人共用,最忌“所有人都是管理员”。底层逻辑还是 K8s 的 Namespace 加 RBAC。我的习惯是每个团队或每个项目创建一个 Namespace,并给资源配额。
创建和配额示例:
kubectl create ns team-ml kubectl create quota resource-quota \ --hard=cpu=100,memory=200Gi,pods=200 \ --namespace=team-ml权限上,用 RoleBinding 把具体角色绑定到用户的 Namespace 里,避免团队之间互相干扰。在内网环境,安全边界同样重要,尤其是大模型推理服务涉及模型权重文件,更要控制访问。
6. Sealos、K8s、Docker 到底什么关系,以及我的最终建议
很多人第一次听说 Sealos 时都会问同一个问题:它和 Docker、K8s 是什么关系?这里统一解释清楚。
6.1 三者的定位差异
Docker 解决的是单机上的容器打包和运行问题。K8s 解决的是多台机器上的容器编排问题,包括调度、服务发现、扩容、故障恢复。Sealos 则是在 K8s 之上做交付和产品化,它把 K8s 集群本身当成一个可运行的镜像,并在此基础上提供云平台的能力。
用个类比:Docker 是集装箱,负责把货物标准化装起来;K8s 是港口调度系统,负责安排集装箱在哪个码头装卸、往哪条船送;Sealos 是整套交钥匙港口方案,你只需要把需求提出来,港口就能快速落地。Sealos 底层容器运行时默认是 containerd,并不依赖 Docker,所以不用担心“装 Docker 很占资源”或者“Docker 和 K8s 兼容性”这些老问题。
6.2 内网私有化的“人间真实”建议
几台机器搭出来的集群容易,让它长期稳定运行难。这次交付下来,我有几点很实在的建议:
- 版本统一。sealos、集群镜像、K8s 版本、节点操作系统版本最好都固定下来,不要今天升级一个明天升级一个。
- 镜像清单和离线包放在公司内部共享存储里,最好和版本管理一起维护。
- 一定要有监控。内网环境没有云厂商的监控大盘,自己部署 Prometheus 和 Grafana 是值得的。
- 定期演练备份恢复。K8s 平台本身的备份可以用 Velero 这类工具,别等集群挂了才后悔。
- 写文档。内网环境里遇到的每一个怪问题,都值得记录到团队知识库,因为过几个月可能又会踩到同样的坑。
6.3 后续可以怎么扩展
这套平台跑稳定之后,可以扩展的方向不少。加 Sealos Cloud 控制台让非运维同事也能自助创建应用;接 Argo CD 做 GitOps 交付;部署日志采集和统一告警;做多集群管理和容灾。顺着业务需求一步步来,不要一上来就把所有东西都装上。
我个人在实际操作中的体会是:15 分钟把集群拉起来只是一个开始,真正让内网云平台“活”下去的是镜像管理、存储方案、权限边界和团队规范。Sealos 把我从繁琐的集群安装细节里解放出来,让我有精力把更多时间花在这些真正影响稳定性的地方。希望这篇记录能帮你在内网私有化部署的路上少踩几个坑。