service简介
Service 主要负责集群内部通讯流量,称之为东西流量(具有 Namespace 隔离性);Service 是 Kubernetes 实现微服务架构的核心概念,通过创建 Service,可以为一组具有相同功能的容器应用提供一个统一的入口地址,并且将请求负载分发到后端的各个容器应用上。Service 用于为一组提供服务的 Pod 抽象一个稳定的网络访问地址。
Label 和 Selector
Label(标签)是 Kubernetes 系统中的另一个核心概念,相当于我们熟悉的"标签"。一个 Label 是一个 key=value 键值对,其中的 key 与 value 由用户自己指定。Label 可以被附加到各种资源对象上,例如 Node、 Pod、Service、Deployment 等,一个资源对象可以定义任意数量的 Label,同一个 Label 也可以被添加到任意数量的资源对象上。Label 通常在资源对象定义时确定,也可以在对象创建后动态添加或者删除。可以通过给指定的资源对象捆绑一个或多个不同的 Label 来实现多维度的资源分组管理功能,以便灵活、方便地进行资源分配、调度、配置、 部署等管理工作。
Label Selector(标签选择器)查询和筛选拥有某些 Label 的资源对象,Kubernetes 通过这种方式实现了类似 SQL 的简单又通用的对象查询机制。Label Selector 可以被类比为 SQL 语句中的 where 查询条件,例如,"name=redis-slave"这个 Label Selector 作用于 Pod 时,可以被类比 为 select * from pod where name='redis-slave' 这样的语句。当前有两种 Label Selector 表达式:基于等式的(Equality-based)Selector表达式和基于集合的(Set-based)Selector表达式。
-
等式类表达式
- name=redis-slave:匹配所有具有 name=redis-slave 标签的资源对象。
- env != prod:匹配所有不具有 env=prod 标签的资源对象,比如"env=test"就是满足此条件的标签之一。
-
集合操作类表达式
- name in (redis-master,redis-slave):匹配所有具有 name=redis-master 标签或者 name=redis-slave 标签的资源对象。
- name not in (php-frontend):匹配所有不具有 name=php-frontend 标签的资源对象。
示例:
# Step 1:查看节点所有的标签`
`$ kubectl get nodes --show-labels`
`# Step 2:查看符合指定标签的节点`
`$ kubectl get nodes -l node-role.kubernetes.io/control-plane=`
`NAME STATUS ROLES AGE VERSION`
`prod-k8s-master01 Ready control-plane 6d3h v1.31.12`
`prod-k8s-master02 Ready control-plane 6d3h v1.31.12`
`prod-k8s-master03 Ready control-plane 6d3h v1.31.12`
`# Step 3:给指定节点打上标签`
`$ kubectl label nodes prod-k8s-master0{1..3}` `role=master`
`node/prod-k8s-master01 labeled`
`node/prod-k8s-master02 la-beled`
`node/prod-k8s-master03 labeled`
`$ kubectl label nodes prod-k8s-node0{1..3}` `role=work`
`node/prod-k8s-node01 labeled`
`node/prod-k8s-node02 labeled`
`node/prod-k8s-node03 labeled`
`# Step 3:查看不符合指定标签的节点`
`$ kubectl get nodes -l role!=master`
`NAME STATUS ROLES AGE VERSION`
`prod-k8s-node01 Ready <none> 6d4h v1.31.12`
`prod-k8s-node02 Ready <none> 6d4h v1.31.12`
`prod-k8s-node03 Ready <none> 4d23h v1.31.12`
`# Step 4:集合方式查看`
`$ kubectl get nodes -l 'role in (master,work)'`
`NAME STATUS ROLES AGE VERSION`
`prod-k8s-master01 Ready control-plane 6d4h v1.31.12`
`prod-k8s-master02 Ready control-plane 6d4h v1.31.12`
`prod-k8s-master03 Ready control-plane 6d4h v1.31.12`
`prod-k8s-node01 Ready <none> 6d4h v1.31.12`
`prod-k8s-node02 Ready <none> 6d4h v1.31.12`
`prod-k8s-node03 Ready <none> 4d23h v1.31.12`
`$ kubectl get nodes -l 'role notin (master,work)'`
`# Step 5:通过标签key查看`
`kubectl get nodes -l role`
`NAME STATUS ROLES AGE VERSION`
`prod-k8s-master01 Ready control-plane 6d4h v1.31.12`
`prod-k8s-master02 Ready control-plane 6d4h v1.31.12`
`prod-k8s-master03 Ready control-plane 6d4h v1.31.12`
`prod-k8s-node01 Ready <none> 6d4h v1.31.12`
`prod-k8s-node02 Ready <none> 6d4h v1.31.12`
`prod-k8s-node03 Ready <none> 4d23h v1.31.12`
`# Step 6:修改标签`
`$ kubectl label node prod-k8s-node01 role=node --overwrite `
`node/prod-k8s-node01 labeled`
`$ kubectl get nodes -l role=node`
`NAME STATUS ROLES AGE VERSION`
`prod-k8s-node01 Ready <none> 6d4h v1.31.12`
`# Step 7:删除标签`
`$ kubectl label nodes prod-k8s-node01 node-
软件定义型网络


现在常用IPVS

service类型: ClusterIP

创建 ClusterIP service
查看 service-db.yml
kubectl create -f service-db.yml
# cat service-db.yml`
`apiVersion:` `"v1"`
`kind:` `"Service"`
`metadata:`
`name:` `"database-service"`
`spec:`
`type:` `"ClusterIP"`
`ports:`
`-` `protocol:` `"TCP"`
`port:` `3306`
`selector:`
`app:` `"db"`
`sessionAffinity: ClientIP
检查服务及其端点
kubectl get services -o wide
kubectl get pods -o wide --show-labels
kubectl get endpoints

查看地址转换

重建webserver pod
kubectl delete pod webserver
kubectl create -f pod-web.yml
访问 http://WEBSERVER-POD-IP/cgi-bin/action
可以看到在没有更改数据库连接地址,依然可以访问数据库,为什么?
因为应用程序根本不需要知道数据库真实的 IP 是什么,它只需要连接 Kubernetes 为数据库分配的那个"永远不会变的虚拟 IP(ClusterIP)"即可

使用以下命令探索
kubectl exec -it webserver -- bash
grep connect /var/www/cgi-bin/action
env | grep DATABASE_SERVICE

会发现当service创建之后,pod在重建时会自动配置环境变量
SVCNAME_SERVICE_HOST
SVCNAME_SERVICE_PORT
CoreDNS (KubeDNS/SkyDNS)
- 通过 Kubernetes 监控服务和端点
- 管理相关 DNS 资源
- 创建默认集群 DNS 名称
- cluster.local
- 将 DNS 名称分配给命名空间
- default.svc.cluster.local
- 为服务分配 DNS 名称
- database-service.default.svc.cluster.local
- 创建A类资源记录:ClusterIP
- 创建默认集群 DNS 名称

查看kube-dns
kubectl get namespaces
kubectl -n kube-public describe configmap cluster-info
kubectl -n kube-system get svc -o wide
kubectl -n kube-system get po -o wide -l k8s-app=kube-dns
kubectl -n kube-system describe ep kube-dns
检查服务主机名
kubectl exec -it webserver -- bash
ping -c1 database-service
ping -c1 database-service.default
telnet database-service 3306
cat /etc/resolv.conf
最佳实践
在k8s集群中组件之间直接通过服务名称互访
kubectl exec -it webserver -- bash
vi /var/www/cgi-bin/action

重构镜像
查看 /resources/build-dns.sh
# cat build-dns.sh`
`#!/bin/bash`
`#export CID=$(docker ps -a | grep webapp | cut -f1 -d ' ')`
`#docker rm -f $CID &>/dev/null`
`export CID=$(docker create reg.westos.org/library/httpd:webapp)`
`#export CID=$(docker ps -a | grep webapp | cut -f1 -d ' ')`
`docker cp /resources/httpd.conf $CID:/etc/httpd/conf/`
`docker cp /resources/run-httpd.sh $CID:/`
`docker cp /resources/action $CID:/var/www/cgi-bin/`
`docker commit $CID reg.westos.org/library/httpd:dns`
`docker push reg.westos.org/library/httpd:dns`
`docker rm $CID`
`


使用查询 DNS 数据库服务的新应用程序创建镜像: /resources/action
con = mdb.connect('database-service', 'root', 'redhat', 'mysql')
# cat action`
`#!/usr/bin/python`
`# -*- coding: utf-8 -*-`
`import MySQLdb as mdb`
`import os`
`con = mdb.connect('database-service',` `'root',` `'redhat',` `'mysql')`
`with` `con:`
` cur = con.cursor()`
` cur.execute("SELECT User FROM user")`
` rows = cur.fetchall()`
` print 'Content-type:text/html\r\n\r\n'`
` print '<html>'`
` print '<head>'`
` print '<title>My Application</title>'`
` print '</head>'`
` print '<body>'`
` print '<h1>'` `+` `'Here comes the list of database users:'` `+` `'</h1>'`
`for row in` `rows:`
` print '<h2>'` `+ row[0]` `+` `'</h2>'`
` print '</body>'`
` print '</html>'`
`

运行 /resources/build-dns.sh,稍后将使用新创建的应用程序镜像

Kube-proxy 代理模式
在 Kubernetes 中,kube-proxy 负责实现 Service 与 Pod 之间的流量转发,主要支持 iptables 和 IPVS 两种模式。
mode: "" 为空表示默认使用iptables

iptables模式与ipvs模式区别
|------------------------|------------------------------------------------------------------------------|------------------------------------------------------------------------------------------------------|
| | iptables 模式 | IPVS 模式 |
| 技术基础 | 基于 Linux 内核的 iptables 防火墙规则(属于内核态的包过滤系统)。 | 基于 Linux 内核的 IPVS(IP Virtual Server,专门用于负载均衡的内核模块)。 |
| 转发逻辑 | 通过在 nat 表中添加大量规则(如 KUBE-SERVICE、KUBE-SEP 链),实现 Service 到 Pod 的 DNAT 转发和负载均衡。 | 通过创建虚拟服务(VS)和真实服务器(RS),直接在内核态完成流量调度,规则更简洁(仅记录 Service 与 Pod 的映射关系)。 |
| 规则存储 | 规则以链式结构存储在 iptables 表中,查找时需遍历链条,复杂度随规则数量增加而上升。 | 规则存储在哈希表中,查找效率为 O (1),与规则数量无关。 |
| 大规模集群(Pod 多) | 性能下降明显:当 Service 和 Pod 数量较多时(如数千个),iptables 规则链会变得冗长,遍历规则耗时增加,导致转发延迟升高。 | 性能稳定:IPVS 专为负载均衡设计,哈希表查找效率高,即使集群规模很大(上万 Pod),转发延迟也能保持较低水平。 |
| 流量转发效率 | 较低:iptables 本质是防火墙,转发过程需经过多次规则匹配,额外开销大。 | 较高:IPVS 直接在内核态完成流量调度,路径更短,开销更小(尤其高并发场景下优势明显)。 |
| 负载均衡算法 | 仅支持 随机(random) 和 轮询(round-robin) 两种简单算法。 | 支持 8 种算法,包括:轮询(rr)、加权轮询(wrr)、最少连接(lc)、加权最少连接(wlc)、基于局部性的最少连接(lblc)等,可根据业务场景灵活选择(如对后端负载敏感的服务用 lc 算法)。 |
| 会话保持(Session Affinity) | 支持,但依赖 iptables 的 ip_hash 模块,实现较简单。 | 原生支持更高效的会话保持,通过 persistent 选项实现,性能优于 iptables。 |
切换IPVS模式
修改proxy配置


重启pod

在集群节点上确认是否切换

切换ipvs模式后,kube-proxy会在宿主机上添加一个虚拟网卡:kube-ipvs0,并分配service IP

查看ipvs规则

service类型 : NodePort


使用 NodePort 发布 web 服务器
创建 NodePort service



替换 web server Pod
修改 pod-web.yml

使用标签为dns的新镜像

检查端点

查看 NodePort

访问应用程序


nodeport默认端口
cat service-web-np.yml,这里为30000

尝试修改为33333

结果报错,nodeport默认端口是30000-32767,超出会报错

在master节点上修改api-server 的配置
添加如下参数,端口范围可以自定义
- --service-node-port-range=30000-50000


修改后api-server会自动重启,等apiserver正常启动后才能操作集群

service类型: LoadBalancer
LoadBalancer模式适用云平台,裸金属环境需要安装metallb提供支持
将服务直接关联到ip

metallb
官网:https://metallb.universe.tf/installation/
kube-proxy 需要启用严格ARP模式


重启服务

下载部署文件

下载镜像


harbor新建项目


给 MetalLB 相关的 Docker 镜像重新打标签并推送到私有仓库


安装 MetalLB 控制器
修改部署文件

部署服务

验证部署状态

配置 IP 地址池和Layer 2 模式



使用 LoadBalancer 发布 Web 服务器

cat service-web-lb.yml
apiVersion: "v1"
kind: "Service"
metadata:
name: "web-service-lb"
spec:
allocateLoadBalancerNodePorts: false
type: "LoadBalancer"
ports:
- name: "http"
protocol: "TCP"
port: 80
targetPort: 80
selector:
app: "web"
注意 MetalLB 分配的 EXTERNAL-IP


查看 LoadBalancer

访问

service类型: externalname
在 Kubernetes 中,ExternalName 是一种特殊类型的 Service,它不通过选择器(selector)关联任何 Pod,而是直接将 Service 映射到一个外部域名(FQDN),用于将集群内部的服务请求转发到集群外部的域名。
核心特点
- 无选择器:不关联任何 Pod,也不会创建 Endpoints 或 EndpointSlice 资源。
- 域名映射:通过 externalName 字段指定一个外部域名(如 example.com),Kubernetes 会自动在集群 DNS 中创建一条 CNAME 记录,将 Service 名称解析为该外部域名。
- 无端口配置:无需指定端口(ports),因为它仅做域名映射,不处理流量转发。
典型用途
- 访问集群外服务:将外部服务(如第三方 API、数据库)以 Kubernetes Service 的形式暴露给集群内的 Pod,统一服务访问方式。
- 服务迁移过渡:在将外部服务迁移到集群内的过程中,先通过 ExternalName 指向外部地址,迁移完成后再切换为普通 Service,避免修改应用代码。
- 简化配置:集群内 Pod 只需使用 Service 名称(如 external-service.default.svc.cluster.local)访问,无需硬编码外部域名,便于统一管理。
创建 ExternalName 类型的 Service

service-externalname.yml
apiVersion: v1
kind: Service
metadata:
name: my-service
spec:
type: ExternalName
externalName: www.baidu.com

测试dns解析

headless服务
在 Kubernetes 中,Headless Service(无头服务) 是一种特殊的 ClusterIP 类型 Service,核心特点是不分配集群虚拟 IP(ClusterIP),而是直接通过 DNS 解析返回其关联的所有 Pod IP 列表,让客户端自主选择 Pod 进行通信。
- 不分配 ClusterIP:与普通 ClusterIP Service 最大区别,DNS 解析时不会返回单一虚拟 IP。
- DNS 直接返回 Pod IP:客户端解析 Headless Service 名称时,DNS 会返回所有健康 Pod 的 IP 列表(A/AAAA 记录)。
- 支持自定义域名:结合 externalName 可实现更灵活的 DNS 配置(较少用)。
- 依赖 Endpoints/EndpointSlice:需通过 selector 关联 Pod,或手动创建 Endpoints 绑定 IP。





与普通ClusterIP的对比,当前无头服务被使用较多,因为其省去了中间的一层转换,直接找到了端口的port,但同时也失去了负载均衡的能力,之后我们会讲解如何使用无头服务实现负载均衡

"tailless"服务
并不是官方的说法,虽然叫做无尾服务,但在此篇中,实际上使用的是无头无尾(不完整)服务
- 可以在没有选择器的情况下创建服务,并手动创建端点
- Kubernetes 应用程序可以通过创建"Tailless"服务连接到现有基础设施

cat service-tailless.yml
apiVersion: "v1"
kind: "Service"
metadata:
name: "tailless"
spec:
clusterIP: None
ports:
- name: dns
protocol: UDP
port: 53
#请注意,该服务没有选择器

可以看到比起headless没有端点

cat endpointslices-internet.yml
apiVersion: discovery.k8s.io/v1
kind: EndpointSlice
metadata:
name: tailless-1 # 按惯例将 Service 的名称用作 EndpointSlice 名称的前缀
labels:
kubernetes.io/service-name: tailless # 匹配 Service 的名称
addressType: IPv4
ports:
- name: dns
protocol: UDP
port: 53
endpoints:
-
addresses:
-
"114.114.114.114"

测试
kubectl run -it --rm --image=reg.westos.org/library/busybox:1.30.1 -- sh
If you don't see a command prompt, try pressing enter.
/ # nslookup yahoo.com tailless
Server: tailless
Address: 114.114.114.114:53
Non-authoritative answer:
Name: yahoo.com
Address: 98.137.11.164
Name: yahoo.com
Address: 74.6.143.25
Name: yahoo.com
Address: 74.6.143.26
将端点IP地址更改为 223.5.5.5
kubectl edit endpointslices.discovery.k8s.io tailless-1
测试
kubectl run -it --rm --image=reg.westos.org/library/busybox:1.30.1 -- sh
If you don't see a command prompt, try pressing enter.
/ # nslookup yahoo.com tailless
Server: tailless
Address: 223.5.5.5:53
Non-authoritative answer:
Name: yahoo.com
Address: 74.6.143.26
Name: yahoo.com
Address: 74.6.143.25
Name: yahoo.com
Address: 74.6.231.21
Ingress
Service 的表现形式为 IP 地址和端口号( ClusterIP:Port ),即工作在 TCP/IP 层。而对于基于 HTTP 的服务来说,不同的 URL 地址经常对应到不同的后端服务或者虚拟服务器,这些应用层的转发机制仅通过 Kubernetes 的 Service 机制是无法实现的。
Kubernetes 引入 Ingress 资源对象,用于将 Kubernetes 集群外的客户端请求路由到集群内部的服务上,同时提供 7 层( HTTP 和 HTTPS )路由功能。使用 Ingress 策略定义和一个具体提供转发服务的 Ingress Controller ,两者结合,实现了基于灵活 Ingress 策略定义的服务路由功能。Ingress 只能以 HTTP 和 HTTPS 提供服务,对于使用其他网络协议的服务,可以通过设置 Service 的类型( type )为 NodePort 或LoadBalancer 对集群外部的客户端提供服务。 使用 Ingress 进行服务路由时,Ingress Controller 基于 Ingress 规则将客户端请求直接转发到 Service 对应的后端 Endpoint ( Pod )上。提供负载均衡、SSL 终止和基于名称的虚拟主机,应用的灰度发布等功能。
Ingress Controller
Ingress Controller 需要实现基于不同HTTP URL向后转发的负载分发规则,并可以灵活设置7层负载分发策略。目前 Ingress Controller 已经有许多实现方案,包括 Nginx、HAProxy、Kong、Traefik、Istio 等开源软件的实现,以及公有云GCE、Azure、AWS 等提供的 Ingress 应用网关。
Ingress Controller 会持续监控 API Server 的 /ingress 接口(即用户定义的到后端服务的转发规则)的变化。当 /ingress 接口后端的服务信息发生变化时,Ingress Controller 会自动更新其转发规则。


部署ingress-nginx
官网:https://kubernetes.github.io/ingress-nginx/
下载镜像:




上传镜像


下载部署文件

修改部署文件,镜像位置与私有仓库匹配,一共是三处位置




部署服务

检查资源

可以看到默认使用NodePort方式
Loadbalancer+ingress-nginx部署方式
架构灵活且高可用,但性能有损失。

修改service类型为:LoadBalancer


即刻生效

D aemonSet+hostNetwork 部署方式
链路简单且高效,极致性能。
删除
kubectl delete -f deploy.yaml
修改部署文件
vim deploy.yaml


参数解释:
kind: DaemonSet #使用DaemonSet控制器
updateStrategy #更新策略
hostNetwork: true # 使用主机网络
dnsPolicy: ClusterFirstWithHostNet # 优先集群 DNS(内部域名),再用节点 DNS ,设置 "hostNetwork: true "时是必须要配置的。
nodeSelector: #选择专用节点
添加节点标签
kubectl label node k8s-worker-01 ingress-node="true"
重新部署
kubectl apply -f deploy.yaml
查看pod是否使用主机IP
kubectl -n ingress-nginx get pod -o wide
查看ingressclass
kubectl get ingressclasses.networking.k8s.io
NAME CONTROLLER PARAMETERS AGE
nginx k8s.io/ingress-nginx <none> 13m
基于名称的虚拟主机服务

Ingress 资源的作用 :通过编写 YAML 文件,可以将外部的域名(如 web.example.com)与集群内部的后端 Service(如 web-service:80)进行绑定。
流量调度机制:当外部请求携带特定的域名(Host 头)进入集群时,nginx-ingress-controller 能够根据 Ingress 规则,将流量精准地路由(转发)到对应的后端 Pod 上,从而实现"一个 IP 对应多个不同域名网站"的虚拟主机功能。
创建ingress资源

cat ingress-virtual-host.yml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: ingress-virtual-host
spec:
ingressClassName: nginx
rules:
- host: web.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: web-service
port:
number: 80
创建后查看资源

测试
域名访问需要在hosts文件中添加解析



还可以进入Ingress Controller的终端,查看,发现与正常的nginx服务基本相同

查看配置文件,与正常配置虚拟ip类似

多域名访问
创建测试服务

cat deploy-web1.yml
apiVersion: "v1"
kind: "Pod"
metadata:
name: "web1"
labels:
app: "web1"
spec:
containers:
- name: "web1"
image: "reg.westos.org/library/myapp:v1"
ports:
- containerPort: 80
apiVersion: v1
kind: Service
metadata:
labels:
app: web-v1
name: web-v1
spec:
ports:
- port: 80
protocol: TCP
targetPort: 80
selector:
app: web1
type: ClusterIP

apiVersion: "v1"
kind: "Pod"
metadata:
name: "web2"
labels:
app: "web2"
spec:
containers:
- name: "web2"
image: "reg.westos.org/library/myapp:v2"
ports:
- containerPort: 80
apiVersion: v1
kind: Service
metadata:
labels:
app: web-v2
name: web-v2
spec:
ports:
- port: 80
protocol: TCP
targetPort: 80
selector:
app: web2
type: ClusterIP

修改ingress资源



拉取myqpp镜像,分别拉取v1,v2

推送到仓库

删除重建使其重新拉取镜像

查看ingress资源

测试
添加解析

或者直接curl该pod的IP

多路径访问

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: ingress-virtual-path
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
spec:
ingressClassName: nginx
rules:
- host: web.example.com
http:
paths:
- path: /v1
pathType: Prefix
backend:
service:
name: web-v1
port:
number: 80
- path: /v2
pathType: Prefix
backend:
service:
name: web-v2
port:
number: 80



default backend
自定义错误页面
https://kubernetes.github.io/ingress-nginx/examples/customization/custom-errors/
apiVersion: v1
kind: Service
metadata:
name: nginx-errors
labels:
app.kubernetes.io/name: nginx-errors
app.kubernetes.io/part-of: ingress-nginx
spec:
selector:
app.kubernetes.io/name: nginx-errors
app.kubernetes.io/part-of: ingress-nginx
ports:
- port: 80
targetPort: 8080
name: http
apiVersion: v1
kind: ConfigMap
metadata:
name: custom-error-pages
data:
404: |
<!DOCTYPE html>
<html>
<head><title>PAGE NOT FOUND</title></head>
<body>PAGE NOT FOUND</body>
</html>
503: |
<!DOCTYPE html>
<html>
<head><title>CUSTOM SERVICE UNAVAILABLE</title></head>
<body>CUSTOM SERVICE UNAVAILABLE</body>
</html>
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-errors
labels:
app.kubernetes.io/name: nginx-errors
app.kubernetes.io/part-of: ingress-nginx
spec:
replicas: 1
selector:
matchLabels:
app.kubernetes.io/name: nginx-errors
app.kubernetes.io/part-of: ingress-nginx
template:
metadata:
labels:
app.kubernetes.io/name: nginx-errors
app.kubernetes.io/part-of: ingress-nginx
spec:
containers:
- name: nginx-error-server
image: reg.westos.org/ingress-nginx/custom-error-pages:v1.2.4
ports:
- containerPort: 8080
Setting the environment variable DEBUG we can see the headers sent
by the ingress controller to the backend in the client response.
env:
- name: DEBUG
value: "true"
Mounting custom error page from configMap
volumeMounts:
- name: custom-error-pages
mountPath: /www
Mounting custom error page from configMap
volumes:
- name: custom-error-pages
configMap:
name: custom-error-pages
items:
- key: "404"
path: "404.html"
- key: "503"
path: "503.html"
需要拉取镜像

打标签推送

创建资源

查看资源

修改ingress-nginx-controller的DS控制器配置

添加以下行
- --default-backend-service=ingress-nginx/nginx-errors
严格按照 namespace/servicename 的方式指定

测试

TLS termination
创建证书

查看secret

创建ingress资源
除之前的资源不然会冲突


apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: ingress-web-tls
spec:
tls:
-
hosts:
secretName: tls-secret
ingressClassName: nginx
rules:
- host: web1.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: web-v1
port:
number: 80
- host: web2.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: web-v2
port:
number: 80

查看

添加解析

强制重定向80到443


认证访问
创建认证文件

输入密码不可见



创建ingress


cat ingress-web-tls-auth.yml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: ingress-web-tls-auth
annotations:
nginx.ingress.kubernetes.io/auth-type: basic
nginx.ingress.kubernetes.io/auth-secret: basic-auth
nginx.ingress.kubernetes.io/auth-realm: 'Authentication Required - ljx'
spec:
tls:
-
hosts:
secretName: tls-secret
ingressClassName: nginx
rules:
- host: web1.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: web-v1
port:
number: 80
- host: web2.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: web-v2
port:
number: 80

查看

测试

rewrite重定向
基于路径重定向

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: ingress-rewrite-1
annotations:
nginx.ingress.kubernetes.io/auth-type: basic
nginx.ingress.kubernetes.io/auth-secret: basic-auth
nginx.ingress.kubernetes.io/auth-realm: 'Authentication Required - ljx'
nginx.ingress.kubernetes.io/app-root: /cgi-bin/action
spec:
tls:
-
hosts:
secretName: tls-secret
ingressClassName: nginx
rules:
- host: web.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: web-service
port:
number: 80

查看

测试,注意最后的地址

基于正则表达式重定向

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: ingress-rewrite-2
annotations:
nginx.ingress.kubernetes.io/auth-type: basic
nginx.ingress.kubernetes.io/auth-secret: basic-auth
nginx.ingress.kubernetes.io/auth-realm: 'Authentication Required - ljx'
nginx.ingress.kubernetes.io/use-regex: "true"
nginx.ingress.kubernetes.io/rewrite-target: /$2
spec:
tls:
-
hosts:
secretName: tls-secret
ingressClassName: nginx
rules:
- host: web.example.com
http:
paths:
- path: /testing(/|$)(.*)
pathType: ImplementationSpecific
backend:
service:
name: web-service
port:
number: 80
回收之前的路径重定向,创建

查看

测试


canary金丝雀发布
金丝雀发布的思想则是将少量的请求引流到新版本上,因此部署新版本服务只需极小数的机器。验证新版本符合预期后,逐步调整流量权重比例,使得流量慢慢从老版本迁移至新版本,期间可以根据设置的流量比例,对新版本服务进行扩容,同时对老版本服务进行缩容,使得底层资源得到最大化利用。
• 优点:按比例将流量无差别地导向新版本,新版本故障影响范围小; 发布期间逐步对新版本扩容,同时对老版本缩容,资源利用率高。
• 缺点:流量无差别地导向新版本,可能会影响重要用户的体验;发布周期长。

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: ingress-canary-v1
spec:
ingressClassName: nginx
rules:
- host: myapp.example.com
http:
paths:
- pathType: Prefix
path: /
backend:
service:
name: web-v1
port:
number: 80
先回收之前的ingress,否则会冲突


查看


apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: ingress-canary-v2
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:
- host: myapp.example.com
http:
paths:
- pathType: Prefix
path: /
backend:
service:
name: web-v2
port:
number: 80
创建,查看

编写测试脚本

#!/bin/bash
v1=0
v2=0
for (( i=0; i<100; i++))
do
response=`curl -s myapp.example.com |grep -c v1` # 域名需要解析
v1=`expr v1 + response`
v2=`expr v2 + 1 - response`
done
echo "v1:v1, v2:v2"
集群外部测试


A/B测试
A/B 测试基于用户请求的元信息将流量路由到新版本,这是一种基于请求内容匹配的灰度发布策略。只有匹配特定规则的请求才会被引流到新版本,常见的做法包括基于 Http Header 和 Cookie。
基于 Header 的流量切分

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: ingress-ab-header
annotations:
nginx.ingress.kubernetes.io/canary: "true"
nginx.ingress.kubernetes.io/canary-by-header: stage
nginx.ingress.kubernetes.io/canary-by-header-value: gray
spec:
ingressClassName: nginx
rules:
- host: myapp.example.com
http:
paths:
- pathType: Prefix
path: /
backend:
service:
name: web-v2
port:
number: 80

测试

基于Cookie的流量切分

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: ingress-ab-cookie
annotations:
nginx.ingress.kubernetes.io/canary: "true"
nginx.ingress.kubernetes.io/canary-by-cookie: "user_from_sz"
spec:
ingressClassName: nginx
rules:
- host: myapp.example.com
http:
paths: - pathType: Prefix
path: /
backend:
service:
name: web-v2
port:
number: 80

测试

