知识广场
按学科筛选:计算机科学 / 分布式与云计算 / Kubernetes
«计算机科学 / 分布式与云计算 / Kubernetes» 分类下共 5 篇帖子
## 起因 K8s 整个 cluster 状态存在 etcd: - 所有 deployment / service / configmap / secret - node 状态 - 所有 namespace etcd 挂 → cluster 整体瘫。 更恐怖:etcd 数据损坏(disk 错 / 误操作)→ 数据丢失。 定期 etcd backup + 演练 restore 是 cluster 运维基础功。 没做过 restore 演练等于没 backup。 ## 看 etcd 状态 ```bash # kubeadm 部署的 cluster sudo etcdctl --endpoints=https://127.0.0.1:2379 \ --cacert=/etc/kubernetes/pki/etcd/ca.crt \ --cert=/etc/kubernetes/pki/etcd/server.crt \ --key=/etc/kubernetes/pki/etcd/server.key \ endpoint status --write-out=table ``` ``` +------------------------+------------+---------+---------+--------+ | ENDPOINT | DB SIZE | LEADER | RAFT IDX| ALARMS | +------------------------+------------+---------+---------+--------+ | 10.0.1.10:2379 | 250 MB | true | 123456 | | | 10.0.1.11:2379 | 250 MB | false | 123456 | | | 10.0.1.12:2379 | 250 MB | false | 123456 | | +------------------------+------------+---------+---------+--------+ ``` 3 个 endpoint 应一致 + 1 个 leader + 无 alarms。 ## 创建 snapshot ```bash sudo ETCDCTL_API=3 etcdctl \ --endpoints=https://127.0.0.1:2379 \ --cacert=/etc/kubernetes/pki/etcd/ca.crt \ --cert=/etc/kubernetes/pki/etcd/server.crt \ --key=/etc/kubernetes/pki/etcd/server.key \ snapshot save /backup/etcd-$(date +%Y%m%d-%H%M%S).db ``` `Snapshot saved at /backup/etcd-...db` snapshot 是单 binary 文件,几百 MB 量级(小 cluster)。 ## 自动化备份 (cronjob) ```bash # /etc/cron.d/etcd-backup 0 */6 * * * root /usr/local/bin/etcd-backup.sh ``` ```bash #!/bin/bash # /usr/local/bin/etcd-backup.sh set -euo pipefail BACKUP_DIR=/backup RETENTION_DAYS=7 TIMESTAMP=$(date +%Y%m%d-%H%M%S) ETCDCTL_API=3 etcdctl \ --endpoints=https://127.0.0.1:2379 \ --cacert=/etc/kubernetes/pki/etcd/ca.crt \ --cert=/etc/kubernetes/pki/etcd/server.crt \ --key=/etc/kubernetes/pki/etcd/server.key \ snapshot save "$BACKUP_DIR/etcd-$TIMESTAMP.db" # 上传到 S3 aws s3 cp "$BACKUP_DIR/etcd-$TIMESTAMP.db" s3://my-backups/etcd/ # 删本地老备份 find $BACKUP_DIR -name 'etcd-*.db' -mtime +$RETENTION_DAYS -delete # 删 S3 老备份(lifecycle policy 也行) aws s3 ls s3://my-backups/etcd/ | awk '{print $4}' | while read f; do days_old=$((($(date +%s) - $(date -d $(echo $f | sed 's/etcd-\(....\)\(..\)\(..\)-.*/\1-\2-\3/') +%s)) / 86400)) if [ $days_old -gt 30 ]; then aws s3 rm s3://my-backups/etcd/$f fi done ``` 每 6 小时备份 + 7 天本地 + 30 天 S3。 ## restore (灾难恢复) **演练步骤**(请在测试环境跑过几次): ```bash # 1. 停所有 etcd 节点的 etcd(kubeadm 用 static pod 控制) sudo mv /etc/kubernetes/manifests/etcd.yaml /tmp/ # 等几秒确认 etcd 停了 sudo crictl ps | grep etcd # 2. 备份当前 data dir sudo mv /var/lib/etcd /var/lib/etcd.bak # 3. restore snapshot sudo ETCDCTL_API=3 etcdctl snapshot restore /backup/etcd-xxx.db \ --data-dir /var/lib/etcd \ --name etcd-node-1 \ --initial-cluster etcd-node-1=https://10.0.1.10:2380,etcd-node-2=https://10.0.1.11:2380,etcd-node-3=https://10.0.1.12:2380 \ --initial-cluster-token etcd-cluster-1 \ --initial-advertise-peer-urls https://10.0.1.10:2380 # 4. 在每节点上做 3 / restore # 5. 启动 etcd sudo mv /tmp/etcd.yaml /etc/kubernetes/manifests/ # 6. 验证 kubectl get nodes kubectl get pods -A ``` cluster 回到 snapshot 时点状态。 snapshot 之后创建的资源(pod / deployment 等)丢失(除非应用 IaC / GitOps 能重 apply)。 ## velero (更高层备份) etcd snapshot 是 raw K8s API state。 **Velero**:备份 + restore K8s 资源 + PV 数据: ```bash helm install velero vmware-tanzu/velero \ --namespace velero --create-namespace \ --set configuration.provider=aws \ --set configuration.backupStorageLocation.bucket=my-backups \ ... ``` ```bash # 备份 namespace velero backup create myapp-backup --include-namespaces myapp # 备份全集群(除 system) velero backup create cluster-backup --exclude-namespaces kube-system,kube-public # 列出 velero backup get # restore velero restore create --from-backup myapp-backup --namespace-mappings myapp:myapp-restore ``` Velero 优势 vs etcd snapshot: - 选择性备份(按 namespace / label) - restore 到不同 namespace / cluster - PV 数据快照(CSI snapshot 支持) - 跨 cluster migration etcd snapshot 是最后兜底(整 cluster 灾难); Velero 是日常运维(误删 namespace / 迁移 / 测试 restore)。 两者都做。 ## 测试 restore 至关重要 经验:**没演练过的 backup = 没 backup**。 每季度跑一次: 1. spin up 临时 cluster 2. 从 backup restore 3. 验证应用能跑 4. 文档化每步 第一次跑会发现: - 漏备份某 resource - restore script 步骤错 - 某 PV 数据没快照 修完 → real disaster 时不慌。 ## etcd 调优 defrag (DB 碎片整理): ```bash etcdctl defrag --endpoints=... ``` DB size 大但 key 少 → 碎片多。定期 defrag。 每 leader change / 大批量改后跑。 quota: ```bash etcd --quota-backend-bytes=8589934592 # 8 GB ``` 默认 2 GB → 大 cluster 不够。 monitor: ```promql etcd_mvcc_db_total_size_in_bytes etcd_disk_wal_fsync_duration_seconds etcd_server_leader_changes_seen_total ``` leader changes 频繁 → 网络 / disk 问题。 ## 多 cluster: 跨 region backup ```bash # velero schedule velero schedule create daily-backup --schedule="0 2 * * *" --ttl 720h \ --include-namespaces myapp \ --storage-location aws-prod-east # 跨 region replication(备份不放同 region 防 region-wide 灾) aws s3 cp s3://my-backups-east/... s3://my-backups-west/... ``` ## 与 cloud managed (EKS / GKE / AKS) cloud managed K8s 的 etcd 是 cloud provider 维护。 - 自动备份 / failover - 但你不能直接 etcdctl snapshot 仍要用 Velero 备份 resource 层(防 namespace 误删 / restore 到其它 cluster)。 ## 真实 incident case 某客户误执行 `kubectl delete namespace prod`。 恢复: 1. 看最近 velero backup(4 小时前) 2. `velero restore create --from-backup ... --include-namespaces prod` 3. 30 分钟后 deployment / service / configmap / secret 全回 4. PV 数据完整(CSI snapshot) 无 backup → cluster 完蛋。有 backup + 演练 → 30 分钟恢复。 ## 踩过的坑 1. **backup 没测**:以为有 backup → 真灾难时发现 backup file 损坏 / 不完整。定期 restore 测试。 2. **etcd snapshot 不包括 secret in etcd-encryption-config 外**: K8s 1.13+ 支持 etcd 加密。restore 后 encryption config 不存在 → 解密失败。备份时同时 cp encryption config。 3. **velero 不备 PV 数据 by default**:要装 CSI plugin 或者 restic integration。 4. **restore 后 IP 变**:service 重新创建 ClusterIP 可能变 → DNS 改 传播延迟。 5. **etcd full**:DB size 超 quota → cluster read-only。`defrag` + `alarm disarm`。
## 起因 K8s pod 用 PV: - 云上:EBS / GCE PD / Azure Disk - 自托管:hostPath(坏到没救)/ NFS(慢 + 没 snapshot)/ Ceph(运维炸) 需要"PVC 跑 stateful 应用"但又不在云上: - 边缘 cluster - 自建机房 - 本地 dev / 小 prod **Longhorn**(Rancher / SUSE,CNCF):K8s-native distributed block storage。 轻量 + 部署简单 + UI 友好。 ## 装 ```bash helm install longhorn longhorn/longhorn \ -n longhorn-system --create-namespace ``` 每 node 自动跑 longhorn-manager pod + 用本地 disk 做 storage。 `StorageClass` 自动创建: ```bash kubectl get sc longhorn (default) driver.longhorn.io Delete Immediate ``` ## 用 ```yaml apiVersion: v1 kind: PersistentVolumeClaim metadata: name: data spec: storageClassName: longhorn accessModes: [ReadWriteOnce] resources: requests: storage: 10Gi ``` ```yaml spec: containers: - volumeMounts: - mountPath: /data name: data volumes: - name: data persistentVolumeClaim: claimName: data ``` 挂载即用。Longhorn 在背后: - 找有空间的 node 创建 volume - replica 跨 3 node 同步(默认) - pod schedule 到任意 node,volume 自动跟随 ## replica 跨 node 3 replica = 3 个 node 各存一份。 任一 node 挂 → 还有 2 副本,pod 在别 node 重启接着用。 ## snapshot + backup ```yaml # 创建 snapshot apiVersion: longhorn.io/v1beta2 kind: Snapshot metadata: name: snap-1 namespace: longhorn-system spec: volume: pvc-xxx ``` snapshot 是 volume 状态 point-in-time copy(本地,秒级)。 backup 是把 snapshot 上传到 S3 / NFS: ```bash # Longhorn UI 配 S3 backup target # 或者 CR ``` ```yaml apiVersion: longhorn.io/v1beta2 kind: Backup metadata: name: backup-1 spec: snapshotName: snap-1 ``` 恢复:从 backup 创建新 volume → PVC → pod 挂载。 跨集群迁移:cluster A backup → cluster B restore。 ## recurring job ```yaml apiVersion: longhorn.io/v1beta2 kind: RecurringJob metadata: name: daily-backup spec: cron: "0 2 * * *" task: backup retain: 7 groups: [default] ``` 每天 2:00 自动 snapshot + backup,保留 7 份。 ## UI ```bash kubectl -n longhorn-system port-forward svc/longhorn-frontend 8080:80 # http://localhost:8080 ``` UI 看 volume / replica 状态 / backup / settings。 比 yaml 直观,运维友好。 ## 性能 3-node cluster + NVMe disk + Longhorn 3 replica: - random read 4k: ~50k IOPS - random write 4k: ~15k IOPS - sequential write: ~600 MB/s 跟单盘比有 30-50% overhead(network + replication)。 跟 EBS gp3 接近。够多数 workload。 ## 与 Ceph (Rook) 对比 | | Longhorn | Rook-Ceph | |---|---|---| | 复杂度 | 低 | 极高 | | 性能 | 中 | 高 | | scale | 中(几十 node) | 巨(几百+) | | object storage | ❌ | ✅ | | file storage (NFS-like) | RWX 实验 | ✅ | | block storage | ✅ | ✅ | 中小 cluster + 主要 block storage → Longhorn。 大 scale + 需 object / file → Ceph。 ## RWX (多 pod 同时读写) ```yaml accessModes: [ReadWriteMany] # RWX ``` Longhorn RWX 用内置 NFS share volume 之上。 性能比 RWO 弱,但能用。 ReadWriteOncePod (K8s 1.27+) 是更严格 RWO。 ## 与 hostPath ```yaml volumes: - name: data hostPath: path: /mnt/data ``` 简单粗暴 但: - pod schedule 必须在那 node(pin) - 没备份 / 副本 - 移走 node 数据丢 dev 还行,prod 别用。 ## 与 NFS NFS provisioner:装个 NFS server + provisioner,PVC 在 NFS 上分 volume。 | | NFS | Longhorn | |---|---|---| | RWX | ✅ | ✅(弱) | | 性能 | 中 | 高 | | HA | NFS server 单点 | replica HA | | 部署 | 简 | 中 | 小数据 / RWX 重 → NFS 简单。 HA / 性能 → Longhorn。 ## 真实 case 某客户私有云 cluster: - 5 node bare metal - 每 node 1 TB NVMe - Longhorn 3 replica - PG / Redis / app data 全 Longhorn 效果: - Postgres 跑得跟单盘差 30%(可接受) - 任一 node down → pod 自动迁移 + volume 跟随 - 每天自动 backup 到 S3 - UI 让 ops 直观看 storage 状态 挑战: - 网络 IO 飙(replica sync 占带宽)→ 10 GbE 网卡 - node 重启时 replica rebuild 几小时 ## 监控 Prometheus metrics: - `longhorn_volume_actual_size_bytes` - `longhorn_volume_state` - `longhorn_node_status` Grafana dashboard 官方提供。 alert 关键: - replica 不足(应 3 实际 < 3) - volume detached - node down - backup 失败 ## 与 cloud volume 对比 | | Longhorn | EBS / PD | |---|---|---| | 部署 | 自管 | 托管 | | 跨 AZ | 自配 | 内置 | | 性能 | 看本地 disk | 一致 | | 成本 | hardware 一次性 | 按月 | | 适合 | 自托管 / 边缘 | 云 | 在云上没必要 Longhorn(用 EBS)。 自托管 / 混合云 → Longhorn 填补"K8s storage" 空白。 ## 踩过的坑 1. **每 node 一份 replica = 数据膨胀**:3 replica 占 3x 空间。 规划存储 capacity * 3。 2. **kernel module**:Longhorn 用 iSCSI 协议。某些 minimal OS 没装 `open-iscsi` → 启不来。 3. **disk fill 90%**:默认 reserve 30% 给系统。改 `Storage Minimal Available Percentage`。 4. **node drain 慢**:drain 时 volume detach + reattach 慢(几十秒)。 maintenance window 留时间。 5. **backup target 配错**:S3 endpoint / credential 错 → 备份失败但 UI 显示成功初看。定期手 restore 验证。
## 起因 K8s 部署演化: 1. `kubectl apply -f` 手动(不知道现在集群什么状态) 2. CI script `kubectl apply` 自动化(但 git 跟 cluster 不一致仍可能) 3. **GitOps**:git 是 source of truth,controller 自动同步到 cluster ArgoCD 是 GitOps controller。修改 yaml + push git → cluster 自动 apply。 diff / rollback / approval flow 全自动化。 ## 装 ```bash kubectl create namespace argocd kubectl apply -n argocd -f https://raw.githubusercontent.com/argoproj/argo-cd/stable/manifests/install.yaml # UI kubectl port-forward svc/argocd-server -n argocd 8080:443 # https://localhost:8080 # 默认密码: kubectl -n argocd get secret argocd-initial-admin-secret -o jsonpath="{.data.password}" | base64 -d ``` ## 第一个 Application ```yaml # argocd-apps/web.yaml apiVersion: argoproj.io/v1alpha1 kind: Application metadata: name: web namespace: argocd spec: project: default source: repoURL: https://github.com/myorg/k8s-manifests targetRevision: main path: apps/web destination: server: https://kubernetes.default.svc namespace: web syncPolicy: automated: prune: true # git 删了 yaml → cluster 也删 selfHeal: true # 手动改 cluster → 自动 revert 回 git 状态 syncOptions: - CreateNamespace=true ``` ```bash kubectl apply -f argocd-apps/web.yaml ``` argocd 会: 1. clone git repo 2. apply `apps/web/*.yaml` 到 `web` namespace 3. 持续监听 git → 有 change pull + apply 4. 持续监听 cluster → drift 自动修复 ## UI ArgoCD UI 显示: - 所有 Application 健康状态 - 每 Application 的 K8s resource 图(service → deploy → pod) - 跟 git desired state 的 diff - sync 历史 + commit message ``` ┌─ Application: web ──────────────────────────────────┐ │ Status: Synced Healthy │ │ Last sync: 2 min ago (commit abc123) │ │ ┌─Service──┐ ┌─Deployment──┐ ┌─Pod ×3─┐ │ │ │ web │ → │ web (3/3) │ → │ ... │ │ │ └──────────┘ └─────────────┘ └────────┘ │ └─────────────────────────────────────────────────────┘ ``` ## kustomize / helm 支持 ```yaml # Application 用 helm spec: source: repoURL: https://github.com/myorg/charts path: charts/web helm: values: | replicaCount: 3 image: tag: v1.2.3 ``` 或者 kustomize: ```yaml spec: source: path: overlays/production kustomize: images: - myorg/web:v1.2.3 ``` ## ApplicationSet(多 cluster / 多 env) ```yaml apiVersion: argoproj.io/v1alpha1 kind: ApplicationSet metadata: name: web-multi-env spec: generators: - list: elements: - cluster: prod url: https://prod.k8s values: values-prod.yaml - cluster: staging url: https://staging.k8s values: values-staging.yaml template: metadata: name: 'web-{{cluster}}' spec: destination: server: '{{url}}' namespace: web source: repoURL: ... helm: valueFiles: - '{{values}}' ``` 一份 template → 给 prod / staging 生成两个 Application。 git 改 → 两个 env 同步。 ## 部署流程 ``` 1. dev 提 PR 改 image tag (v1.2.3 → v1.2.4) 2. PR review + merge to main 3. ArgoCD 检测 main 改动 (default 3 min polling 或 webhook 即时) 4. ArgoCD diff: deployment image change 5. ArgoCD apply: rolling update deployment 6. 健康 check 通过 → Sync success ``` 整个过程 git 是源 + UI 可见。 错了 git revert → ArgoCD 自动 revert cluster。 ## image automation (argocd-image-updater) 不想手改 image tag → image-updater 监听 registry,新 tag 自动 commit git: ```yaml metadata: annotations: argocd-image-updater.argoproj.io/image-list: web=myorg/web argocd-image-updater.argoproj.io/web.update-strategy: semver argocd-image-updater.argoproj.io/write-back-method: git ``` dev 推 image → image-updater 改 git → ArgoCD 同步 cluster。 全流程自动。 ## sync wave ```yaml metadata: annotations: argoproj.io/sync-wave: "1" # 先 apply(如 namespace / CRD) ``` ```yaml metadata: annotations: argoproj.io/sync-wave: "2" # 后 apply(如 deployment) ``` 控制 apply 顺序:CRD 先 → operator 后 → custom resource 最后。 ## sync hook ```yaml metadata: annotations: argoproj.io/hook: PreSync # apply 之前跑 argoproj.io/hook-delete-policy: HookSucceeded spec: template: spec: containers: - name: migrate image: myorg/migrate command: ['./migrate.sh'] ``` PreSync = 部署前跑 db migrate。 PostSync = 部署后跑 smoke test。 SyncFail = 失败时通知。 类似 helm hook。 ## 与 FluxCD 对比 | | ArgoCD | FluxCD | |---|---|---| | 哲学 | UI + CLI first | CLI + GitOps Toolkit | | UI | 强 | 弱(无官方 UI) | | 配置 | Application CRD | Kustomization / HelmRelease | | 多 cluster | ApplicationSet | 不擅长 | | 学习 | 简单 UI 上手 | CLI 思维 | | CNCF | graduated | graduated | ArgoCD 适合 visual ops + 多 cluster。 Flux 适合 git-pure / 自动化 first。 我们用 ArgoCD(UI 让 dev 也能看部署状态,减少 ops 沟通)。 ## 安全 / RBAC ```yaml # AppProject 限制 apiVersion: argoproj.io/v1alpha1 kind: AppProject metadata: name: dev-team spec: sourceRepos: - https://github.com/myorg/dev-manifests.git destinations: - namespace: 'dev-*' server: '*' clusterResourceWhitelist: - group: '' kind: Namespace namespaceResourceWhitelist: - group: 'apps' kind: Deployment ``` dev team 只能从特定 git repo 部署到 dev-* namespace,不能改 cluster-wide 资源。 ## SSO 集成 ArgoCD 接 OIDC(Okta / Google / GitHub)→ 用 SSO 登录 UI + CLI。 ```yaml # argocd-cm ConfigMap data: oidc.config: | name: GitHub issuer: https://github.com/login/oauth clientID: ... clientSecret: ... ``` ## 真实部署 case 我们 prod + staging + 多个 dev cluster: - 1 个 manifest repo(gitops/) - 每 env 一个 ApplicationSet - 每 app 在 manifest repo 下 apps/<name>/{base,overlays/{prod,staging}}/ - image-updater 自动 promotion staging(main branch tag) - prod promotion 手动(PR + approval) ops 改东西 = PR 改 yaml。dev 看 ArgoCD UI 知道部署进度。 不需要 dev 学 kubectl。 ## 缺点 - Application CRD 增加学习 - ArgoCD 自身要运维(HA setup) - bug:自动 sync 时偶有 race condition ## 踩过的坑 1. **selfHeal 改不动 cluster**:dev 手 kubectl edit 救火 → 5 秒被 ArgoCD revert。临时 disable selfHeal 或者改 git。 2. **diff 噪声**:cluster 自动加 annotation(如 deployment.kubernetes.io/revision) → ArgoCD 看到 diff。`ignoreDifferences` 配置过滤。 3. **CRD 顺序**:先 install operator 再 apply custom resource。 sync-wave 控制。 4. **大 manifest repo 慢**:几千 yaml → ArgoCD slow。拆多 repo 或者 多 Application。 5. **secret 不放 git**:用 sealed-secret / external-secret operator, git 存加密版本。
## 起因 K8s 全套 (kubeadm) 在小机器(2-4 vCPU / 4 GB)跑得费力: - etcd + apiserver + controller-manager + scheduler 几 GB RAM - 启动 5 分钟 - 升级痛苦 但有时只想: - 边缘设备(树莓派 / IoT gateway)跑 K8s 编排 - 笔记本本地 dev - 单租户产品打包"K8s on appliance" - 小公司 1-2 server prod **k3s**(Rancher,2019+):单 binary(~50 MB),裁剪 K8s 到 ~512 MB RAM。 **microk8s**(Canonical):类似目标,更 batteries-included。 ## k3s 装 ```bash # 一键装(server) curl -sfL https://get.k3s.io | sh - # kubectl 立刻可用 sudo k3s kubectl get nodes # 或者复制 kubeconfig 用普通 kubectl sudo cp /etc/rancher/k3s/k3s.yaml ~/.kube/config sudo chown $USER ~/.kube/config ``` 完事。1 分钟起一个 K8s。 ## 加 worker node ```bash # server 拿 token sudo cat /var/lib/rancher/k3s/server/node-token # worker 上 curl -sfL https://get.k3s.io | K3S_URL=https://server:6443 K3S_TOKEN=xxx sh - ``` ## k3s 是什么 K8s - **完整 K8s API**(不是 mini K8s) - 替代 etcd 用 SQLite(也支持 etcd / MySQL / PG external) - 替代 docker 用 containerd - 内置 traefik ingress(可关) - 内置 helm controller / local storage provisioner / metrics-server - 删了 in-tree cloud provider / 实验性 feature 90% workload 跟 vanilla K8s 一样跑。 ## 资源占用 | | k3s | kubeadm K8s | docker swarm | |---|---|---|---| | RAM | 512 MB | 2 GB+ | 50 MB | | 启动 | 30s | 5 min | 5s | | Binary | 50 MB | 几百 MB | 50 MB | 树莓派 4 (4 GB RAM) 跑 k3s 余 3+ GB 给应用 → 完全实用。 ## HA k3s ```bash # server 1 curl -sfL https://get.k3s.io | sh -s - server --cluster-init # server 2 / 3 curl -sfL https://get.k3s.io | sh -s - server --server https://server1:6443 --token xxx ``` 3 个 server 自动 embedded etcd HA。 worker 同前面加。 ## microk8s Ubuntu 系强推: ```bash sudo snap install microk8s --classic sudo usermod -aG microk8s $USER microk8s status microk8s kubectl get nodes # 启用 addon microk8s enable dns ingress storage cert-manager ``` addon 系统比 k3s 友好: ``` dns / ingress / cert-manager / metallb / observability / istio / linkerd / hostpath-storage / openebs / cilium / dashboard ``` 一行启用,省手动 helm。 ## k3s vs microk8s | | k3s | microk8s | |---|---|---| | 母公司 | Rancher / SUSE | Canonical | | 分发 | shell script | snap | | 多 distro | 是 | snap 限制(Ubuntu / 部分) | | HA | embedded etcd | 自动 (3+ nodes) | | addon | 内置少,手动 helm | addon 丰富 | | 升级 | 手动 | snap 自动 | | 默认 ingress | traefik | nginx | | 体量 | 50 MB | 200 MB+ | 我倾向 k3s(更轻 + 跨 distro),但 ubuntu 系统 microk8s 顺手。 ## 适合场景 - **edge / IoT**:低资源 + 远程管理 - **CI / 测试**:临时拉一个 k3s 测 manifest - **个人 / 小 团队 prod**:1-3 server 足够 - **embedded product**:appliance 内置 K8s 不适合: - 千节点集群(k3s SQLite 不行;要 PostgreSQL 后端) - 重 K8s feature(webhooks 多 / CRD 多) 仍 OK 但优势减 - 合规要求企业级 K8s 发行版 ## k3d (k3s in docker) ```bash brew install k3d k3d cluster create mycluster --servers 3 --agents 2 kubectl get nodes ``` 3 master + 2 worker 在 5 个 docker container 起来 → laptop 测多 节点行为。 比 kind 轻量。 ## 真实部署 case 某 IoT 客户: - 100 个边缘 gateway(4 vCPU / 8 GB) - 每 gateway 跑 k3s + 几个微服务 + 本地 DB - 中心 cluster 用 Rancher 管 100 个 k3s 集群 - 应用更新通过 Fleet / ArgoCD 推 效果: - 单 gateway 装 K8s 5 分钟(自动化 script) - 中心可视化所有 edge 状态 - 应用迭代独立各 gateway vs 老方案(docker compose + ansible):管理统一 + K8s API 标准化 + 故障恢复更智能。 ## 本地 dev: k3s vs kind vs minikube ```bash # kind (K8s in docker) kind create cluster # k3d (k3s in docker) k3d cluster create # minikube (VM) minikube start ``` | | 启动 | 资源 | 多节点 | |---|---|---|---| | kind | 30s | 中 | ✅ | | k3d | 15s | 低 | ✅ | | minikube | 1 min | 高(VM) | 慢 | 我本地 dev 用 k3d。 ## 升级 k3s ```bash # 同样 curl 命令 + INSTALL_K3S_VERSION curl -sfL https://get.k3s.io | INSTALL_K3S_VERSION=v1.30.0+k3s1 sh - ``` 或者用 Rancher / system-upgrade-controller 自动滚动升级 多 node。 ## monitoring ```bash helm install kube-prometheus-stack prometheus-community/kube-prometheus-stack \ -n monitoring --create-namespace ``` 跟 vanilla K8s 一样 helm install。 metrics-server 已内置 (k3s)。 ## 与 Talos Linux 对比 Talos Linux:Linux distro for K8s。OS 本身是 K8s。 极简 + 安全 + immutable。 | | k3s | Talos | |---|---|---| | Host OS | 任意 | Talos only | | 管理 | systemd | API only(无 ssh) | | 升级 | 手动 / 工具 | 强 immutable | | 学习 | 易 | 中 | Talos 是新潮选择,适合"K8s as appliance"。 ## 踩过的坑 1. **SQLite 单 server 限制**:k3s 默认 SQLite 不支持多 server HA。 3+ server 要 embedded etcd(默认 `--cluster-init`)。 2. **storage 默认 hostpath**:pod restart 跨 node 数据丢。生产用 longhorn / NFS / cloud volume。 3. **traefik 内置版本旧**:k3s 自带 traefik 跟最新版本可能差几个版本。 `--disable traefik` + 自装最新。 4. **resource 限制**:CPU 紧张时 etcd / apiserver 慢 → pod schedule 失败。监控 system pod CPU。 5. **firewall blocking 6443**:worker 加入失败常见原因。`ufw allow 6443` / 防火墙规则。
## 起因 K8s 默认 CNI(flannel / calico iptables 模式)问题: - 服务多了 iptables 规则数万条 → packet 经过 N rules 慢 - network policy 通过 iptables 模拟 → 性能差 + 难调试 - 没原生 L7 (HTTP) policy - 跨节点流量 encap (VXLAN) 开销 **Cilium** 用 eBPF 在内核态做: - pod 间通信(直接路由 / VXLAN / WireGuard) - network policy(L3/4/7) - service LB 替代 kube-proxy - observability(hubble) - mTLS eBPF 不走 iptables 链 → 性能高 + 灵活。 ## 装 (kind 本地) ```bash # kind cluster 不带默认 CNI kind create cluster --config kind-config.yaml cat > kind-config.yaml <<EOF kind: Cluster apiVersion: kind.x-k8s.io/v1alpha4 networking: disableDefaultCNI: true kubeProxyMode: none # cilium 替代 EOF # 装 cilium cilium install --version 1.16.0 cilium status ``` ## 网络 policy(L3/L4) ```yaml apiVersion: cilium.io/v2 kind: CiliumNetworkPolicy metadata: name: api-policy namespace: app spec: endpointSelector: matchLabels: app: api ingress: - fromEndpoints: - matchLabels: app: frontend toPorts: - ports: - port: "8080" protocol: TCP ``` `api` pod 只接受 `frontend` pod 的 8080 流量。 其它源(包括同 namespace 别的 pod)阻断。 ## L7 policy (HTTP) ```yaml spec: endpointSelector: matchLabels: app: api ingress: - fromEndpoints: - matchLabels: app: frontend toPorts: - ports: - port: "8080" rules: http: - method: "GET" path: "/api/users/.*" - method: "POST" path: "/api/login" ``` frontend 只能 GET `/api/users/*` 和 POST `/api/login`,其它 404。 传统 iptables 做不到。 ## hubble (observability) ```bash cilium hubble enable # CLI hubble observe --namespace=app TIMESTAMP SOURCE DESTINATION TYPE VERDICT 12:34:56 frontend-xxx:34521 api-yyy:8080 L7 ALLOWED (GET /api/users/42) 12:34:57 frontend-xxx:34522 api-yyy:8080 L7 DROPPED (POST /admin/delete) ``` 每 packet 看 source / dest / verdict。 debug network 神器。 hubble UI 浏览器看: ```bash cilium hubble ui ``` 实时 service map + flow log。 ## kube-proxy 替代 ```bash # install 时 --set kubeProxyReplacement=true helm install cilium ... --set kubeProxyReplacement=true ``` Cilium 用 eBPF 实现 service routing → 删 kube-proxy → 删几万条 iptables。 性能: | | iptables | Cilium eBPF | |---|---|---| | service connect 延迟 | 50 μs | 5 μs | | pod-to-pod throughput | 7 Gbps | 9.5 Gbps | | iptables rule 数 | 几万 | 0 | 大 cluster 显著。 ## 跨节点流量 模式选: - **VXLAN**:兼容性最好(默认) - **Geneve**:VXLAN 替代 - **直接路由**:节点同 L2 网(性能最好) - **WireGuard**:跨 region 加密 - **IPsec**:类似 我们 prod 用直接路由(节点同 VPC)+ WireGuard 用于跨 region。 ## bandwidth manager ```yaml apiVersion: v1 kind: Pod metadata: annotations: kubernetes.io/egress-bandwidth: "10M" ``` cilium 用 eBPF 限 pod 出口带宽 → 防 noisy neighbor。 ## clustermesh (多 cluster) ```bash cilium clustermesh enable --context cluster1 cilium clustermesh connect --context cluster1 --destination-context cluster2 ``` 两个 cluster 互通 service: ```yaml # Service on cluster2 metadata: annotations: service.cilium.io/global: "true" ``` cluster1 的 pod 访问该 service → cilium 跨 cluster 路由。 无需 service mesh / API gateway。 ## mTLS (cilium 1.14+) ```yaml spec: endpointSelector: matchLabels: { app: api } ingress: - fromEndpoints: - matchLabels: { app: frontend } authentication: mode: required # 强制 mTLS ``` cilium 用 SPIFFE 标识自动 mTLS。 比 Istio 简单(不需要 sidecar)。 ## 性能 CNI throughput benchmark(10 Gbps 网络): | | Pod-to-Pod | |---|---| | flannel VXLAN | 6 Gbps | | calico iptables | 7 Gbps | | calico eBPF | 9 Gbps | | Cilium (native routing) | 9.5 Gbps | cilium 几乎跑满。 ## 与 calico eBPF 对比 | | Cilium | Calico (eBPF mode) | |---|---|---| | L7 policy | ✅ | 弱 | | Hubble observability | ✅ 强 | 基本 | | clustermesh | ✅ | 弱 | | mTLS | ✅ | 计划中 | | 复杂度 | 高 | 中 | | 生态 | 大(CNCF) | 大 | 两者都好。cilium 是更现代 / 功能多。calico 更老更广。 ## 与 Istio 对比 | | Cilium | Istio | |---|---|---| | 层次 | CNI + L7 policy | service mesh (L7+) | | sidecar | 不需要 | envoy sidecar | | 资源开销 | 低 (eBPF kernel) | 高 (sidecar 每 pod) | | mTLS | ✅ | ✅ | | traffic policy | 中 | 强 (canary / mirror 等) | | 复杂度 | 中 | 高 | Cilium Service Mesh(cilium 1.12+)能部分替代 Istio。 重 traffic management 还是 Istio。 ## 实战 case:从 calico 迁 cilium 我们 prod cluster 用 calico 几年,问题: - network policy 调试痛苦 - 没 L7 policy - 缺 observability 迁 cilium: 1. 装 cilium + 关 calico(drain 一台一台测) 2. policy 翻译(calico NetworkPolicy → CiliumNetworkPolicy,多数语法兼容) 3. 启用 hubble + kube-proxy replacement 4. 启用 mTLS(替代 Istio mTLS) 效果: - service-to-service latency 平均 -30%(无 iptables) - 一次 debug "为啥 A 连不上 B" 从一上午 → 5 分钟(hubble 直接看 verdict) - 节点 CPU -10%(kube-proxy 不跑了) 迁移挑战: - L7 policy 需要 sidecar (envoy embed in cilium),资源 +20% - WireGuard 跨 region 需要内核 5.6+ ## 监控 prometheus metrics 几百个: - `cilium_drop_count_total` - `cilium_policy_l7_total` - `cilium_endpoint_state` Grafana 官方 dashboard 拉来直接看。 ## 踩过的坑 1. **内核版本**:很多 eBPF feature 要内核 5.10+。Ubuntu 20.04 默认 5.4 → 升级。 2. **kube-proxy replacement + HostNetwork**:HostNetwork pod 跟 cilium service 不交互 → 部分场景 fall back iptables。 3. **policy 默认 allow**:没 CiliumNetworkPolicy 时 default 允许所有 流量。要 default-deny → 加 catch-all policy。 4. **hubble retention**:默认内存只存 4096 flow → 大 cluster 看不到 历史。配 hubble-export 推 ELK。 5. **multi-cluster identity 冲突**:clustermesh 时不同 cluster pod labels 同 → 路由错。namespace / label 命名规范。