1. Introducción al ingreso
La función del servicio se refleja en dos aspectos: para el interior del clúster, rastrea continuamente los cambios de los pods, actualiza los objetos correspondientes a los pods en el punto final (punto final) y proporciona un mecanismo de descubrimiento de servicios para los pods con IP cambiante. direcciones; para fuera del clúster, es similar a la carga. El equilibrador proporciona acceso a los pods dentro y fuera del clúster.
En Kubernetes, la dirección IP del Pod y la ClusterIP del servicio solo se pueden usar dentro de la red del clúster y son invisibles para las aplicaciones fuera del clúster. Para permitir que las aplicaciones externas accedan a los servicios en el clúster, Kubernetes actualmente proporciona las siguientes soluciones:
- NodePort: Expone el servicio en la red de nodos. Detrás de NodePort está Kube-Proxy. Kube-Proxy es el puente que se comunica con la red de servicios, la red Pod y la red de nodos.
El entorno de prueba está bien para su uso, pero cuando hay docenas o cientos de servicios ejecutándose en el clúster, la administración de puertos de NodePort es un desastre. Debido a que cada puerto solo puede ser un servicio, el rango de puertos solo puede ser 30000-32767. - LoadBalancer: asigne LoadBalancer a la dirección de LoadBalancer proporcionada por el proveedor de servicios en la nube configurándolo. Este uso solo se utiliza en escenarios en los que el Servicio está configurado en la plataforma de nube de un proveedor de servicios de nube pública. Limitado por la plataforma en la nube y, por lo general, la implementación de LoadBalancer en la plataforma en la nube requiere costos adicionales.
Una vez enviado el servicio, Kubernetes llamará a CloudProvider para crear un servicio de equilibrio de carga para usted en la nube pública y configurará la dirección IP del Pod proxy para el servicio de equilibrio de carga como backend. - IP externas: El servicio permite que se le asignen IP externas, si la IP externa se enruta a uno o más Nodos del cluster, el Servicio quedará expuesto a estas IP externas. El tráfico que ingresa al clúster a través de una IP externa se enrutará al punto final de servicio.
- Ingreso: solo se necesita una o una pequeña cantidad de IP y LB públicos para exponer múltiples servicios HTTP a la red externa al mismo tiempo, utilizando un proxy inverso de siete capas.
Puede entenderse simplemente como un servicio: en realidad, es un conjunto de reglas que reenvían las solicitudes de los usuarios a uno o más servicios en función de los nombres de dominio y las rutas URL.
1. Composición de ingreso
- ingreso: Ingress es un objeto API, configurado a través de un archivo yaml, la función del objeto de ingreso es definir las reglas sobre cómo se reenvían las solicitudes al servicio, lo que puede entenderse como una plantilla de configuración.
Ingress expone los servicios internos del clúster a través de http o https y proporciona servicios con URL externas, equilibrio de carga, capacidades SSL/TLS y proxy inverso basado en nombres de dominio. Ingress se basa en el controlador de ingreso para implementar las funciones anteriores. - ingress-controller:
ingress-controller es un programa que implementa específicamente proxy inverso y equilibrio de carga. Analiza las reglas definidas por el ingreso y reenvía solicitudes de acuerdo con las reglas configuradas.
ingress-controller no es un componente que viene con k8s. De hecho, ingress-controller es solo un término general. Los usuarios pueden elegir diferentes implementaciones de ingress-controller. Actualmente, los únicos dos controladores de ingreso mantenidos por k8s son GCE e ingress de Google Cloud. -nginx., y hay muchos otros controladores de ingreso mantenidos por terceros. Para obtener más detalles, consulte la documentación oficial. Pero no importa qué tipo de controlador de ingreso, el mecanismo de implementación es similar, pero existen diferencias en la configuración específica.
En términos generales, el controlador de entrada tiene la forma de un pod, que ejecuta un programa demonio y un programa de proxy inverso. El demonio es responsable de monitorear constantemente los cambios en el clúster, generar configuraciones basadas en el objeto de entrada y aplicar nuevas configuraciones al proxy inverso. Por ejemplo, ingress-nginx genera dinámicamente configuraciones de nginx, actualiza dinámicamente en sentido ascendente y recarga el programa para aplicar nuevas configuraciones cuando sea necesario. Por conveniencia, los siguientes ejemplos toman como ejemplo ingress-nginx mantenido oficialmente por k8s.
Dirección de github de Ingress-Nginx: https://github.com/kubernetes/ingress-nginx
Sitio web oficial de Ingress-Nginx: https://kubernetes.github.io/ingress-nginx/
2. Resumen
El controlador de entrada es el componente responsable del reenvío específico. Está expuesto en la entrada del clúster a través de varios métodos. El tráfico de solicitudes externas al clúster irá primero al controlador de entrada y el objeto de entrada se utiliza para informarle al controlador de entrada. cómo reenviar la solicitud. Por ejemplo, qué nombres de dominio, qué URL deben reenviarse a qué servicios, etc.
2. Cómo funciona Ingress
- El controlador de ingreso interactúa con Kubernetes APIServer para detectar dinámicamente cambios en las reglas de ingreso en el clúster.
- Luego léalo y genere una configuración de nginx de acuerdo con las reglas personalizadas, que especifican qué nombre de dominio corresponde a qué servicio.
- Luego escríbalo en el pod de nginx-ingress-controller. Este pod de controlador de ingreso ejecuta un servicio Nginx. El controlador escribirá la configuración de nginx generada en el archivo /etc/nginx.conf.
- Luego recárguelo para que la configuración surta efecto. Esto logra la función de configuración de distinción de nombres de dominio y actualización dinámica.
3. Implementar el controlador de ingreso nginx
1. Implementar el pod del controlador de ingreso y los recursos relacionados
mkdir /opt/ingress
cd /opt/ingress
官方下载地址:
wget https://raw.githubusercontent.com/kubernetes/ingress-nginx/nginx-0.25.0/deploy/static/mandatory.yaml
上面可能无法下载,可用国内的 gitee
wget https://gitee.com/mirrors/ingress-nginx/raw/nginx-0.25.0/deploy/static/mandatory.yaml
wget https://gitee.com/mirrors/ingress-nginx/raw/nginx-0.30.0/deploy/static/mandatory.yaml
#mandatory.yaml文件中包含了很多资源的创建,包括namespace、ConfigMap、role,ServiceAccount等等所有部署ingress-controller需要的资源。
2. Modificar la configuración del recurso ClusterRole
vim mandatory.yaml
......
apiVersion: rbac.authorization.k8s.io/v1beta1
#RBAC相关资源从1.17版本开始改用rbac.authorization.k8s.io/v1,rbac.authorization.k8s.io/v1beta1在1.22版本即将弃用
kind: ClusterRole
metadata:
name: nginx-ingress-clusterrole
labels:
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
rules:
- apiGroups:
- ""
resources:
- configmaps
- endpoints
- nodes
- pods
- secrets
verbs:
- list
- watch
- apiGroups:
- ""
resources:
- nodes
verbs:
- get
- apiGroups:
- ""
resources:
- services
verbs:
- get
- list
- watch
- apiGroups:
- "extensions"
- "networking.k8s.io" # (0.25版本)增加 networking.k8s.io Ingress 资源的 api
resources:
- ingresses
verbs:
- get
- list
- watch
- apiGroups:
- ""
resources:
- events
verbs:
- create
- patch
- apiGroups:
- "extensions"
- "networking.k8s.io" # (0.25版本)增加 networking.k8s.io/v1 Ingress 资源的 api
resources:
- ingresses/status
verbs:
- update
Cómo el ingreso expone los servicios
- Método 1: Servicio en modo Implementación + LoadBalancer
Si desea implementar el ingreso en la nube pública, este método es más adecuado. Utilice Implementación para implementar el controlador de ingreso y crear un servicio de tipo LoadBalancer para asociarlo con este grupo de pods. La mayoría de las nubes públicas crearán automáticamente un equilibrador de carga para el servicio LoadBalancer, generalmente vinculado a una dirección de red pública. Siempre que la resolución del nombre de dominio apunte a esta dirección, el servicio de clúster estará expuesto al mundo exterior. - 方式二:DaemonSet+HostNetwork+nodeSelector
用DaemonSet结合nodeselector来部署ingress-controller到特定的node上,然后使用HostNetwork直接把该pod与宿主机node的网络打通,直接使用宿主机的80/433端口就能访问服务。这时,ingress-controller所在的node机器就很类似传统架构的边缘节点,比如机房入口的nginx服务器。该方式整个请求链路最简单,性能相对NodePort模式更好。缺点是由于直接利用宿主机节点的网络和端口,一个node只能部署一个ingress-controller pod。 比较适合大并发的生产环境使用。 - 方式三:Deployment+NodePort模式的Service
同样用deployment模式部署ingress-controller,并创建对应的service,但是type为NodePort。这样,ingress就会暴露在集群节点ip的特定端口上。由于nodeport暴露的端口是随机端口,一般会在前面再搭建一套负载均衡器来转发请求。该方式一般用于宿主机是相对固定的环境ip地址不变的场景。
NodePort方式暴露ingress虽然简单方便,但是NodePort多了一层NAT,在请求量级很大时可能对性能会有一定影响。
3、指定 nginx-ingress-controller 运行在 node02 节点
采用方式二:DaemonSet+HostNetwork+nodeSelector
kubectl label node node02 ingress=true
kubectl get nodes --show-labels
4、修改 Deployment 为 DaemonSet ,指定节点运行,并开启 hostNetwork 网络
vim mandatory.yaml
...
apiVersion: apps/v1
# 修改 kind
# kind: Deployment
kind: DaemonSet
metadata:
name: nginx-ingress-controller
namespace: ingress-nginx
labels:
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
spec:
# 删除Replicas
# replicas: 1
selector:
matchLabels:
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
template:
metadata:
labels:
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
annotations:
prometheus.io/port: "10254"
prometheus.io/scrape: "true"
spec:
# 使用主机网络
hostNetwork: true
# 选择节点运行
nodeSelector:
ingress: "true"
serviceAccountName: nginx-ingress-serviceaccount
......
5、在所有 node 节点上传 nginx-ingress-controller 镜像压缩包 ingree.contro.tar.gz 到/opt/ingress 目录,并解压和加载镜像
cd /opt/ingress
tar zxvf ingree.contro.tar.gz
docker load -i ingree.contro.tar
6、启动 nginx-ingress-controller
kubectl apply -f mandatory.yaml
#nginx-ingress-controller 已经运行 node02 节点
kubectl get pod -n ingress-nginx -o wide
kubectl get cm,daemonset -n ingress-nginx -o wide
到 node02 节点查看
netstat -lntp | grep nginx
由于配置了 hostnetwork,nginx 已经在 node 主机本地监听 80/443/8181 端口。其中 8181 是 nginx-controller 默认配置的一个 default backend(Ingress 资源没有匹配的 rule 对象时,流量就会被导向这个 default backend)。这样,只要访问 node 主机有公网 IP,就可以直接映射域名来对外网暴露服务了。如果要 nginx 高可用的话,可以在多个 node上部署,并在前面再搭建一套 LVS+keepalived 做负载均衡。
7、创建 ingress 规则
创建一个 deploy 和 svc
vim service-nginx.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-app
spec:
replicas: 2
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx
imagePullPolicy: IfNotPresent
ports:
- containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
name: nginx-app-svc
spec:
type: ClusterIP
ports:
- protocol: TCP
port: 80
targetPort: 80
selector:
app: nginx
创建 ingress
用的是方法二
#方法一:(extensions/v1beta1 Ingress 在1.22版本即将弃用)
vim ingress-app.yaml
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: nginx-app-ingress
spec:
rules:
- host: www.mcl.com
http:
paths:
- path: /
backend:
serviceName: nginx-app-svc
servicePort: 80
#方法二:
vim ingress-app.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: nginx-app-ingress
spec:
rules:
- host: www.mcl.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: nginx-app-svc
port:
number: 80
kubectl apply -f service-nginx.yaml
kubectl apply -f ingress-app.yaml
kubectl get pods
kubectl get ingress
8、测试访问
本地 host 添加域名解析
vim /etc/hosts
curl www.mcl.com
9、查看 nginx-ingress-controller
kubectl get pod -n ingress-nginx -o wide
kubectl exec -it nginx-ingress-controller-p7tdq -n ingress-nginx /bin/bash
可以看到从 start server www.mcl.com 到 end server www.mcl.com 之间包含了此域名用于反向代理的配置
四、采用方式三:Deployment+NodePort模式的Service
1、下载 nginx-ingress-controller 和 ingress-nginx 暴露端口配置文件
mkdir /opt/ingress-nodeport
cd /opt/ingress-nodeport
官方下载地址:
wget https://raw.githubusercontent.com/kubernetes/ingress-nginx/nginx-0.30.0/deploy/static/mandatory.yaml
wget https://raw.githubusercontent.com/kubernetes/ingress-nginx/nginx-0.30.0/deploy/static/provider/baremetal/service-nodeport.yaml
国内 gitee 资源地址:
wget https://gitee.com/mirrors/ingress-nginx/raw/nginx-0.30.0/deploy/static/mandatory.yaml
wget https://gitee.com/mirrors/ingress-nginx/raw/nginx-0.30.0/deploy/static/provider/baremetal/service-nodeport.yaml
2、在所有 node 节点上传镜像包 ingress-controller-0.30.0.tar 到 /opt/ingress-nodeport 目录,并加载镜像
tar zxvf ingree.contro-0.30.0.tar.gz
docker load -i ingress-controller-0.30.0.tar
3、启动 nginx-ingress-controller
kubectl apply -f mandatory.yaml
kubectl apply -f service-nodeport.yaml
如果K8S Pod 调度失败,在 kubectl describe pod资源时显示:
Warning FailedScheduling 18s (x2 over 18s) default-scheduler 0/2 nodes are available: 2 node(s) didn't match node selector
解决方案:
- 给需要调度的node加上对应标签
相对上面这个Yaml文件的例子
kubectl label nodes node_name kubernetes.io/os=linux - 删除Yaml文件中的nodeSelector,如果对节点没有要求的话,直接删除节点选择器即可
4、Ingress HTTP 代理访问
创建 deployment、Service、Ingress Yaml 资源
vim ingress-nginx.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-myapp
spec:
replicas: 2
selector:
matchLabels:
name: nginx
template:
metadata:
labels:
name: nginx
spec:
containers:
- name: nginx
image: nginx
imagePullPolicy: IfNotPresent
ports:
- containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
name: nginx-svc
spec:
ports:
- port: 80
targetPort: 80
protocol: TCP
selector:
name: nginx
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: nginx-test
spec:
rules:
- host: www.long.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: nginx-svc
port:
number: 80
kubectl get pods,svc -o wide
kubectl exec -it pod/nginx-myapp-57dd86f5cc-l48l2 bash
kubectl exec -it pod/nginx-myapp-57dd86f5cc-lpnfz bash
5、测试访问
curl 10.244.1.18
kubectl get svc -n ingress-nginx
vim /etc/hosts
192.168.160.20 master
192.168.160.40 node01
192.168.160.90 node02
192.168.160.70 hub.mcl.com
192.168.160.90 www.mcl.com
#添加域名解析
192.168.160.40 www.mcl.com www.long.com
#外部访问
curl http://www.long.com:31751
6、Ingress HTTP 代理访问虚拟主机
mkdir /opt/ingress-nodeport/vhost
cd /opt/ingress-nodeport/vhost
#创建虚拟主机1资源
vim deployment1.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: deployment1
spec:
replicas: 2
selector:
matchLabels:
name: nginx1
template:
metadata:
labels:
name: nginx1
spec:
containers:
- name: nginx1
image: soscscs/myapp:v1
imagePullPolicy: IfNotPresent
ports:
- containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
name: svc-1
spec:
ports:
- port: 80
targetPort: 80
protocol: TCP
selector:
name: nginx1
kubectl apply -f deployment1.yaml
#创建虚拟主机2资源
vim deployment2.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: deployment2
spec:
replicas: 2
selector:
matchLabels:
name: nginx2
template:
metadata:
labels:
name: nginx2
spec:
containers:
- name: nginx2
image: soscscs/myapp:v2
imagePullPolicy: IfNotPresent
ports:
- containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
name: svc-2
spec:
ports:
- port: 80
targetPort: 80
protocol: TCP
selector:
name: nginx2
kubectl apply -f deployment2.yaml
#创建ingress资源
vim ingress-nginx.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: ingress1
spec:
rules:
- host: www1.mcl.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: svc-1
port:
number: 80
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: ingress2
spec:
rules:
- host: www2.mcl.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: svc-2
port:
number: 80
kubectl apply -f ingress-nginx.yaml
7、测试访问
kubectl get svc -n ingress-nginx
#做主机映射
vim /etc/hosts
curl www1.mcl.com:31751
curl www2.mcl.com:31751
8、Ingress HTTPS 代理访问
mkdir /opt/ingress-nodeport/https
cd /opt/ingress-nodeport/https
8.1 创建ssl证书
openssl req -x509 -sha256 -nodes -days 365 -newkey rsa:2048 -keyout tls.key -out tls.crt -subj "/CN=nginxsvc/O=nginxsvc"
8.2 创建 secret 资源进行存储
kubectl create secret tls tls-secret --key tls.key --cert tls.crt
kubectl get secret
kubectl describe secret tls-secret
8.3 创建 deployment、Service、Ingress Yaml 资源
vim ingress-https.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-app
spec:
replicas: 2
selector:
matchLabels:
name: nginx
template:
metadata:
labels:
name: nginx
spec:
containers:
- name: nginx
image: nginx
imagePullPolicy: IfNotPresent
ports:
- containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
name: nginx-svc
spec:
ports:
- port: 80
targetPort: 80
protocol: TCP
selector:
name: nginx
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: nginx-https
spec:
tls:
- hosts:
- www3.long.com
secretName: tls-secret
rules:
- host: www3.kgc.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: nginx-svc
port:
number: 80
kubectl apply -f ingress-https.yaml
9、Nginx 进行 BasicAuth
mkdir /opt/ingress-nodeport/basic-auth
cd /opt/ingress-nodeport/basic-auth
9.1 生成用户密码认证文件,创建 secret 资源进行存储
yum -y install httpd
htpasswd -c auth mcl #认证文件名必须为 auth
kubectl create secret generic basic-auth --from-file=auth
kubectl get secrets
kubectl describe secrets basic-auth
9.2 创建 ingress 资源
vim ingress-auth.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: ingress-auth
annotations:
#设置认证类型basic
nginx.ingress.kubernetes.io/auth-type: basic
#设置secret资源名称basic-auth
nginx.ingress.kubernetes.io/auth-secret: basic-auth
#设置认证窗口提示信息
nginx.ingress.kubernetes.io/auth-realm: 'Authentication Required - mcl'
spec:
rules:
- host: auth.mcl.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: nginx-svc
port:
number: 80
//具体详细设置方法可参考官网https://kubernetes.github.io/ingress-nginx/examples/auth/basic/
9.3 访问测试
kubectl apply -f ingress-auth.yaml
kubectl get svc -n ingress-nginx
echo '192.168.160.40 auth.mcl.com' >> /etc/hosts
浏览器访问:http://auth.mcl.com:31751
10、Nginx 进行重写
metadata.annotations 配置说明
nginx.ingress.kubernetes.io/rewrite-target: <字符串> #必须重定向流量的目标URI
nginx.ingress.kubernetes.io/ssl-redirect: <布尔值> #指示位置部分是否仅可访问SSL(当Ingress包含证书时,默认为true)
nginx.ingress.kubernetes.io/force-ssl-redirect: <布尔值> #即使Ingress未启用TLS,也强制重定向到HTTPS
nginx.ingress.kubernetes.io/app-root: <字符串> #定义Controller必须重定向的应用程序根,如果它在'/'上下文中
nginx.ingress.kubernetes.io/use-regex: <布尔值> #指示Ingress上定义的路径是否使用正则表达式
编写ingress-rewrite.yaml
vim ingress-rewrite.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: nginx-rewrite
annotations:
nginx.ingress.kubernetes.io/rewrite-target: http://www1.mcl.com:31751
spec:
rules:
- host: re.mcl.com
http:
paths:
- path: /
pathType: Prefix
backend:
#由于re.kgc.com只是用于跳转不需要真实站点存在,因此svc资源名称可随意定义
service:
name: nginx-svc
port:
number: 80
访问测试
kubectl apply -f ingress-rewrite.yaml
echo '192.168.160.40 re.mcl.com' >> /etc/hosts
浏览器访问:http://re.mcl.com:31751
五、总结
ingress是k8s集群的请求入口,可以理解为对多个service的再次抽象
通常说的ingress一般包括ingress资源对象及ingress-controller两部分组成
ingress-controller有多种实现,社区原生的是ingress-nginx,根据具体需求选择
ingress自身的暴露有多种方式,需要根据基础环境及业务类型选择合适的方式