我们知道,Kubernetes对外暴露服务的方式有三种:LoadBlancer
,ExternalName
和NodePort
。
采用 NodePort 方式暴露服务面临的一个问题是,服务一旦多起来,NodePort Service在每个节点上开启的端口会及其庞大,而且难以维护。这时候引出的思考问题是 “能不能使用 Nginx 啥的只监听一个端口,比如 80,然后按照域名向后转发?” 这思路很好,简单的实现就是使用 DaemonSet 在每个 node 上监听 80,然后写好规则,因为 Nginx外面绑定了宿主机 80 端口(就像 NodePort),本身又在集群内,那么向后直接转发到相应 Service IP 就行了。
从上面的思路,采用 Nginx 似乎已经解决了问题,但是其实这里面有一个很大缺陷:每次有新服务加入怎么改 Nginx 配置?总不能手动改或者来个 Rolling Update 前端 Nginx Pod 吧?为了解决这个问题,出现了Ingress。将nginx的配置,即配置各种域名对应哪个 Service,抽象成一个 Ingress 对象,你可以用 yml 创建,每次不需要修改Nginx的配置文件了,直接修改yml 然后创建/更新就行了。
Ingress Controller 通过与 Kubernetes API 交互,动态的去感知集群中 Ingress 规则变化,然后读取他,按照他自己模板生成一段 Nginx配置,再写到 Nginx Pod 里,最后 reload一下,从而使更新后的Nginx工作。
1. 准备工作
由于Ingress Controller并不是kube-controller-manager中的一部分,因此要使用Ingress,我们必须首先在Kubernetes集群中安装一个Ingress Controller。常见的Ingress Controller包括 Nginx,Traefik,Istio等等。
使用Helm安装方式Nginx Ingress Controller:
helm install stable/nginx-ingress --name my-nginx
查看安装的Nginx Ingress Controller版本:
POD_NAME=$(kubectl get pods -l app.kubernetes.io/name=ingress-nginx -o jsonpath='{.items[0].metadata.name}')
kubectl exec -it $POD_NAME -- /nginx-ingress-controller --version
2. 创建一个Ingress对象
下面是一个最简单的Ingress对象文件:
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
name: test-ingress
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
spec:
rules:
- http:
paths:
- path: /testpath
backend:
serviceName: test
servicePort: 80
- Ingress通常使用annotation来定义一些可重写的选项。例如Nginx Ingress Controller可重写的选项包括:rewrite-target annotation
-
spec.rules
则用于定义路由规则。通常包含三部分信息:host,path和service。host是可选的,如果未定义,则适用于该IP收到的所有请求。否则只适用于host规定的URL。path可以包含多个,用于将满足path的请求路由到对应的service中。 - 如果一个请求找不到对应的路由规则,那么它将被转发到
default backend
。default backend
通常是Ingress Controller的一个可选配置项。Ingress对象文件无需定义它。
下面是一个复杂的Ingress定义:
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
name: simple-fanout-example
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
spec:
rules:
- host: foo.bar.com
http:
paths:
- path: /foo
backend:
serviceName: service1
servicePort: 4200
- path: /bar
backend:
serviceName: service2
servicePort: 8080
上面的Ingress对象实现了如下路由规则:
foo.bar.com -> 178.91.123.132 -> / foo service1:4200
/ bar service2:8080
可以使用kubectl describe ingress simple-fanout-example
命令查看:
Name: simple-fanout-example
Namespace: default
Address: 178.91.123.132
Default backend: default-http-backend:80 (10.8.2.3:8080)
Rules:
Host Path Backends
---- ---- --------
foo.bar.com
/foo service1:4200 (10.8.0.90:4200)
/bar service2:8080 (10.8.0.91:8080)
Annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal ADD 22s loadbalancer-controller default/test
下面是一个启用了TLS的Ingress:
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
name: cafe-ingress
annotations:
nginx.org/sticky-cookie-services: "serviceName=coffee-svc srv_id expires=1h path=/coffee"
nginx.com/jwt-realm: "Cafe App"
nginx.com/jwt-token: "$cookie_auth_token"
nginx.com/jwt-key: "cafe-jwk"
spec:
tls:
- hosts:
- cafe.example.com
secretName: cafe-secret
rules:
- host: cafe.example.com
http:
paths:
- path: /tea
backend:
serviceName: tea-svc
servicePort: 80
- path: /coffee
backend:
serviceName: coffee-svc
servicePort: 80
更多关于TLS的Ingress,请参考:https://mritd.me/2017/03/04/how-to-use-nginx-ingress/
网友评论