Kubernetes Nginx Ingress 教程.md
一、Ingress 介绍
Kubernetes 暴露服务的方式目前只有三种:LoadBlancer Service、NodePort Service、Ingress;
Ingress 是什么?
众所周知 Kubernetes 具有强大的副本控制能力,能保证在任意副本(Pod)挂掉时自动从其他机器启动一个新的,还可以动态扩容等,总之一句话,这个 Pod 可能在任何时刻出现在任何节点上,也可能在任何时刻死在任何节点上;那么自然随着 Pod 的创建和销毁,Pod IP 肯定会动态变化;那么如何把这个动态的 Pod IP 暴露出去?
借助于 Kubernetes 的 Service 机制,Service 可以以标签的形式选定一组带有指定标签的 Pod,并监控和自动负载他们的 Pod IP,那么我们向外暴露只暴露 Service IP 就行了;这就是 NodePort 模式:即在每个节点上开起一个端口,然后转发到内部 Service IP 上,如下图所示NodePort
采用 NodePort 方式暴露服务面临一个坑爹的问题是,服务一旦多起来,NodePort 在每个节点上开启的端口会及其庞大,而且难以维护;这时候引出的思考问题是 “能不能使用 Nginx 啥的只监听一个端口,比如 80,然后按照域名向后转发?” 这思路很好,简单的实现就是使用 DaemonSet 在每个 node 上监听 80,然后写好规则,因为 Nginx 外面绑定了宿主机 80 端口(就像 NodePort),本身又在集群内,那么向后直接转发到相应 Service IP 就行了,如下图所示
从上面的思路,采用 Nginx 似乎已经解决了问题,但是其实这里面有一个很大缺陷:每次有新服务加入怎么改 Nginx 配置?总不能手动改或者来个 Rolling Update 前端 Nginx Pod 吧?这时候 “伟大而又正直勇敢的” Ingress 登场,如果不算上面的 Nginx,Ingress 只有两大组件:Ingress Controller 和 Ingress
Ingress 这个玩意,简单的理解就是 你原来要改 Nginx 配置,然后配置各种域名对应哪个 Service,现在把这个动作抽象出来,变成一个 Ingress 对象,你可以用 yml 创建,每次不要去改 Nginx 了,直接改 yml 然后创建/更新就行了;那么问题来了:”Nginx 咋整?”
Ingress Controller 这东西就是解决 “Nginx 咋整” 的;Ingress Controoler 通过与 Kubernetes API 交互,动态的去感知集群中 Ingress 规则变化,然后读取他,按照他自己模板生成一段 Nginx 配置,再写到 Nginx Pod 里,最后 reload 一下,工作流程如下图
当然在实际应用中,最新版本 Kubernetes 已经将 Nginx 与 Ingress Controller 合并为一个组件,所以 Nginx 无需单独部署,只需要部署 Ingress Controller 即可
二、部署Nginx Ingress Controller
建议使用DaemonSet方式部署
官方给出的配置文件在 https://github.com/kubernetes/ingress-nginx/tree/master/deploy
我的kubernetes集群是1.5的版本,以下是我的配置文件
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: nginx-ingress-serviceaccount
---
apiVersion: extensions/v1beta1
kind: DaemonSet
metadata:
name: nginx-ingress-lb
spec:
template:
metadata:
labels:
name: nginx-ingress-lb
spec:
serviceAccountName: nginx-ingress-serviceaccount
terminationGracePeriodSeconds: 60
hostNetwork: true
containers:
- image: 47.52.174.242:5000/google_containers/nginx-ingress-controller:0.8.3
name: nginx-ingress-lb
imagePullPolicy: IfNotPresent
securityContext:
privileged: true
# use downward API
ports:
- containerPort: 80
hostPort: 80
- containerPort: 443
hostPort: 443
livenessProbe:
failureThreshold: 3
httpGet:
path: /healthz
port: 10254
scheme: HTTP
initialDelaySeconds: 10
periodSeconds: 10
successThreshold: 1
timeoutSeconds: 1
readinessProbe:
failureThreshold: 3
httpGet:
path: /healthz
port: 10254
scheme: HTTP
periodSeconds: 10
successThreshold: 1
timeoutSeconds: 1
env:
- name: POD_NAME
valueFrom:
fieldRef:
fieldPath: metadata.name
- name: POD_NAMESPACE
valueFrom:
fieldRef:
fieldPath: metadata.namespace
args:
- /nginx-ingress-controller
- --default-backend-service=default/svc-nginx
知得注意的以下几点:
- 这里面需要使用ServiceAccount,否则Pod会报错无法连接APIServer
- 使用hostNetwork和hostPort直接监听Node服务器上的端口。
- 创建Nginx Ingress Controller之前必须有一个默认后端default backend,随便找个nginx放上就好,需要创建好service。
三、创建ingress
这里我借用了traefik的案例 https://github.com/containous/traefik/tree/master/examples/k8s
需要现部署3个服务stilton,cheddar和wensleydale,然后再基于虚拟主机创建ingress
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: cheese
spec:
rules:
- host: stilton.minikube
http:
paths:
- path: /
backend:
serviceName: stilton
servicePort: http
- host: cheddar.minikube
http:
paths:
- path: /
backend:
serviceName: cheddar
servicePort: http
- host: wensleydale.minikube
http:
paths:
- path: /
backend:
serviceName: wensleydale
servicePort: http
四、测试
[root@k80 k8s]# curl http://cheddar.minikube/ -x 10.130.8.25:80
<html>
...
<body>
<h1>Cheddar</h1>
</body>
</html>
[root@k80 k8s]# curl http://wensleydale.minikube/ -x 10.130.8.25:80
<html>
...
<body>
<h1>Wensleydale</h1>
</body>
</html>
通过指定不同的域名,显示出不同的内容。
五、业务状态健康检查
Nginx Ingress Controller 需要配置livenessProbe和readinessProbe。
Service和Ingress没有健康检查功能。
提供服务的Pod或者Deployment也可以通过livenessProbe和readinessProbe来进行健康检查。
六、HTTPS的配置
随着https站点的普及,支持https站点也是必须的,接下来我们给nginx配置证书:
首先我们需要将我们的证书文件转换为K8S中的Secret。
kubectl create secret tls ipcpu.tls --key server.key --cert server.pem
然后创建支持https的Ingress:
cat <<EOF | kubectl create -f -
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: tls-fanout
spec:
tls:
- hosts:
- foo.ipcpu.com.cn
secretName: ipcpu.tls
rules:
- host: foo.ipcpu.com.cn
http:
paths:
- path: /
backend:
serviceName: wensleydale
servicePort: 80
EOF
然后测试
[root@k80 nginx-ingress]# cat <<EOF >>/etc/hosts
> 10.130.8.25 foo.ipcpu.com.cn
> EOF
[root@k80 nginx-ingress]# curl -I https://foo.ipcpu.com.cn
HTTP/1.1 200 OK
Server: nginx/1.11.3
Content-Type: text/html
Content-Length: 521
七、参考资料
https://mritd.me/2017/03/04/how-to-use-nginx-ingress/
http://blog.opskumu.com/k8s-ingress.html
http://www.jianshu.com/p/8afb493dc4eb
https://my.oschina.net/jxcdwangtao/blog/1523812
https://github.com/kubernetes/ingress-nginx/
https://help.aliyun.com/document_detail/53770.html?spm=5176.doc56336.6.826.YOsGbq