1. 项目概述K8S 部署流程到底在部署什么“K8S 部署流程”这六个字是运维、开发、SRE 和云原生初学者每天刷屏看到的高频词但很多人卡在第一步——它到底指哪一段操作不是单纯装几个二进制文件也不是点几下控制台就算完事。我带过二十多个从零搭建生产级 K8S 集群的团队发现90%的人在“部署流程”上栽跟头根本原因在于混淆了三个完全不同的层次环境准备层、集群构建层、应用交付层。你查到的“ubuntu24安装k8s教程”通常只覆盖第一层而“sealos部署k8s”或“railway部署”属于第二层的封装工具至于“dify本地部署”“ragflow知识库搭建全流程”“k8s部署mysql”全都是第三层——也就是真正让业务跑起来的落地环节。这三层环环相扣漏掉任何一环后续所有操作都会变成空中楼阁。举个最典型的例子你在 Ubuntu 24.04 上用 kubeadm 成功 init 出 master 节点kubectl get nodes显示 Ready你以为部署完成了错。这时候连一个 Pod 都可能起不来——因为 CNI 插件没配Pod CIDR 和节点网段冲突或者 kube-proxy 没启用 IPVS 模式Service ClusterIP 在高并发下开始丢包更常见的是你压根没配置 containerd 的镜像仓库认证拉取私有 registry 里的 dify 镜像时卡在ImagePullBackOff翻遍日志只看到failed to resolve reference却不知道问题出在/etc/containerd/config.toml里少加了auths段。这些都不是“不会装 K8S”而是对“K8S 部署流程”的认知断层。所以这篇内容不讲“怎么下载 kubectl”也不罗列 10 种安装脚本。我要带你把整个流程拆成可验证、可回滚、可审计的原子动作从物理机 BIOS 设置里关闭 swap 的那一刻开始到你用kubectl port-forward svc/dify-web 8080:80在本地浏览器打开 dify 界面为止。中间每一步我都告诉你为什么必须这么做、不做会触发什么具体故障、如何用一条命令快速验证是否生效。比如为什么swapoff -a后还要注释/etc/fstab里的 swap 行因为系统重启后 systemd 会自动挂载 swap导致 kubelet 直接 panic —— 这个细节在绝大多数“k8s安装部署步骤”教程里都被跳过了。再比如“k8s和docker的关系与区别”这种泛泛而谈的问题放到部署流程里就变成硬核选择题你现在用的是 containerd 还是 dockershim如果是 Ubuntu 24.04默认内核 6.8containerd 1.7 必须开启systemd_cgroup true否则 cgroup v2 下 CPU 限流完全失效你的大模型推理服务会莫名其妙被 OOM kill。这些不是理论是我在金融客户集群里连续三天抓包、比对 cgroup.procs 文件、最终定位到的血泪教训。如果你正面临这些场景刚买好三台阿里云 ECS 准备搭测试集群但卡在kubeadm join失败想把本地跑通的 ragflow 知识库一键推到 K8S却搞不清 ConfigMap 和 Secret 怎么拆分或者面试官问“k8s部署mysql怎么保证数据不丢”你只能答出“用 PV/PVC”——那这篇就是为你写的。它不假设你懂 etcd 原理但要求你愿意敲命令、看日志、改配置。接下来的内容每一行都能直接粘贴进终端执行每一个参数都有真实压测数据支撑每一个“注意”背后都对应一个曾经导致线上服务中断两小时的事故。2. 部署流程的三层解构为什么不能只学“安装”2.1 环境准备层被99%教程忽略的底层地基K8S 不是独立运行的软件它是寄生在 Linux 内核之上的调度框架。所谓“部署流程”的起点从来不在kubeadm init命令而在你第一次登录服务器执行lsmod | grep br_netfilter的那一刻。这一层的目标只有一个让 Linux 内核准备好接纳 K8S 的所有网络、存储、安全能力。但现实是Ubuntu 24.04、CentOS Stream 9、Rocky Linux 9 这些主流发行版出厂设置几乎全部与 K8S 要求背道而驰。先说最致命的swap 问题。网上所有教程都写swapoff -a但没人告诉你swapoff -a只是临时禁用系统重启后/etc/fstab里带swap标签的行会被 systemd 自动挂载。一旦 kubelet 启动时检测到 swap 启用它会直接 panic 并退出日志里只有一行FATAL: The swap partition is enabled. Kubernetes does not support swap.。这不是警告是硬性终止。解决方案必须两步走执行sudo swapoff -a清除当前 swap执行sudo sed -i / swap / s/^\(.*\)$/#\1/g /etc/fstab注释 fstab 中所有 swap 行。提示别用vi /etc/fstab手动编辑容易误删其他关键挂载项。这条 sed 命令精准匹配含空格包围的 swap 字符串实测在 Ubuntu 24.04 和 Rocky 9 上 100% 安全。再看内核模块加载。K8S 网络依赖br_netfilter桥接 netfilter、ip_vsIPVS 负载均衡、nf_conntrack连接跟踪。Ubuntu 24.04 默认不加载ip_vs导致 kube-proxy 无法启用 IPVS 模式。验证方法很简单lsmod | grep -E br_netfilter|ip_vs|nf_conntrack。如果ip_vs缺失执行sudo modprobe ip_vs sudo modprobe ip_vs_rr sudo modprobe ip_vs_wrr sudo modprobe ip_vs_sh echo ip_vs | sudo tee -a /etc/modules echo ip_vs_rr | sudo tee -a /etc/modules echo ip_vs_wrr | sudo tee -a /etc/modules echo ip_vs_sh | sudo tee -a /etc/modules注意ip_vs_sh源哈希在 K8S Service SessionAffinity 场景中至关重要但很多教程只加载ip_vs_rr。如果你的应用需要用户会话保持比如某些老 ERP 系统漏掉这行会导致负载不均甚至 503 错误。最后是iptables 规则链兼容性。K8S 1.28 强制要求iptables-legacy或iptables-nft一致。Ubuntu 24.04 默认使用iptables-nft但部分 CNI 插件如 Flannel 0.22.3仍依赖iptables-legacy。验证命令sudo update-alternatives --query iptables。如果显示iptables-nft为优先项必须切换sudo update-alternatives --set iptables /usr/sbin/iptables-legacy sudo update-alternatives --set ip6tables /usr/sbin/ip6tables-legacy这个操作影响全局防火墙但 K8S 集群启动前必须完成。我见过客户因未切换在kubeadm init后kube-proxy日志疯狂报Failed to ensure chain: Failed to execute iptables-restore排查三天才发现是 iptables 版本不匹配。2.2 集群构建层kubeadm 不是黑盒是可调试的流水线很多人把kubeadm init当作魔法命令输入就完事。实际上kubeadm 是一个高度可配置的集群构建引擎它的每个参数都对应一个真实的系统状态。理解这些参数等于掌握了集群的“出生证明”。先看最核心的--pod-network-cidr。这个值不是随便填的。它必须满足两个硬性条件不能与宿主机所在网段重叠比如你的服务器是 192.168.1.100/24Pod 网段就不能设为 192.168.1.0/16必须与你选用的 CNI 插件默认配置一致。Flannel 默认用10.244.0.0/16Calico 默认用192.168.0.0/16而 Cilium 默认用10.0.0.0/8。填错的后果极其隐蔽kubectl get pods -A显示所有 CoreDNS Pod 都是ContainerCreatingkubectl describe pod coredns-xxx却只显示NetworkPluginNotReady死活找不到具体错误。这是因为 kubelet 等待 CNI 插件返回网络就绪信号而插件因 CIDR 冲突拒绝初始化。再看--cri-socket。Ubuntu 24.04 默认安装 containerd但 socket 路径是/run/containerd/containerd.sock而 kubeadm 1.28 默认查找/var/run/containerd/containerd.sock。如果不显式指定kubeadm init会静默 fallback 到 docker如果已安装导致后续所有容器运行时行为异常。正确做法是sudo kubeadm init \ --pod-network-cidr10.244.0.0/16 \ --cri-socket/run/containerd/containerd.sock \ --kubernetes-versionv1.28.11实操心得永远显式指定--kubernetes-version。K8S 补丁版本如 1.28.10 → 1.28.11可能包含关键 CVE 修复如 CVE-2024-21626 containerd 漏洞跳过版本号会让 kubeadm 自动拉取最新 minor 版可能引入不兼容变更。kubeadm init执行后生成的admin.conf是集群的“命脉”。它包含 CA 证书、API Server 地址、token 等敏感信息。但很多人直接cp -i /etc/kubernetes/admin.conf $HOME/.kube/config就完事。这里有个致命陷阱admin.conf中的server:字段默认是https://127.0.0.1:6443这是 localhost 地址。当你在远程机器上执行kubectl时它会尝试连接本地 6443 端口必然失败。必须手动修改sed -i s#https://127.0.0.1:6443#https://$(hostname -I | awk {print $1}):6443#g $HOME/.kube/config这条命令用服务器实际 IP 替换 localhost确保远程访问有效。我帮某电商客户排查时发现他们所有运维人员的kubectl都连不上集群根源就是这个配置没改大家一直用ssh登录 master 节点本地操作。2.3 应用交付层从 YAML 到可用服务的完整闭环集群建好只是开始。真正的“部署流程”高潮在这一层如何把一个业务应用比如 dify、ragflow、mysql变成 K8S 中稳定运行的服务。这里没有银弹只有精确的资源编排。以 “k8s部署mysql” 为例。新手常犯的错误是直接kubectl run mysql --imagemysql:8.0然后发现 Pod 一直 Pending。为什么因为 MySQL 需要持久化存储而kubectl run创建的是无状态 Pod没有关联 PVC。正确的流程必须包含四个不可省略的 YAML 文件Secret存储 root 密码避免明文写在 Deployment 里PersistentVolumeClaim (PVC)声明 20Gi 存储空间绑定到 NFS 或本地路径Service定义 ClusterIP 类型暴露 3306 端口StatefulSet替代 Deployment确保 Pod 有稳定网络标识和存储绑定。其中 Secret 的创建方式很关键。kubectl create secret generic mysql-root-pass --from-literalpasswordmy-secret-pw是最安全的方式密码不会出现在 bash history 或进程列表中。而--from-file方式要求密码先存为文件存在文件权限泄露风险。再看 “dify本地部署” 迁移到 K8S 的典型坑。Dify 前端web、后端api、Workercelery三个组件必须解耦部署。但很多教程把它们塞进同一个 Deployment导致水平扩展时 Worker 和 API 互相抢占 CPU。正确做法是Web 组件用 Deployment HPACPU 使用率 70% 时扩容API 组件用 Deployment PodDisruptionBudget保障至少 2 个副本在线Worker 组件用 StatefulSet initContainer启动前检查 Redis 连接是否就绪。initContainer 的作用常被低估。它会在主容器启动前执行预检脚本比如initContainers: - name: wait-for-redis image: busybox:1.35 command: [sh, -c, until nc -z redis-headless.default.svc.cluster.local 6379; do echo waiting for redis; sleep 2; done]这段代码确保 Worker 容器绝不会在 Redis 不可用时启动避免 Celery 启动失败后反复 CrashLoopBackOff。3. 核心环节实操从零搭建可验证的 K8S 集群3.1 环境准备三台 Ubuntu 24.04 节点的标准化初始化我们以最典型的三节点集群为例1 台 Master4C8G2 台 Worker4C8G。所有操作均在 root 用户下执行避免 sudo 权限问题。第一步基础系统加固在每台节点上执行以下命令。这不是可选项是 K8S 生产环境的强制前提# 关闭 swap 并永久禁用 swapoff -a sed -i / swap / s/^\(.*\)$/#\1/g /etc/fstab # 加载必要内核模块 modprobe br_netfilter modprobe ip_vs modprobe ip_vs_rr modprobe ip_vs_wrr modprobe ip_vs_sh modprobe nf_conntrack # 持久化内核模块加载 cat EOF | sudo tee /etc/modules-load.d/k8s.conf br_netfilter ip_vs ip_vs_rr ip_vs_wrr ip_vs_sh nf_conntrack EOF # 配置 sysctl 参数启用网桥流量转发 cat EOF | sudo tee /etc/sysctl.d/k8s.conf net.bridge.bridge-nf-call-ip6tables 1 net.bridge.bridge-nf-call-iptables 1 net.ipv4.ip_forward 1 EOF sysctl --system注意sysctl --system会重新加载所有/etc/sysctl.d/下的配置比单独sysctl -p更可靠。我曾遇到客户sysctl -p /etc/sysctl.d/k8s.conf失败因为--system会按字母序加载确保br_netfilter在iptables之前生效。第二步安装 containerd 运行时Ubuntu 24.04 自带 containerd 1.7.13但默认配置不满足 K8S 要求。必须修改其配置# 生成默认配置 mkdir -p /etc/containerd containerd config default | sudo tee /etc/containerd/config.toml # 修改关键参数启用 systemd cgroup 和镜像仓库配置 sed -i s/SystemdCgroup false/SystemdCgroup true/g /etc/containerd/config.toml sed -i /\[plugins.io.containerd.grpc.v1.cri.registry.mirrors\]/a [plugins.io.containerd.grpc.v1.cri.registry.configs.docker.io.auth]\n username your-username\n password your-password /etc/containerd/config.toml实操心得SystemdCgroup true是 Ubuntu 24.04 K8S 1.28 的生死线。不开启会导致 cgroup v2 下 CPU 和内存限制完全失效。你可以用crictl inspect container-id | grep cgroupParent验证输出应为/kubepods.slice而非/system.slice。第三步安装 kubeadm、kubelet、kubectl# 添加 K8S APT 仓库 curl -fsSL https://pkgs.k8s.io/core:/stable:/v1.28/deb/Release.key | sudo gpg --dearmor -o /usr/share/keyrings/kubernetes-apt-keyring.gpg echo deb [archamd64 signed-by/usr/share/keyrings/kubernetes-apt-keyring.gpg] https://pkgs.k8s.io/core:/stable:/v1.28/deb/ / | sudo tee /etc/apt/sources.list.d/kubernetes.list # 安装指定版本避免自动升级 apt-get update apt-get install -y kubelet1.28.11-1.1 kubeadm1.28.11-1.1 kubectl1.28.11-1.1 apt-mark hold kubelet kubeadm kubectl提示“apt-mark hold” 锁定版本至关重要。K8S 补丁升级可能破坏 CNI 兼容性如 Calico 3.26.3 与 K8S 1.28.12 的 RBAC 变更锁定能避免意外升级。3.2 集群初始化Master 节点的精确配置与验证现在进入最关键的kubeadm init环节。我们不用默认配置而是构建一个生产就绪的初始化命令kubeadm init \ --pod-network-cidr10.244.0.0/16 \ --service-cidr10.96.0.0/12 \ --cri-socket/run/containerd/containerd.sock \ --kubernetes-versionv1.28.11 \ --control-plane-endpoint192.168.1.100:6443 \ --upload-certs \ --ignore-preflight-errorsNumCPU,Mem \ --node-name$(hostname -s)逐个解析参数--control-plane-endpoint指定高可用 VIP 或 Master IP这里是单节点直接填 Master 的局域网 IP--upload-certs启用证书分发为后续添加 Control Plane 节点做准备--ignore-preflight-errors跳过 CPU 和内存检查测试环境允许但生产环境必须满足 2C2G 最低要求--node-name强制使用短主机名避免kubeadm join时因 FQDN 解析失败。执行成功后你会看到类似这样的输出Your Kubernetes control-plane has initialized successfully! To start using your cluster, you need to run the following as a regular user: mkdir -p $HOME/.kube sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config sudo chown $(id -u):$(id -g) $HOME/.kube/config You should now deploy a pod network to the cluster. Run kubectl apply -f [podnetwork].yaml with one of the options listed at: https://kubernetes.io/docs/concepts/cluster-administration/addons/立刻执行配置mkdir -p $HOME/.kube sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config sudo chown $(id -u):$(id -g) $HOME/.kube/config然后立即验证kubectl get nodes # 应显示 master 节点为 NotReady kubectl get pods -A # 应显示 kube-system 命名空间下 core-dns 处于 Pending出现NotReady和Pending是完全正常的这说明 kubeadm init 成功但 CNI 插件还没部署。此时不要慌这是流程设计的必经阶段。3.3 CNI 插件部署Flannel 的精确配置与故障排除我们选择 Flannel因为它的轻量和稳定性在中小集群中无可替代。但 Flannel 0.24.0 对 Ubuntu 24.04 有特殊要求。# 下载并修改 Flannel 配置适配 containerd curl -O https://raw.githubusercontent.com/flannel-io/flannel/v0.24.0/Documentation/kube-flannel.yml # 修改 containerRuntimeConfig sed -i s/containerRuntime:docker/containerRuntime:containerd/g kube-flannel.yml # 修改镜像地址国内加速 sed -i s/quay.io\/coreos\/flannel:/registry.cn-hangzhou.aliyuncs.com\/google_containers\/flannel:/g kube-flannel.yml kubectl apply -f kube-flannel.yml注意containerRuntime必须设为containerd否则 Flannel 无法与 containerd 通信。这个字段在旧版 Flannel 文档中被忽略但 0.24.0 已强制校验。部署后等待 60 秒执行验证kubectl get pods -n kube-flannel # 应全部 Running kubectl get nodes # 应变为 Ready kubectl get pods -A | grep -i flannel # 确认 flannel 容器在每个节点运行如果kubectl get nodes仍是 NotReady请检查journalctl -u kubelet -n 100 --no-pager | grep -i flannel—— 查看 kubelet 是否报告 CNI 初始化失败ls /opt/cni/bin/—— 确认 flannel 插件二进制文件是否存在cat /var/lib/cni/networks/k8s-pod-network/—— 检查 Flannel 是否成功分配子网。3.4 Worker 节点加入安全 token 的生成与复用Master 初始化成功后会输出kubeadm join命令。但该命令中的 token 24 小时后过期。生产环境中你需要生成长期有效的 token# 在 Master 上生成新 token永不过期 kubeadm token create --ttl 0 # 获取 ca cert hash用于验证证书 openssl x509 -pubkey -in /etc/kubernetes/pki/ca.crt | openssl rsa -pubin -outform der 2/dev/null | openssl dgst -sha256 -hex | sed s/^.* // # 构造 join 命令替换 YOUR-TOKEN 和 YOUR-HASH kubeadm join 192.168.1.100:6443 --token YOUR-TOKEN --discovery-token-ca-cert-hash sha256:YOUR-HASH在每台 Worker 节点上执行此命令。加入成功后在 Master 上执行kubectl get nodes # 应显示 1 master 2 worker全部 Ready kubectl get nodes -o wide # 查看各节点 IP 和内核版本确认一致性实操心得kubeadm join失败最常见的原因是时间不同步。务必在所有节点执行timedatectl set-ntp true启用 NTP并用timedatectl status确认同步状态。K8S 组件间通信大量使用 TLS 证书时间偏差超过 1 分钟就会导致证书验证失败。4. 应用部署实战dify 与 mysql 的生产级 YAML 编排4.1 dify 全组件部署解耦、健康检查与资源限制Dify 由 Web 前端、API 后端、Celery Worker 三大组件构成。我们将它们拆分为三个独立的 YAML 文件实现精细化管控。第一步创建 Secret 存储敏感信息# dify-secret.yaml apiVersion: v1 kind: Secret metadata: name: dify-secret namespace: default type: Opaque data: DATABASE_URL: cG9zdGdyZXM6Ly9kb2NrbWFuOmRvY2ttYW4tMTIzQGRvY2ttYW4tZGI6NTQzMjMvZGlm eQ # postgresql://dockman:dockman-123dockman-db:5432/dify REDIS_URL: cmVkaXM6Ly86cmVkaXMtMTIzQHJlZGlzLWhlYWRsZXNzOjYzNzkuMA # redis://:redis-123redis-headless:6379.0 SECRET_KEY: ZGlm eS1zZWNyZXQta2V5LWZvci1wcm9kdWN0aW9u # dify-secret-key-for-production注意所有值必须 base64 编码。用echo -n your-string | base64生成-n参数避免换行符混入。第二步部署 PostgreSQL 数据库StatefulSet# dify-postgres.yaml apiVersion: apps/v1 kind: StatefulSet metadata: name: dify-db namespace: default spec: serviceName: dify-db replicas: 1 selector: matchLabels: app: dify-db template: metadata: labels: app: dify-db spec: containers: - name: postgres image: postgres:15-alpine envFrom: - secretRef: name: dify-secret ports: - containerPort: 5432 volumeMounts: - name: postgres-storage mountPath: /var/lib/postgresql/data resources: requests: memory: 512Mi cpu: 250m limits: memory: 1Gi cpu: 500m volumes: - name: postgres-storage persistentVolumeClaim: claimName: dify-db-pvc --- apiVersion: v1 kind: PersistentVolumeClaim metadata: name: dify-db-pvc namespace: default spec: accessModes: - ReadWriteOnce resources: requests: storage: 10Gi --- apiVersion: v1 kind: Service metadata: name: dify-db namespace: default spec: selector: app: dify-db ports: - protocol: TCP port: 5432 targetPort: 5432关键点StatefulSet 保证 Pod 名称固定如dify-db-0PVC 名称也固定实现存储绑定。resources.limits防止数据库吃光节点内存。第三步部署 RedisHeadless Service# dify-redis.yaml apiVersion: apps/v1 kind: StatefulSet metadata: name: redis namespace: default spec: serviceName: redis-headless replicas: 1 selector: matchLabels: app: redis template: metadata: labels: app: redis spec: containers: - name: redis image: redis:7-alpine envFrom: - secretRef: name: dify-secret ports: - containerPort: 6379 volumeMounts: - name: redis-storage mountPath: /data volumes: - name: redis-storage persistentVolumeClaim: claimName: redis-pvc --- apiVersion: v1 kind: PersistentVolumeClaim metadata: name: redis-pvc namespace: default spec: accessModes: - ReadWriteOnce resources: requests: storage: 5Gi --- apiVersion: v1 kind: Service metadata: name: redis-headless namespace: default annotations: service.alpha.kubernetes.io/tolerate-unready-endpoints: true spec: clusterIP: None selector: app: redis ports: - port: 6379 targetPort: 6379为什么用 Headless Service因为 Celery Worker 需要直接连接 Redis Pod IP而非通过 ClusterIP 负载均衡。clusterIP: None禁用 DNS A 记录只生成 Pod IP 的 DNS 记录如redis-0.redis-headless.default.svc.cluster.local。第四步部署 Dify API 和 WebDeployment Service# dify-api-web.yaml apiVersion: apps/v1 kind: Deployment metadata: name: dify-api namespace: default spec: replicas: 2 selector: matchLabels: app: dify-api template: metadata: labels: app: dify-api spec: containers: - name: api image: langgenius/dify-api:latest envFrom: - secretRef: name: dify-secret ports: - containerPort: 5001 livenessProbe: httpGet: path: /health port: 5001 initialDelaySeconds: 60 periodSeconds: 30 readinessProbe: httpGet: path: /health port: 5001 initialDelaySeconds: 30 periodSeconds: 10 resources: requests: memory: 1Gi cpu: 500m limits: memory: 2Gi cpu: 1 --- apiVersion: apps/v1 kind: Deployment metadata: name: dify-web namespace: default spec: replicas: 2 selector: matchLabels: app: dify-web template: metadata: labels: app: dify-web spec: containers: - name: web image: langgenius/dify-web:latest ports: - containerPort: 3000 env: - name: API_URL value: http://dify-api:5001 livenessProbe: httpGet: path: / port: 3000 initialDelaySeconds: 30 periodSeconds: 10 resources: requests: memory: 512Mi cpu: 250m limits: memory: 1Gi cpu: 500m --- apiVersion: v1 kind: Service metadata: name: dify-api namespace: default spec: selector: app: dify-api ports: - protocol: TCP port: 5001 targetPort: 5001 --- apiVersion: v1 kind: Service metadata: name: dify-web namespace: default spec: type: NodePort selector: app: dify-web ports: - protocol: TCP port: 80 targetPort: 3000 nodePort: 30080关键设计livenessProbe和readinessProbe确保容器健康NodePort: 30080暴露 Web 界面浏览器访问http://master-ip:30080即可env.API_URL用 Service 名dify-api利用 K8S DNS 自动解析为 ClusterIP。4.2 MySQL 部署高可用与数据持久化的硬核实践“k8s部署mysql” 的核心诉求是数据不丢、服务不宕、扩容不裂。我们采用 StatefulSet PVC 主从复制架构。第一步创建 MySQL 主从配置文件# mysql-configmap.yaml apiVersion: v1 kind: ConfigMap metadata: name: mysql-config namespace: default data: master.cnf: | [mysqld] log-bin server-id1 slave.cnf: | [mysqld] server-id2第二步部署 MySQL StatefulSet主节点# mysql-statefulset.yaml apiVersion: apps/v1 kind: StatefulSet metadata: name: mysql namespace: default spec: serviceName: mysql replicas: 2 selector: matchLabels: app: mysql template: metadata: labels: app: mysql spec: initContainers: - name: clone-m