更新日期:2022-03 调整 nginx-controller 版本; 更新 ingress 资源 apiversion。
0. 背景和环境
Service 对集群之外暴露服务的主要方式有两种:NotePort和LoadBalancer,但是这两种方式,都有一定的缺点:
- NodePort方式的缺点是会占用很多集群机器的端口,那么当集群服务变多的时候,这个缺点就愈发明显,另外实际业务是通过域名访问的,根据不同的域名跳转到不同端口服务。
- LB方式的缺点是每个service需要一个LB,浪费、麻烦,并且需要kubernetes之外设备的支持
基于这种现状,kubernetes提供了Ingress资源对象,Ingress只需要一个NodePort或者一个LB就可以满足暴露多个Service的需求。
node1 | master | Ubuntu 20.04(ARM64) | 192.168.50.11 |
---|---|---|---|
node2 | worker | Ubuntu 20.04(ARM64) | 192.168.50.12 |
node3 | worker | Ubuntu 20.04(ARM64) | 192.168.50.13 |
node4 | Storage | Ubuntu 20.04(ARM64) | 192.168.50.147 |
1. Ingress 和 Ingress Controller
什么是 Ingress?ingress
是 kubernetes 中的一种 API 资源,需要使用 ingress controller
来实现 ingress。
什么是 Ingress Controller?
为了使 Ingress 正常工作,集群中必须运行 Ingress controller。 这与其他类型的控制器不同,其他类型的控制器通常作为 kube-controller-manager 二进制文件的一部分运行,在集群启动时自动启动。 你需要选择最适合自己集群的 Ingress controller 或者自己实现一个。
- Kubernetes 当前支持并维护 GCE 和 nginx 两种 controller
- Nginx 社区提供维护支持的 Controller
- F5(公司)支持并维护 F5 BIG-IP Controller for Kubernetes
- Kong 同时支持并维护 社区版 与 企业版 的 Kong Ingress Controller for Kubernetes
- Traefik 是功能齐全的 ingress controller(Let’s Encrypt, secrets, http2, websocket…), Containous 也对其提供商业支持。
- Istio 使用 CRD Gateway 来 控制 Ingress 流量。
一个最简单的 ingress
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: test-ingress
spec:
rules:
- http:
paths:
- path: /testpath
backend:
serviceName: test
servicePort: 80
如果没有配置 Ingress controller 就将其 POST 到 API server 不会有任何用处。
总结一下:
ingress 是 kubernetes 中的一个对象,作用是定义请求如何转发到service的规则
ingress controller 是具体实现反向代理及负载均衡的程序,对ingress定义的规则进行解析,根据配置的规则来实现请求转发,实现方式有很多,比如Nginx, Contour, Haproxy等等
2. Ingress Controller 工作原理
a. ingress controller 通过与 k8s api 进行交互,动态感知 k8s 集群中 ingress 服务规则的变化,然后读取它,并按照定义的 ingress 规则,转发到 k8s 集群中对应的 service。
b. ingress 规则写明了哪个域名对应 k8s 集群中的哪个 service,然后再根据 ingress-controller 中的 nginx 配置模板,生成一段对应的 nginx 配置。
c. 然后再把该配置动态的写到 ingress-controller 的 pod 里,该 ingress-controller 的 pod 里面运行着一个 nginx 服务,控制器会把生成的 nginx 配置写入到 nginx 的配置文件中,然后 reload 一下,使其配置生效, 以此来达到域名配置及动态更新的效果。
处理 http 请求的过程需要经过service 吗?
通过Ingress可从集群外访问K8s资源,访问流程如下:
- 从dns获取域名对应的ip。
- 将请求发送到该IP,Ingress Controller收到请求。
- Ingress Controller根据转发规则,找到对应到Service及其背后的Endpoint。
- Ingress Controller随机挑选一个Pod将请求转发给该Pod。
3. 部署 Ingress Controller
Deployment 和 DaemonSet 部署的区别
使用 deployment,并且 replicate 为 1 时,这样将会在某一台节点上启动对应的 nginx-ingress-controller pod。外部流量访问至该节点,由该节点负载分担至内部的 service。测试环境考虑防止单点故障,改为 DaemonSet ,配合亲和性部署在指定节点上启动 nginx-ingress-controller pod,确保有多个节点启动 nginx-ingress-controller pod,后续将这些节点加入到外部硬件负载均衡组实现高可用性。3.1 使用 Deployment 方式部署
3.1.1准备配置文件
wget https://raw.githubusercontent.com/kubernetes/ingress-nginx/main/deploy/static/provider/baremetal/1.21/deploy.yaml
3.1.2 调整配置文件
# 修改Pod 网络类型,暴露 nginx-ingress-controller pod 的服务端口(80) sed -i '/dnsPolicy:/i\ hostNetwork: true' deploy.yaml # 国内镜像加速 sed -i 's/k8s.gcr.io/lank8s.cn/' deploy.yaml
3.1.3 创建 Nginx Controller 相关资源
kubectl apply -f deploy.yaml
3.1.4 检查
```shell $ kubectl get pods -n ingress-nginx NAME READY STATUS RESTARTS AGE ingress-nginx-admission-create-666gb 0/1 Completed 0 7m17s ingress-nginx-admission-patch-7t5jj 0/1 Completed 3 7m17s ingress-nginx-controller-7cd586cc64-2k2qt 1/1 Running 0 7m17s
$ kubectl get svc -n ingress-nginx
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
ingress-nginx-controller NodePort 10.96.63.215
<a name="DH02V"></a>
#### 3.1.5 绑定 Node 节点(可选)
目前 ingress-controller 会被调度器分配到某一个节点,如果需要指定一台独立的 node 节点运行 ingress-controller,就需要 node 节点打标签。
```shell
# 获取节点标签
kubectl get nodes --show-labels
# 给指定的节点打标签
kubectl label nodes 节点_IP nginx=nginx
调整 deployment 中节点选择器的标签
更新配置
kubectl apply -f deploy.yaml
检查
kubectl get pods -n ingress-nginx
$ kubectl get pods -n ingress-nginx -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
ingress-nginx-admission-create-666gb 0/1 Completed 0 28m 10.244.104.3 node2 <none> <none>
ingress-nginx-admission-patch-7t5jj 0/1 Completed 3 28m 10.244.135.2 node3 <none> <none>
ingress-nginx-controller-767f5dcbf4-tmrdw 0/1 ContainerCreating 0 15m 192.168.50.12 node2 <none> <none>
ingress-nginx-controller-7cd586cc64-2k2qt 1/1 Running 0 28m 192.168.50.13 node3 <none> <none>
$ kubectl get pods -n ingress-nginx -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
ingress-nginx-admission-create-666gb 0/1 Completed 0 29m 10.244.104.3 node2 <none> <none>
ingress-nginx-admission-patch-7t5jj 0/1 Completed 3 29m 10.244.135.2 node3 <none> <none>
ingress-nginx-controller-767f5dcbf4-tmrdw 1/1 Running 0 16m 192.168.50.12 node2 <none> <none>
ingress-nginx-controller-7cd586cc64-2k2qt 0/1 Terminating 0 29m 192.168.50.13 node3 <none> <none>
$ kubectl get pods -n ingress-nginx -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
ingress-nginx-admission-create-666gb 0/1 Completed 0 30m 10.244.104.3 node2 <none> <none>
ingress-nginx-admission-patch-7t5jj 0/1 Completed 3 30m 10.244.135.2 node3 <none> <none>
ingress-nginx-controller-767f5dcbf4-tmrdw 1/1 Running 0 16m 192.168.50.12 node2 <none> <none>
3.2 使用 DaemonSet 方式部署
3.2.1 准备配置文件
wget https://raw.githubusercontent.com/kubernetes/ingress-nginx/main/deploy/static/provider/baremetal/1.21/deploy.yaml
#https://github.com/kubernetes/ingress-nginx/blob/nginx-0.30.0/deploy/static/mandatory.yaml
#wget https://raw.githubusercontent.com/kubernetes/ingress-nginx/nginx-0.30.0/deploy/static/mandatory.yaml
#https://github.com/kubernetes/ingress-nginx/blob/nginx-0.30.0/deploy/static/provider/baremetal/service-nodeport.yaml
#wget https://raw.githubusercontent.com/kubernetes/ingress-nginx/nginx-0.30.0/deploy/static/provider/baremetal/service-nodeport.yaml
3.2.2 调整配置文件
在没有可用的外部负载均衡器并且不使用 NodePorts 的设置中,可以配置 ingress-nginx Pod 使用它们运行的主机的网络,而不是专用的网络命名空间。 这种方法的好处是 NGINX Ingress 控制器可以将端口 80 和 443 直接绑定到 Kubernetes 节点的网络接口,而无需 NodePort 服务强加的额外网络转换。
# 修改为 DaemonSet 类型
sed -i 's/Deployment/DaemonSet/' deploy.yaml
#修改 Pod 网络
#template:
# spec:
# hostNetwork: true
sed -i '/dnsPolicy:/i\ hostNetwork: true' deploy.yaml
由于镜像在 k8s.gcr.io,所有需要替换国内可以访问的镜像地址。
sed -i 's/k8s.gcr.io/lank8s.cn/' deploy.yaml
安全考虑:启用此选项会将 NGINX Ingress 控制器每个系统守护进程暴露给任何网络接口上 ,包括主机的回环接口。请仔细评估这可能对您的系统安全产生的影响。
3.2.3 创建Nginx Controller 相关资源
kubectl apply -f deploy.yaml
3.2.4 检查
$ k get pod -n ingress-nginx -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
ingress-nginx-admission-create-sknfj 0/1 Completed 0 27s 10.244.104.6 node2 <none> <none>
ingress-nginx-admission-patch-w2djb 0/1 Completed 1 27s 10.244.135.5 node3 <none> <none>
ingress-nginx-controller-kptlw 1/1 Running 0 27s 192.168.50.13 node3 <none> <none>
ingress-nginx-controller-s2plx 1/1 Running 0 27s 192.168.50.12 node2 <none> <none>
$ k get svc -n ingress-nginx
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
ingress-nginx-controller NodePort 10.96.199.16 <none> 80:31687/TCP,443:32298/TCP 58s
ingress-nginx-controller-admission ClusterIP 10.96.238.5 <none> 443/TCP 58s
3.2.5 绑定 Node 节点(可选)
#添加亲和性属性
#增加亲和性部署,有 custom/ingress-controller-ready 标签的节点才会部署该 DaemonSet
kubectl label node 192.168.50.12 custom/ingress-controller-ready=true
kubectl label node 192.168.50.13 custom/ingress-controller-ready=true
在 yaml 中增加 nodeSelector 指定标签并更新资源即可。由于 true 是比较特殊的字符,因此需要加双引号。
4. 测试应用
4.1 创建测试应用
创建测试应用kubectl apply -f tomcat-nginx.yaml
cat > tomcat-nginx.yaml << EOF
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
namespace: default
spec:
replicas: 2
selector:
matchLabels:
app: nginx-pod
template:
metadata:
labels:
app: nginx-pod
spec:
containers:
- name: nginx
image: nginx:1.17.1
ports:
- containerPort: 80
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: tomcat-deployment
namespace: default
spec:
replicas: 2
selector:
matchLabels:
app: tomcat-pod
template:
metadata:
labels:
app: tomcat-pod
spec:
containers:
- name: tomcat
image: tomcat:8.5-jre10-slim
ports:
- containerPort: 8080
---
apiVersion: v1
kind: Service
metadata:
name: nginx-service
namespace: default
spec:
selector:
app: nginx-pod
clusterIP: None
type: ClusterIP
ports:
- port: 80
targetPort: 80
---
apiVersion: v1
kind: Service
metadata:
name: tomcat-service
namespace: default
spec:
selector:
app: tomcat-pod
clusterIP: None
type: ClusterIP
ports:
- port: 8080
targetPort: 8080
EOF
检查
$ kubectl get pods
NAME READY STATUS RESTARTS AGE
nginx-deployment-5ffc5bf56c-5vfwl 1/1 Running 0 8h
nginx-deployment-5ffc5bf56c-km5cm 1/1 Running 0 8h
tomcat-deployment-7db86c59b7-6qxfs 1/1 Running 0 8h
tomcat-deployment-7db86c59b7-9d92t 1/1 Running 0 8h
$ kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 3d9h
nginx-service ClusterIP None <none> 80/TCP 8h
tomcat-service ClusterIP None <none> 8080/TCP 8h
4.2 创建 ingress http 规则
4.2.1 使用 networking.k8s.io/v1 版本
cat > ingress-http-v1.yaml << EOF
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: ingress-http
namespace: default
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
spec:
defaultBackend:
resource:
apiGroup: k8s.example.com
kind: StorageBucket
name: static-assets
rules:
- host: nginx.kubernetes.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: nginx-service
port:
number: 80
- host: tomcat.kubernetes.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: tomcat-service
port:
number: 8080
EOF
4.2.2 使用 networking.k8s.io/v1beta1 版本[1.22+将被弃用]
cat > ingress-http-v1beta1.yaml << EOF
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: ingress-http
namespace: default
spec:
rules:
- host: nginx.kubernetes.com
http:
paths:
- path: /
backend:
serviceName: nginx-service
servicePort: 80
- host: tomcat.kubernetes.com
http:
paths:
- path: /
backend:
serviceName: tomcat-service
servicePort: 8080
EOF
4.2.3 创建 ingress https 规则
4.2.3.1 创建 SSL 证书和 Secret 资源
申请证书
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=kubernetes.com"
创建 Secret 资源
kubectl create secret tls tls-secret --key tls.key --cert tls.crt
# kubectl get secrets
4.2.3.2 使用 networking.k8s.io/v1 版本
cat > ingress-https-v1.yaml << EOF
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: ingress-https
namespace: default
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
spec:
tls:
- hosts:
- nginx.kubernetes.com
- tomcat.kubernetes.com
secretName: tls-secret # 指定秘钥
rules:
- host: nginx.kubernetes.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: nginx-service
port:
number: 80
- host: tomcat.kubernetes.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: tomcat-service
port:
number: 8080
EOF
验证
$ kubectl get ingress
NAME CLASS HOSTS ADDRESS PORTS AGE
ingress-https <none> nginx.kubernetes.com,tomcat.kubernetes.com 80, 443 70s
$ kubectl describe ing ingress-https
Name: ingress-https
Namespace: default
Address:
Default backend: default-http-backend:80 (<error: endpoints "default-http-backend" not found>)
TLS:
tls-secret terminates nginx.kubernetes.com,tomcat.kubernetes.com
Rules:
Host Path Backends
---- ---- --------
nginx.kubernetes.com
/ nginx-service:80 (10.244.104.5:80,10.244.135.4:80)
tomcat.kubernetes.com
/ tomcat-service:8080 (10.244.104.4:8080,10.244.135.3:8080)
Annotations: nginx.ingress.kubernetes.io/rewrite-target: /
Events: <none>
4.2.3.3 使用networking.k8s.io/v1beta1 版本
cat > ingress-https-v1beta1.yaml << EOF
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: ingress-https
namespace: default
spec:
tls:
- hosts:
- nginx.kubernetes.com
- tomcat.kubernetes.com
secretName: tls-secret # 指定秘钥
rules:
- host: nginx.kubernetes.com
http:
paths:
- path: /
backend:
serviceName: nginx-service
servicePort: 80
- host: tomcat.kubernetes.com
http:
paths:
- path: /
backend:
serviceName: tomcat-service
servicePort: 8080
EOF
4.3 验证 ingress
kubectl get pods -n ingress-nginx -o wide
kubectl get ingress [-o yaml]
4.5 配置访问
配置 host 文件,指定测试域名和 ingress Controller 绑定的 Node IP后,测试访问域名
192.168.50.12 nginx.kubernetes.com
192.168.50.12 tomcat.kubernetes.com
curl -I -k https://nginx.kubernetes.com
curl -I -k https://tomcat.kubernetes.com
5. ingress 实验
6. 参考文档
https://www.jianshu.com/p/52889bc8571d
https://blog.csdn.net/weixin_44729138/article/details/105978555
https://jimmysong.io/kubernetes-handbook/concepts/ingress.html
https://www.yuque.com/polaris-docs/container/cw8t2e
https://www.yuque.com/woshinianshaodexihuan/zt9p71/hd8u0y
https://kubernetes.io/zh/docs/concepts/services-networking/ingress/
https://www.cnblogs.com/varden/p/15126662.html
https://www.cnblogs.com/varden/p/15127374.html
https://www.icode9.com/content-4-984126.html