跳过正文
Background Image
  1. Posts/

K8s 集群部署踩过的坑

·432 字·3 分钟· loading · loading ·
yuzjing
作者
yuzjing
目录

1. 通用部署注意事项
#

  1. 版本兼容性:K8s 各项组件都存在版本兼容性问题, 因此在部署时需要注意版本的选择, 尤其是 containerd, kubernetes-dashboard, etcd 等组件。
  2. Calico 网络插件:部署时可能需翻墙。若使用国内源,需修改 containerdconfig.toml 文件。如还无法部署成功, 可尝试手动拉取镜像再部署。
  3. Helm 国内源:Helm 本质是 Charts, 实际的拉取镜像还是在集群上进行, 所以还是要保证集群的 containerd 源可用。
  4. 本地管理工具:在个人电脑上安装 helmkubectl, 并配置好环境变量后, 可以直接使用这两个命令来管理远程的 K8s 集群。

2. Dashboard 没数据问题
#

安装好 Dashboard 后发现没有数据,可能是以下原因:

  • 命名空间选择错误:请检查是否选择了正确的命名空间,默认的 default 命名空间是没有监控数据的。
  • Metrics Server 未安装:需要安装 metrics-server 组件来采集指标。
    1
    
    kubectl apply -f https://github.com/kubernetes-sigs/metrics-server/releases/latest/download/components.yaml
    
  • Kubelet 证书问题:如果 Kubelet 的证书不是由 Metrics Server 信任的 CA 签发的,TLS 握手会失败,导致无法获取指标。此时需要在 metrics-server 的部署配置中,为其 args 添加以下参数,以信任不安全的 Kubelet 证书:
    1
    
    - --kubelet-insecure-tls=true
    

3. K8s 集群高可用流程
#

  1. 检测故障:Kubernetes (通过 Node Controller 或 Liveness Probe) 检测到 Pod 或其所在 Node 出现问题。
  2. 触发重建:副本控制器 (Deployment/StatefulSet) 发现运行的 Pod 数量不足。
  3. 调度新 Pod:Kubernetes 调度器在另一个健康的 Node 上选择一个位置来创建新的 Pod。
  4. 使用持久化配置 (如果启用):
    • 新的 Pod 会根据其定义请求之前使用的同一个 PersistentVolumeClaim (PVC)。
    • 如果是网络存储 (如 NFS),新 Pod 直接挂载访问。
    • 如果是块存储 (如 EBS),Kubernetes 和 CSI 驱动会确保存储卷从故障 Node 安全分离,然后附加到新 Node,再由新 Pod 挂载。
  5. 服务发现:Service 会将流量自动导向这个新的、健康的 Pod 实例。

4. 如何查看期望副本数
#

  • 对于 Deployment:
    1
    
    kubectl get deployment <deployment-name> -n <namespace> -o wide
    

观察 DESIRED 列即可。

对于 StatefulSet:
code Shell

IGNORE_WHEN_COPYING_START IGNORE_WHEN_COPYING_END

kubectl get statefulset -n -o wide

对于 ReplicaSet: code Shell

IGNORE_WHEN_COPYING_START
IGNORE_WHEN_COPYING_END

      
kubectl get replicaset <replicaset-name> -n <namespace> -o wide

5. 理解 Pod 的 READY 列和副本数
#

kubectl get pods 中 READY 列的分母(例如 1/1 中的第二个 1)是单个 Pod 内部定义的容器数量。

这与控制器的期望副本数是两个概念。期望副本数指的是控制器应该运行多少个这样的 Pod 实例。

"Ready的容器数可以理解为编排":是的,Pod 内可以有多个容器,它们被 Kubernetes "编排"在一起,作为一个整体来调度和管理。

控制器的期望副本数需要通过 kubectl get deployment/statefulset 来查看。

6. 关于持久化存储
#

如果你的 Pod 没有配置持久化存储(即它使用的是 Pod 的临时存储,如 emptyDir,或者是容器文件系统本身的临时层),那么:当 Pod 因任何原因被删除并重新创建时,Pod 内所有容器写入到其临时存储中的数据都会丢失。

新的 Pod 实例会以一个全新的、干净的状态启动。

7. 理解 Service 中的端口
#

一个请求的流向通常是这样的: 外部请求 -> Node(NodeIP:nodePort) -> Service(ClusterIP:port) -> Pod(PodIP:targetPort)

targetPort (目标端口)

    定义:Service 将流量最终转发到后端 Pod 容器监听的端口。

    作用域:Pod 内部。

    值:可以是数字(8080)或在 Pod 中定义的端口名称(http-api)。

nodePort (节点端口)

    定义:当 Service 类型为 NodePort 或 LoadBalancer 时,在每个 Node 的 IP 上暴露的静态端口。

    作用域:集群 Node 外部。

    值:默认范围是 30000-32767。允许从集群外部通过 http://<Node-IP>:<nodePort> 访问。

port (服务端口)

    定义:Service 自身在其内部 ClusterIP 地址上暴露的端口。

    作用域:集群内部。

    作用:集群内部的其他 Pod 可以通过 http://<ServiceName>.<Namespace>.svc.cluster.local:<port> 访问此服务。

8. 部署 Fluentd 遇到的坑
#

部署 bitnami/fluentd 时遇到了以下问题 (成功的 values 见 Fluentd.yaml 文件):

缺少 CRI 插件:官方 chart 缺少 forword 的 CRI 插件, 默认是 drop all, 导致容器日志无法被正确处理和解析。

缺少 Elasticsearch 插件:其 Aggregator 同样没有 Elasticsearch 的插件, 导致无法将日志发送到 ES。

协议错误:连接 ES 时, 默认的 scheme 是 http, 但 ES 的 9200 端口通常是 https, 需要修改。

认证失败:连接 ES 时需要指定用户名和密码(通常是 Kibana 的登录凭据),否则会报 401 错误。

命名空间标签问题:发现 efk 命名空间的日志被 ES 全部拒绝。AI 提示可能是标签中包含 . 和 / 影响。检查发现该命名空间的 labels 多了一行 name: efk。
code Yaml

IGNORE_WHEN_COPYING_START
IGNORE_WHEN_COPYING_END

      
# 错误的命名空间标签
❯ kubectl get ns efk -o yaml
apiVersion: v1
kind: Namespace
metadata:
  creationTimestamp: "2025-06-06T06:56:03Z"
  labels:
    kubernetes.io/metadata.name: efk
    name: efk  # <-- 这行是多余的
...

# 正常的命名空间标签
❯ kubectl get ns monitoring -o yaml
apiVersion: v1
kind: Namespace
metadata:
  creationTimestamp: "2025-05-22T05:45:59Z"
  labels:
    kubernetes.io/metadata.name: monitoring
  name: monitoring
...

    

    神奇的是,尝试删除多余标签并用 Ruby 脚本替换特殊字符都无效。但第二天该问题自动解决,看来确实是 name 标签的问题。

9. Ingress 和 MetalLB:解决外部访问问题
#

Ingress 工作在7层(应用层),可以实现内部反向代理和负载均衡。外部通过访问 Ingress Controller 的 nodePort 来访问服务。

缺点:nodePort 必须使用高位端口(如 30000+),外部访问不方便且不优雅。

解决方案:安装 MetalLB 插件。

    作用:当 Service 类型为 LoadBalancer 时,MetalLB 会自动从预设的外部地址池中分配一个 IP 给这个 Service,作为其 EXTERNAL-IP。

    优点:

        解决了访问需要加高位端口的问题,可以直接用 IP 访问。

        提供了高可用方案,避免了使用 iptables 转发流量时可能出现的单点故障。