Kubernetes Ingress
[TOC]
Ingress 介绍
Ingress能把Service(Kubernetes的服务)配置成外网能够访问的URL,流量负载均衡,终止SSL,提供于域名访问的虚拟主机等,用户通过访问URL(API资源服务的形式,例如:caas.one/kibana)进入和请求Service,一个Ingress控制器负责处理所有Ingress的请求流量,它通常是一个负载均衡器,它也可以设置在边界路由器上,或者由额外的前端来帮助处理HA方式的流量。
Kubernetes暴露服务的方式目前只有三种:
1.LoadBlancer Service 2.NodePort Service 3.Ingress
1. LadBlancer Service
LadBlancer Service 是Kubernetes深度结合云平台的一个组件;当使用LoadBlancer Service 暴露服务时,实际上是通过向底层云平台申请创建一个负载均衡器来向外暴露服务;目前LoadBlancer Service支持的云平台已经相对完善,比如国外的GCE、DigitalOcean,国内的阿里云,私有云(Openstack)等等,由于LoadBlancer Service深度结合了云平台,所以只能在一些云平台上使用
2. NodePort Service
NodePort Service顾名思义,实质上就是通过在集群的每个Node上暴露一个端口,然后将这个端口映射到某个具体的Service来实现的,虽然每个Node的端口有很多(0~65535),但是由于安全性和易用性(服务多了就乱了,端口冲突问题)实际使用可能并不多
3. Ingress
Ingress 是在Kubernetes 1.2后出现的,通过Ingress用户可以实现使用Nginx等开源的反向代理负载均衡实现对外暴露服务,以下详细说一下Ingress,traefik
用的就是Ingress
Ingress 三大组件
1.反向代理负载均衡器 2.Ingress Controller 3.Ingress
反向代理负载均衡器 反向代理负载均衡器很简单,说白了就是nginx、apche等;在集群中反向代理负载均衡器可以自由部署,可以使用Replication Controller、Deployment、DaemonSet等等
Ingress Controller Ingress Controller实质上可以理解为是个监视器,Ingress Controller通过不断地跟Kubernetes API打交道,实时的感知后端Service、Pod等变化,比如新增和减少Pod,Service增加与减少等;当得到这些变化信息后,Ingress Controller在结合下文的Ingress生成配置,然后更新反向代理负载均衡器,并刷新其配置,达到服务发现的作用。
总结:Ingress解决的是新的服务加入后,域名和服务的对应问题,基本上是一个ingress的对象,通过yaml进行创建和更新进行加载。
Ingress Ingress简单理解就是个规则定义;比如某个域名对应某个Serivce,即当某个域名的请求进来时转发给某个Service;这个规则将与Ingress Controller结合,然后Ingress Controller将其动态写入到负载均衡器中,从而实现整体的服务发现和负载均衡 总结:Ingress解决的是新的服务加入后,域名和服务的对应问题,基本上是一个ingress的对象,通过yaml进行创建和更新进行加载。
解释:从上图可以很清晰的看到,实际上请求进行被负载均衡器拦截,比如nginx,然后Ingress Controller通过交互得知某个域名对应哪个Service,再通过跟Kubernetes API交互得知Service地址等信息;综合以后生成配置文件实时写入负载均衡器,然后负载均衡器reload该规则便可实现服务发现,即动态映射
小结
Ingress
其实就是从 kuberenets 集群外部访问集群的一个入口,将外部的请求转发到集群内不同的 Service 上,其实就相当于 nginx、haproxy 等负载均衡代理服务器,有的同学可能觉得我们直接使用 nginx 就实现了,但是只使用 nginx 这种方式有很大缺陷,每次有新服务加入的时候怎么改 Nginx 配置?不可能让我们去手动更改或者滚动更新前端的 Nginx Pod 吧?那我们再加上一个服务发现的工具比如 consul 如何?貌似是可以,对吧?而且在之前单独使用 docker 的时候,这种方式已经使用得很普遍了,Ingress 实际上就是这样实现的,只是服务发现的功能自己实现了,不需要使用第三方的服务了,然后再加上一个域名规则定义,路由信息的刷新需要一个靠 Ingress controller 来提供。Ingress controller 可以理解为一个监听器,通过不断地与 kube-apiserver 打交道,实时的感知后端 service、pod 的变化,当得到这些变化信息后,Ingress controller 再结合 Ingress 的配置,更新反向代理负载均衡器,达到服务发现的作用。其实这点和服务发现工具 consul consul-template 非常类似。
现在可以供大家使用的 Ingress controller 有很多,比如 traefik、nginx-controller、Kubernetes Ingress Controller for Kong、HAProxy Ingress controller,当然你也可以自己实现一个 Ingress Controller,现在普遍用得较多的是 traefik 和 nginx-controller,traefik 的性能较 nginx-controller 差,但是配置使用要简单许多
我以下的操作不使用Daemon Set,使用Deployment的模式
很多人提议最好将负载均衡器部署为Daemon Set;因为无论如何请求首先是被负载均衡器拦截,所以在每个Node上都部署一下,同时hostport方式监听80端口;那么就解决了其他方式部署不确定,负载均衡器在哪的问题,同时访问每个Node的80都能正确解析请求;如果前端在放个Nginx就又实现了一层负载均衡器
参考:http://mritd.me/2016/12/06/try-traefik-on-kubernetes/
4. 域名分配及动态更新问题
从上面的思路,采用 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 一下,工作流程如下图
Ingress Install
我们知道,前端的Nginx最重要负载到后端的Service上,那么如果service上没有pod该如何解决? 官方给出的建议是部署一个默认后端,对于未知请求全部负载到这个默认后端上,这个后端不提供其它服务,只返回404.它还提供了一个http检测功能,检测nginx-ingress-controll健康状态的,通过每隔一定时间访问nginx-ingress-controll的/healthz页面,如是没有响应就 返回404之类的错误码。
GitHub项目地址:https://github.com/kubernetes/ingress-nginx/tree/master/deploy
下载安装包 ingress-nginx github文档中讲Namespave、ConfigMap、ServiceAccount、Deployment、default-backend等服务的yaml配置文件独立保存
mkdir /root/ingress -p && cd /root/ingress/
wget https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/namespace.yaml
wget https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/configmap.yaml
wget https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/default-backend.yaml
wget https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/tcp-services-configmap.yaml
wget https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/udp-services-configmap.yaml
wget https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/rbac.yaml
wget https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/with-rbac.yaml
Yaml 修改
namespace.yaml
# namespace.yaml不做修改,创建1个独立的namespace
[root@master ingress]# cat namespace.yaml
---
apiVersion: v1
kind: Namespace
metadata:
name: ingress-nginx
default-backend.yaml
# 提供1个默认的后台404错误页面与/healthz的健康检查页;
# 含1个Deployment 与 1个service;
# 只需要修改Pod启动调用的image文件,可以下载我上传的镜像,导入进去修改一下版本即可
[root@master ingress]# cat default-backend.yaml
---
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: default-http-backend
labels:
app: default-http-backend
namespace: ingress-nginx
spec:
replicas: 1
selector:
matchLabels:
app: default-http-backend
template:
metadata:
labels:
app: default-http-backend
spec:
terminationGracePeriodSeconds: 60
containers:
- name: default-http-backend
# Any image is permissible as long as:
# 1. It serves a 404 page at /
# 2. It serves 200 on a /healthz endpoint
# 镜像需要我们上传上去,或者使用别的
image: gcr.io/google_containers/defaultbackend:1.4
livenessProbe:
httpGet:
path: /healthz
port: 8080
scheme: HTTP
initialDelaySeconds: 30
timeoutSeconds: 5
ports:
- containerPort: 8080
resources:
limits:
cpu: 10m
memory: 20Mi
requests:
cpu: 10m
memory: 20Mi
---
apiVersion: v1
kind: Service
metadata:
name: default-http-backend
namespace: ingress-nginx
labels:
app: default-http-backend
spec:
ports:
- port: 80
targetPort: 8080
selector:
app: default-http-backend
configmap.yaml 这里不做修改(具体可以了解 资源对象)
[root@master ingress]# cat configmap.yaml
---
kind: ConfigMap
apiVersion: v1
metadata:
name: nginx-configuration
namespace: ingress-nginx
labels:
app: ingress-nginx
tcp-services-configmap.yaml
[root@master ingress]# cat tcp-services-configmap.yaml
---
kind: ConfigMap
apiVersion: v1
metadata:
name: tcp-services
namespace: ingress-nginx
udp-services-configmap.yaml
[root@master ingress]# cat udp-services-configmap.yaml
---
kind: ConfigMap
apiVersion: v1
metadata:
name: udp-services
namespace: ingress-nginx
rbac.yaml
# ingress-controller需要监听apiserver,获取ingress定义,通过rbac授权;
# rbac不需要我们修改
[root@master ingress]# cat rbac.yaml
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: nginx-ingress-serviceaccount
namespace: ingress-nginx
---
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRole
metadata:
name: nginx-ingress-clusterrole
rules:
- apiGroups:
- ""
resources:
- configmaps
- endpoints
- nodes
- pods
- secrets
verbs:
- list
- watch
- apiGroups:
- ""
resources:
- nodes
verbs:
- get
- apiGroups:
- ""
resources:
- services
verbs:
- get
- list
- watch
- apiGroups:
- "extensions"
resources:
- ingresses
verbs:
- get
- list
- watch
- apiGroups:
- ""
resources:
- events
verbs:
- create
- patch
- apiGroups:
- "extensions"
resources:
- ingresses/status
verbs:
- update
---
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: Role
metadata:
name: nginx-ingress-role
namespace: ingress-nginx
rules:
- apiGroups:
- ""
resources:
- configmaps
- pods
- secrets
- namespaces
verbs:
- get
- apiGroups:
- ""
resources:
- configmaps
resourceNames:
# Defaults to "<election-id>-<ingress-class>"
# Here: "<ingress-controller-leader>-<nginx>"
# This has to be adapted if you change either parameter
# when launching the nginx-ingress-controller.
- "ingress-controller-leader-nginx"
verbs:
- get
- update
- apiGroups:
- ""
resources:
- configmaps
verbs:
- create
- apiGroups:
- ""
resources:
- endpoints
verbs:
- get
---
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: RoleBinding
metadata:
name: nginx-ingress-role-nisa-binding
namespace: ingress-nginx
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: nginx-ingress-role
subjects:
- kind: ServiceAccount
name: nginx-ingress-serviceaccount
namespace: ingress-nginx
---
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRoleBinding
metadata:
name: nginx-ingress-clusterrole-nisa-binding
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: nginx-ingress-clusterrole
subjects:
- kind: ServiceAccount
name: nginx-ingress-serviceaccount
namespace: ingress-nginx
with-rbac.yaml
Ingress-Controller以Pod的形式运行,监控apiserver的/ingress接口后端的backend services,如果service发生变化,则Ingress-Controller自动更新转发规则
基本逻辑如下: 1.监听apiserver,获取全部Ingress定义; 2.基于Ingress定义,生成nginx的配置文件/etc/nginx/nginx.conf; 3.执行nginx -s reload,重新加载nginx.conf配置文件的内容
# wuthout-rbac.yaml和with-rbac.yaml的区别是没用调用rbac.yaml中定义的ServiceAccount;nginx-ingress-serviceaccount,这里访问apiserver需要认证;
# github文档给的kind: Deployment,replicas:1,即在1个节点上启动1个ingress-nginx controller Pod,外部流量访问该节点,由该节点负载后端services;但Pod本身会因为故障而转移,节点ip会变更,DaemonSet会在多个节点(可以利用Pod的亲和性将指定Pod部署到指定节点)生成ingress-nginx controller pod,则客户端可以访问任意节点;或者在前端部署负载,使用vip访问后端3个节点;(我们这里继续使用Deployment的模式,我们replicas设置为2,DaemonSet可以参考https://www.cnblogs.com/netonline/p/8877324.html)
# hostNetwork:true 暴露ingress-nginx controller的相关业务端口到主机
# 验证中暂时用不到的服务可以不启动注释26-32行即可
[root@master ingress]# cat with-rbac.yaml_bak
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: nginx-ingress-controller
namespace: ingress-nginx
spec:
replicas: 2
selector:
matchLabels:
app: ingress-nginx
template:
metadata:
labels:
app: ingress-nginx
annotations:
prometheus.io/port: '10254'
prometheus.io/scrape: 'true'
spec:
hostNetwork: true
## 增加hostNetwork:true
serviceAccountName: nginx-ingress-serviceaccount
containers:
- name: nginx-ingress-controller
#image: quay.io/kubernetes-ingress-controller/nginx-ingress-controller:0.17.1
##修改镜像地址
image: registry.cn-beijing.aliyuncs.com/k8s_apps/nginx-ingress-controller:0.14.0
args:
- /nginx-ingress-controller
- --default-backend-service=$(POD_NAMESPACE)/default-http-backend
- --configmap=$(POD_NAMESPACE)/nginx-configuration
- --tcp-services-configmap=$(POD_NAMESPACE)/tcp-services
- --udp-services-configmap=$(POD_NAMESPACE)/udp-services
- --annotations-prefix=nginx.ingress.kubernetes.io
#securityContext:
# capabilities:
# drop:
# - ALL
# add:
# - NET_BIND_SERVICE
# www-data -> 33
# runAsUser: 33
env:
- name: POD_NAME
valueFrom:
fieldRef:
fieldPath: metadata.name
- name: POD_NAMESPACE
valueFrom:
fieldRef:
fieldPath: metadata.namespace
ports:
- name: http
containerPort: 80
- name: https
containerPort: 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
注意:with-rbac.yaml
需要注释32-39行
总的来说with-rbac.yaml只是增加了hostNetwork和修改了image镜像地址以及注释了防火墙一些配置
下载镜像:
##下载nginx-ingres-controller
docker pull registry.cn-beijing.aliyuncs.com/k8s_apps/nginx-ingress-controller:0.14.0
##下载默认404页面镜像
docker pull registry.cn-hangzhou.aliyuncs.com/google_containers/defaultbackend:1.4
Ingress所用的软件包及配置文件 密码:fd3b
安装ingress
创建:
kubectl create -f namespace.yaml
kubectl create -f default-backend.yaml
kubectl create -f configmap.yaml
kubectl create -f tcp-services-configmap.yaml
kubectl create -f udp-services-configmap.yaml
kubectl create -f rbac.yaml
kubectl create -f with-rbac.yaml
验证: 检查ingress-nginx 命名空间的pod
[root@master ingress]# kubectl get pods -n ingress-nginx -o wide
NAME READY STATUS RESTARTS AGE IP NODE
default-http-backend-846b65fb5f-462qt 1/1 Running 0 1h 172.16.219.68 master
nginx-ingress-controller-56c45cc5bc-28j76 1/1 Running 0 27m 192.168.60.24 master
nginx-ingress-controller-56c45cc5bc-trcs8 1/1 Running 0 26m 192.168.60.25 node
节点本机相应端口已经使用
[root@master ingress]# netstat -lntup|grep nginx
tcp 0 0 0.0.0.0:80 0.0.0.0:* LISTEN 106281/nginx: maste
tcp 0 0 0.0.0.0:443 0.0.0.0:* LISTEN 106281/nginx: maste
tcp 0 0 0.0.0.0:18080 0.0.0.0:* LISTEN 106281/nginx: maste
tcp6 0 0 :::10254 :::* LISTEN 106260/nginx-ingres
tcp6 0 0 :::80 :::* LISTEN 106281/nginx: maste
tcp6 0 0 :::443 :::* LISTEN 106281/nginx: maste
tcp6 0 0 :::18080 :::* LISTEN 106281/nginx: maste
访问我们ingress-nginx的80任意节点,反回404。ingress-nginx controller与default-http-backend生效
[root@master ingress]# curl 192.168.60.24
default backend - 404
[root@master ingress]# curl 192.168.60.25
default backend - 404
##master或者node节点都可以
以上的操作就是我们生成ingress所需要的配置,现在inagress还需要我们配置后端service
安装nginx进行测试
配置service service关联pod
[root@master test]# cat test.service.yaml
kind: Service
apiVersion: v1
metadata:
name: nginx-service
spec:
selector:
app: nginx
ports:
- protocol: TCP
port: 80
targetPort: 80
nodePort: 31000
type: NodePort
配置deploy文件 创建pod
[root@master test]# cat test.deploy.yaml
apiVersion: apps/v1beta2
kind: Deployment
metadata:
name: nginx-deployment
spec:
replicas: 5
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: daocloud.io/library/nginx:1.13.0-alpine
imagePullPolicy: IfNotPresent
ports:
- containerPort: 80
设置ingress service代理文件 为ingress 关联service
[root@master ingress]# cat nginx.yaml
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: nginx-test-ingress # ingress 名称
namespace: default # 命名空间
spec:
rules:
# 域名
- host: k8s.nginx.com
http:
paths:
- path: /
backend:
# 后端service
serviceName: nginx-service
# service 端口
servicePort: 80
更多配置ingress优化参数可以参考 https://www.cnblogs.com/netonline/p/8877324.html