三亩地 三亩地SAN MU DI · CODE DIARY
ARTICLE DETAIL

日记详情

真实记录编程学习的某一天,欢迎挑你感兴趣的翻一翻。

K3s 双节点集群部署

K3s 双节点集群部署

本文采用 1 Server + 1 Agent 架构,仅实现工作负载双节点运行,不属于 Kubernetes Control Plane 高可用方案。版本:
K3s: v1.36.3+k3s1
Helm: v3.21.3
cert-manager: 1.19.6
Traefik:3.7.1

一、 环境规划与前置准备

在进行任何安装步骤之前,必须在所有节点(Server 及 Agent 节点)上完成操作系统(OS)级的内核模块加载与系统参数调优,以避免重启后 Pod 通信异常或系统资源句柄不足。

1. 节点基础信息

节点主机名节点角色IP 地址核心服务名主要职责
masterServer / Control Plane192.168.31.100k3s.serviceKubernetes API、调度、控制器、K3s Server、也可运行 Pod
node1Agent / Worker192.168.31.101k3s-agent.service运行业务 Pod

2. 前置准备(所有节点必做)

(1) 内核模块与参数加固
# 1、配置文件持久化(重启后自动加载) # overlay 模块用于 containerd 镜像分层挂载,br_netfilter 用于 K8s iptables 流量桥接过滤 sudo tee /etc/modules-load.d/k3s.conf >/dev/null <<'EOF' overlay br_netfilter nf_conntrack EOF # 2、立即加载模块 sudo modprobe overlay && sudo modprobe br_netfilter && sudo modprobe nf_conntrack # 3、开启 IPv4 转发、二层网桥 iptables 处理以及调高文件监听/连接跟踪上限: sudo tee /etc/sysctl.d/k3s.conf >/dev/null <<'EOF' net.bridge.bridge-nf-call-iptables=1 net.bridge.bridge-nf-call-ip6tables=1 net.ipv4.ip_forward=1 net.ipv4.conf.all.forwarding=1 net.netfilter.nf_conntrack_max=131072 fs.inotify.max_user_instances=8192 fs.inotify.max_user_watches=524288 vm.max_map_count=262144 EOF # 4、使所有参数生效 sudo sysctl --system # 5. 验证 (确保两个模块都在) lsmod | grep -E "br_netfilter|overlay" # 输出如下 overlay 155648 21 br_netfilter 32768 0 bridge 270336 1 br_netfilter
(2) 其它设置
# 本地使用 VMWare 部署需要执行下面操作,云服务器下面设置一般默认都是关闭的 # 唯一需要关注的是 selinux,建议设置为宽容模式或不设置也可以。但如果项目涉及金钱或核心机密或者追求极致安全,将模式设为 Enforcing # 1、关闭防火墙 sudo systemctl disable --now firewalld # 查看防火墙状态 firewall-cmd --state # 2、禁用 swap (虽然标准 K8s 要求关闭,但 K3s 支持开启) swapoff -a && sed -ri 's/.*swap.*/#&/' /etc/fstab # 3、关闭 selinux sudo setenforce 0 && sudo sed -i 's/^SELINUX=.*/SELINUX=permissive/' /etc/selinux/config # 4、设置 hostname # 在 IP 为 192.168.31.100 的机器上执行: sudo hostnamectl set-hostname master # 在 IP 为 192.168.31.101 的机器上执行: sudo hostnamectl set-hostname node1 检查: hostnamectl # 5、配置 /etc/hosts(所有节点): echo -e "192.168.31.100 master\n192.168.31.101 node1" | sudo tee -a /etc/hosts

二、 核心配置文件编写

1、创建目录

sudo mkdir -p /etc/rancher/k3s/

2. Server 节点的 config.yaml(控制面定制)

# 在 master 节点创建 /etc/rancher/k3s/config.yaml。使用 config.yaml 可以避免在 curl 一键脚本中写过长且易错的环境变量 # 下面内容是一整条命令 sudo tee /etc/rancher/k3s/config.yaml >/dev/null <<'EOF' # 1. 节点名称 node-name: "master" # 2. 数据与镜像存储路径(指向独立的磁盘挂载点,防止撑爆系统盘目录)>3. 所有节点的镜像加速配置
# 在 master 和 node1 节点同时创建 /etc/rancher/k3s/registries.yaml # 国内镜像服务的可用性、同步范围和访问策略可能变化 # 生产环境建议优先使用企业自己的私有镜像仓库,并将业务镜像及关键基础镜像同步到自己的 SWR/ACR Harbor 等 Registry。 sudo tee /etc/rancher/k3s/registries.yaml >/dev/null <<'EOF' mirrors: "docker.io": endpoint: - "https://docker.m.daocloud.io" "registry.k8s.io": endpoint: - "https://k8s.m.daocloud.io" "gcr.io": endpoint: - "https://gcr.m.daocloud.io" "ghcr.io": endpoint: - "https://ghcr.m.daocloud.io" "quay.io": endpoint: - "https://quay.m.daocloud.io" EOF

三、 集群部署

1、部署 Server 节点 (master)

由于之前已写好 /etc/rancher/k3s/config.yaml,K3s 安装脚本启动时会自动加载该文件的所有配置。

在 master (192.168.31.100) 上运行国内镜像安装脚本:

curl -sfL https://rancher-mirror.rancher.cn/k3s/k3s-install.sh | \ INSTALL_K3S_MIRROR=cn \ INSTALL_K3S_VERSION="v1.36.3+k3s1" \ sh -

安装完成后,获取 Worker 节点加入集群所需的 Token,记录输出的 Token 字符串,形如 K10xxx…::server:abc123xxx。

# 上面 config.yaml 中自定义了数据目录 # 如果没有自定义,执行 sudo cat /var/lib/rancher/k3s/server/node-token cat /data/k3s/server/node-token

2、部署 Agent 节点 (node1)

登录到 node1 (192.168.31.101),使用 K3S_URL 和 K3S_TOKEN 环境变量启动 Agent 安装脚本:

curl -sfL https://rancher-mirror.rancher.cn/k3s/k3s-install.sh | \ INSTALL_K3S_MIRROR=cn \ INSTALL_K3S_VERSION="v1.36.3+k3s1" \ K3S_URL=https://192.168.31.100:6443 \ K3S_TOKEN=从Master获取的Token \ sh -

注:安装脚本在启动 k3s-agent 服务时,会自动读取之前写好的 /etc/rancher/k3s/registries.yaml,无需手动重启。如后续修改该文件,需运行 sudo systemctl restart k3s-agent 生效。

3、 验证节点连接

回到 master 上验证节点加入状态:

kubectl get nodes

标准预期输出:

NAME STATUS ROLES AGE VERSION master Ready control-plane 3h v1.36.3+k3s1 node1 Ready <none> 5m v1.36.3+k3s1

四、 集群组件 Helm 安装

Helm 是 Kubernetes 的官方包管理工具(Package Manager),相当于 Linux 世界的 apt / yum,或 Node.js 世界的 npm。它把多个关联的 Kubernetes 资源打包成一个整体(Chart),实现应用的一键安装、升级、配置和回滚。只在 Server(master) 节点安装。

1、Helm 国内安装

# 1. 创建临时目录并下载 Helm 3 二进制包 # 如果下载慢,可以访问 https://mirrors.huaweicloud.com/helm/ 或利用 GitHub wget https://mirrors.huaweicloud.com/helm/v3.21.3/helm-v3.21.3-linux-amd64.tar.gz # 2. 解压 tar -zxvf helm-v3.21.3-linux-amd64.tar.gz # 3. 将解压出来的 helm 二进制移动到系统 PATH 路径中 mv linux-amd64/helm /usr/local/bin/helm # 4. 验证安装 helm version

2、配置 K3s 权限

# 1. 创建 root 用户的默认 config 目录 mkdir -p /root/.kube # 2. 复制 K3s 的配置文件到默认位置 cp /etc/rancher/k3s/k3s.yaml /root/.kube/config # 3. 赋予正确的权限 chmod 600 /root/.kube/config

3、配置 Helm 镜像仓库

# 1. 添加 Bitnami 仓库(这是全球最全的开源软件库,如 MySQL, Redis) helm repo add bitnami https://charts.bitnami.com/bitnami # 2. 添加 cert-manager 官方仓库 # cert-manager(自动 HTTPS 证书签发与续签) helm repo add jetstack https://charts.jetstack.io # 3. 更新本地仓库索引 helm repo update # 4. 查看已添加的仓库列表 helm repo list # 5. 在仓库中搜索 Chart(如搜索 nginx) helm search repo nginx # 移除已经添加的仓库 (stable 替换为想要移除的仓库) helm repo remove stable

K8s 官方推出了 [Artifact Hub](https://artifacthub.io/)。Artifact Hub 不是仓库,而是一个搜索引擎/目录索引网站。它不存文件,只告诉你某个组件(如 cert-manager)的官方 Repo 网址是什么,你需要自己把它添加(helm repo add)到本地。

4、使用 Helm 部署应用

4.1 直接以默认配置创建一个 Chart
# 创建一个 Chart 模版(其实就是项目或者应用) helm create my-webapp # 为什么叫 "Chart"(海图/航海图) # 这源于 Kubernetes 生态系统深度使用的 航海/航海术主题命名法: # Kubernetes (k8s):源自希腊语 κυβερνήτης,意思是 “舵手” 或 “船长” # Helm:字面意思是 “舵轮” 或 “船舵”(掌控船只航向的工具) # Docker:字面意思是 “码头工人”(负责搬运集装箱) # Container:字面意思是 “集装箱” # 在这一整套航海隐喻下:你的集群是一个在海里航行的庞大舰队;Helm 是控制方向的船舵;而 Chart(航海图/海图) 就是指导这艘船该去哪里、如何布置各个集装箱(容器)的路线图与设计蓝图。
4.2 创建私有容器镜像仓库凭证
# 在 Kubernetes 集群中创建一个类型为 docker-registry 的 Secret 资源,存储访问私有容器镜像仓库的认证凭证(用户名和密码/Token) # docker-registry:Secret 的类型,专门用于镜像仓库身份验证 # huawei-swr-secret:这个 Secret 自定义的名称,后续在 YAML 中的 imagePullSecrets.name 引用的就是这个名字 # --docker-server:镜像仓库的域名地址 # --docker-username:登录镜像仓库的账号名称 # --docker-password:登录镜像仓库的密码,,或者在云厂商控制台中生成的临时/长效镜像拉取密钥(Token) # --namespace=default:指定将这个 Secret 创建到哪一个命名空间下(默认为 default) # 注意:Secret 是隔离在 Namespace(命名空间)中的,如果你的 Pod 部署在 default 命名空间,该 Secret 必须创建在 default kubectl create secret docker-registry huawei-swr-secret \ --docker-server=swr.cn-north-4.myhuaweicloud.com \ --docker-username='你的用户名' \ --docker-password='你的密码' \ --namespace=default
4.3 修改 values.yaml

本地部署 values.yaml

# 副本,Pod 个数 replicaCount: 2 # 镜像,这里提供了一个公共的镜像 it-tools ,可以直接使用 image: # 镜像仓库地址 repository: swr.cn-east-5.myhuaweicloud.com/zhixu/it-tools pullPolicy: IfNotPresent # 镜像版本号 tag: "1.0" # 下载私有镜像的凭证,如果是公开镜像,设置不设置都无所谓,如果是私有镜像,必须设置 imagePullSecrets: - name: huawei-swr-secret nameOverride: "" fullnameOverride: "" serviceAccount: create: true automount: true annotations: {} name: "" podAnnotations: {} podLabels: {} podSecurityContext: {} securityContext: {} # 网络服务配置 # type: 服务以什么方式暴露,有四种 # ① NodePort(通过宿主机物理端口暴露):本地或者临时调试使用 # ② ClusterIP(默认模式,集群内部服务):应用首选。配合网关实现统一公网域名暴露。生产环境通常优先使用 ClusterIP + Ingress/Gateway,由统一入口负责域名和 HTTPS。 # ③ LoadBalancer(配合云厂商的公网负载均衡器):云上环境通常只为网关 配置 1~2 个,不建议每个微服务都开。 # ④ ExternalName(服务别名/外链映射):用于访问集群外预设的第三方服务或 RDS # targetPort:如果 Pod 内部程序监听的端口 恰好 和 Service 对外暴露的端口完全相同,此时 targetPort 可以省略不写,Kubernetes 默认会把 targetPort 设置为与 port 相同的值。 # 比如 Java/Spring Boot 或者 .NET Core 默认 8080、Node.js/Express 默认 3000、Python/Django 默认 8000时,需要写 targetPort # 如果设置了targetPort,那 service.yaml 中 targetPort 改成引用 values 中的变量: targetPort: {{ .Values.service.targetPort }} service: type: NodePort # 通过节点 IP + NodePort 对外暴露服务,适合测试或没有 Ingress/LB 的简单场景。 port: 80 # 服务对外的端口 targetPort: 80 # 流量转发到容器内部的端口 # 外网访问与证书 ingress: enabled: false className: "" annotations: {} # kubernetes.io/ingress.class: nginx # kubernetes.io/tls-acme: "true" hosts: - host: chart-example.local paths: - path: / pathType: ImplementationSpecific tls: [] # - secretName: chart-example-tls # hosts: # - chart-example.local httpRoute: enabled: false annotations: {} parentRefs: - name: gateway sectionName: http hostnames: - chart-example.local rules: - matches: - path: type: PathPrefix value: /headers # 扩展与高级配置 resources: # requests: K8s 调度时“预留”的资源,保证 Pod 至少能拿到这么多 requests: cpu: 100m # 0.1 核 memory: 256Mi # 256 MB # limits: 强制上限,超过这个值会被限制或杀掉 limits: cpu: 1000m # 1 核 (通常不建议给太低,否则启动慢,请求高峰会卡顿) memory: 512Mi # 512 MB # 健康检查 livenessProbe: # (存活检查): 如果 GET / 失败,K8s 会直接重启容器 httpGet: path: / port: 80 readinessProbe: # (就绪检查): 如果 GET / 失败,K8s 会把这个 Pod 从负载均衡中剔除,停止发给它流量,直到它恢复正常。 httpGet: path: / port: 80 autoscaling: enabled: false minReplicas: 1 maxReplicas: 100 targetCPUUtilizationPercentage: 80 volumes: [] volumeMounts: [] nodeSelector: {} tolerations: [] affinity: {}

生产环境部署 values.yaml,主要区别在 service 和 ingress

# 副本,Pod 个数 replicaCount: 2 # 镜像,这里提供了一个公共的镜像 it-tools ,可以直接使用 image: # 镜像仓库地址 repository: swr.cn-east-5.myhuaweicloud.com/zhixu/it-tools pullPolicy: IfNotPresent # 镜像版本号 tag: "1.0" # 下载私有镜像的凭证 imagePullSecrets: - name: huawei-swr-secret nameOverride: "" fullnameOverride: "" serviceAccount: create: true automount: true annotations: {} name: "" podAnnotations: {} podLabels: {} podSecurityContext: {} securityContext: {} # 网络服务配置 service: type: ClusterIP # 默认模式,仅在集群内部可用 port: 80 # 服务对外的端口 # 外网访问与证书 # 需要配置 cert-manager 使用,letsencrypt-prod 怎么来的下面会详细介绍 ingress: enabled: true className: "traefik" annotations: cert-manager.io/cluster-issuer: "letsencrypt-prod" # 证书签发指令 hosts: - host: ittools.ddzhixu.com paths: - path: / pathType: ImplementationSpecific tls: - secretName: ittools-prod-zhixu-tls hosts: - ittools.ddzhixu.com httpRoute: enabled: false annotations: {} parentRefs: - name: gateway sectionName: http hostnames: - chart-example.local rules: - matches: - path: type: PathPrefix value: /headers # 扩展与高级配置 resources: # requests: K8s 调度时“预留”的资源,保证 Pod 至少能拿到这么多 requests: cpu: 100m # 0.1 核 memory: 256Mi # 256 MB # limits: 强制上限,超过这个值会被限制或杀掉 limits: cpu: 1000m # 1 核 (通常不建议给太低,否则启动慢,请求高峰会卡顿) memory: 512Mi # 512 MB # 健康检查 # 在项目中实际提供这些接口 /health/live 和 /health/ready startupProbe: # 启动探针:给慢启动应用充分的时间,成功后才交棒给下面两个探针 httpGet: path: /health/live port: 80 failureThreshold: 30 periodSeconds: 5 livenessProbe: # 存活探针:轻量,只检查进程 httpGet: path: /health/live port: 80 periodSeconds: 10 timeoutSeconds: 2 failureThreshold: 3 readinessProbe: # 就绪探针:检查依赖,决定是否接收流量 httpGet: path: /health/ready port: 80 periodSeconds: 5 timeoutSeconds: 2 failureThreshold: 3 autoscaling: enabled: false minReplicas: 1 maxReplicas: 100 targetCPUUtilizationPercentage: 80 volumes: [] volumeMounts: [] nodeSelector: {} tolerations: [] # 高可用打散策略:避免两个副本分到同一个节点 # 软亲和性,单节点也可以设置 affinity: podAntiAffinity: preferredDuringSchedulingIgnoredDuringExecution: - weight: 100 podAffinityTerm: labelSelector: matchExpressions: - key: app.kubernetes.io/name operator: In values: - it-tools topologyKey: kubernetes.io/hostname

Affinity tips

# 不要配置硬性的“反亲和性(Anti-Affinity)” 如果你此前在 YAML 中配置了 podAntiAffinity(强制要求同一个 Pod 的多个副本不能放在同一台节点),那么: # 当你设置 replicaCount: 2 时,第 1 个副本会顺利落到 Agent 1 上。 # 第 2 个副本因为“不能与第 1 个副本同节点”,且 Master 节点有污点无法投递,就会直接变成 Pending 挂起状态! # 解决办法:只有 1 台 Agent 时,不要加反亲和性,或者配置为 preferredDuringScheduling...(弱亲和,能分散就分散,分散不了就挤在一块),允许 2 个副本同时挤在这一台 Agent 上运行。
4.4 安装项目
# 把应用部署到了 Kubernetes 的 zhixu 命名空间中,并且利用 NodePort 成功拿到访问地址 # -n 指定命名空间,--create-namespace 命名空间不存在会自动建 # ittools(第一个):本次发布的 Release 名称(相当于实例名) # ./ittools(第二个):你本地的 Chart 文件夹路径 # -n zhixu(--namespace):指定部署到名为 zhixu 的命名空间中 # --create-namespace:自动检查,如果 zhixu 这个命名空间不存在,就先帮创建它 [root@master ~]# helm upgrade --install ittools ./ittools -n zhixu --create-namespace Release "ittools" does not exist. Installing it now. NAME: ittools LAST DEPLOYED: Thu Aug 13 16:59:32 2026 NAMESPACE: zhixu STATUS: deployed REVISION: 1 NOTES: 1. Get the application URL by running these commands: export NODE_PORT=$(kubectl get --namespace zhixu -o jsonpath="{.spec.ports[0].nodePort}" services ittools) export NODE_IP=$(kubectl get nodes --namespace zhixu -o jsonpath="{.items[0].status.addresses[0].address}") echo http://$NODE_IP:$NODE_PORT [root@master ~]# export NODE_PORT=$(kubectl get --namespace zhixu -o jsonpath="{.spec.ports[0].nodePort}" services ittools) [root@master ~]# export NODE_IP=$(kubectl get nodes --namespace zhixu -o jsonpath="{.items[0].status.addresses[0].address}") [root@master ~]# echo http://$NODE_IP:$NODE_PORT http://192.168.31.101:32061 # 上面是执行了三条命令之后获取的 ip + 端口号 # 获取 zhixu 命名空间下 NodePort 模式下的端口号 32061 [root@master ~]# kubectl get svc -n zhixu NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE ittools NodePort 10.43.177.71 <none> 80:32061/TCP 16h # 获取 ip:192.168.31.101 kubectl get nodes -o wide # 查看 release 分布的节点 kubectl get pods -n zhixu -o wide
4.5 常用命令
# 1. 创建 Chart 模版(其实就是项目或者应用) helm create my-webapp # 2. 语法静态检查,检查 Chart YAML 语法是否符合标准 helm lint ./my-webapp # 3. 本地预览生成的 K8s YAML(调试用) helm template my-app ./my-webapp -f values.yaml # 4. 安装/升级应用(推荐带上 --install 参数,自动兼容初次部署与续更新) # 第一个参数 my-webapp 是 Release 名称,第二个参数 ./webmy-app 是 Chart 目录路径 helm upgrade --install my-webapp ./my-webapp -f values.yaml -n zhixu --create-namespace # 如果只有一份 values.yaml,下面和上面命令执行结果是一样的 helm upgrade --install my-webapp ./my-webapp -n zhixu --create-namespace # 上面的 upgrade 和 install 拆开也可以用 # 安装项目 helm install my-webapp ./my-webapp -n zhixu --create-namespace # 当你修改了 values.yaml 或想要更新应用版本时,使用 upgrade 命令: helm upgrade my-webapp ./my-webapp -n default # 实际开发中,通常用 -f values.yaml 区分开发/生产环境,比如 # values-dev.yaml:开发环境 (Development),本地或开发联调环境(资源给得少,方便调试) # values-test.yaml:测试环境 (Testing / QA),QA 团队自动化/功能测试环境 # values-staging.yaml:预发/灰度环境 (Staging),生产前的最终验证环境(连接生产只读库或镜像生产数据) # values-prod.yaml:生产环境 (Production),线上正式环境(高可用、高资源、严格证书与安全策略) # 5. 查看版本与状态 helm list -n zhixu # 查看当前 Namespace 下的 Release 列表 helm status my-app -n zhixu # 查看特定 Release 的详细部署信息和状态 helm history my-app -n zhixu # 查看历史版本记录 helm get values my-app -n zhixu # 查看特定 Release 当前生效的所有配置参数 # 6. 回滚与卸载 helm rollback my-app 1 -n zhixu # 回滚到指定的 Revision (如 1) helm uninstall my-app -n zhixu # 卸载并清除 Release 包含的所有 Kubernetes 资源(Deployment、Service、Secret 等)

五、生产环境中域名 + SSL证书的处理方案

本地部署不需要看这一部分内容,部署到云服务器上的时候需要关注

1、cert-manager

推荐使用 Helm 进行安装(官方最推荐的方式,易于后续升级和管理),上面已经添加并更新 Helm 仓库(https://charts.jetstack.io)

# 1、执行安装命令 helm upgrade --install cert-manager jetstack/cert-manager \ --version 1.19.6 \ --namespace cert-manager \ --create-namespace \ --set installCRDs=true # 2、验证安装状态 # 安装完成后,需确保 3 个 Pod 全部处于 Running 状态: kubectl get pods --namespace cert-manager # 你应该看到: # cert-manager-xxx: 核心控制器。 # cert-manager-cainjector-xxx: 负责注入 CA 证书。 # cert-manager-webhook-xxx: 负责校验配置。 以及(安装完成后会退出的)startupapicheck

2、创建证书签发器(ClusterIssuer)

证书签发器集群中可以创建多个,下面是生产环境签发器:新建 cluster-issuer.yaml 文件,,内容如下:

apiVersion: cert-manager.io/v1 kind: ClusterIssuer metadata: name: letsencrypt-prod spec: acme: # Let's Encrypt 官方 ACME 生产环境 API server: https://acme-v02.api.letsencrypt.org/directory # ⚠️ 务必替换为你自己的真实邮箱(证书即将到期但自动续期失败时,Let's Encrypt 会发邮件提醒) email: your-email@example.com # 保存 ACME 账户私钥的 Secret 名称 privateKeySecretRef: name: letsencrypt-prod-account-key solvers: - http01: ingress: class: traefik # 如果你的网关是 NGINX,写 nginx;K3s 默认写 traefik

测试环境签发器:调试时使用,防止触发公网频率限制,新建 cluster-staging-issuer.yaml 文件,内容如下:

apiVersion: cert-manager.io/v1 kind: ClusterIssuer metadata: name: letsencrypt-staging spec: acme: server: https://acme-staging-v02.api.letsencrypt.org/directory email: your-email@example.com # 替换为真实邮箱 privateKeySecretRef: name: letsencrypt-staging-account-key solvers: - http01: ingress: class: traefik

3、证书签发器配置到集群

# 应用配置: kubectl apply -f cluster-issuer.yaml # 检查 ClusterIssuer 状态 # 查看名为 letsencrypt-prod 的这一个 ClusterIssuer 资源状态 kubectl get clusterissuer letsencrypt-prod # 或者查看当前集群中已创建的所有 ClusterIssuer 资源状态 kubectl get clusterissuer # 正常输出示例: NAME READY AGE letsencrypt-prod True 38h # 如果 READY 为 False 或没有显示,使用 describe 命令查看具体的事件(Events)和状态条件(Conditions): kubectl describe clusterissuer letsencrypt-prod

4、HTTPS 证书处理方案

方案 A:在 Ingress 中启用 SSL 自动签发和续期(最推荐、全自动)

签发器配置好后,使用者完全不需要写繁琐的证书申请命令,只需要在应用的 Ingress 配置里加上一行 annotation 规则,cert-manager 就会全自动感知并完成证书申请、域名验证和 Secret 创建。以上面的 it-tools 应用配置为例,在 values.yaml 中配置:

# 域名 ittools.ddzhixu.com 必须解析到正确的公网 IP ingress: enabled: true className: "traefik" annotations: # 核心步骤:通过注解绑定刚才创建的 ClusterIssuer cert-manager.io/cluster-issuer: "letsencrypt-prod" hosts: - host: ittools.ddzhixu.com paths: - path: / pathType: ImplementationSpecific tls: - secretName: ittools-prod-zhixu-tls # cert-manager 自动创建并存储证书的 Secret 名称 hosts: - ittools.ddzhixu.com
让配置生效
# 部署/升级该 Helm Chart 后,cert-manager 会自动触发签发流程。 helm upgrade --install ittools ./ittools -n zhixu --create-namespace # 查看与排查证书状态 # 如果签发顺利,READY 列会变为 True kubectl get certificate -n zhixu # 如果 READY 一直是 False,可以通过以下命令诊断排查: # 1. 查看证书详细描述(通常包含了失败的原因) kubectl describe certificate <certificate-name> -n zhixu # 2. 查看 cert-manager 订单和挑战状态 kubectl get order -n zhixu kubectl get challenge -n zhixu

方案 B:手动绑定已有的商业证书/免费证书

如果你已经在云厂商(如阿里云/腾讯云)申请到了域名的 SSL 证书文件(tls.crt 和 tls.key):

# 1、手动在命名空间 zhixu 下创建 typecraft-tls-secret: kubectl create secret tls typecraft-tls-secret \ --cert=path/to/tls.crt \ --key=path/to/tls.key \ -n zhixu # 2、发布应用:只要 Secret 名字(typecraft-tls-secret)与 values.yaml 中的 tls[0].secretName 保持一致,Traefik 就会自动加载该证书。

六、其它

1、K3s 主要端口

端口协议源地址 (Source)目标 (Destination)用途与作用安全组放行建议(以阿里云/腾讯云为例)
6443TCPAgent 节点 IP
(及管理员运维 IP)
Server (Master)K3s API Server 通信切勿对 0.0.0.0/0 全网开放!
仅放行 Agent 节点内网 IP(如 192.168.31.101/32)及公司堡垒机/运维 IP。
8472UDP集群所有节点内网 IP
(Node ↔ Node)
所有节点Flannel VXLAN 跨节点容器网络叠加包传输内网互通即可。仅在安全组中设置集群节点内网 IP 互通,严禁对公网暴露 UDP
10250TCP集群所有节点内网 IP
(Server ↔ Agent)
所有节点kubelet API(用于 kubectl logs、exec 及 Metrics-Server 收集指标)仅限集群内网节点互通。如果对外暴露,黑客可利用 kubelet 接口未授权访问执行命令。
80TCPInternet (0.0.0.0/0)所有节点 / IngressHTTP 业务流量入口及 ACME (cert-manager) HTTP-01 证书签发校验公网全网开放 (0.0.0.0/0)
cert-manager 自动签发 Let’s Encrypt 证书必须依赖公网 80 端口的回调。
443TCPInternet (0.0.0.0/0)所有节点 / IngressHTTPS 加密业务流量入口公网全网开放 (0.0.0.0/0)
30000-32767TCP按需放行 / 内网放行所有节点K8s NodePort 默认端口范围按需开放
生产环境如果使用了 Ingress (80/443),建议不要向公网全量放行整个 30000-32767 网段,仅在需要裸露特定 Service 时针对性放行某个端口(如 32061)。

2、常用诊断命令

# 节点 kubectl get nodes -o wide # 所有 Pod kubectl get pods -A -o wide # 服务 kubectl get svc -A # Ingress kubectl get ingress -A # Deployment kubectl get deployment -A # 事件 kubectl get events -A --sort-by=.lastTimestamp # Pod 日志 kubectl logs <pod> -n <namespace> # Pod 描述 kubectl describe pod <pod> -n <namespace> # 常见 ImagePullBackOff,重点看:Events,如果:ImagePullBackOff # 检查:镜像地址 / Registry / 网络 / DNS / 认证 / registries.yaml # 可以直接测试:sudo crictl pull <image> # 常见 Pending # 重点看:Insufficient cpu / Insufficient memory / node affinity / pod anti-affinity / taint / toleration / PVC # 节点资源 kubectl top nodes # Pod 资源 kubectl top pods -A

3、K3s 服务日志

# Server: sudo journalctl -u k3s -n 200 --no-pager # 实时: sudo journalctl -u k3s -f # Agent: sudo journalctl -u k3s-agent -n 200 --no-pager # 实时: sudo journalctl -u k3s-agent -f

4、磁盘问题

# 检查: df -h # 检查 inode: df -i # 检查 K3s: sudo du -sh /var/lib/rancher/k3s # 检查容器数据: sudo du -sh /var/lib/rancher/k3s/agent # 如果磁盘不断增长,重点检查: 容器日志 镜像 Pod 临时文件 应用日志 数据库数据

5、常见证书问题

# 执行: kubectl get certificate -A # 然后: kubectl describe certificate <name> -n <namespace> # 再: kubectl get order -n <namespace> kubectl get challenge -n <namespace> 重点排查: DNS 80/TCP IngressClass Traefik ClusterIssuer 域名 公网 IP

6、环境检查

# 查看内核版本 uname -r # 查看系统架构 uname -m # 查看 hostname hostnamectl # 查看 cgroup stat -fc %T /sys/fs/cgroup # 查看 IP 转发 sysctl net.ipv4.ip_forward # 查看 bridge netfilter sysctl net.bridge.bridge-nf-call-iptables sysctl net.bridge.bridge-nf-call-ip6tables # 查看模块 lsmod | grep -E 'overlay|br_netfilter' # 查看磁盘 df -h # 查看内存 free -h # 查看防火墙 sudo systemctl status firewalld 2>/dev/null sudo systemctl status ufw 2>/dev/null # 查看监听端口 sudo ss -lntup # 如果虚拟机设置了快照,恢复快照出现时间不一致问题 systemctl restart chronyd && chronyc makestep # 检查时间 date

7、部署完成后的最终检查

# 建议按照下面顺序检查。 # 1. 节点 kubectl get nodes -o wide # 必须: Ready # 2. 系统 Pod kubectl get pods -A 不能长期: Pending CrashLoopBackOff ImagePullBackOff Error # 3. Storage kubectl get storageclass # 4. Ingress kubectl get ingress -A # 5. Certificate kubectl get certificate -A # 应该: READY=True # 6. Service kubectl get svc -A # 7. 应用 kubectl get deployment -A kubectl get pods -A -o wide # 8. HTTPS curl -I https://ittools.example.com
← 返回列表