ingress-nginx实践
一、说明
写这篇文章的时候(2021年9月6号上午10点左右)k8s的最新release版本已经是1.22.1了,但我生产环境已经运行的版本为1.19.13,所以在此我以1.19.13为例子进行演示说明,但这并不影响你以此作为案例在其余版本的k8s上实践ingress-nginx,因为我整个安装、使用过程都是基于官网,你需要做的的仅仅是跟着节凑、对照官网总结方法。方法对了,版本再怎么变、官网再怎么更新,你也不必置疑,因为你参考的是官网、你已经学会了随机应变,下面开始。
二、环境
为了方便,在此事先准备了"k8s的单master节点简易集群(kubeadm安装)"进行演示(多master集群模式也一样),"k8s集群安装"篇幅也马上补上,集群信息见下:
ip | hostname | k8s版本 | remark |
---|---|---|---|
192.168.16.211 | vm-1 | 1.19.13 | master |
192.168.16.212 | vm-2 | 1.19.13 | node |
三、官网解读
# ingress-nginx官网地址
https://kubernetes.github.io/ingress-nginx/
# ingress-nginx和k8s版本以及语法问题。在写这篇文章的时候,下面链接最近更新时间为2021-07-26日,后续更新,可能造成地址改变的问题,可从ingress-nginx官网重新进入。
https://kubernetes.io/blog/2021/07/26/update-with-ingress-nginx/
# ingress class
https://kubernetes.io/docs/concepts/services-networking/ingress/#ingress-class
# ingress基本使用
https://kubernetes.io/zh/docs/concepts/services-networking/ingress/
# github ingress-nginx
https://github.com/kubernetes/ingress-nginx
解读1、版本
先看一下"k8s blog"的说明信息:
ingress-nginx k8s version
对于k8s v1.19 Notes部分信息:
Bugfixes only, and just for security issues or crashes. Fixes only provided until 6 months after Kubernetes v1.22.0 is released.
翻译过来就是:
仅修复错误,仅用于安全问题或崩溃。 仅在 Kubernetes v1.22.0 发布后 6 个月内提供修复。
1.22发行后,相信1.19版本的常见bug已经被发现并且修复完了,所以假如你生产环境的k8s集群也是1.19版本的,那么不要怀疑,请选择ingress-nginx 0.47版本。
解读2、api version
大体意思是说k8s 1.22 release版本出来后,尽量用"networking.k8s.io/v1"。
解读3、ingressClass
当安装完ingress-nginx后,核心组件"ingress nginx controller"就相当于nginx应用程序,而且你可以在你的k8s集群中启动多个controller,这个很容易理解,就相当于你启动了多个nginx进程。而后续你编写的Ingress资源就相当于nginx的配置文件。如何将你编写的nginx配置文件应用到指定的nginx应用程序上面,或者说nginx配置文件如何找到对应的nginx应用,这个就是ingressClass需要做的事情,下面文档也会涉及这一块。
解读4、安装
官网提供了各种场景下ingress-nginx的各种安装方法,找到适合你的就行了。我这里用的是阿里云服务器,假如你是公司机房的服务器或者其它云厂商的服务器你也可以和我一样选择"bare-metal"裸机部署的方式。
解读5、权限
k8s里面有namespace的概念,默认的ingress nginx controller会安装在自创的ingress-nginx的namespace下,也就相当于:你的nginx应用程序是安装在ingress-nginx的命名空间下面。假如你后续定义的ingress资源跑在别的命名空间,那你的nginx应用程序是否有权限读取你的nginx配置文件。
答案是:。
ingress nginx controller会监听所有命名空间中与它相关联的ingress资源。
四、ingress-nginx安装
4.1、下载
在官网找到"裸机部署"处,见下截图:
download
"备注1"处,这里我先下载到本地,进行适量修改后,在进行apply。
"备注2"处,是裸机安装ingress-nginx其它需要考虑的事项,eg:端口暴露、安全角度等。
假如你需要下载对应版本的deploy.yaml文件,就需要借助github了:
github ingress-nginx
选择对应的分支,这里我以"dev-v1"为例,最终结果见下图:
dev-v1 github
[root@vm-1 jianshu]# wget https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v1.0.0/deploy/static/provider/baremetal/deploy.yaml
4.2、固定
既然是流量出入口,我们当然希望部署的ingress-nginx固定在特定的虚拟机上,一方面减少其余应用的干扰,避免造成宕机,另一方面也便于后续我们对ingress-nginx的反向代理。这里我修改两个地方:
如果你下载的yaml文件原deployment模式中有replicas申明则删除,由于我下载的这个版本也就是最新的4.7.0版本没有此选项,故在此忽略。
nodeSelector
DaemonSet和nodeSelect的联合使用能够保证ingress-nginx在具有"item=ingress"标签的节点上仅运行一个ingress-nginx的pod实例。
4.3、端口暴露
ingress-nginx其实质就是一个nginx,对外暴露nginx的端口(80、443)供外部访问,对内它可以代理到部署在k8s环境上的应用,这和你平时配置nginx的操作没什么区别。
暴露端口我们常用的方式有nodeport方式,host模式等等。
4.3.1、host模式
host mode4.3.2、nodeport模式
这也是"4.1、下载"部分我们得到的deploy.yaml文件中默认的端口暴露方式,在此我将端口号固定:
请确保具有item=ingress标签的node节点上30080和30443端口没有被占用,如被占用,可将其修改为其它端口。
在此我选择nodeport的模式。
4.4、总结
A: 修改deployment为DaemonSet,有replicas则删除
B: 修改nodeSector为item: ingress,根据自己习惯,其余命名亦可
C: 端口暴露,host、nodeport选择一种即可
4.5、apply
# 由于我的node节点只有一个,因此只有一个标签为item=ingress的节点,你可以使用两个或多个
[root@vm-1 jianshu]# kubectl label node vm-2 item=ingress
[root@vm-1 jianshu]# kubectl apply -f deploy.yaml
[root@vm-1 jianshu]# kubectl get pods -n ingress-nginx -l app.kubernetes.io/name=ingress-nginx --watch
pods
到这就算安装成功了。
4.6、使用
4.6.1、后端资源准备
[root@vm-1 jianshu]# cat crm1-service.yaml
apiVersion: v1
kind: Service
metadata:
name: crm1-service
namespace: dev
spec:
selector:
app: crm1
env: dev
ports:
- name: http
port: 80
targetPort: 80
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: crm1-deployment
namespace: dev
spec:
replicas: 1
selector:
matchLabels:
app: crm1
env: dev
template:
metadata:
labels:
app: crm1
env: dev
spec:
containers:
- name: crm1-system
image: nginx:1.15-alpine
imagePullPolicy: IfNotPresent
lifecycle:
postStart:
exec:
command: ["/bin/sh","-c","echo crm1.fengzhihai.cn > /usr/share/nginx/html/index.html"]
ports:
- name: httpd
containerPort: 80
[root@vm-1 jianshu]# cat crm2-service.yaml
apiVersion: v1
kind: Service
metadata:
name: crm2-service
namespace: dev
spec:
selector:
app: crm2
env: dev
ports:
- name: http
port: 80
targetPort: 80
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: crm2-deployment
namespace: dev
spec:
replicas: 1
selector:
matchLabels:
app: crm2
env: dev
template:
metadata:
labels:
app: crm2
env: dev
spec:
containers:
- name: crm2-system
image: nginx:1.15-alpine
imagePullPolicy: IfNotPresent
lifecycle:
postStart:
exec:
command: ["/bin/sh", "-c", "echo crm2.fengzhihai.cn > /usr/share/nginx/html/index.html"]
ports:
- name: httpd
containerPort: 80
[root@vm-1 jianshu]# kubectl apply -f crm1-service.yaml
[root@vm-1 jianshu]# kubectl apply -f crm2-service.yaml
4.6.2、ingress
[root@vm-1 jianshu]# cat crm-ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: crm-ingress
namespace: dev
spec:
ingressClassName: nginx
rules:
- host: "crm1.fengzhihai.cn"
http:
paths:
- path: "/"
pathType: Prefix
backend:
service:
name: crm1-service
port:
number: 80
- host: "crm2.fengzhihai.cn"
http:
paths:
- path: "/"
pathType: Prefix
backend:
service:
name: crm2-service
port:
number: 80
[root@vm-1 jianshu]# kubectl apply -f crm-ingress.yaml
4.6.3、nginx配置
我这里的nginx是脱离k8s集群与ingress-ingix之外的单独部署的nginx,是实际环境中流量分发的出入口nginx。
upstream ingress-controller {
server 192.168.16.212:30080;
}
server {
listen 80;
server_name crm1.fengzhihai.cn;
location / {
proxy_pass http://ingress-controller;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
server {
listen 80;
server_name crm2.fengzhihai.cn;
location / {
proxy_pass http://ingress-controller;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
4.6.4、浏览器访问
crm1.fengzhihai.cncrm2.fengzhihai.cn
4.7、ingress配置
以我上面的为例:
[root@vm-1 jianshu]# cat crm-ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: crm-ingress
namespace: dev
spec:
ingressClassName: nginx
rules:
- host: "crm1.fengzhihai.cn"
http:
paths:
- path: "/"
pathType: Prefix
backend:
service:
name: crm1-service
port:
number: 80
- host: "crm2.fengzhihai.cn"
http:
paths:
- path: "/"
pathType: Prefix
backend:
service:
name: crm2-service
port:
number: 80
这里申明了"ingressClassName: nginx",假如你像下面这样将ingressclass写在metadata里面也是可以的:
[root@vm-1 jianshu]# cat crm-ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: crm-ingress
namespace: dev
annotations:
kubernetes.io/ingress.class: "nginx"
spec:
rules:
- host: "crm1.fengzhihai.cn"
http:
paths:
- path: "/"
pathType: Prefix
backend:
service:
name: crm1-service
port:
number: 80
- host: "crm2.fengzhihai.cn"
http:
paths:
- path: "/"
pathType: Prefix
backend:
service:
name: crm2-service
port:
number: 80
无论怎么写,这个地方其实就是上文提到的ingressclass,假如不写,就会报错(仅在1.19.13版本测试过)。
下面我们来看看这个叫着"nginx"的ingresscalss从哪里来的。
很明显它对应的ingress nginx controller为"k8s.io/ingress-nginx",当前我们只有一个controller,所以可以在我们之前下载的deploy.yaml中去寻找:
k8s.io/ingress-nginx
我们再回过头来看看官网说的:
https://kubernetes.io/docs/concepts/services-networking/ingress/
ingressclass
也就是官网建议每个ingress nginx controller都应该定义一个ingressclass,而官网给我们提供的deploy.yaml已经给我们创建好了,假如你自己额外定义一个controller,那就可以照着上面的官网额外定义一个ingressclass了。
4.8、ingress-nginx工作原理
按照上面的步骤你应该已经大致了解了ingress-nginx的工作原理了,我们用一副官方给的图形为例:
我在"备注1"和"备注3"之间跨过了"备注2",因为在实际的生产环境中这里少了些许步骤:
上面的流程图中"阿里云ecs服务器"便于我们统计日志,基于日志做一些流量分析等。
你也可以进入ingress nginx controller中,看一下其中的代理配置,和nginx同,在此省。
4.9、排错
面对报错不知所措是最可怕的事情,官网也给出了一些排错建议:
https://kubernetes.github.io/ingress-nginx/troubleshooting/
总结起来就两点:
A: 通过logs/events进行排错
B: debug
4.10、写在最后
后续对ingress-nginx有不同理解或者功能增加会及时更新此文章,希望多质疑留言,谢谢。