我们通过deployment和statefulSet部署了多个POD了。这些POD一般会对外提供服务,比如前面的实验我们通过web这个POD提供了WEB服务。我们当然可以在集群内直接访问POD的IP来访问这些服务,但POD的IP是可能变化的,所以更标准的做法是通过service来访问POD服务。
service主要是定义POD的访问端口,可以让集群内外方便的访问POD开放的服务。它本身就相当于是一个负载均衡器,通过kube-porxy可以把访问请求路由到实际的多个POD内,实现负载均衡。
service的type有ClusterIP、ExternalName、LoadBalancer和NodePort。如果只是集群内部访问,使用ClusterIP就足够了。每个service它的ClusterIP是始终不变的,并且会自动跟踪POD的IP变化。而集群外部的访问呢更多的是借助LoadBalancer类型的service。但标准的K8S安装是没有LoadBalancer,公有云服务商有自己内部的实现,会监控LoadBalancer类型的service创建,并自动创建一个负载均衡器跟这个service关联。所以我们需要先安装一个插件用于实现这个功能。本次实验我们使用开源的metallb来实现负载均衡器功能。
LoadBalancer类型的service确实可以方便的实现集群外部的访问。但每个服务都要创建一个负载均衡器属实有些浪费了。毕竟负载均衡器是要消耗系统资源的,在公有云环境还是会产生费用的。另外负载均衡器太粗糙了,不利于根据规则,如URL匹配等进行更精细的控制。所以后面又出现了ingress和ingress controller。每个ingress controller都会创建一个LoadBalancer类型的service用于跟负载均衡器关联。而每个ingress则可描述多个service,并且复用同一个ingress controller。ingress controller会监控ingress的创建,并动态修改自己的配置以实现ingress描述的规则。所以总结下来的关系如下:负载均衡器和ingress controller是一对一的。ingress controller和ingress是一对多的,而ingress跟service也是一对多(实际上一个ingress可以描述多个服务,也可描述一个服务,不过这不重要,因为你也可以创建多个ingress)
下面的实验将从头开始一步步操作:
一、创建metallb负载均衡器
1、安装metallb负载均衡器
curl -Lo https://raw.githubusercontent.com/metallb/metallb/v0.14.8/config/manifests/metallb-native.yaml
quay.io在国内访问很慢,所以要修改一下这个文件改成在国内比较容易访问的仓库
修改metallb-native.yaml文件把:
image: quay.io/metallb/controller:v0.14.8
image: quay.io/metallb/speaker:v0.14.8
替换为:
image: quay.m.daocloud.io/metallb/controller:v0.14.8
image: quay.m.daocloud.io/metallb/speaker:v0.14.8
TIPS:
DaoCloud 镜像加速
方法一 (推荐): 直接添加前缀 m.daocloud.io/
docker pull m.daocloud.io/quay.io/metallb/controller:v0.14.8
方法二: 替换仓库源
docker pull quay.m.daocloud.io/metallb/controller:v0.14.8
kubectl apply -f metallb-native.yaml
2、创建metallb的配置
more metallb-config.yaml
apiVersion: metallb.io/v1beta1
kind: IPAddressPool
metadata:
name: my-ip-pool
namespace: metallb-system
spec:
addresses:
- 192.168.23.70-192.168.1.80 # 替换为你网段内的空闲IP
我的工作节点IP为:192.168.23.44-192.168.1.45,我为负载均衡器预分配的IP地址段为:192.168.23.70-192.168.1.80。
kubectl apply -f metallb-config.yaml
这样我们metallb就安装好了,它会监控集群里面LoadBalancer类型的service创建,如果有的话就会创建一个负载均衡器(地址从192.168.23.70-192.168.1.80里面取),并跟这个service相关联。这里我们先不用创建LoadBalancer类型的service,后面安装ingress controller的时候会自动创建的。
二、安装和创建ingress controller
ingress controller有很多种,开源用的最多的应该就是nginx ingress controller。它可以用helm安装,也可以直接用yaml文件安装,如果用helm安装的话,有些镜像在国内无法下载,所以最好还是使用yaml文件安装,方便我们修改镜像。
直接下载
curl -Lo ingress-nginx4.yaml https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v1.10.1/deploy/static/provider/cloud/deploy.yaml
修改deploy.yaml:
把registry.k8s.io/ingress-nginx/controller:v1.14.3@sha256:82917be97c0939f6ada1717bb39aa7e66c229d6cfb10dcfc8f1bd42f9efe0f81改为 registry.aliyuncs.com/google_containers/nginx-ingress-controller:v1.14.3
kubectl apply -f ingress-nginx4.yaml
查看ingress controller的POD
kubectl get pods -n ingress-nginx
NAME READY STATUS RESTARTS AGE
ingress-nginx-controller-59cd5c7fb5-fvcvt 1/1 Running 0 39h
查看ingress controller的service
kubectl get svc -n ingress-nginx
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
ingress-nginx-controller LoadBalancer 10.106.227.11 192.168.23.70 80:32131/TCP,443:30519/TCP 2d22h
ingress-nginx-controller-admission ClusterIP 10.110.249.216 <none> 443/TCP 2d22h
可以看到有个LoadBalancer类型的service起来了,并且关联的外部负载均衡器的IP是:192.168.23.70。这就是我们前面创建的metallb自动帮我们创建的负载均衡器。
三、创建delployment和service部署无状态业务
这个是常规操作,就不多解释了。主要是用delployment创建2个pod提供web服务,另外创建了一个service关联这2个pod。
more deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: mydeploy
labels:
app: nginx
spec:
replicas: 2
selector:
matchLabels:
app: web
template:
metadata:
labels:
app: web
spec:
containers:
- image: nginx
name: nginx
创建的2个POD都有标签:app: web
现创建名字为nginx的service跟这个标签关联:
more service.yaml
apiVersion: v1
kind: Service
metadata:
name: nginx
labels:
app: nginx
spec:
type: ClusterIP
ports:
- name: web
port: 8080
protocol: TCP
targetPort: 80
selector:
app: web
kubectrl apply -f service.yaml
再确定我们的ingressclass
kubectl get ingressclass
NAME CONTROLLER PARAMETERS AGE
nginx k8s.io/ingress-nginx <none> 21h
可见已经在了一个名字叫nginx的 ingressclass,其对应的controller就是ingress-nginx
四、创建ingress,描述规则
可以在一个ingress部署多个service,也可以一个ingress部署一个service
more ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: example-ingress
annotations:
# 这里可以根据你使用的 Ingress Controller 添加特定注解
# 例如,使用 nginx 时,可以配置重写规则等
# nginx.ingress.kubernetes.io/rewrite-target: /
spec:
ingressClassName: nginx # 指定使用名为 "nginx" 的 IngressClass
rules:
- host: myapp.example.com # 域名规则
http:
paths:
- path: / # 路径规则,匹配所有路径
pathType: Prefix # 路径类型为前缀匹配
backend: # 指定后端服务
service:
name: nginx # 后端 Service 的名字
port:
number: 80 # 后端 Service 的端口
kubectl apply -f ingress.yaml
这个ingress是基于域名的,所以HTTP请求里面一定要有host头,否则会请求失败。另外port.number是后端服务的端口,不是ingress的端口,ingress的端口是80或者443。并且好像不生效,总会按service实际的port来进行访问,而忽略这里面配置的port.number。
测试的时候需要修改hosts文件,把myapp.example.com指向192.168.23.70。访问http://myapp.example.com就相当于访问nginx服务了。
再创建一个pod作为默认后端,即当请求的路径没有匹配到任何ingress规则时,就会转发到这个pod。这里的backend.service.name是nginx3,而不是nginx,并且没有配置host,所以这个ingress是默认后端。无法匹配域名或者无域名就匹配到这个规则
more ingress_default.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: default-ingress
annotations:
# 这里可以根据你使用的 Ingress Controller 添加特定注解
# 例如,使用 nginx 时,可以配置重写规则等
# nginx.ingress.kubernetes.io/rewrite-target: /
spec:
ingressClassName: nginx # 指定使用名为 "nginx" 的 IngressClass
rules:
#- host: myapp.example.com # 域名规则
- http:
paths:
- path: / # 路径规则,匹配所有路径
pathType: Prefix # 路径类型为前缀匹配
backend: # 指定后端服务
service:
name: nginx3 # 后端 Service 的名字
port:
number: 8080 # 后端 Service 的端口
kubectl apply -f ingress_default.yaml
查看当前生效的所有ingress规则
kubectl get ingress
NAME CLASS HOSTS ADDRESS PORTS AGE
default-ingress nginx * 192.168.23.70 80 13m
example-ingress nginx myapp.example.com 192.168.23.70 80 72m
这时访问http://myapp.example.com就会转发到nginx服务了,而直接访问http://192.168.23.70就会转发到nginx3服务了。