目录
一、Ingress 和 Ingress Controller 概述
1.1 回顾下 service 四层代理
1.2 Ingress 介绍
1.3 Ingress Controller 介绍
1.4 Ingress 和 Ingress Controller 总结
1.5 使用 Ingress Controller 代理 k8s 内部 pod 的流程
二、创建两个 ingress-controller 高可用的 pod
三、通过 keepalived + nginx 实现 ingress-nginx-controller 高可用
3.1 安装 nginx 主备
3.2 修改 nginx 配置文件
3.3 keepalive 配置
3.4 启动服务
3.5 测试 keeplived
四、测试 Ingress HTTP 代理 k8s 内部 pod
4.1 部署后端 tomcat 服务
4.2 编写 ingress 规则
4.3 测试访问 tomcat
五、测试 Ingress HTTPS 代理 k8s 内部 pod
5.1 构建 TLS 站点
5.2 创建 Ingress
5.3 测试访问 tomcat
一、Ingress 和 Ingress Controller 概述
1.1 回顾下 service 四层代理
- 在 k8s 中为什么要做负载均衡?
Pod 漂问题,可以理解成 PodIP 是变化的。Kubernetes 具有强大的副本控制能力,能保证在任意副本(Pod)挂掉时自动从其他机器启动一个新的,还可以动态扩容等。通俗地说,这个 Pod 可能在任何时刻出现在任何节点上,也可能在任何时刻死在任何节点上;那么自然随着 Pod 的创建和销毁,PodIP 肯定会动态变化;那么如何把这个动态的PodIP 暴露出去?这里借助于 Kubernetes 的 Service 机制,Service 可以以标签的形式选定一组带有指定标签的 Pod,并监控和自动负载他们的 Pod IP,那么我们向外暴露只暴露 Service IP 就行了;这就是NodePort模式,即在每个节点上开起一个端口,然后转发到内部 PodIP 上。
Service 可以通过标签选择器找到它所关联的 Pod。但是属于四层代理,只能基于 IP 和端口代理。
- Service 存在一个问题,什么问题呢?
Service 的 type类型有很多,如 NodePort、clusterlp、loadbalancer、externalname,如果Service 想要被 k8s 集群外部访问,需要用 NodePort 类型,但是NodePort 类型的 svc有如下几个问题:
nodeport 会在物理机映射一个端口,绑定到物理机上,这样就导致,每个服务都要映射一个端口端口过多,维护困难,还有就是 Service 底层使用的是iptables 或者 ipvs,仅支持四层代理,无法基于 https 协议做代理,因此我们这次讲解的是 ingress-controller 七层代理。
- 四层负载和七层负载的区别:
1)四层负载:四层的负载均衡就是基于 IP+端口的负载均衡:在三层负载均衡的基础上,通过发布三层的 IP 地址(VIP),然后加四层的端口号,来决定哪些流量需要做负载均衡,对需要处理的流量进行 NAT 处理,转发至后台服务器,并记录下这个 TCP 或者 UDP 的流量是由哪台服务器处理的,后续这个连接的所有流量都同样转发到同一台服务器处理。
2)七层的负载均衡就是基于虚拟的 URL 或主机IP 的负载均衡:在四层负载均衡的基础上(没有四层是绝对不可能有七层的),再考虑应用层的特征,比如同一个 Web 服务器的负载均衡,除了根据 VIP 加 80 端口辨别是否需要处理的流量,还可根据七层的 URL、浏览器类别、语言来决定是否要进行负载均衡。举个例子,如果你的 Web 服务器分成两组,一组是中文语言的,一组是英文语言的,那么七层负载均衡就可以当用户来访问你的域名时,自动辨别用户语言,然后选择对应的语言服务器组进行负载均衡处理。
3)四层负载均衡工作在传输层,七层负载均衡工作在应用层。
【云原生 | Kubernetes 实战】12、K8s 四层代理 Service 入门到企业实战应用(上)_Stars.Sky的博客-CSDN博客
1.2 Ingress 介绍
Ingress 官网定义:Ingress可以把进入到集群内部的请求转发到集群中的一些服务上,从而可以把服务映射到集群外部。Ingress 能把集群内Service 配置成外网能够访问的 URL,流量负载均衡,提供基于域名访问的虚拟主机等。
Ingress 简单的理解就是你原来需要改Nginx配置,然后配置各种域名对应哪个 Service,现在把这个动作抽象出来,变成一个 Ingress 对象,你可以用 yaml 创建,每次不要去改Nginx 了,直接改yaml然后创建/更新就行了;那么问题来了:”Nginx 该怎么处理?”
Ingress Controller 这东西就是解决 “Nginx 的处理方式” 的;Ingress Controller 通过与 Kubernetes API 交互,动态的去感知集群中Ingress规则变化,然后读取他,按照他自己模板生成一段 Nginx 配置,再写到 Nginx Pod 里,最后 reload 一下。
Ingress 总结:ingress 是 k8s 中的资源,主要是管理 ingress-controller 这个代理的配置文件。
1.3 Ingress Controller 介绍
Ingress Controller 是一个七层负载均衡调度器,客户端的请求先到达这个七层负载均衡调度器,由七层负载均衡器在反向代理到后端 pod,常见的七层负载均衡器有 nginx、traefik,以我们熟悉的 nginx 为例,假如请求到达 nginx,会通过 upstream 反向代理到后端 pod 应用,但是后端pod 的 ip 地址是一直在变化的,因此在后端 pod 前需要加一个 service,这个 service 只是起到分组的作用,那么我们 upstream 只需要填写 service 地址即可。
Ingress-controller 里面封装就是 nginx,那我直接在物理机上装个 nginx 就行了啊,为啥还弄个 Ingress-controller?
nginx 配置文件一改动,你还需要手动 reload 一下才可以生效,但是如果用 ingress-controller 封装的 nginx,你 ingress 维护配置,ingress 创建好之后,会自动的把配置文件传到ingress-controller 这个 pod 里,会自动进行 reload,然后配置就生效了。
1.4 Ingress 和 Ingress Controller 总结
Ingress Controller 结合 Ingress 定义的规则生成配置,然后动态更新 ingress-controller 里的Nginx 或者 trafik 负载均衡器,并刷新使配置生效,来达到服务自动发现的作用。
Ingress 则是定义规则,通过它定义某个域名的请求过来之后转发到集群中指定的 Service。它可以通过 Yaml 文件定义,可以给一个或多个 Service 定义一个或多个 Ingress 规则。
1.5 使用 Ingress Controller 代理 k8s 内部 pod 的流程
- 部署 Ingress controller,我们 ingress controller 使用的是 nginx;
- 创建 Pod 应用,可以通过控制器创建 pod;
- 创建 Service,用来分组 pod;
- 创建 Ingress http,测试通过 http 访问应用;
- 创建Ingress https,测试通过 https 访问应用。
使用七层负载均衡调度器 ingress controller 时,当客户端访问 kubernetes 集群内部的应用时,数据包走向如下图流程所示:
二、创建两个 ingress-controller 高可用的 pod
Ingress Controller 是集群流量的接入层,对它做高可用非常重要,可以基于 keepalive 实现nginx-ingress-controller 高可用,具体实现如下:
Ingress-controller 根据 Deployment + nodeSeletor + pod 反亲和性方式部署在 k8s 指定的两个 work 节点,nginx-ingress-controller 这个 pod 共享宿主机 ip,然后通过 keepalive + nginx 实现nginx-ingress-controller 高可用。
GitHub 项目地址:GitHub - kubernetes/ingress-nginx: Ingress-NGINX Controller for Kubernetes
ingress-nginx/deploy/static/provider/baremetal at main · kubernetes/ingress-nginx · GitHub
上传 ingress-nginx-controllerv1.1.0.tar.gz 和 kube-webhook-certgen-v1.1.0.tar.gz 相关镜像到 node1 和 node2 并解压:
相关资料下载地址:https://download.csdn.net/download/weixin_46560589/87355471
注意:因为我们现在安装的 k8s 版本是 1.25,那就需要用ctr -n=k8s.io images import 导出镜像,如果 k8s 版本是 1.24 之前的,可以用 docker load -i 解压。
[root@k8s-node1 ~]# ctr -n=k8s.io images import ingress-nginx-controllerv1.1.0.tar.gz
[root@k8s-node1 ~]# ctr -n=k8s.io images import kube-webhook-certgen-v1.1.0.tar.gz
[root@k8s-node2 ~]# ctr -n=k8s.io images import ingress-nginx-controllerv1.1.0.tar.gz
[root@k8s-node2 ~]# ctr -n=k8s.io images import kube-webhook-certgen-v1.1.0.tar.gz
# 把 ingress-deploy.yaml 上传到这,创建 pod
[root@k8s-master01 ~]# mkdir ingress
[root@k8s-master01 ~]# cd ingress/
[root@k8s-master01 ingress]# ls
ingress-deploy.yaml
[root@k8s-master01 ingress]# kubectl apply -f ingress-deploy.yaml
[root@k8s-master01 ingress]# kubectl get pods -n ingress-nginx -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
ingress-nginx-admission-create-2hbsq 0/1 Completed 0 27s 10.244.169.144 k8s-node2 <none> <none>
ingress-nginx-admission-patch-vbj8r 0/1 Completed 1 27s 10.244.169.145 k8s-node2 <none> <none>
ingress-nginx-controller-64bdc78c96-6j844 1/1 Running 0 27s 192.168.78.131 k8s-node1 <none> <none>
ingress-nginx-controller-64bdc78c96-9jpsp 1/1 Running 0 27s 192.168.78.132 k8s-node2 <none> <none>
如果执行创建资源命令时报错如下错误:
[root@k8s-master01 ingress]# kubectl apply -f ingress-deploy.yaml
Error from server (InternalError): error when creating "ingress-myapp.yaml": Internal error occurred: failed calling webhook "validate.nginx .inaress kubernetes .io":failed to call webhook: Post "https://ingress-nginx-controller-admission.ingress-nginx.svc:443/networkina/wl/inaresses ?timeout=10s":context deadline exceeded
# 解决办法
[root@k8s-master01 ingress]# kubectl delete -A ValidatingWebhookConfiguration ingress-nginx-admission
[root@k8s-master01 ingress]# kubectl apply -f ingress-deploy.yaml
三、通过 keepalived + nginx 实现 ingress-nginx-controller 高可用
3.1 安装 nginx 主备
在 node1 和 node2 上做 nginx 主备安装
[root@k8s-node1 ~]# yum install epel-release nginx keepalived nginx-mod-stream -y
[root@k8s-node2 ~]# yum install epel-release nginx keepalived nginx-mod-stream -y
3.2 修改 nginx 配置文件
在 node1 和 node2 上都要修改
vim /etc/nginx/nginx.conf
user nginx;
worker_processes auto;
error_log /var/log/nginx/error.log;
pid /run/nginx.pid;
include /usr/share/nginx/modules/*.conf;
events {
worker_connections 1024;
}
# 四层负载均衡,为两台 Master apiserver 组件提供负载均衡
stream {
log_format main '$remote_addr $upstream_addr - [$time_local] $status $upstream_bytes_sent';
access_log /var/log/nginx/k8s-access.log main;
upstream k8s-ingress-controller {
server 192.168.78.131:80 weight=5 max_fails=3 fail_timeout=30s; # node1 IP:PORT
server 192.168.78.132:80 weight=5 max_fails=3 fail_timeout=30s; # node2 IP:PORT
}
server {
listen 30080;
proxy_pass k8s-ingress-controller;
}
}
http {
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
access_log /var/log/nginx/access.log main;
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 65;
types_hash_max_size 2048;
include /etc/nginx/mime.types;
default_type application/octet-stream;
}
注意:nginx 监听端口变成大于 30000 的端口,比方说 30080,这样访问 域名:30080 就可以了,必须是满足大于 30000 以上,才能代理 ingress-controller。
3.3 keepalive 配置
node1 为主 keepalived 配置
[root@k8s-node1 ~]# vim /etc/keepalived/keepalived.conf
global_defs {
notification_email {
acassen@firewall.loc
failover@firewall.loc
sysadmin@firewall.loc
}
notification_email_from Alexandre.Cassen@firewall.loc
smtp_server 127.0.0.1
smtp_connect_timeout 30
router_id NGINX_MASTER
}
# 指定检查 nginx 工作状态脚本(根据 nginx 状态判断是否故障转移)
vrrp_script check_nginx {
script "/etc/keepalived/check_nginx.sh"
}
vrrp_instance VI_1 {
state MASTER # 主服务器,备服务器设置为 BACKUP
interface ens32 # 修改为实际网卡名
virtual_router_id 51 # VRRP 路由 ID 实例,每个实例是唯一的
priority 100 # 优先级,备服务器设置 90
advert_int 1 # 指定 VRRP 心跳包通告间隔时间,默认 1 秒
authentication {
auth_type PASS
auth_pass 1111
}
# 虚拟 IP
virtual_ipaddress {
192.168.78.199/24 # 虚拟 ip 要和 node 节点物理 ip 同网段,且该 ip 没有被占用
}
track_script {
check_nginx
}
}
# 编写 nginx 检测脚本
[root@k8s-node1 ~]# vim /etc/keepalived/check_nginx.sh
#!/bin/bash
#1、判断 Nginx 是否存活
counter=$(ps -ef |grep nginx | grep sbin | egrep -cv "grep|$$" )
if [ $counter -eq 0 ]; then
#2、如果不存活则尝试启动 Nginx
systemctl restart nginx.service
sleep 2
#3、等待 2 秒后再次获取一次 Nginx 状态
counter=$(ps -ef |grep nginx | grep sbin | egrep -cv "grep|$$" )
#4、再次进行判断,如 Nginx 还不存活则停止 Keepalived,让地址进行漂移
if [ $counter -eq 0 ]; then
systemctl stop keepalived.service
fi
fi
# 添加可执行权限
[root@k8s-node1 ~]# chmod +x /etc/keepalived/check_nginx.sh
node2 为备 keeplived 配置
[root@k8s-node2 ~]# vim /etc/keepalived/keepalived.conf
global_defs {
notification_email {
acassen@firewall.loc
failover@firewall.loc
sysadmin@firewall.loc
}
notification_email_from Alexandre.Cassen@firewall.loc
smtp_server 127.0.0.1
smtp_connect_timeout 30
router_id NGINX_MASTER
}
# 指定检查 nginx 工作状态脚本(根据 nginx 状态判断是否故障转移)
vrrp_script check_nginx {
script "/etc/keepalived/check_nginx.sh"
}
vrrp_instance VI_1 {
state BACKUP # 主服务器,备服务器设置为 BACKUP
interface ens32 # 修改为实际网卡名
virtual_router_id 51 # VRRP 路由 ID 实例,每个实例是唯一的
priority 90 # 优先级,备服务器设置 90
advert_int 1 # 指定 VRRP 心跳包通告间隔时间,默认 1 秒
authentication {
auth_type PASS
auth_pass 1111
}
# 虚拟 IP
virtual_ipaddress {
192.168.78.199/24 # 虚拟 ip 要和 node 节点物理 ip 同网段,且该 ip 没有被占用
}
track_script {
check_nginx
}
}
# 编写 nginx 检测脚本
[root@k8s-node2 ~]# vim /etc/keepalived/check_nginx.sh
#!/bin/bash
#1、判断 Nginx 是否存活
counter=$(ps -ef |grep nginx | grep sbin | egrep -cv "grep|$$" )
if [ $counter -eq 0 ]; then
#2、如果不存活则尝试启动 Nginx
systemctl restart nginx.service
sleep 2
#3、等待 2 秒后再次获取一次 Nginx 状态
counter=$(ps -ef |grep nginx | grep sbin | egrep -cv "grep|$$" )
#4、再次进行判断,如 Nginx 还不存活则停止 Keepalived,让地址进行漂移
if [ $counter -eq 0 ]; then
systemctl stop keepalived.service
fi
fi
# 添加可执行权限
[root@k8s-node2 ~]# chmod +x /etc/keepalived/check_nginx.sh
3.4 启动服务
node1 和 node2 都要启动服务:
systemctl daemon-reload
systemctl enable nginx.service --now
systemctl enable keepalived.service --now
3.5 测试 keeplived
# vip 是在 node1 上,node2 没有,因为 node1 优先级高
[root@k8s-node1 ~]# ip addr
······
2: ens32: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
link/ether 00:0c:29:9c:58:75 brd ff:ff:ff:ff:ff:ff
inet 192.168.78.131/24 brd 192.168.78.255 scope global noprefixroute ens32
valid_lft forever preferred_lft forever
inet 192.168.78.199/24 scope global secondary ens32
valid_lft forever preferred_lft forever
inet6 fe80::20c:29ff:fe9c:5875/64 scope link
valid_lft forever preferred_lft forever
······
# 在 node1 暂停 keeplived 服务
[root@k8s-node1 ~]# systemctl stop keepalived.service
# vip 会漂移到 node2
[root@k8s-node2 ~]# ip addr
······
2: ens32: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
link/ether 00:0c:29:eb:b1:2b brd ff:ff:ff:ff:ff:ff
inet 192.168.78.132/24 brd 192.168.78.255 scope global noprefixroute ens32
valid_lft forever preferred_lft forever
inet 192.168.78.199/24 scope global secondary ens32
valid_lft forever preferred_lft forever
inet6 fe80::20c:29ff:feeb:b12b/64 scope link
valid_lft forever preferred_lft forever
······
# node1 恢复 keeplived 服务
[root@k8s-node1 ~]# systemctl start keepalived.service
# vip 又漂移回来了
[root@k8s-node1 ~]# ip addr
······
2: ens32: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
link/ether 00:0c:29:9c:58:75 brd ff:ff:ff:ff:ff:ff
inet 192.168.78.131/24 brd 192.168.78.255 scope global noprefixroute ens32
valid_lft forever preferred_lft forever
inet 192.168.78.199/24 scope global secondary ens32
valid_lft forever preferred_lft forever
inet6 fe80::20c:29ff:fe9c:5875/64 scope link
valid_lft forever preferred_lft forever
······
四、测试 Ingress HTTP 代理 k8s 内部 pod
4.1 部署后端 tomcat 服务
[root@k8s-master01 ingress]# vim ingress-demo.yaml
apiVersion: v1
kind: Service
metadata:
name: tomcat
namespace: default
spec:
selector:
app: tomcat
release: canary
ports:
- name: http
targetPort: 8080
port: 8080
- name: ajp
targetPort: 8009
port: 8009
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: tomcat-deploy
namespace: default
spec:
replicas: 2
selector:
matchLabels:
app: tomcat
release: canary
template:
metadata:
labels:
app: tomcat
release: canary
spec:
containers:
- name: tomcat
image: tomcat:8.5.34-jre8-alpine
imagePullPolicy: IfNotPresent
ports:
- name: http
containerPort: 8080
name: ajp
containerPort: 8009
[root@k8s-master01 ingress]# kubectl apply -f ingress-demo.yaml
[root@k8s-master01 ingress]# kubectl get pods
NAME READY STATUS RESTARTS AGE
tomcat-deploy-64d6489dd9-l2xlq 1/1 Running 0 39s
tomcat-deploy-64d6489dd9-qc5dc 1/1 Running 0 39s
4.2 编写 ingress 规则
# 编写 ingress 的配置清单
[root@k8s-master01 ingress]# vim ingress-myapp.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: ingress-myapp
namespace: default
spec:
ingressClassName: nginx
rules: # 定义后端转发的规则
- host: tomcat.lucky.com # 通过域名进行转发
http:
paths:
- backend: # 配置后端服务
service:
name: tomcat
port:
number: 8080
path: / # 配置访问路径,如果 url 进行转发,需要修改,默认访问的路径为 "/"
pathType: Prefix
[root@k8s-master01 ingress]# kubectl apply -f ingress-myapp.yaml
ingress.networking.k8s.io/ingress-myapp created
[root@k8s-master01 ingress]# kubectl get ingress
NAME CLASS HOSTS ADDRESS PORTS AGE
ingress-myapp nginx tomcat.lucky.com 192.168.78.131,192.168.78.132 80 92s
[root@k8s-master01 ingress]# kubectl describe ingress ingress-myapp
Name: ingress-myapp
Labels: <none>
Namespace: default
Address: 192.168.78.131,192.168.78.132
Ingress Class: nginx
Default backend: <default>
Rules:
Host Path Backends
---- ---- --------
tomcat.lucky.com
/ tomcat:8080 (10.244.169.147:8080,10.244.36.109:8080)
Annotations: <none>
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal Sync 16s (x2 over 48s) nginx-ingress-controller Scheduled for sync
Normal Sync 16s (x2 over 47s) nginx-ingress-controller Scheduled for sync
4.3 测试访问 tomcat
修改电脑本地的 C:\Windows\System32\drivers\etc\host 文件,增加如下一行,下面的 ip 是 vip:
192.168.78.199 tomcat.lucky.com
在浏览器访问 http://tomcat.lucky.com
代理流程:
tomcat.lucky.com:30080 -> 192.168.78.199:30080 -> 192.168.40.181:80、192.168.40.182:80 -> svc:tomcat:8080 -> pod:tomcat-deploy-xxx
基于名称的虚拟托管:Ingress | Kubernetes
五、测试 Ingress HTTPS 代理 k8s 内部 pod
5.1 构建 TLS 站点
# 准备证书,在 master1 节点操作
[root@k8s-master01 ~]# openssl genrsa -out tls.key 2048
[root@k8s-master01 ~]# openssl req -new -x509 -key tls.key -out tls.crt -subj /C=CN/ST=Beijing/L=Beijing/O=DevOps/CN=sky.lucky.com
# 生成 secret
[root@k8s-master01 ~]# kubectl create secret tls tomcat-ingress-secret --cert=tls.crt --key=tls.key
# 查看 secrets
[root@k8s-master01 ~]# kubectl get secrets
NAME TYPE DATA AGE
tomcat-ingress-secret kubernetes.io/tls 2 18s
[root@k8s-master01 ~]# kubectl describe secrets tomcat-ingress-secret
Name: tomcat-ingress-secret
Namespace: default
Labels: <none>
Annotations: <none>
Type: kubernetes.io/tls
Data
====
tls.crt: 1285 bytes
tls.key: 1675 bytes
5.2 创建 Ingress
[root@k8s-master01 ingress]# vim ingress-tomcat-tls.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: ingress-tomcat-tls
namespace: default
spec:
ingressClassName: nginx
tls:
- hosts:
- sky.lucky.com
secretName: tomcat-ingress-secret
rules:
- host: sky.lucky.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: tomcat
port:
number: 8080
[root@k8s-master01 ingress]# kubectl apply -f ingress-tomcat-tls.yaml
[root@k8s-master01 ingress]# kubectl get ingress
NAME CLASS HOSTS ADDRESS PORTS AGE
ingress-myapp nginx tomcat.lucky.com 192.168.78.131,192.168.78.132 80 37m
ingress-tomcat-tls nginx sky.lucky.com 192.168.78.131,192.168.78.132 80, 443 86s
5.3 测试访问 tomcat
修改电脑本地的 C:\Windows\System32\drivers\etc\host 文件,增加如下一行,下面的 ip 是 vip:
192.168.78.199 sky.lucky.com
在浏览器访问 sky.lucky.com
TLS:Ingress | Kubernetes
上一篇文章:【云原生 | Kubernetes 实战】18、K8s 安全实战篇之 RBAC 认证授权(下)_Stars.Sky的博客-CSDN博客