1、介绍
在前面文章中已经提到,Service对集群之外暴露服务的主要方式有两种:NotePort和LoadBalancer,但是这两种方式,都有一定的缺点:
NodePort方式的缺点是会占用很多集群机器的端口,那么当集群服务变多的时候,这个缺点就愈发明显。
LB方式的缺点是每个service需要一个LB,浪费、麻烦,并且需要kubernetes之外设备的支持。
基于这种现状,kubernetes提供了Ingress资源对象,Ingress只需要一个NodePort或者一个LB就可以满足暴露多个Service的需求。工作机制大致如下图表示:
在Kubernetes中,Ingress是管理Kubernetes集群内部服务的外部访问的API对象。
实际上,Ingress相当于一个7层的负载均衡器,是kubernetes对反向代理的一个抽象,它的工作原理类似于Nginx,可以理解成在Ingress里建立诸多映射规则,Ingress Controller通过监听这些配置规则并转化成Nginx的反向代理配置 , 然后对外部提供服务。在这里有两个核心概念:
-
ingress:kubernetes中的一个对象,作用是定义请求如何转发到service的规则
-
ingress controller:具体实现反向代理及负载均衡的程序,对ingress定义的规则进行解析,根据配置的规则来实现请求转发,实现方式有很多,比如Nginx, Contour, Haproxy等等
Ingress-Nginx github 地址:https://github.com/kubernetes/ingress-nginx
Ingress-Nginx 官方网站:https://kubernetes.github.io/ingress-nginx
版本与k8s对照表
Supported | Ingress-NGINX version | k8s supported version | Alpine Version | Nginx Version | Helm Chart Version |
---|---|---|---|---|---|
🔄 | v1.10.1 | 1.29, 1.28, 1.27, 1.26 | 3.19.1 | 1.25.3 | 4.10.1* |
🔄 | v1.10.0 | 1.29, 1.28, 1.27, 1.26 | 3.19.1 | 1.25.3 | 4.10.0* |
🔄 | v1.9.6 | 1.29, 1.28, 1.27, 1.26, 1.25 | 3.19.0 | 1.21.6 | 4.9.1* |
🔄 | v1.9.5 | 1.28, 1.27, 1.26, 1.25 | 3.18.4 | 1.21.6 | 4.9.0* |
🔄 | v1.9.4 | 1.28, 1.27, 1.26, 1.25 | 3.18.4 | 1.21.6 | 4.8.3 |
🔄 | v1.9.3 | 1.28, 1.27, 1.26, 1.25 | 3.18.4 | 1.21.6 | 4.8.* |
🔄 | v1.9.1 | 1.28, 1.27, 1.26, 1.25 | 3.18.4 | 1.21.6 | 4.8.* |
🔄 | v1.9.0 | 1.28, 1.27, 1.26, 1.25 | 3.18.2 | 1.21.6 | 4.8.* |
v1.8.4 | 1.27, 1.26, 1.25, 1.24 | 3.18.2 | 1.21.6 | 4.7.* | |
v1.7.1 | 1.27, 1.26, 1.25, 1.24 | 3.17.2 | 1.21.6 | 4.6.* | |
v1.6.4 | 1.26, 1.25, 1.24, 1.23 | 3.17.0 | 1.21.6 | 4.5.* | |
v1.5.1 | 1.25, 1.24, 1.23 | 3.16.2 | 1.21.6 | 4.4.* | |
v1.4.0 | 1.25, 1.24, 1.23, 1.22 | 3.16.2 | 1.19.10† | 4.3.0 | |
v1.3.1 | 1.24, 1.23, 1.22, 1.21, 1.20 | 3.16.2 | 1.19.10† | 4.2.5 |
部署 Ingress-Nginx
# https://kubernetes.github.io/ingress-nginx/deploy/
# 下载部署用yaml文件,大家根据自己的k8s版本更换版本号
wget https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v1.6.4/deploy/static/provider/cloud/deploy.yaml
# 修改镜像地址为国内镜像地址,否则镜像拉取会失败
vim deploy.yaml
# -----------------------------------------------------------------
# 在第439行
# 将image改为registry.cn-hangzhou.aliyuncs.com/google_containers/nginx-ingress-controller:v1.6.3
# 教室局域网可以使用:192.168.3.200:8099/ingress-nginx/controller:v1.6.3
# 第536行和第585行
# 将registry.k8s.io/ingress-nginx/替换为registry.aliyuncs.com/google_containers/
# 教室局域网可以使用:192.168.3.200:8099/ingress-nginx/kube-webhook-certgen:v20220916-gd32f8c343
# -----------------------------------------------------------------
kubectl apply -f deploy.yaml
# 教室局域网专用版本,针对无法使用外网的情况。(已安装,可忽略)
# wget http://192.168.3.200/Software/ingress-nginx-v1.6.3-deploy.yaml
# kubectl apply -f ingress-nginx-v1.6.3-deploy.yaml
[root@k8s-master ~]# kubectl get pod -n ingress-nginx
NAME READY STATUS RESTARTS AGE
ingress-nginx-admission-create-db6jl 0/1 Completed 0 5h6m
ingress-nginx-admission-patch-m6rvd 0/1 Completed 0 5h6m
ingress-nginx-controller-7998c976fc-ln7z9 1/1 Running 0 5h6m
# 查看ingress-nginx-controller svc 注意: 80:30577/TCP,443:32667/TCP 此处 30577和32667 后续需要使用到
[root@k8s-master ~]# kubectl get svc -n ingress-nginx
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
ingress-nginx-controller LoadBalancer 10.68.155.84 <pending> 80:30577/TC,443:32667/TCP 5h6m
ingress-nginx-controller-admission ClusterIP 10.68.89.135 <none> 443/TCP 5h6m
2、准备Service、Pod
为了后面的实验比较方便,创建如下图所示的模型
安装上述图片模型,我们创建3个Nginx Pod和3个Tomcat Pod,并分别为他们创建servce ,yaml文件名叫tomcat-nginx.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
namespace: dev
spec:
replicas: 3
selector:
matchLabels:
app: nginx-pod
template:
metadata:
labels:
app: nginx-pod
spec:
containers:
- name: nginx
image: nginx
ports:
- containerPort: 80
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: tomcat-deployment
namespace: dev
spec:
replicas: 3
selector:
matchLabels:
app: tomcat-pod
template:
metadata:
labels:
app: tomcat-pod
spec:
containers:
- name: tomcat
image: tomcat:8.0
ports:
- containerPort: 8080
---
apiVersion: v1
kind: Service
metadata:
name: nginx-service
namespace: dev
spec:
selector:
app: nginx-pod
clusterIP: None
type: ClusterIP
ports:
- port: 80
targetPort: 80
---
apiVersion: v1
kind: Service
metadata:
name: tomcat-service
namespace: dev
spec:
selector:
app: tomcat-pod
clusterIP: None
type: ClusterIP
ports:
- port: 8080
targetPort: 8080
执行文件并查看创建结果
# 1.先创建dev命令空间
[root@k8s-master ~]# kubectl create ns dev
# 2.创建nginx-deployment和tomcat-deployment
[root@k8s-master ~]# kubectl apply -f tomcat-nginx.yaml
deployment.apps/nginx-deployment created
deployment.apps/tomcat-deployment created
service/nginx-service created
service/tomcat-service created
[root@k8s-master ~]#
# 3.查看 deploy
[root@k8s-master ~]# kubectl get deploy -n dev
NAME READY UP-TO-DATE AVAILABLE AGE
nginx-deployment 2/3 3 2 7s
tomcat-deployment 3/3 3 3 7s
[root@k8s-master ~]#
# 4.查看pod
[root@k8s-master ~]# kubectl get pod -n dev
NAME READY STATUS RESTARTS AGE
nginx-deployment-69cbb4f6b6-2nwkd 1/1 Running 0 13s
nginx-deployment-69cbb4f6b6-lsqcp 1/1 Running 0 13s
nginx-deployment-69cbb4f6b6-rmfzc 0/1 ContainerCreating 0 13s
tomcat-deployment-798c966d9d-cg59r 1/1 Running 0 13s
tomcat-deployment-798c966d9d-s5blw 1/1 Running 0 13s
tomcat-deployment-798c966d9d-zrjdf 1/1 Running 0 13s
# 5.查看svc
[root@k8s-master ~]# kubectl get svc -n dev
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
nginx-service ClusterIP None <none> 80/TCP 17s
tomcat-service ClusterIP None <none> 8080/TCP 17s
3.在本机配置host
更改本机host,模拟两个域名
# 我的master IP 为192.168.8.201 模拟 nginx域名为 nginx.lz.com
[root@k8s-master ~]# echo "192.168.8.201 nginx.lz.com" >> /etc/hosts
# 我的master IP 为192.168.8.201 模拟 tomcat域名为 tomcat.lz.com
[root@k8s-master ~]# echo "192.168.8.201 tomcat.lz.com" >> /etc/hosts
# 查看已添加hosts
[root@k8s-master ~]# cat /etc/hosts
192.168.8.201 nginx.lz.com
192.168.8.201 tomcat.lz.com
4、Http代理
创建ingress-http.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: ingress-http
namespace: dev
spec:
# 这个很关键,如果写错会导致访问404
ingressClassName: nginx
rules:
- host: nginx.lz.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: nginx-service
port:
number: 80
- host: tomcat.lz.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: tomcat-service
port:
number: 8080
ingressClassName 如果忘记自己设置的是什么,可以通过以下方式查询
命令:
kubectl describe deploy ingress-nginx-controller -n ingress-nginx
实际操作
# 创建
[root@k8s-master ~]# kubectl apply -f ingress-http.yaml
ingress.networking.k8s.io/ingress-http created
# 查看ingress
[root@k8s-master ~]# kubectl get ing ingress-http -n dev
NAME CLASS HOSTS ADDRESS PORTS AGE
ingress-http nginx nginx.lz.com,tomcat.lz.com 80 64s
# 查看ingress详情
[root@k8s-master ~]# kubectl describe ing ingress-http -n dev
Name: ingress-http
Labels: <none>
Namespace: dev
Address:
Ingress Class: ingress
Default backend: <default>
Rules:
Host Path Backends
---- ---- --------
# 可以看出域名 nginx.lz.com 代理了后端 三个nginx pod 访问
nginx.lz.com
/ nginx-service:80 (172.17.169.187:80,172.17.169.190:80,172.17.36.106:80)
# 可以看出域名 tomcat.lz.com 代理了后端 三个tomcat pod
tomcat.lz.com
/ tomcat-service:8080 (172.17.169.185:8080,172.17.169.188:8080,172.17.36.105:8080)
Annotations: <none>
Events: <none>
# 还记得上篇文章中我们 安装完ingree-nginx 后,查看 ingress-nginx-controller service的结果吗
# 在上面我们已经安装完ingress-http 如果想在外部访问则需此处PORTS,这个端口意思是,如果ing代理的是http即80端口,则外部访问需要使用30577(随机生成的,可以自定义)端口访问,如果ing代理的是https即443端口,则外部访问需要使用32667(也是随机生成,当然可以自定义)端口访问
[root@k8s-master ~]# kubectl get svc -n ingress-nginx
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
ingress-nginx-controller NodePort 10.15.245.169 <none> 80:30577/TCP,443:32667/TCP 41h
ingress-nginx-controller-admission ClusterIP 10.0.156.229 <none> 443/TCP
# 本次实例我们的tomcat和nginx都是80 端口,所以访问的时候都需要在域名 后面增加 :30577 才可正常访问
本机访问效果
5、Https代理
5.1、创建证书
实际生产我们需要申请https nginx证书,这里我们就模拟创建一个证书
# 创建证书
[root@k8s-master ~]# openssl req -x509 -sha256 -nodes -days 365 -newkey rsa:2048 -keyout tls.key -out tls.crt -subj "/C=CN/ST=BJ/L=BJ/O=nginx/CN=lz.com"
Generating a 2048 bit RSA private key
...........+++
..............................+++
writing new private key to 'tls.key'
-----
# 证书已创建
[root@k8s-master ~]# ls
tls.crt tls.key
# 创建密钥 这个秘钥创建,如果不会先记着,后续有讲解
[root@k8s-master ~]# kubectl create secret tls tls-secret --key tls.key --cert tls.crt
secret/tls-secret created
# 查看已创建秘钥
[root@k8s-master ~]# kubectl get secret
NAME TYPE DATA AGE
tls-secret kubernetes.io/tls 2 6s
# 5.2、创建ingress-https.yaml
vim ingress-https.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: ingress-https
namespace: dev
spec:
tls:
- hosts:
- nginx.lz.com
- tomcat.lz.com
secretName: tls-secret # 指定秘钥
# 这个很关键,如果写错会导致访问404
ingressClassName: nginx
rules:
- host: nginx.lz.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: nginx-service
port:
number: 80
- host: tomcat.lz.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: tomcat-service
port:
number: 8080
5.3、实例操作效果
# 创建
[root@k8s-master ~]# kubectl apply -f ingress-https.yaml
ingress.networking.k8s.io/ingress-https created
[root@k8s-master ~]#
# 查看ing
[root@k8s-master ~]# kubectl get ing ingress-https -n dev
NAME CLASS HOSTS ADDRESS PORTS AGE
ingress-https ingress-nginx nginx.lz.com,tomcat.lz.com 80, 443 7s
# 查看ing 详情
[root@k8s-master ~]# kubectl describe ing ingress-https -n dev
Name: ingress-https
Labels: <none>
Namespace: dev
Address:
Ingress Class: ingress-nginx
Default backend: <default>
# TLS已关联
TLS:
tls-secret terminates nginx.lz.com,tomcat.lz.com
Rules:
# 规则也已经创建
Host Path Backends
---- ---- --------
nginx.lz.com
/ nginx-service:80 (172.17.169.187:80,172.17.169.190:80,172.17.36.106:80)
tomcat.lz.com
/ tomcat-service:8080 (172.17.169.185:8080,172.17.169.188:8080,172.17.36.105:8080)
Annotations: <none>
Events: <none>
# 查看访问443 需要什么用什么端口 此处是32667
[root@k8s-master ~]# kubectl get svc -n ingress-nginx
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
ingress-nginx-controller NodePort 10.15.245.169 <none> 80:30577/TCP,443:32667/TCP 41h
ingress-nginx-controller-admission ClusterIP 10.0.156.229 <none> 443/TCP
# 在本地访问 https://tomcat.lz.com:32667 和 https://nginx.lz.com:32667 查看效果