1. 通用部署注意事项#
- 版本兼容性:K8s 各项组件都存在版本兼容性问题, 因此在部署时需要注意版本的选择, 尤其是
containerd
,kubernetes-dashboard
,etcd
等组件。 - Calico 网络插件:部署时可能需翻墙。若使用国内源,需修改
containerd
的config.toml
文件。如还无法部署成功, 可尝试手动拉取镜像再部署。 - Helm 国内源:Helm 本质是 Charts, 实际的拉取镜像还是在集群上进行, 所以还是要保证集群的
containerd
源可用。 - 本地管理工具:在个人电脑上安装
helm
和kubectl
, 并配置好环境变量后, 可以直接使用这两个命令来管理远程的 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 集群高可用流程#
- 检测故障:Kubernetes (通过 Node Controller 或 Liveness Probe) 检测到 Pod 或其所在 Node 出现问题。
- 触发重建:副本控制器 (Deployment/StatefulSet) 发现运行的 Pod 数量不足。
- 调度新 Pod:Kubernetes 调度器在另一个健康的 Node 上选择一个位置来创建新的 Pod。
- 使用持久化配置 (如果启用):
- 新的 Pod 会根据其定义请求之前使用的同一个 PersistentVolumeClaim (PVC)。
- 如果是网络存储 (如 NFS),新 Pod 直接挂载访问。
- 如果是块存储 (如 EBS),Kubernetes 和 CSI 驱动会确保存储卷从故障 Node 安全分离,然后附加到新 Node,再由新 Pod 挂载。
- 服务发现: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
对于 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 转发流量时可能出现的单点故障。