在裸机内网环境中部署 Kubernetes 时,最容易卡住的通常不是 Pod 本身,而是入口流量、LoadBalancer 地址分配、证书、Service 与 Gateway 之间的关系。本文记录一套两节点开发环境的完整落地路径:从 kubeadm 初始化集群,到安装 Calico、MetalLB、Envoy Gateway,再到通过独立域名暴露 Kite 管理界面。
适用环境
本文示例基于以下环境:
- Ubuntu Server 26.04
- Kubernetes v1.36.x
- kubeadm
- containerd
- Calico CNI
- Envoy Gateway
- MetalLB Layer 2
- Kite Kubernetes Web UI
- 1 个控制平面节点和 1 个工作节点
- 裸机内网,节点位于同一个二层网段
示例拓扑如下:
| 角色 |
主机名 |
IP |
| 控制平面 |
k8s-master-1 |
192.168.110.200 |
| 工作节点 |
k8s-node-1 |
192.168.110.201 |
MetalLB 地址池建议预留:
1
| 192.168.110.220-192.168.110.230
|
这些 IP 必须满足以下条件:
- 不与任何主机冲突
- 不在 DHCP 地址池内
- 与 Kubernetes 节点处于同一个 VLAN 或二层网络
- 已经和网络管理员确认可以使用
总体架构
开发环境推荐链路如下:
1 2 3 4 5 6 7 8 9 10 11
| Calico | MetalLB Layer 2 | Envoy Gateway | HTTPRoute / TLSRoute | Kubernetes Service | Deployment
|
组件选择:
- Gateway API 使用标准 CRD 通道。
- Gateway Controller 使用 Envoy Gateway。
- 裸机 LoadBalancer 使用 MetalLB Layer 2。
- TLS 在开发环境使用自签名证书,测试和生产环境使用 cert-manager 或企业 CA。
- Kite 使用单独域名访问,不建议挂在
/kite 子路径下。
当前场景不建议仅为了 Gateway API 更换 Calico。只有当项目计划同时引入 eBPF、Cilium NetworkPolicy、Cilium Service LB 和 Cilium Gateway API 时,再考虑整体迁移到 Cilium。
安装 Kubernetes 基础环境
如果集群已经初始化并且节点已经加入,可以跳过本节,直接从安装 Kite、Envoy Gateway 和 MetalLB 开始。
设置主机名和 hosts
在 192.168.110.200 上执行:
1
| hostnamectl set-hostname k8s-master-1
|
在 192.168.110.201 上执行:
1
| hostnamectl set-hostname k8s-node-1
|
两台机器都执行:
1 2 3 4 5 6 7 8
| sed -i '/k8s-master-1/d;/k8s-node-1/d' /etc/hosts
cat >> /etc/hosts <<'EOF' 192.168.110.200 k8s-master-1 192.168.110.201 k8s-node-1 EOF
getent hosts k8s-master-1 k8s-node-1
|
互相测试网络:
1 2
| ping -c 3 192.168.110.200 ping -c 3 192.168.110.201
|
安装基础工具
两台机器都执行:
1 2 3 4 5 6 7 8 9 10 11 12
| apt-get update apt-get full-upgrade -y apt-get install -y \ ca-certificates \ curl \ gpg \ chrony \ conntrack \ socat \ openssl
systemctl enable --now chrony
|
如存在重启标记,应重启后继续:
1
| test -f /var/run/reboot-required && echo "请重启后继续"
|
关闭 swap
两台机器都执行:
1 2 3
| swapoff -a sed -ri '/\sswap\s/ s/^/#/' /etc/fstab swapon --show
|
swapon --show 必须没有输出。
配置内核模块和 sysctl
两台机器都执行:
1 2 3 4 5 6 7
| cat > /etc/modules-load.d/k8s.conf <<'EOF' overlay br_netfilter EOF
modprobe overlay modprobe br_netfilter
|
配置网络转发:
1 2 3 4 5 6 7
| cat > /etc/sysctl.d/99-kubernetes-cri.conf <<'EOF' net.bridge.bridge-nf-call-iptables = 1 net.bridge.bridge-nf-call-ip6tables = 1 net.ipv4.ip_forward = 1 EOF
sysctl --system
|
确认:
1 2
| sysctl net.ipv4.ip_forward lsmod | grep -E 'overlay|br_netfilter'
|
配置防火墙
两台节点之间至少需要允许:
| 方向 |
协议/端口 |
用途 |
| 管理端到控制平面 |
TCP 6443 |
Kubernetes API |
| 控制平面自身 |
TCP 2379-2380 |
etcd |
| 控制平面与节点 |
TCP 10250 |
kubelet |
| 节点之间 |
UDP 4789 |
Calico VXLAN |
| 节点之间 |
TCP/UDP 7946 |
MetalLB memberlist |
| 外部到工作节点 |
TCP/UDP 30000-32767 |
NodePort,可选 |
如果这是隔离的开发内网,可以暂时关闭 UFW:
1 2 3
| if command -v ufw >/dev/null 2>&1; then ufw disable fi
|
生产环境不要无条件关闭防火墙,应在上游防火墙精确放行端口。
安装 containerd
两台机器都执行:
1 2 3 4
| apt-get install -y containerd runc
mkdir -p /etc/containerd containerd config default > /etc/containerd/config.toml
|
配置 systemd cgroup:
1 2
| sed -i 's/SystemdCgroup = false/SystemdCgroup = true/' \ /etc/containerd/config.toml
|
确认 CRI 没有被禁用:
1 2
| grep -nE 'disabled_plugins|SystemdCgroup' \ /etc/containerd/config.toml
|
如果看到:
1
| disabled_plugins = ["cri"]
|
执行:
1 2
| sed -i '/disabled_plugins.*cri/s/^/#/' \ /etc/containerd/config.toml
|
启动 containerd:
1 2 3 4 5 6
| systemctl daemon-reload systemctl enable --now containerd systemctl restart containerd
systemctl status containerd --no-pager ctr plugins ls | grep -E 'cri|io.containerd'
|
Kubernetes v1.36 要求 CRI v1;containerd 和 kubelet 的 cgroup 驱动必须一致,推荐使用 systemd。
安装 kubeadm、kubelet 和 kubectl
以下使用 Kubernetes v1.36 小版本仓库。官方仓库使用 pkgs.k8s.io,不要使用已经废弃的 apt.kubernetes.io。
两台机器都执行:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| K8S_MINOR='v1.36'
mkdir -p -m 755 /etc/apt/keyrings
curl -fsSL \ "https://pkgs.k8s.io/core:/stable:/${K8S_MINOR}/deb/Release.key" \ | gpg --dearmor --yes \ -o /etc/apt/keyrings/kubernetes-apt-keyring.gpg
echo "deb [signed-by=/etc/apt/keyrings/kubernetes-apt-keyring.gpg] https://pkgs.k8s.io/core:/stable:/${K8S_MINOR}/deb/ /" \ > /etc/apt/sources.list.d/kubernetes.list
apt-get update apt-cache madison kubeadm
apt-get install -y kubelet kubeadm kubectl apt-mark hold kubelet kubeadm kubectl
systemctl enable kubelet
kubeadm version -o short kubelet --version kubectl version --client
|
两台机器的 kubeadm、kubelet 和 kubectl 主版本必须一致。
初始化控制平面
只在 192.168.110.200 执行。
先拉取 Kubernetes 核心镜像:
1 2
| kubeadm config images pull \ --cri-socket unix:///run/containerd/containerd.sock
|
如果访问 registry.k8s.io 超时,应先配置 containerd 代理或使用内部镜像仓库,不要直接使用 --ignore-preflight-errors=all。
1 2 3 4 5 6 7 8 9 10 11 12 13
| mkdir -p /etc/systemd/system/containerd.service.d
cat > /etc/systemd/system/containerd.service.d/proxy.conf <<'EOF' [Service] Environment="HTTP_PROXY=http://PROXY_HOST:PROXY_PORT" Environment="HTTPS_PROXY=http://PROXY_HOST:PROXY_PORT" Environment="NO_PROXY=127.0.0.1,localhost,192.168.110.0/24,192.168.0.0/16,10.96.0.0/12,.svc,.cluster.local" EOF
systemctl daemon-reload systemctl restart containerd
systemctl show containerd -p Environment
|
初始化集群:
1 2 3 4 5 6 7
| kubeadm init \ --apiserver-advertise-address=192.168.110.200 \ --control-plane-endpoint=192.168.110.200:6443 \ --pod-network-cidr=192.168.0.0/16 \ --service-cidr=10.96.0.0/12 \ --cri-socket=unix:///run/containerd/containerd.sock \ --kubernetes-version="$(kubeadm version -o short)"
|
保存命令输出的 kubeadm join 命令,后续 worker 加入集群需要使用。
配置 kubectl:
1 2 3 4 5 6
| export KUBECONFIG=/etc/kubernetes/admin.conf kubectl get nodes
mkdir -p $HOME/.kube sudo cp /etc/kubernetes/admin.conf $HOME/.kube/config sudo chown $(id -u):$(id -g) $HOME/.kube/config
|
此时节点显示 NotReady 是正常的,因为 CNI 尚未安装。
注意:/etc/kubernetes/admin.conf 具有集群管理员权限,不要复制给不可信用户。
安装 Calico CNI
仍然在控制平面执行。本文固定使用 Calico v3.32.1:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| mkdir -p /root/calico-v3.32.1 cd /root/calico-v3.32.1
curl -fsSLo operator-crds.yaml \ https://raw.githubusercontent.com/projectcalico/calico/v3.32.1/manifests/operator-crds.yaml
curl -fsSLo tigera-operator.yaml \ https://raw.githubusercontent.com/projectcalico/calico/v3.32.1/manifests/tigera-operator.yaml
curl -fsSLo custom-resources.yaml \ https://raw.githubusercontent.com/projectcalico/calico/v3.32.1/manifests/custom-resources.yaml
kubectl apply -f operator-crds.yaml kubectl apply -f tigera-operator.yaml
kubectl -n tigera-operator rollout status \ deployment/tigera-operator \ --timeout=5m
kubectl apply -f custom-resources.yaml
|
等待组件就绪:
1 2
| kubectl get tigerastatus watch kubectl get pods -A -o wide
|
Calico 使用的 Pod 网段必须与物理网络不重叠。本文示例使用:
加入工作节点
在控制平面生成新的 join 命令:
1 2 3
| kubeadm token create \ --ttl 24h \ --print-join-command
|
把输出复制到 192.168.110.201,并追加 containerd 参数:
1 2 3 4
| kubeadm join 192.168.110.200:6443 \ --token <TOKEN> \ --discovery-token-ca-cert-hash sha256:<HASH> \ --cri-socket unix:///run/containerd/containerd.sock
|
回到控制平面验证:
1 2
| watch kubectl get nodes -o wide watch kubectl get pods -A -o wide
|
最终应看到两台节点都处于 Ready:
| NAME |
STATUS |
ROLES |
INTERNAL-IP |
CONTAINER-RUNTIME |
| k8s-master-1 |
Ready |
control-plane |
192.168.110.200 |
containerd |
| k8s-node-1 |
Ready |
<none> |
192.168.110.201 |
containerd |
Kubernetes 基础验收
1 2 3 4
| kubectl cluster-info kubectl get --raw='/readyz?verbose' kubectl get nodes -o wide kubectl get pods -A
|
部署一个简单测试应用:
1 2 3
| kubectl create deployment nginx --image=nginx:stable kubectl expose deployment nginx --port=80 kubectl get deployment,pod,svc -o wide
|
测试集群内 DNS 和 Service:
1 2 3 4 5
| kubectl run nettest \ --rm -it \ --restart=Never \ --image=busybox:1.36 \ -- wget -qO- http://nginx
|
清理测试应用:
1 2
| kubectl delete deployment nginx kubectl delete service nginx
|
安装 Kite
Kite 是一个 Kubernetes Web UI。本文建议通过独立域名访问 Kite,而不是挂在某个已有域名的子路径下。
根据官方文档安装
先确认 Helm:
如果没有 Helm,先按 Helm 官方文档安装。Kite 的安装方式以官方文档为准,完成安装后重点确认 Service:
1 2
| kubectl get svc kite -n kite-system kubectl get pods -n kite-system -l app=kite -o wide
|
本文后续假设 Kite Service 位于 kite-system 命名空间,并监听 8080:
1
| kite ClusterIP ... 8080/TCP
|
Gateway API 与 Envoy Gateway
开发环境推荐:
1 2 3 4
| Envoy Gateway + port-forward 或 MetalLB + 自签名证书 + HTTPRoute
|
测试环境推荐:
1 2 3 4 5
| Envoy Gateway + MetalLB Layer 2 + cert-manager + 内网 DNS + 与生产一致的 Gateway API 和 Envoy Gateway 版本
|
生产环境推荐:
1 2 3 4 5
| Envoy Gateway + MetalLB BGP 或外部负载均衡器 + cert-manager 或企业 CA + GitOps + Prometheus、日志和告警
|
当前 1 个 control-plane + 1 个 worker 只能作为开发或验证环境,不是高可用生产拓扑。
安装 Gateway API 与 Envoy Gateway CRD
下面固定使用 Envoy Gateway v1.9.0。如果更换版本,Helm Chart 和 quickstart YAML 必须使用相同版本。
1 2 3 4 5 6 7
| helm template eg-crds \ oci://docker.io/envoyproxy/gateway-crds-helm \ --version v1.9.0 \ --set crds.gatewayAPI.enabled=true \ --set crds.gatewayAPI.channel=standard \ --set crds.envoyGateway.enabled=true \ | kubectl apply --server-side -f -
|
如果出现:
1
| apiVersion not set, kind not set
|
将输出保存到文件并使用:
1 2 3 4 5 6 7 8 9
| helm template eg-crds \ oci://docker.io/envoyproxy/gateway-crds-helm \ --version v1.9.0 \ --set crds.gatewayAPI.enabled=true \ --set crds.gatewayAPI.channel=standard \ --set crds.envoyGateway.enabled=true \ > /tmp/eg-crds.yaml
kubectl apply --server-side --validate=false -f /tmp/eg-crds.yaml
|
如果当前集群没有由其他组件管理 Gateway API CRD,也可以直接让主 chart 管理 CRD:
1 2 3 4 5
| helm install eg \ oci://docker.io/envoyproxy/gateway-helm \ --version v1.9.0 \ -n envoy-gateway-system \ --create-namespace
|
两种 CRD 管理方式不要混用。
安装 Envoy Gateway Controller
如果已经单独安装 CRD:
1 2 3 4 5 6
| helm upgrade --install eg \ oci://docker.io/envoyproxy/gateway-helm \ --version v1.9.0 \ -n envoy-gateway-system \ --create-namespace \ --set crds.enabled=false
|
等待就绪:
1 2 3 4 5 6 7
| kubectl wait \ --timeout=5m \ -n envoy-gateway-system \ deployment/envoy-gateway \ --for=condition=Available
kubectl get pods -n envoy-gateway-system -o wide
|
部署官方示例
1 2 3
| kubectl apply -f \ https://github.com/envoyproxy/gateway/releases/download/v1.9.0/quickstart.yaml \ -n default
|
检查资源状态:
1 2 3
| kubectl get gatewayclass kubectl get gateway,httproute -A kubectl get pods -A -o wide
|
重点看这些条件:
1 2 3 4
| GatewayClass: Accepted=True Gateway: Programmed=True HTTPRoute: Accepted=True HTTPRoute: ResolvedRefs=True
|
使用 port-forward 验证
查找 Envoy 数据面 Service:
1 2 3 4 5 6
| export ENVOY_SERVICE=$(kubectl get svc \ -n envoy-gateway-system \ --selector=gateway.envoyproxy.io/owning-gateway-namespace=default,gateway.envoyproxy.io/owning-gateway-name=eg \ -o jsonpath='{.items[0].metadata.name}')
echo "$ENVOY_SERVICE"
|
转发:
1 2
| kubectl -n envoy-gateway-system port-forward \ service/${ENVOY_SERVICE} 8888:80
|
另开终端测试:
1 2 3
| curl -v \ -H "Host: www.example.com" \ http://127.0.0.1:8888/get
|
如果返回示例应用内容,说明 Gateway、HTTPRoute、Envoy 数据面和后端 Service 均已连通。如果返回 404,优先检查 Host 是否与 HTTPRoute.spec.hostnames 一致。
节点位于同一网段时,开发环境可以使用 MetalLB Layer 2 模式。
网络准备
MetalLB Layer 2 需要:
- 节点间 TCP/UDP
7946
- 客户端和节点处于可互通的二层网络
- 地址池不与 DHCP 或其他主机冲突
如果启用 UFW:
1 2
| ufw allow from 192.168.110.0/24 to any port 7946 proto tcp ufw allow from 192.168.110.0/24 to any port 7946 proto udp
|
检查 kube-proxy
1 2
| kubectl -n kube-system get configmap kube-proxy \ -o jsonpath='{.data.config\.conf}' | grep -E 'mode:|strictARP'
|
如果是 IPVS 模式,确保:
修改后重启 kube-proxy:
1
| kubectl -n kube-system rollout restart daemonset/kube-proxy
|
本文固定使用 MetalLB v0.16.1:
1 2 3 4 5 6 7 8 9 10 11 12 13
| kubectl create namespace metallb-system \ --dry-run=client -o yaml | kubectl apply -f -
kubectl label namespace metallb-system \ pod-security.kubernetes.io/enforce=privileged \ pod-security.kubernetes.io/audit=privileged \ pod-security.kubernetes.io/warn=privileged \ --overwrite
curl -fsSLo /root/metallb-native-v0.16.1.yaml \ https://raw.githubusercontent.com/metallb/metallb/v0.16.1/config/manifests/metallb-native.yaml
kubectl apply -f /root/metallb-native-v0.16.1.yaml
|
等待:
1 2 3 4 5 6 7 8 9
| kubectl wait \ --namespace metallb-system \ --for=condition=Available \ deployment/controller \ --timeout=5m
kubectl rollout status daemonset/speaker \ -n metallb-system \ --timeout=5m
|
检查:
1 2
| kubectl get pods -n metallb-system -o wide kubectl get crd | grep metallb
|
配置地址池
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| cat > /root/metallb-l2-config.yaml <<'EOF' apiVersion: metallb.io/v1beta1 kind: IPAddressPool metadata: name: lan-pool namespace: metallb-system spec: addresses: - 192.168.110.220-192.168.110.230 --- apiVersion: metallb.io/v1beta1 kind: L2Advertisement metadata: name: lan-l2 namespace: metallb-system spec: ipAddressPools: - lan-pool EOF
kubectl apply -f /root/metallb-l2-config.yaml
|
确认:
1 2
| kubectl get ipaddresspool -n metallb-system kubectl get l2advertisement -n metallb-system
|
测试 LoadBalancer
1 2 3 4 5 6 7 8 9 10
| kubectl create namespace metallb-test \ --dry-run=client -o yaml | kubectl apply -f -
kubectl -n metallb-test create deployment nginx \ --image=nginx:stable
kubectl -n metallb-test expose deployment nginx \ --port=80 \ --target-port=80 \ --type=LoadBalancer
|
查看:
1
| kubectl get svc -n metallb-test -w
|
如果输出类似:
1 2
| NAME TYPE EXTERNAL-IP PORT(S) nginx LoadBalancer 192.168.110.221 80:29286/TCP
|
访问时必须使用实际分配到的 EXTERNAL-IP,而不是地址池中的其他地址:
1
| curl -v http://192.168.110.221
|
检查后端:
1 2 3
| kubectl get pods -n metallb-test -o wide kubectl get endpoints -n metallb-test nginx kubectl describe svc -n metallb-test nginx
|
如果 EXTERNAL-IP 已分配但访问不通:
1 2 3
| kubectl logs -n metallb-system deployment/controller --tail=100 kubectl logs -n metallb-system daemonset/speaker --since=10m ip neigh show 192.168.110.221
|
从其他 Linux 客户端测试 ARP:
1
| arping -I eth0 192.168.110.221
|
把 eth0 换成实际网卡名。
将 Kite 接入 Envoy Gateway
推荐使用独立域名:
不建议优先使用:
1
| https://example.com/kite/
|
Kite 默认 Service 是 HTTP kite:8080,因此不需要额外的 HTTPS 后端适配、Envoy Gateway Backend 资源或 insecureSkipVerify。
确认 Kite 后端
1
| kubectl get svc kite -n kite-system
|
确认 Service 存在并监听 8080:
1
| kite ClusterIP ... 8080/TCP
|
创建 Gateway TLS 证书
开发环境生成自签名证书:
1 2 3 4 5 6 7 8 9 10
| openssl req -x509 -nodes -days 365 -newkey rsa:2048 \ -keyout /root/kite.k8s.local.key \ -out /root/kite.k8s.local.crt \ -subj "/CN=kite.k8s.local" \ -addext "subjectAltName=DNS:kite.k8s.local"
kubectl -n kite-system create secret tls kite-gateway-cert \ --key=/root/kite.k8s.local.key \ --cert=/root/kite.k8s.local.crt \ --dry-run=client -o yaml | kubectl apply -f -
|
创建 Kite Gateway 和 HTTPRoute
前提是已经存在 Envoy Gateway 的 GatewayClass:
1
| kubectl get gatewayclass
|
如果名称不是 eg,将下面 YAML 中的 gatewayClassName 改成实际名称。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41
| cat <<'EOF' | kubectl apply -f - apiVersion: gateway.networking.k8s.io/v1 kind: Gateway metadata: name: kite-gateway namespace: kite-system spec: gatewayClassName: eg listeners: - name: https hostname: kite.k8s.local port: 443 protocol: HTTPS tls: mode: Terminate certificateRefs: - name: kite-gateway-cert allowedRoutes: namespaces: from: Same --- apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: name: kite-route namespace: kite-system spec: parentRefs: - name: kite-gateway sectionName: https hostnames: - kite.k8s.local rules: - matches: - path: type: PathPrefix value: / backendRefs: - name: kite port: 8080 EOF
|
获取 Kite Gateway IP
1 2 3 4 5 6 7
| kubectl get gateway \ -n kite-system \ kite-gateway -o wide
kubectl get svc -n envoy-gateway-system \ -l gateway.envoyproxy.io/owning-gateway-namespace=kite-system,gateway.envoyproxy.io/owning-gateway-name=kite-gateway \ -o wide
|
如果 MetalLB 分配:
则在 Windows 客户端的 hosts 文件中添加:
1
| 192.168.110.222 kite.k8s.local
|
hosts 文件路径:
1
| C:\Windows\System32\drivers\etc\hosts
|
测试访问
在控制平面测试:
1 2 3
| curl -vk \ --resolve kite.k8s.local:443:192.168.110.222 \ https://kite.k8s.local/
|
浏览器访问:
开发环境使用自签名证书,浏览器出现证书警告属于预期结果。
登录 Token:
1
| kubectl -n kite-system create token kite-admin
|
常见故障排查
worker 上 kubectl 连接 localhost:8080
如果在 worker 直接执行 kubectl 时看到:
1
| The connection to the server localhost:8080 was refused
|
这不代表集群故障,只代表当前用户没有 kubeconfig。如确实需要在 worker 使用 kubectl:
1 2 3
| mkdir -p ~/.kube scp root@192.168.110.200:/etc/kubernetes/admin.conf ~/.kube/config chmod 600 ~/.kube/config
|
生产环境不建议把管理员 kubeconfig 长期复制到 worker。
containerd 镜像拉取超时
如果 Kubernetes 镜像拉取超时,例如:
1 2
| failed to pull image "registry.k8s.io/pause:3.10.1" dial tcp 74.125.20.82:443: i/o timeout
|
这通常是出口、防火墙或代理问题,不是 kubeadm 参数问题。
测试:
1 2 3 4
| curl -I --connect-timeout 10 --max-time 20 \ https://registry.k8s.io/v2/
ctr -n k8s.io images pull registry.k8s.io/pause:3.10.1
|
如果 worker 无法拉取镜像,可以从 master 导出后导入:
1 2 3 4 5 6 7 8 9 10
| ctr -n k8s.io images export /root/worker-images.tar \ registry.k8s.io/pause:3.10.1
scp /root/worker-images.tar root@192.168.110.201:/root/
ctr -n k8s.io images import /root/worker-images.tar systemctl restart containerd systemctl restart kubelet
|
注意:只导入 pause 镜像不能解决所有问题。worker 还可能需要 kube-proxy、Calico 和 CSI 相关镜像。
错误:
1 2
| MountVolume.SetUp failed for volume "memberlist": secret "memberlist" not found
|
检查:
1 2
| kubectl get secret -n metallb-system kubectl logs -n metallb-system deployment/controller --tail=100
|
如果确实不存在,可以手动创建:
1 2 3 4 5 6 7
| apt-get install -y openssl
kubectl create secret generic memberlist \ -n metallb-system \ --from-literal=secretkey="$(openssl rand -base64 128)"
kubectl rollout restart daemonset/speaker -n metallb-system
|
如果 Secret 已存在,不要反复重新生成。
1 2 3
| kubectl get pods -n metallb-system -o wide kubectl describe pod -n metallb-system <SPEAKER_POD> kubectl logs -n metallb-system daemonset/speaker --tail=200
|
重点检查:
- 镜像拉取是否失败
- Pod Security 是否阻止
- TCP/UDP 7946 是否被拦截
- memberlist Secret 是否存在
- 节点网卡和默认路由是否正确
Kite Gateway 访问失败
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| kubectl describe gateway \ -n kite-system kite-gateway
kubectl describe httproute \ -n kite-system kite-route
kubectl get svc kite \ -n kite-system
kubectl get pods -n kite-system \ -l app=kite \ -o wide
kubectl get pods -n envoy-gateway-system -o wide kubectl logs -n envoy-gateway-system deployment/envoy-gateway --tail=100
|
重点检查:
1 2 3
| Gateway: Accepted=True, Programmed=True HTTPRoute: Accepted=True, ResolvedRefs=True Backend Service: kite-system/kite:8080
|
常见原因:
- 访问域名没有配置 hosts 或 DNS
- 访问了 MetalLB 地址池中错误的 IP
- HTTPRoute 的 hostname 与浏览器 Host 不一致
kite-system/kite Service 不存在
- Kite Pod 没有 Running
GatewayClass 名称不是 eg
- Gateway 监听器证书 Secret 不存在
- MetalLB 没有给 Envoy Gateway Service 分配外部 IP
最终检查清单
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| kubectl get nodes -o wide kubectl get pods -A
kubectl get pods -n calico-system -o wide kubectl get tigerastatus
kubectl get pods -n metallb-system -o wide kubectl get ipaddresspool,l2advertisement -n metallb-system kubectl get svc -A | grep LoadBalancer
kubectl get pods -n envoy-gateway-system -o wide kubectl get gatewayclass kubectl get gateway,httproute -A
kubectl get pods -n kite-system \ -l app=kite kubectl get svc kite -n kite-system
systemctl status containerd --no-pager systemctl status kubelet --no-pager
|
目标状态:
1 2 3 4 5 6 7
| 所有节点 Ready Calico Pod Running MetalLB controller/speaker Running LoadBalancer Service 获得 192.168.110.220-230 地址 Gateway Programmed=True HTTPRoute Accepted=True Kite 可以通过独立域名访问
|
生产环境注意事项
这套配置适合开发和验证环境。进入生产前至少需要补齐:
- 使用企业 CA 或 cert-manager 管理证书。
- 使用 OIDC/SSO 登录 Kite,不依赖临时管理员 Token。
- 限制 Gateway IP 的访问来源。
- 不直接把 Kite 暴露到公网。
- 将 YAML 资源纳入 GitOps 或 CI/CD 管理。
- 为 Envoy Gateway、MetalLB、kubelet 和核心业务 Pod 接入监控、日志和告警。
- 控制平面、etcd、负载均衡和存储都需要重新设计高可用方案。
参考文档