Kubernetes高可用集群部署完整指南

原来部署都用用集群外的haproxy来代理(OCP)养成的习惯,最近看了一个文档见的是 集群内 静态 nginx-proxy pod版本 挺有意思 记录一下
简单对比一下先 目前主流的方案:
kubeadm(kubesphere ) 开箱急用初学者
轻量k3s 定位好像是边缘设备
ranche研发用的多 适合研发二开自己玩
ocp 最笨插件也多 其实红帽做了很多工作 不多评价

比较适合研究学习的也就二进制和晕厂商了 一个细 一个实用
静态Pod nginx-proxy方案在成本、简单性和自包含方面具有明显优势,特别适合中小型自建环境。虽然功能相对基础,但对于大多数Kubernetes集群来说已经足够,是性价比高。
对于追求企业级和有专业运维团队的,外部HAProxy方案仍然是黄金标准。
云厂商方案我局的最合适,则适合专注于业务开发的团队,维护简单。

一 架构和部署

本方案采用二进制部署 + nginx-proxy静态Pod的高可用架构,无需外部负载均衡器。

集群节点规划

控制平面节点 (3节点高可用):

  • Master1: 10.10.10.1
  • Master2: 10.10.10.2
  • Master3: 10.10.10.3

工作节点 (3节点):

  • Node1: 10.10.100.1
  • Node2: 10.10.100.2
  • Node3: 10.10.100.3

网络架构

工作节点(kubelet) → 本地nginx-proxy(127.0.0.1:6443) → 负载均衡 → 后端API Server集群(10.10.10.1:6443, 10.10.10.2:6443, 10.10.10.3:6443)

1. 证书生成与配置

1.1 创建证书目录

在所有节点创建证书目录:

mkdir -p /etc/kubernetes/ssl

1.2 生成CA证书(在Master1执行)

# 生成CA私钥
openssl genrsa -out /etc/kubernetes/ssl/ca-key.pem 2048

# 生成CA证书(有效期5年)
openssl req -x509 -new -nodes -key /etc/kubernetes/ssl/ca-key.pem \
  -days 1825 -out /etc/kubernetes/ssl/ca.pem \
  -subj "/CN=kubernetes-ca"

1.3 生成API Server证书(包含所有SAN)

# 生成API Server私钥
openssl genrsa -out /etc/kubernetes/ssl/kubernetes-key.pem 2048

# 创建证书签名请求(内联配置SAN)
openssl req -new -key /etc/kubernetes/ssl/kubernetes-key.pem \
  -out /etc/kubernetes/ssl/kubernetes.csr \
  -subj "/CN=kube-apiserver" \
  -config <(
    cat <<EOF
[req]
req_extensions = v3_req
distinguished_name = req_distinguished_name
[req_distinguished_name]
[ v3_req ]
basicConstraints = CA:FALSE
keyUsage = digitalSignature, keyEncipherment
extendedKeyUsage = serverAuth
subjectAltName = @alt_names
[alt_names]
DNS.1 = kubernetes
DNS.2 = kubernetes.default
DNS.3 = kubernetes.default.svc
DNS.4 = kubernetes.default.svc.cluster
DNS.5 = kubernetes.svc.cluster.local
IP.1 = 10.233.0.1
IP.2 = 10.10.10.1
IP.3 = 10.10.10.2
IP.4 = 10.10.10.3
IP.5 = 127.0.0.1
EOF
  )

# 使用CA签名生成证书
openssl x509 -req -in /etc/kubernetes/ssl/kubernetes.csr \
  -CA /etc/kubernetes/ssl/ca.pem -CAkey /etc/kubernetes/ssl/ca-key.pem \
  -CAcreateserial -out /etc/kubernetes/ssl/kubernetes.pem \
  -days 365 -extensions v3_req -extfile <(
    cat <<EOF
[ v3_req ]
basicConstraints = CA:FALSE
keyUsage = digitalSignature, keyEncipherment
extendedKeyUsage = serverAuth
subjectAltName = @alt_names
[alt_names]
DNS.1 = kubernetes
DNS.2 = kubernetes.default
DNS.3 = kubernetes.default.svc
DNS.4 = kubernetes.default.svc.cluster
DNS.5 = kubernetes.svc.cluster.local
IP.1 = 10.233.0.1
IP.2 = 10.10.10.1
IP.3 = 10.10.10.2
IP.4 = 10.10.10.3
IP.5 = 127.0.0.1
EOF
  )

1.4 生成Service Account证书

openssl genrsa -out /etc/kubernetes/ssl/service-account-key.pem 2048
openssl req -new -key /etc/kubernetes/ssl/service-account-key.pem \
  -out /etc/kubernetes/ssl/service-account.csr -subj "/CN=service-account"
openssl x509 -req -in /etc/kubernetes/ssl/service-account.csr \
  -CA /etc/kubernetes/ssl/ca.pem -CAkey /etc/kubernetes/ssl/ca-key.pem \
  -CAcreateserial -out /etc/kubernetes/ssl/service-account.pem -days 365

1.5 生成代理客户端证书

openssl genrsa -out /etc/kubernetes/ssl/proxy-client-key.pem 2048
openssl req -new -key /etc/kubernetes/ssl/proxy-client-key.pem \
  -out /etc/kubernetes/ssl/proxy-client.csr -subj "/CN=aggregator"
openssl x509 -req -in /etc/kubernetes/ssl/proxy-client.csr \
  -CA /etc/kubernetes/ssl/ca.pem -CAkey /etc/kubernetes/ssl/ca-key.pem \
  -CAcreateserial -out /etc/kubernetes/ssl/proxy-client.pem -days 365

1.6 分发证书到其他Master节点

scp -r /etc/kubernetes/ssl/ root@10.10.10.2:/etc/kubernetes/
scp -r /etc/kubernetes/ssl/ root@10.10.10.3:/etc/kubernetes/

1.7 为工作节点生成专用证书

为每个工作节点生成节点证书(以Node1为例):

openssl genrsa -out /etc/kubernetes/ssl/node1-key.pem 2048
openssl req -new -key /etc/kubernetes/ssl/node1-key.pem \
  -out /etc/kubernetes/ssl/node1.csr \
  -subj "/CN=system:node:node1/O=system:nodes"
openssl x509 -req -in /etc/kubernetes/ssl/node1.csr \
  -CA /etc/kubernetes/ssl/ca.pem -CAkey /etc/kubernetes/ssl/ca-key.pem \
  -CAcreateserial -out /etc/kubernetes/ssl/node1.pem -days 365

2. 控制平面部署

2.1 安装二进制文件

在所有控制平面节点安装以下二进制文件到 /usr/local/bin/

  • kube-apiserver
  • kube-controller-manager
  • kube-scheduler
  • etcd
  • kubelet
  • kubectl

2.2 配置etcd服务

创建 /etc/systemd/system/etcd.service

[Unit]
Description=Etcd Server
After=network.target

[Service]
Type=notify
ExecStart=/usr/local/bin/etcd \
  --name=master1 \
  --data-dir=/var/lib/etcd \
  --listen-client-urls=https://10.10.10.1:2379,https://127.0.0.1:2379 \
  --advertise-client-urls=https://10.10.10.1:2379 \
  --listen-peer-urls=https://10.10.10.1:2380 \
  --initial-advertise-peer-urls=https://10.10.10.1:2380 \
  --initial-cluster=master1=https://10.10.10.1:2380,master2=https://10.10.10.2:2380,master3=https://10.10.10.3:2380 \
  --client-cert-auth=true \
  --trusted-ca-file=/etc/kubernetes/ssl/ca.pem \
  --cert-file=/etc/kubernetes/ssl/kubernetes.pem \
  --key-file=/etc/kubernetes/ssl/kubernetes-key.pem \
  --peer-client-cert-auth=true \
  --peer-trusted-ca-file=/etc/kubernetes/ssl/ca.pem \
  --peer-cert-file=/etc/kubernetes/ssl/kubernetes.pem \
  --peer-key-file=/etc/kubernetes/ssl/kubernetes-key.pem
Restart=always
RestartSec=5

[Install]
WantedBy=multi-user.target

2.3 配置kube-apiserver服务

创建 /etc/systemd/system/kube-apiserver.service

[Unit]
Description=Kubernetes API Server
After=etcd.service

[Service]
ExecStart=/usr/local/bin/kube-apiserver \
  --advertise-address=10.10.10.1 \
  --allow-privileged=true \
  --apiserver-count=3 \
  --authorization-mode=Node,RBAC \
  --bind-address=0.0.0.0 \
  --client-ca-file=/etc/kubernetes/ssl/ca.pem \
  --enable-admission-plugins=NamespaceLifecycle,NodeRestriction,LimitRanger,ServiceAccount,DefaultStorageClass,ResourceQuota \
  --etcd-cafile=/etc/kubernetes/ssl/ca.pem \
  --etcd-certfile=/etc/kubernetes/ssl/kubernetes.pem \
  --etcd-keyfile=/etc/kubernetes/ssl/kubernetes-key.pem \
  --etcd-servers=https://10.10.10.1:2379,https://10.10.10.2:2379,https://10.10.10.3:2379 \
  --kubelet-client-certificate=/etc/kubernetes/ssl/kubernetes.pem \
  --kubelet-client-key=/etc/kubernetes/ssl/kubernetes-key.pem \
  --secure-port=6443 \
  --service-account-key-file=/etc/kubernetes/ssl/service-account.pem \
  --service-cluster-ip-range=10.233.0.0/18 \
  --tls-cert-file=/etc/kubernetes/ssl/kubernetes.pem \
  --tls-private-key-file=/etc/kubernetes/ssl/kubernetes-key.pem
Restart=always
RestartSec=5

[Install]
WantedBy=multi-user.target

2.4 启动控制平面服务

systemctl daemon-reload
systemctl enable etcd kube-apiserver kube-controller-manager kube-scheduler
systemctl start etcd kube-apiserver kube-controller-manager kube-scheduler

3. 工作节点部署

3.1 配置nginx代理

在所有工作节点创建 /etc/nginx/nginx.conf

user nginx;
worker_processes auto;
error_log /var/log/nginx/error.log;
pid /run/nginx.pid;

events {
    worker_connections 1024;
}

stream {
    upstream kubernetes {
        server 10.10.10.1:6443 max_fails=3 fail_timeout=30s;
        server 10.10.10.2:6443 max_fails=3 fail_timeout=30s;
        server 10.10.10.3:6443 max_fails=3 fail_timeout=30s;
    }
    
    server {
        listen 127.0.0.1:6443;
        proxy_pass kubernetes;
        proxy_timeout 3s;
        proxy_connect_timeout 1s;
    }
    
    server {
        listen 127.0.0.1:8081;
        return 200 "healthy\n";
    }
}

3.2 配置nginx-proxy静态Pod

创建 /etc/kubernetes/manifests/nginx-proxy.yaml

apiVersion: v1
kind: Pod
metadata:
  name: nginx-proxy
  namespace: kube-system
  labels:
    addonmanager.kubernetes.io/mode: Reconcile
    k8s-app: kube-nginx
spec:
  hostNetwork: true
  dnsPolicy: ClusterFirstWithHostNet
  nodeSelector:
    kubernetes.io/os: linux
  priorityClassName: system-node-critical
  containers:
  - name: nginx-proxy
    image: docker.io/library/nginx:1.19
    imagePullPolicy: IfNotPresent
    resources:
      requests:
        cpu: 25m
        memory: 32M
    securityContext:
      privileged: true
    livenessProbe:
      httpGet:
        path: /healthz
        port: 8081
    readinessProbe:
      httpGet:
        path: /healthz
        port: 8081
    volumeMounts:
    - mountPath: /etc/nginx
      name: etc-nginx
      readOnly: true
  volumes:
  - name: etc-nginx
    hostPath:
      path: /etc/nginx

3.3 配置kubelet

创建 /etc/kubernetes/kubelet-config.yaml

kind: KubeletConfiguration
apiVersion: kubelet.config.k8s.io/v1beta1
staticPodPath: /etc/kubernetes/manifests
authentication:
  x509:
    clientCAFile: "/etc/kubernetes/ssl/ca.pem"
authorization:
  mode: Webhook
clusterDNS:
  - "169.254.25.10"
address: 10.10.100.1
tlsCertFile: "/etc/kubernetes/ssl/node1.pem"
tlsPrivateKeyFile: "/etc/kubernetes/ssl/node1-key.pem"

3.4 启动工作节点

systemctl enable kubelet && systemctl start kubelet

4. 验证集群状态

4.1 检查节点状态

kubectl get nodes -o wide

4.2 检查组件状态

kubectl get componentstatuses

4.3 验证网络连通性

curl -k https://127.0.0.1:6443/version

5. 所需软件版本

容器运行时

  • containerd: 1.4.3+
  • crictl: 1.18.0+

Kubernetes组件

  • Kubernetes: v1.20.2
  • etcd: 3.4.13+

核心镜像 简介

quay.io/kubernetes-ingress-controller/nginx-ingress-controller:0.19.0
docker.io/library/nginx:1.19
registry.cn-hangzhou.aliyuncs.com/kubernetes-kubespray/pause:3.2
docker.io/calico/cni:v3.20.6
docker.io/calico/node:v3.20.6

6. 运维常用命令

6.1 证书管理

# 查看证书有效期
openssl x509 -in /etc/kubernetes/ssl/ca.pem -noout -dates

# 检查证书SAN信息
openssl x509 -in /etc/kubernetes/ssl/kubernetes.pem -text -noout | grep -A10 "Subject Alternative Name"

# 批量检查证书
for cert in /etc/kubernetes/ssl/*.pem; do
  echo "=== $(basename $cert) ==="
  openssl x509 -in $cert -noout -subject -dates 2>/dev/null || echo "私钥文件"
done

6.2 集群状态检查

# 节点和Pod状态
kubectl get nodes -o wide
kubectl get pods -A -o wide

# 服务状态
kubectl get svc -A
kubectl get componentstatuses

6.3 服务管理

# 控制平面服务
systemctl status kube-apiserver
systemctl status kube-controller-manager
systemctl status kube-scheduler
systemctl status etcd

# 工作节点服务
systemctl status kubelet
systemctl status containerd

6.4 网络诊断

# 检查nginx代理
kubectl get pods -n kube-system | grep nginx-proxy
kubectl logs -n kube-system nginx-proxy-xxx

# 端口监听检查
netstat -lntp | grep 6443

6.5 集群备份

# 备份证书和配置
cp -r /etc/kubernetes/ssl /backup/kubernetes-ssl-$(date +%Y%m%d)
cp -r /etc/kubernetes/manifests /backup/manifests-$(date +%Y%m%d)

# 备份资源定义
kubectl get all --all-namespaces -o yaml > /backup/k8s-resources-$(date +%Y%m%d).yaml

总结

本方案通过静态Pod nginx-proxy实现了高可用负载均衡,具有以下优势:

  1. 无外部依赖:无需额外的负载均衡器硬件/软件
  2. 配置一致:所有工作节点使用相同的连接地址
  3. 高可用:内置故障检测和自动故障转移
  4. 易于维护:静态Pod由kubelet自动管理

这种架构特别适合自建环境,在保证高可用的同时简化了网络配置和外部依赖。

二 镜像架构概述

有些同学可能第一次接触部署,加上这部分吧

在Kubernetes高可用集群中,镜像分为多个层次,每个层次承担不同的功能。以下是完整的镜像分类和使用说明。

1. 核心基础设施镜像

1.1 基础运行时镜像

# Pause容器 - 所有Pod的基础基础设施容器
registry.cn-hangzhou.aliyuncs.com/kubernetes-kubespray/pause:3.2
# 或
k8s.gcr.io/pause:3.2

# 功能:为Pod提供共享的Linux命名空间,作为Pod内所有容器的"父容器"
# 用途:每个Pod都会自动创建pause容器

1.2 nginx代理镜像

# nginx代理 - 用于API Server负载均衡
docker.io/library/nginx:1.19

# 功能:作为静态Pod运行,代理所有到API Server的请求
# 配置:通过HostPath挂载nginx配置文件
# 网络模式:使用主机网络,监听127.0.0.1:6443

2. 网络插件镜像 (Calico)

2.1 Calico核心组件

# Calico CNI插件 - 负责Pod网络配置
docker.io/calico/cni:v3.20.6
# 功能:安装CNI二进制文件,配置Pod网络接口
# 运行方式:DaemonSet,每个节点运行

# Calico节点组件 - 核心网络服务
docker.io/calico/node:v3.20.6
# 功能:BGP路由发布、Felix策略执行、网络状态报告
# 包含:bird, felix, confd等组件
# 运行方式:DaemonSet,每个节点运行

# FlexVolume驱动 - 用于网络策略
docker.io/calico/pod2daemon-flexvol:v3.20.6
# 功能:为Calico提供FlexVolume支持
# 运行方式:DaemonSet,每个节点运行

2.2 Calico控制器

# Calico Kube控制器 - 集群级别网络策略
docker.io/calico/kube-controllers:v3.20.6
# 功能:执行网络策略、服务IP广告、节点监控
# 运行方式:Deployment,通常单副本运行

3. DNS服务镜像

3.1 CoreDNS

# CoreDNS - Kubernetes集群DNS服务
k8s.gcr.io/coredns:1.7.0
# 或
registry.cn-hangzhou.aliyuncs.com/kubernetes-kubespray/coredns:1.7.0

# 功能:提供集群内服务发现和DNS解析
# 配置:通过ConfigMap管理
# 运行方式:Deployment,通常2副本运行

3.2 NodeLocal DNS Cache

# 节点本地DNS缓存 - 提升DNS解析性能
registry.cn-hangzhou.aliyuncs.com/kubernetes-kubespray/dns_k8s-dns-node-cache:1.16.0

# 功能:在每个节点运行DNS缓存,减少CoreDNS负载
# 运行方式:DaemonSet,每个节点运行
# 监听:节点上的169.254.25.10:53

4. Ingress控制器镜像

4.1 NGINX Ingress Controller

# NGINX Ingress控制器
quay.io/kubernetes-ingress-controller/nginx-ingress-controller:0.19.0

# 功能:提供HTTP/HTTPS入口流量管理
# 特性:支持负载均衡、SSL终止、基于路径路由
# 运行方式:Deployment,可配置多副本

# 默认后端服务
k8s.gcr.io/defaultbackend-amd64:1.5
# 功能:处理所有未配置路由的请求
# 用途:Ingress控制器的默认回退服务

5. 监控与日志镜像

5.1 指标收集

# metrics-server - 资源指标收集
k8s.gcr.io/metrics-server/metrics-server:v0.5.0

# 功能:收集Node和Pod的CPU、内存使用指标
# 用途:支持kubectl top命令和HPA

6. 镜像拉取与准备

6.1 镜像预加载脚本

#!/bin/bash
# 定义镜像列表
IMAGES=(
    "registry.cn-hangzhou.aliyuncs.com/kubernetes-kubespray/pause:3.2"
    "docker.io/library/nginx:1.19"
    "docker.io/calico/cni:v3.20.6"
    "docker.io/calico/node:v3.20.6"
    "docker.io/calico/kube-controllers:v3.20.6"
    "docker.io/calico/pod2daemon-flexvol:v3.20.6"
    "registry.cn-hangzhou.aliyuncs.com/kubernetes-kubespray/dns_k8s-dns-node-cache:1.16.0"
    "quay.io/kubernetes-ingress-controller/nginx-ingress-controller:0.19.0"
)

# 拉取所有镜像
for image in "${IMAGES[@]}"; do
    echo "Pulling $image"
    crictl pull $image
done

# 验证镜像拉取
crictl images

6.2 镜像导出与导入(离线环境)

# 导出镜像
crictl images --digests > images-list.txt
for image in $(crictl images -q); do
    crictl save $image > $(echo $image | tr '/' '_' | tr ':' '_').tar
done

# 导入镜像(在目标机器)
for tar_file in *.tar; do
    crictl load < $tar_file
done

7. 镜像配置说明

7.1 镜像仓库配置

如果使用私有仓库,需要配置containerd:

# 编辑containerd配置
vim /etc/containerd/config.toml

# 添加镜像仓库mirror
[plugins."io.containerd.grpc.v1.cri".registry.mirrors]
  [plugins."io.containerd.grpc.v1.cri".registry.mirrors."docker.io"]
    endpoint = ["https://registry-1.docker.io"]
  [plugins."io.containerd.grpc.v1.cri".registry.mirrors."k8s.gcr.io"]
    endpoint = ["https://registry.cn-hangzhou.aliyuncs.com"]

7.2 镜像拉取策略

在Kubernetes资源配置中指定拉取策略:

apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: calico-node
spec:
  template:
    spec:
      containers:
      - name: calico-node
        image: docker.io/calico/node:v3.20.6
        imagePullPolicy: IfNotPresent  # 可选:Always, IfNotPresent, Never

8. 镜像版本对应关系

8.1 Kubernetes版本与镜像版本

Kubernetes版本 Calico版本 CoreDNS版本 nginx-ingress版本
v1.20.2 v3.20.6 1.7.0 0.19.0
v1.21.x v3.21.x 1.8.3 1.0.x
v1.22.x v3.22.x 1.8.6 1.1.x

8.2 镜像大小参考

# 常见镜像大小
pause:3.2                    # 300KB
nginx:1.19                   # 50MB
calico/cni:v3.20.6           # 45MB
calico/node:v3.20.6          # 60MB
coredns:1.7.0                # 40MB
nginx-ingress-controller:0.19.0 # 160MB

9. 镜像健康检查

9.1 镜像状态验证

# 检查所有运行的Pod使用的镜像
kubectl get pods -A -o jsonpath='{range .items[*]}{.metadata.name}{"\t"}{.spec.containers[*].image}{"\n"}{end}'

# 检查镜像拉取错误
kubectl get pods -A -o wide | grep -E "ImagePullBackOff|ErrImagePull"

# 检查节点上的镜像
crictl images

9.2 镜像更新策略

# 安全更新镜像步骤
# 1. 拉取新版本镜像
crictl pull docker.io/calico/node:v3.20.7

# 2. 更新DaemonSet/Deployment的镜像版本
kubectl set image daemonset/calico-node calico-node=docker.io/calico/node:v3.20.7 -n kube-system

# 3. 滚动更新验证
kubectl rollout status daemonset/calico-node -n kube-system

10. 镜像安全最佳实践

10.1 安全扫描

# 使用trivy扫描镜像漏洞
trivy image docker.io/calico/node:v3.20.6

# 检查镜像签名
cosign verify docker.io/calico/node:v3.20.6

10.2 镜像源管理

# 只信任官方镜像源
# Calico: docker.io/calico/*
# NGINX: docker.io/library/nginx
# Kubernetes: k8s.gcr.io/*
# 避免使用不明来源的镜像

这个完整的镜像说明涵盖了集群所有核心组件的镜像使用,包括功能说明、配置方法和运维实践。

Logo

码道开发者社区,聚焦华为云码道 CodeArts 代码智能体,沉淀 Agent、Skill、鸿蒙开发实战内容,供开发者查阅资料、交流技术、分享工程实践

更多推荐