【K8s】微服务类型配置实验

微服务类型及特点对比

类型 作用描述 适用场景
ClusterIP 自动分配集群内部虚拟 IP,仅限集群内访问 集群内部服务通信
NodePort 在所有节点开放静态端口(默认 30000-32767),外部通过 NodeIP:NodePort 访问 简单外部访问需求
LoadBalancer 基于 NodePort,结合云厂商负载均衡器分配外部 IP 云环境生产环境
ExternalName 通过 DNS CNAME 记录映射到外部域名,无集群 IP 集群内外服务迁移过渡
Headless 无集群 IP,DNS 直接解析到 Pod IP,不经过负载均衡 需直接访问 Pod 的场景(如 StatefulSet)

关键特点说明

  • ClusterIP:默认类型,安全性高,适合纯内部服务交互。
  • NodePort:通过节点物理端口暴露服务,适合测试或临时访问。
  • LoadBalancer:依赖云平台,自动管理流量分发,适合高可用生产环境。
  • ExternalName:无实际代理,仅提供 DNS 层转发,适用于集成外部服务。
  • Headless:直接暴露 Pod IP,适合有状态服务或需要独立寻址的场景。

以下内容已按照要求整理为结构化、无步骤词汇的Markdown格式:

查看iptables规则

复制代码
iptables -t nat -nL

IPVS

查看宿主机上与服务相关的iptables规则,了解默认的服务调度方式。

1.1, 安装ipvsadm工具

所有节点都下载

复制代码
yum install ipvsadm -y

在所有节点安装ipvsadm工具,用于支持ipvs模式。

修改kube-proxy配置

复制代码
kubectl -n kube-system edit cm kube-proxy

在配置中设置mode: "ipvs",将kube-proxy的模式修改为ipvs以提高大规模Pod场景下的性能。

1.2, 重启kube-proxy pod

复制代码
kubectl -n kube-system get pods | awk '/kube-proxy/{system("kubectl -n kube-system delete pods "$1)}'

使kube-proxy的配置生效,重启后采用ipvs模式。

查看ipvs规则

复制代码
ipvsadm -Ln

1.3,生成控制器和微服务yaml文件

先创建 Deployment 资源

cpp 复制代码
kubectl create deployment timinglee --image myapp:v1  --replicas 2 --dry-run=client -o yaml > timinglee.yaml

编辑 timinglee.yaml,确保 Deployment 和 Service 配置用 --- 分隔:

root@master ingress\]# vi timinglee.yaml ![](https://i-blog.csdnimg.cn/direct/d7546093a1bb497ba652b0d451159728.png) 应用yaml文件 kubectl apply -f timinglee.yaml 确认deployment是否成功创建 ```cpp kubectl get deployment timinglee ``` ****现在可以基于已存在的 Deployment 生成 Service 配置:**** ```cpp kubectl expose deployment timinglee --port 80 --target-port 80 --dry-run=client -o yaml >> timinglee.yaml ``` 生成包含Deployment和Service资源的yaml文件,用于创建部署和对应的微服务。 ```cpp [root@master ingress]# vi timinglee.yaml [root@master ingress]# kubectl apply -f timinglee.yaml deployment.apps/timinglee configured service/timinglee created ``` 文件具体配置 ```cpp apiVersion: apps/v1 kind: Deployment metadata: labels: app: timinglee name: timinglee spec: replicas: 2 selector: matchLabels: app: timinglee template: metadata: creationTimestamp: null labels: app: timinglee spec: containers: - image: myapp:v1 name: myapp --- #不同资源间用---隔开 apiVersion: v1 kind: Service metadata: labels: app: timinglee name: timinglee spec: ports: - port: 80 protocol: TCP targetPort: 80 selector: app: timinglee ``` 根据yaml文件创建Deployment和Service资源。 ```cpp kubectl get services kubectl get services -o wide ``` 查看创建的服务信息,包括名称、类型、集群IP、端口等详细信息。 #### ![](https://i-blog.csdnimg.cn/direct/3f4989a9784841f0b45cb5393d613916.png) 现在这里是没有外部IP的,因为我们没有配置type微服务类型 ### 微服务类型配置示例 #### 2.1,NodePort服务配置 apiVersion: v1 kind: Service metadata: labels: app: timinglee-service name: timinglee-service spec: ports: - port: 80 protocol: TCP targetPort: 80 selector: app: timinglee type: NodePort 通过节点上的端口将服务暴露给外部,外部可通过任意节点的IP和该端口访问服务。 *** ** * ** *** #### 2.2,LoadBalancer服务配置 云平台会为我们分配vip并实现访问,如果是裸金属主机那么需要metallb来实现ip的分配 LoadBalancer 是 Kubernetes 中 Service 类型,期望从底层获取外部 IP 暴露服务;MetalLB 是 开源组件,为无云厂商 LB 的集群,模拟实现 LoadBalancer 功能。 \[root@k8s-master \~\]# vim timinglee.yaml apiVersion: v1 kind: Service metadata: labels: app: timinglee-service name: timinglee-service spec: ports: - port: 80 protocol: TCP targetPort: 80 selector: app: timinglee type: LoadBalancer 在NodePort基础上,借助外部负载均衡器将服务暴露出去,适用于需要更高可用性的场景。 使文件生效 ```cpp kubectl apply -f myapp.yml ``` 这里type已经生效,但是因为还没有配置Metallb,所以一直处于就绪态 因为 Kubernetes 原生不支持自建集群的 LoadBalancer 功能,必须依赖 MetalLB 这类组件提供 IP 分配和网络宣告能力。 ![](https://i-blog.csdnimg.cn/direct/62780673227a41ec866f4a730afb5923.png) 解决办法:部署并配置 MetalLB 后,它会自动检测到该 Service,从 IP 池分配 IP 并完成网络配置,EXTERNAL-IP 会从 \ 变为具体 IP,状态就绪。 后面配置了metallb,就会获取到对外IP(这里的截图用的是后面ingress实验的,方便理解) ![](https://i-blog.csdnimg.cn/direct/6416173e75094befa7b447d5853b75ce.png) *** ** * ** *** #### 2.3,ExternalName服务配置 apiVersion: v1 kind: Service metadata: labels: app: timinglee-service name: timinglee-service spec: selector: app: timinglee type: ExternalName externalName: www.timinglee.org 通过DNS的CNAME记录将服务映射到指定域名,解决IP变化问题。 *** ** * ** *** ### **MetalLB** 前提条件:必须要把集群做成ipvs的模式,为metallb的部署做准备。 触发:创建 LoadBalancer 类型 Service 时,Kubernetes 调用 MetalLB。 分配 IP:MetalLB 从配置的 IP 池选一个 IP,绑定给该 Service。 宣告 IP:MetalLB 通过 ARP/BGP 协议,把 IP "广播" 到集群所在网络,让外部能访问。 #### **3.1,修改kube-proxy配置** kubectl edit cm -n kube-system kube-proxy ![](https://i-blog.csdnimg.cn/direct/cd5598b3cd9d49a6b71b304d2494ee3b.png) ![](https://i-blog.csdnimg.cn/direct/5f1fa0d778cd436cbe69f4fd425d9e8c.png) ![](https://i-blog.csdnimg.cn/direct/98d8495dd996424284146730dc3b85a4.png) 导入镜像 ![](https://i-blog.csdnimg.cn/direct/05b5e1e2bf7d405d9eaf61097bb82569.png) 获取metallb的部署文件并适配本地镜像仓库。 ```cpp [root@master metalLB]# vi configmap.yml [root@master metalLB]# vi metallb-native.yaml 这个文件内容太长就不粘贴了 [root@master metalLB]# ls configmap.yml metallb-native.yaml metalLB.tag.gz [root@master metalLB]# ``` ```cpp [root@master metalLB]# vi configmap.yml apiVersion: metallb.io/v1beta1 kind: IPAddressPool metadata: name: first-pool namespace: metallb-system spec: addresses: - 172.25.254.50-172.25.254.99 #改为自己网段范围的50-99 --- apiVersion: metallb.io/v1beta1 kind: L2Advertisement metadata: name: example namespace: metallb-system spec: ipAddressPools: - first-pool ``` ![](https://i-blog.csdnimg.cn/direct/bdbd24b359694e15aef4bff11318c31f.png) #### 3.2,上传metallb镜像 ![](https://i-blog.csdnimg.cn/direct/d48b7892fe7b427aab8296baf79a63f3.png) ```cpp docker tag quay.io/metallb/controller:v0.14.8 reg.timinglee.org/metallb/controller:v0.14.8 docker tag quay.io/metallb/speaker:v0.14.8 reg.timinglee.org/metallb/speaker:v0.14.8 docker push reg.timinglee.org/metallb/controller:v0.14.8 docker push reg.timinglee.org/metallb/speaker:v0.14.8 ``` ![](https://i-blog.csdnimg.cn/direct/dbee261c98ad46f3b8f75f48914e1e7f.png) ![](https://i-blog.csdnimg.cn/direct/522e405a012d43dd87288d6bc01076c2.png) 将metallb所需镜像上传到本地仓库。 ![](https://i-blog.csdnimg.cn/direct/7008bf8a3cce4305b17a7abc69c5faf9.png) #### 3.3,部署metallb 部署metallb服务,为LoadBalancer类型的服务提供IP分配能力。 按顺序部署 ![](https://i-blog.csdnimg.cn/direct/9cc804639c574b119c80d91b3dc45ad0.png) kubectl apply -f metallb-native.yaml 稍等片刻等待运行 ![](https://i-blog.csdnimg.cn/direct/8adc7e93d5154ca8bf5b94e58d086df5.png) 再部署第二个文件 配置metallb可分配的IP地址范围,使LoadBalancer服务能获取到外部IP。 ![](https://i-blog.csdnimg.cn/direct/ca8dd5590066445e898973ef94d524b2.png) *** ** * ** *** ### **Ingress-nginx** **前提条件:部署完metallb** #### 4.1,下载ingress-nginx部署文件 wget https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v1.11.2/deploy/static/provider/baremetal/deploy.yaml 我这里是直接导入文件 ![](https://i-blog.csdnimg.cn/direct/c29e9bbace7f43568fb7ad1bd64e500d.png) ![](https://i-blog.csdnimg.cn/direct/172e9c9fa541417ea1dc94566f24e41c.png) 导入镜像 ![](https://i-blog.csdnimg.cn/direct/d04f34e8957942298e6628a307cc840c.png) 获取ingress-nginx的部署文件。 #### 4.2,上传ingress-nginx镜像 ```cpp [root@master ingress]# docker tag registry.k8s.io/ingress-nginx/controller:v1.13.1 reg.timinglee.org/ingress-nginx/controller:v1.13.1 [root@master ingress]# docker tag registry.k8s.io/ingress-nginx/kube-webhook-certgen:v1.6.1 reg.timinglee.org/ingress-nginx/kube-webhook-certgen:v1.6.1 [root@master ingress]# docker push reg.timinglee.org/ingress-nginx/kube-webhook-certgen:v1.6.1 [root@master ingress]# docker push reg.timinglee.org/ingress-nginx/controller:v1.13.1 表示上传到 网站地址/目录/名字 上传前如果没有该ingress-nginx目录要先创建 ``` 将ingress-nginx所需镜像上传到本地仓库。 ![](https://i-blog.csdnimg.cn/direct/baf4069cd8984eceacda226316dd1ccd.png) #### 4.3,安装ingress-nginx 修改配置文件 把前缀和后缀删掉,冒号后面要有一个空格,注意不要误删 ![](https://i-blog.csdnimg.cn/direct/9dbd8502940944748c770d1e2ae2cb92.png) ![](https://i-blog.csdnimg.cn/direct/e8fbb4252d114c1cafa305099b4cfc8c.png) ![](https://i-blog.csdnimg.cn/direct/90d6412111674f4ba5753ed97de25331.png) kubectl apply -f deploy.yaml ![](https://i-blog.csdnimg.cn/direct/c1687a0510304bd6a1d7b6fb007242b8.png) ![](https://i-blog.csdnimg.cn/direct/ca7c0a1fa96f4c859facac0a40e88981.png) ```cpp #修改微服务为可以对外开放的loadbalancer [root@k8s-master ~]# kubectl -n ingress-nginx edit svc ingress-nginx-controller 49 type: LoadBalancer ``` ![](https://i-blog.csdnimg.cn/direct/000b354d3cc4444c97962c718f83d915.png) 修改后可以通过该命令查看镜像 ![](https://i-blog.csdnimg.cn/direct/08788450467a46b1aca3d222a545dceb.png) ```cpp kubectl -n ingress-nginx describe pod ingress-nginx-controller-7bf698f798-l5hsv | grep "Image:" ``` ![](https://i-blog.csdnimg.cn/direct/4e8a54380f2c45f5a6c2ef07b7f7442f.png) ![](https://i-blog.csdnimg.cn/direct/4afd4cba687a4cec82db45d2c524fb13.png) 注意:Kubernetes 是增量式应用配置,首次 apply 主要是初始化各种资源,让控制器、服务等逐步就绪。 二次 apply 是补足依赖、修正配置,让整个 ingress-nginx 生态(控制器、服务、规则 )完全就绪。 简单说,就是首次部署是 "搭框架",二次 apply 是 "填细节、补依赖",让整个 ingress 环境从 "部分就绪" 变成 "完全可用",所以需要多次 apply 来推进不同阶段的资源配置和状态调和 这就是为什么查看状态没有问题但状态一直是\的原因 此时就要再次apply 然后修改微服务 ![](https://i-blog.csdnimg.cn/direct/58649339551b4c0bbefeabaa88051dc6.png) ![](https://i-blog.csdnimg.cn/direct/6ad4e7b697a4448e933c50e918403a50.png) ```cpp #生成yaml文件 [root@k8s-master ~]# kubectl create ingress webcluster --rule '*/=timinglee-svc:80' --dry-run=client -o yaml > timinglee-ingress.yml [root@k8s-master ~]# vim timinglee-ingress.yml aapiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: test-ingress spec: ingressClassName: nginx rules: - http: paths: - backend: service: name: timinglee-svc port: number: 80 path: / pathType: Prefix #Exact(精确匹配),ImplementationSpecific(特定实现),Prefix(前缀匹配),Regular expression(正则表达式匹配) ``` 部署ingress-nginx控制器,提供7层负载均衡能力。 ![](https://i-blog.csdnimg.cn/direct/bc99644d5b8443a78fd329433b0ddd96.png) 同理,再次apply ![](https://i-blog.csdnimg.cn/direct/7e519ca5816d4344b3d89bdd7973dd37.png) #### **4.4,测试** ```cpp kubectl -n ingress-nginx get service ingress-nginx-controller ``` ![](https://i-blog.csdnimg.cn/direct/44fa1599f6714e678b0cd3cfef687f59.png) ![](https://i-blog.csdnimg.cn/direct/7517981d41b34fcc98be18adb038a259.png) ![](https://i-blog.csdnimg.cn/direct/333ef007bddb47fe978cb58bf33b5f6d.png) ![](https://i-blog.csdnimg.cn/direct/f4936416d7d4413bb9afeb421c68c1a8.png) *** ** * ** *** ### Ingress高级功能 #### **5.1,基于路径的访问** 配置基于路径的转发将不同路径映射到不同后端服务。 ```cpp [root@master myapp]# kubectl -n ingress-nginx get ingressclasses.networking.k8s.io NAME CONTROLLER PARAMETERS AGE nginx k8s.io/ingress-nginx 5h14m [root@master myapp]# kubectl create ingress ingress-test --class nginx \ > --rule="*/myappv1=myapp-v1:80" \ > --dry-run=client -o yaml > ingress-test.yml [root@master myapp]# ls ingress-test.yml myapp-v1.yaml myapp-v2.yaml [root@master myapp]# vi ingress-test.yml [root@master myapp]# kubectl apply -f ingress-test.yml ``` ![](https://i-blog.csdnimg.cn/direct/67f8c8a538124fd09b473e536896ac69.png) > **Ps:如果文件配置错误,需要重新上传** > > \[root@master myapp\]#**kubectl delete ingress test-ingress** > > ingress.networking.k8s.io "test-ingress" deleted > > \[root@master myapp\]# **kubectl apply -f ingress-test.yml** > > ingress.networking.k8s.io/ingress-test created ![](https://i-blog.csdnimg.cn/direct/0589398376eb40a298a4c6f154309ede.png) \[root@master myapp\]# kubectl describe ingress ![](https://i-blog.csdnimg.cn/direct/8b99c11209334675a6a87ca1438fa24f.png) 执行curl 172.25.254.5(外部访问 IP),返回v1版本响应,确认通过 Ingress 成功从集群外部访问到myappv1。 ![](https://i-blog.csdnimg.cn/direct/be228055e5a8421e9ab23d1124fe03b0.png) *** ** * ** *** #### **5.2,基于域名的访问** 配置基于域名的转发使不同域名指向不同服务。 编辑yml文件 ![](https://i-blog.csdnimg.cn/direct/84baf6cc13f540afa88f75ecd97a8e67.png) ![](https://i-blog.csdnimg.cn/direct/aa02efdcb6504dbaa76a02cbda72fe59.png) ![](https://i-blog.csdnimg.cn/direct/4047e4d02bf44ceea326706b52c58835.png) Name是你的实际服务名,我这里少了一条杠-,已经改过来了 ![](https://i-blog.csdnimg.cn/direct/162b05d1c59249e6879dca70463b3fae.png) ![](https://i-blog.csdnimg.cn/direct/7afe8fa4871b45daa36fed9b0be61b78.png) ```cpp #添加域名解析 [root@master ingress]# cat host-ingress.yml apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: host-ingress annotations: nginx.ingress.kubernetes.io/rewrite-target: / spec: ingressClassName: nginx rules: - http: paths: - backend: service: name: myapp-v1 port: number: 80 path: / pathType: Prefix host: myappv1.timinglee.org - http: paths: - backend: service: name: myapp-v2 port: number: 80 path: / pathType: Prefix host: myappv2.timinglee.org ``` 查看状态有没有问题 \[root@master ingress\]# kubectl describe ingress ![](https://i-blog.csdnimg.cn/direct/437b863ce4e4429080e10e28a1f7838a.png) \[root@master ingress\]# kubectl get ingress ![](https://i-blog.csdnimg.cn/direct/460eaec82f674f1b94c4311e2da9000f.png) > Ps:如果**某个服务有问题**可以通过如下命令具体查看 > > \[root@master ingress\]#**kubectl describe svc myapp-v1** 测试 ![](https://i-blog.csdnimg.cn/direct/5b3a39afccbe473580ab0c6348a5751a.png) ![](https://i-blog.csdnimg.cn/direct/802f7ca36dbc429f8ba12a2834c85566.png) 删除,避免影响后续实验 ![](https://i-blog.csdnimg.cn/direct/be25c24576af4b99a863c1113b07c200.png) #### 5.3,**建立tls加密** 使用自签名或正式证书配置TLS加密。 生成证书去加密 ![](https://i-blog.csdnimg.cn/direct/fee92ed75d1d4ee0a1eec317a2753737.png) 此时证书还没和集群连起来,把证书变成资源,能被集群调用 ```cpp #建立加密资源类型secret [root@k8s-master app]# kubectl create secret tls web-tls-secret --key tls.key --cert tls.crt secret/web-tls-secret created [root@k8s-master app]# kubectl get secrets ``` #建立ingress3基于tls认证的yml文件 ```cs [root@k8s-master app]# vim ingress3.yml apiVersion: networking.k8s.io/v1 kind: Ingress metadata: annotations: nginx.ingress.kubernetes.io/rewrite-target: / name: ingress3 spec: tls: - hosts: - myapp-tls.timinglee.org secretName: web-tls-secret ingressClassName: nginx rules: - host: myapp-v1.timinglee.org http: paths: - backend: service: name: myapp-v1 port: number: 80 path: / pathType: Prefix ``` #测试 ```cs [root@reg ~]# curl -k https://myapp-v1.timinglee.org Hello MyApp | Version: v1 | Pod Name ``` 查看新建的ingress的详细情况,是否加密成功 ![](https://i-blog.csdnimg.cn/direct/55ebb3f116514f3082d750349e392a26.png) 此时无法直接访问 ```cs curl myapp-v1.timinglee.org ``` ![](https://i-blog.csdnimg.cn/direct/c80ed5be384d452db35b203f4d4f1d6c.png) 如何访问 ```bash curl -k https://myapp-v1.timinglee.org ``` ![](https://i-blog.csdnimg.cn/direct/a4fa8e607fc648e3a6a7acbf2bfcee2f.png) https:// 表示使用 HTTPS 协议 访问,符合 Ingress 配置中强制 HTTPS 的要求,因此不会被重定向。 -k 参数的作用是 跳过 SSL 证书验证 *** ** * ** *** #### 5.4,**建立auth认证** 在Ingress层面添加HTTP基本认证保护后端服务。 建立认证文件 ```cpp [root@k8s-master app]# dnf install httpd-tools -y [root@k8s-master app]# htpasswd -cm auth lee New password: Re-type new password: Adding password for user lee [root@k8s-master app]# cat auth ``` 建立认证类型资源,把这个叫做htpasswd的文件抽象成集群中的资源 ```cpp [root@k8s-master app]# kubectl create secret generic auth-web --from-file auth root@k8s-master app]# kubectl describe secrets auth-web ``` ![](https://i-blog.csdnimg.cn/direct/00cf0b52340543b894a13c629b8d526f.png) ```cpp apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name:host-ingress annotations: nginx.ingress.kubernetes.io/auth-type: basic nginx.ingress.kubernetes.io/auth-secret: auth-web nginx.ingress.kubernetes.io/auth-realm: "Please input username and password" nginx.ingress.kubernetes.io/rewrite-target: / spec: ingressClassName: nginx rules: - host: myapp-tls.timinglee.org http: paths: - backend: service: name: myapp-v1 port: number: 80 path: / pathType: Prefix ``` 测试: **不使用用户名和密码访问时** 出现**401** Authorization Required 错误,这是因为在 Ingress 配置中启用了基本认证(Basic Authentication) ,只有提供正确的用户名和密码才能访问后端服务。 ![](https://i-blog.csdnimg.cn/direct/3439d02924544d72bc0b660d77185fed.png) ![](https://i-blog.csdnimg.cn/direct/4e18c3a001af448e808ac68e2680460b.png) ![](https://i-blog.csdnimg.cn/direct/80951ad0cd1e40d08bcf818dc0858d47.png) #### **5.5,Rewrite重定向** 使用正则表达式重写URL路径实现Rewrite重定向。 ![](https://i-blog.csdnimg.cn/direct/e8439459b48142b898fa77c6a9dd9468.png) ```cpp [root@master ingress]# vi rewrite-ingress.yml [root@master ingress]# kubectl apply -f rewrite-ingress.yml [root@master ingress]# cat rewrite-ingress.yml apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: rewrite-ingress annotations: nginx.ingress.kubernetes.io/use-regex: "true" nginx.ingress.kubernetes.io/rewrite-target: /$2 spec: ingressClassName: nginx rules: - http: paths: - backend: service: name: myapp-v1 port: number: 80 path: /haha(/|$)(.*) pathType: ImplementationSpecific ``` > **path: /haha(/\|$)(.\*)** > > 这是用于匹配外部访问 URL 的正则表达式,拆解如下: > > /haha:固定前缀,匹配包含/haha的路径(如/haha、/haha/、/haha/abc等)。 > > (/\|$):匹配/或字符串结尾($),避免误匹配类似/hahaX的路径: > > (/:匹配/haha后的斜杠(如/haha/abc中的/)。 > > $):匹配/haha本身(无后续字符,如/haha)。 > > (.\*):捕获/haha/之后的所有字符(任意长度、任意字符),作为第二个分组($2)。 > > rewrite-target: /$2 > > 定义路径重写规则:将匹配到的 URL 重写为/$2,其中$2对应正则表达式中第二个分组(.\*)捕获的内容。 ****核心作用:**** 通过正则表达式的分组捕获和重写规则,实现了 "外部访问路径/haha/\*映射到后端服务的/\*路径" 的效果。 没有创建haha目录,但我们访问是会重定向到v1对印的 客户端请求 → Ingress 匹配正则 path → 路径重写(/haha/hostname.html → /hostname.html) → 转发到 myapp-v1 Service → Service 负载到 Pod → Pod 返回响应 这样就实现了 "带路径前缀的请求,经 Ingress 重写后,精准转发到后端服务特定路径" 的效果。 ![](https://i-blog.csdnimg.cn/direct/aebe0fe837104ab0a5711e21f3e018bc.png) ![](https://i-blog.csdnimg.cn/direct/bbd16cc1b1a24b8e9cb023627d953015.png) 对比$1和$2:将配置文件的$2改为$1,其他不变 ![](https://i-blog.csdnimg.cn/direct/a95a172d4932497293fc30c5f5f08320.png) ![](https://i-blog.csdnimg.cn/direct/c1603bdf132c4a089da0babbdd1c84ea.png) ![](https://i-blog.csdnimg.cn/direct/bd6df9fd13684f8da16414e230f84796.png) ![](https://i-blog.csdnimg.cn/direct/f051aabd29c44bc48bfde1091baf21f9.png) *** ** * ** *** ### 金丝雀发布 #### 6.1,初始版本 创建原始old版本方便后续对比 ![](https://i-blog.csdnimg.cn/direct/e9bcd938883a475fac09c560e4ba33d7.png) ```cpp [root@master myapp]# cat ingress-test.yml apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: ingress-old spec: ingressClassName: nginx rules: - http: paths: - backend: service: name: myapp-v1 port: number: 80 path: / pathType: Prefix ``` ![](https://i-blog.csdnimg.cn/direct/5cc23515fbcf410aa8f8f08f834e5118.png) ![](https://i-blog.csdnimg.cn/direct/5ae2e4441fd043f4a2a3d4c513c6efa3.png) #### 6.2,****基于header(http包头)灰度**** 通过特定HTTP头将流量路由到新版本实现基于Header的灰度。 创建灰度ingress,配置灰度头部key以及value #建立基于header的ingress ![](https://i-blog.csdnimg.cn/direct/ca8b9804f2f54d22b782316cc1a7a725.png) ```cpp apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: ingress-new annotations: nginx.ingress.kubernetes.io/canary: "true" nginx.ingress.kubernetes.io/canary-by-header: "timinglee" nginx.ingress.kubernetes.io/canary-by-header-value: "6" spec: ingressClassName: nginx rules: - http: paths: - backend: service: name: myapp-v2 port: number: 80 path: / pathType: Prefix ``` ![](https://i-blog.csdnimg.cn/direct/1b2c70d5ff6c45f48c9d6ec6f6d254a1.png) 测试 ![](https://i-blog.csdnimg.cn/direct/8f47e981016442908bb0b59cb77d9c3d.png) ![](https://i-blog.csdnimg.cn/direct/503ecb8e22434f8cb4d3f3215d440af9.png) 基于包头灰度发布 curl -v:-v:开启 verbose 模式,输出请求 / 响应的详细过程(协议交互细节) ![](https://i-blog.csdnimg.cn/direct/350417e7fb6548ce9041a26a24b09818.png) * ****-v**** :开启 verbose 模式,输出请求 / 响应的详细过程(协议交互细节) * ****-H "timinglee:7"**** :****自定义 HTTP 请求头**** ,添加 timinglee:7 键值对(业务自定义头) 可以通过该参数设置包头,并且随时可以改 ![](https://i-blog.csdnimg.cn/direct/c15e1dc72e604c54be15ca4f1defb4af.png) ![](https://i-blog.csdnimg.cn/direct/debf6060f4e74fe98853cf4e7a5961d8.png) #### **6.3,基于权重的灰度发布** 按比例分配流量实现基于权重的灰度。 ![](https://i-blog.csdnimg.cn/direct/fe5190d7a0cc4b9f8892719b56dba71f.png) ```cpp apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: ingress-new annotations: nginx.ingress.kubernetes.io/canary: "true" nginx.ingress.kubernetes.io/canary-weight: "10" nginx.ingress.kubernetes.io/canary-weight-total: "100" spec: ingressClassName: nginx rules: - http: paths: - backend: service: name: myapp-v2 port: number: 80 path: / pathType: Prefix ``` canary-weight: "10":流量分配核心!**表示 10% 的请求会路由到 myapp-v2**(金丝雀版本),剩余 90% 路由到基础 Ingress(需存在路由 myapp-v1 的 Ingress)。 可以看到大部分的访问都划给了v1,只有一个给了v2 ![](https://i-blog.csdnimg.cn/direct/0fedea8fb9184272a405e303aa3f85ea.png) 使用脚本模拟请求验证流量分配比例。 那么具体访问次数对比?手动测试次数太多不方便,于是我们写一个脚本来测试 ```bash #!/bin/bash v1=0 v2=0 for (( i=0; i<100; i++)) do response=`curl -s 192.168.1.50 |grep -c v1` v1=`expr $v1 + $response` v2=`expr $v2 + 1 - $response` done echo "v1:$v1, v2:$v2" ``` 结果没有那么准确但是基本接近 ![](https://i-blog.csdnimg.cn/direct/4eb8df40fc88451fa37ca2347ebea4fa.png) V2值太低,提高一下v2的权重 ```cpp [root@master myapp]# vi ingress-test2.yml [root@master myapp]# kubectl apply -f ingress-test2.yml ingress.networking.k8s.io/ingress-new configured [root@master myapp]# sh check_ingressWeight.sh ``` ![](https://i-blog.csdnimg.cn/direct/c534f91685e246af81fdbd468ed96775.png) ![](https://i-blog.csdnimg.cn/direct/74d06b46fc294dc5b2522a7c2305c72b.png) 再修改文件 修改权重 过滤v1访问v2 ![](https://i-blog.csdnimg.cn/direct/0199c36edcf349429517aa77084badd2.png) ![](https://i-blog.csdnimg.cn/direct/9edf5b4b9e8e41be9295e896d253a2c3.png) 避免影响后续实验,做完后删除配置 ![](https://i-blog.csdnimg.cn/direct/df819e06265f47a0ab9062aec3c4c9f2.png) ### 常见问题与排查 检查Harbor仓库、镜像标签、网络策略解决镜像拉取失败。检查资源配额、节点调度条件、网络插件状态解决Pod一直Pending。 检查Service类型、Ingress配置、防火墙规则解决服务无法访问。检查kubelet状态、网络插件、CNI配置解决节点NotReady。 #### 强制删除正在运行的pod 想让其尽快终止完成,可结合 ```cpp kubectl delete pod myapp-v1-7479d6c54d-g7jh6 --grace-period=0 --force ``` (强制删除,跳过宽限期 ![](https://i-blog.csdnimg.cn/direct/4fcd16c629b6485384b04fd5250c498a.png) *** ** * ** *** #### pod状态运行问题 ![](https://i-blog.csdnimg.cn/direct/2c89b2e3ce2d4685a3183c92105c4525.png) 1.查看镜像拉取失败的具体原因 > \[root@master \~\]# kubectl describe pod -n kube-flannel kube-flannel-ds-2vf9x > > 通过 kubectl describe pod \ 命令查看详细错误信息,确认具体的镜像拉取问题。 错因:镜像拉取不到 没有在harbor上上传这两个镜像,要上传 ![](https://i-blog.csdnimg.cn/direct/a45eb9c47cba4b74b87c34bb2ec1632a.png) 2..检查3个节点状态运行是否正常(是否都是ready) ![](https://i-blog.csdnimg.cn/direct/e649ff036cf144448bd22b5d78343830.png) 3..Ifconfig检查flannel有没有IP ![](https://i-blog.csdnimg.cn/direct/6a7d6c1f1f394131b195c44577f5394c.png) ![](https://i-blog.csdnimg.cn/direct/d6a29e87ed8147f583617e0ea454bf54.png) ![](https://i-blog.csdnimg.cn/direct/033237ad32174589968651971d84395c.png) 4..检查网关 ![](https://i-blog.csdnimg.cn/direct/8d9afc508cd44b1ca22366e4084de702.png) Master的网络挂了 对节点网络不通 ![](https://i-blog.csdnimg.cn/direct/108545a634c34a169241e1c90a495327.png) Ping自己可以 检查策略 ![](https://i-blog.csdnimg.cn/direct/65bb11ca87d6494fbc23f357b749b882.png) #### 连接仓库失败 ![](https://i-blog.csdnimg.cn/direct/508b29fb00a1496daae84397435fbabb.png) 每次关闭虚拟机后重新打开时都要重启一下harbor仓库 ![](https://i-blog.csdnimg.cn/direct/a2d44a0030044d79a6767a7c8662bc1d.png) *** ** * ** *** #### apply文件报错 ![](https://i-blog.csdnimg.cn/direct/f267c2b1ab96449e9881bce22e3d95ca.png) 错误提示表明容器名称包含了点(.)字符,而 Kubernetes 中容器名称不允许包含点。这是因为 Kubernetes 对容器名称有严格的命名规范:只能包含字母、数字、连字符(-)和下划线(_),且必须以字母或数字开头和结尾。 解决方法:需要修改liveness.yml文件中容器的name字段,移除其中的点(.)或替换为允许的字符(如连字符-)。 ![](https://i-blog.csdnimg.cn/direct/1b3b2227c8bc422d9b9753cd911d682d.png) ![](https://i-blog.csdnimg.cn/direct/2ea275bbb33c4eff89163481dd8f53db.png) 说明刚刚敲的配置文件键值对中间少了空格