一、Kubernetes 服务暴露介绍
从 kubernetes 1.2 版本开始,kubernetes提供了 Ingress 对象来实现对外暴露服务;到目前为止 kubernetes 总共有三种暴露服务的方式:
- LoadBlancer Service
- NodePort Service
- Ingress
1.1、LoadBlancer Service
LoadBlancer Service 是 kubernetes 深度结合云平台的一个组件;当使用 LoadBlancer Service 暴露服务时,实际上是通过向底层云平台申请创建一个负载均衡器来向外暴露服务;目前 LoadBlancer Service 支持的云平台已经相对完善,比如国外的 GCE、DigitalOcean,国内的 阿里云,私有云 Openstack 等等,由于 LoadBlancer Service 深度结合了云平台,所以只能在一些云平台上来使用
1.2、NodePort Service
NodePort Service 顾名思义,实质上就是通过在集群的每个 node 上暴露一个端口,然后将这个端口映射到某个具体的 service 来实现的,虽然每个 node 的端口有很多(0~65535),但是由于安全性和易用性(服务多了就乱了,还有端口冲突问题)实际使用可能并不多
1.3、Ingress
Ingress 这个东西是 1.2 后才出现的,通过 Ingress 用户可以实现使用 nginx 等开源的反向代理负载均衡器实现对外暴露服务,以下详细说一下 Ingress,毕竟 traefik 用的就是 Ingress
使用 Ingress 时一般会有三个组件:
- 反向代理负载均衡器
- Ingress Controller
- Ingress
1.3.1、反向代理负载均衡器
反向代理负载均衡器很简单,说白了就是 nginx、apache 什么的;在集群中反向代理负载均衡器可以自由部署,可以使用 Replication Controller、Deployment、DaemonSet 等等,不过个人喜欢以 DaemonSet 的方式部署,感觉比较方便
1.3.2、Ingress Controller
Ingress Controller 实质上可以理解为是个监视器,Ingress Controller 通过不断地跟 kubernetes API 打交道,实时的感知后端 service、pod 等变化,比如新增和减少 pod,service 增加与减少等;当得到这些变化信息后,Ingress Controller 再结合下文的 Ingress 生成配置,然后更新反向代理负载均衡器,并刷新其配置,达到服务发现的作用
1.3.3、Ingress
Ingress 简单理解就是个规则定义;比如说某个域名对应某个 service,即当某个域名的请求进来时转发给某个 service;这个规则将与 Ingress Controller 结合,然后 Ingress Controller 将其动态写入到负载均衡器配置中,从而实现整体的服务发现和负载均衡
有点懵逼,那就看图
从上图中可以很清晰的看到,实际上请求进来还是被负载均衡器拦截,比如 nginx,然后 Ingress Controller 通过跟 Ingress 交互得知某个域名对应哪个 service,再通过跟 kubernetes API 交互得知 service 地址等信息;综合以后生成配置文件实时写入负载均衡器,然后负载均衡器 reload 该规则便可实现服务发现,即动态映射
了解了以上内容以后,这也就很好的说明了我为什么喜欢把负载均衡器部署为 Daemon Set;因为无论如何请求首先是被负载均衡器拦截的,所以在每个 node 上都部署一下,同时 hostport 方式监听 80 端口;那么就解决了其他方式部署不确定 负载均衡器在哪的问题,同时访问每个 node 的 80 都能正确解析请求;如果前端再 放个 nginx 就又实现了一层负载均衡
1.4、总结
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 差,但是配置使用要简单许多,我们这里会以更简单的 traefik 为例给大家介绍 ingress 的使用。
二、Traefik 使用
由于微服务架构以及 Docker 技术和 kubernetes 编排工具最近几年才开始逐渐流行,所以一开始的反向代理服务器比如 nginx、apache 并未提供其支持,毕竟他们也不是先知;所以才会出现 Ingress Controller 这种东西来做 kubernetes 和前端负载均衡器如 nginx 之间做衔接;即 Ingress Controller 的存在就是为了能跟 kubernetes 交互,又能写 nginx 配置,还能 reload 它,这是一种折中方案;而最近开始出现的 traefik 天生就是提供了对 kubernetes 的支持,也就是说 traefik 本身就能跟 kubernetes API 交互,感知后端变化,因此可以得知: 在使用 traefik 时,Ingress Controller 已经无卵用了,所以整体架构如下
2.1、部署 Traefik
首先通过Git下载Traefik源码:
git clone https://github.com/containous/traefik.git
下载完成后进入到 traefik\examples\k8s 文件夹,里面有我们需要用到的所有的配置文件:
traefik/examples/k8s这个目录下就是traefik启动需要用到的yaml文件。实际一般只需要使用traefik-deployment.yaml traefik-rbac.yaml
traefik-rbac.yaml用于创建ServiceAccount traefik-ingress-controller,并创建相关的ClusterRole, ClusterRoleBinding以对其进行授权。由于在Kubernets1.6之后启用了RBAC鉴权机制,所以需配置ClusterRole以及ClusterRoleBinding来对api-server的进行相应权限的鉴权。那rbac这个文件呢就是创建ClusterRole和ClusterRoleBinding的,至于deployment文件这里就不说了,相信看到本篇文章的童鞋已经对K8S有了基本认识。
开始创建rbac
[root@k8smaster k8s]# kubectl apply -f traefik-rbac.yaml
clusterrole.rbac.authorization.k8s.io "traefik-ingress-controller" created
clusterrolebinding.rbac.authorization.k8s.io "traefik-ingress-controller" created
检查是否成功
[root@k8smaster k8s]# kubectl get clusterrolebinding
NAME AGE
cluster-admin 113d
flannel 113d
heapster 113d
kubeadm:kubelet-bootstrap 113d
……….
traefik-ingress-controller 3s
[root@k8smaster k8s]# kubectl get clusterrole
NAME AGE
admin 113d
cluster-admin 113d
edit 113d
flannel 113d
可以看到clusterrole,clusterrolebinding都创建成功了,下面创建Traefik。
[root@k8smaster k8s]# kubectl apply -f traefik-deployment.yaml
serviceaccount "traefik-ingress-controller" created
deployment.extensions "traefik-ingress-controller" created
service "traefik-ingress-service" created
检查是否成功
[root@k8smaster k8s]# kubectl get svc,deployment,pod -n kube-system
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
heapster ClusterIP 10.106.236.144 <none> 80/TCP 113d
kube-dns ClusterIP 10.96.0.10 <none> 53/UDP,53/TCP 113d
kubernetes-dashboard-external NodePort 10.108.106.113 <none> 9090:30090/TCP 113d
traefik-ingress-service NodePort 10.98.76.58 <none> 80:30883/TCP ,8080:30731/TCP 17s
NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE
heapster 1 1 1 1 113d
kube-dns 1 1 1 1 113d
kubernetes-dashboard 1 1 1 1 113d
traefik-ingress-controller 1 1 1 0 18s
NAME READY STATUS RESTARTS AGE
etcd-k8smaster 1/1 Running 6 113d
heapster-6595c54cb9-f7gvz 1/1 Running 4 113d
kube-apiserver-k8smaster 1/1 Running 6 113d
……….
traefik-ingress-controller-bf6486db6-jzd8w 1/1 Running 0 17s
可以看到service和pod都起来了。
刚才前面也说到了有个非常简洁漂亮的界面,非常适合运维统计管理,下面来看看。
[root@k8smaster k8s]# kubectl apply -f ui.yaml
service "traefik-web-ui" created
ingress.extensions "traefik-web-ui" created
运行完成后我们可以通过以下命令查看svc和pod运行情况:
kubectl get svc,deployment,pod -n kube-system
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/kube-dns ClusterIP 10.96.0.10 <none> 53/UDP,53/TCP 98d
service/kubernetes-dashboard ClusterIP 10.107.232.92 <none> 443/TCP 98d
service/traefik-ingress-service NodePort 10.105.165.76 <none> 80:31172/TCP,8080:32419/TCP 49m
service/traefik-web-ui ClusterIP 10.96.161.200 <none> 80/TCP 47m
NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE
deployment.extensions/kube-dns 1 1 1 1 98d
deployment.extensions/kubernetes-dashboard 1 1 1 1 98d
deployment.extensions/traefik-ingress-controller 1 1 1 1 49m
NAME READY STATUS RESTARTS AGE
pod/etcd-docker-for-desktop 1/1 Running 27 98d
pod/kube-apiserver-docker-for-desktop 1/1 Running 27 98d
pod/kube-controller-manager-docker-for-desktop 1/1 Running 27 98d
pod/kube-dns-86f4d74b45-cqwlk 3/3 Running 81 98d
pod/kube-proxy-84jnm 1/1 Running 27 98d
pod/kube-scheduler-docker-for-desktop 1/1 Running 27 98d
pod/kubernetes-dashboard-7b9c7bc8c9-mzn8l 1/1 Running 49 98d
pod/traefik-ingress-controller-7dcd6f447-fzzcw 1/1 Running 0 49m
service,pod都起来了,我们需要关注的一个svc是 service/traefik-ingress-service ,关注下它的接口:
80端口对应的服务端口,8080端口对应的是ui端口,也就是说我们可以通过访问8080端口来访问traefik的web界面,通过k8s集群的任意一个nodeIP:31695,都可以访问到traefik的web ui界面
因为我是本地部署,所以浏览器直接浏览:http://127.0.0.1:32419 就可以:(如果是本地集群(非Docker安装,VM虚拟机安装),则需要用master的IP地址)
二、暴露服务
这里我们使用nginx服务测试,首先准备三个文件,分别是 nginx-deploy.yaml nginx_ingress.yaml nginx_service.yaml
[root@171 nginx]# cat nginx-deploy.yaml
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
annotations:
deployment.kubernetes.io/revision: "2"
creationTimestamp: 2018-04-09T04:02:02Z
generation: 4
labels:
app: nginx
name: nginx-deploy
namespace: default
resourceVersion: "111504"
selfLink: /apis/extensions/v1beta1/namespaces/default/deployments/nginx-deploy
uid: c28090c0-3baa-11e8-b75a-000c29858eab
spec:
replicas: 2
selector:
matchLabels:
app: nginx
strategy:
rollingUpdate:
maxSurge: 1
maxUnavailable: 1
type: RollingUpdate
template:
metadata:
creationTimestamp: null
labels:
app: nginx
spec:
containers:
- image: nginx:1.9.1
imagePullPolicy: IfNotPresent
name: nginx
ports:
- containerPort: 80
protocol: TCP
resources: {}
terminationMessagePath: /dev/termination-log
terminationMessagePolicy: File
dnsPolicy: ClusterFirst
restartPolicy: Always
schedulerName: default-scheduler
securityContext: {}
terminationGracePeriodSeconds: 30
status:
availableReplicas: 2
conditions:
- lastTransitionTime: 2018-04-09T04:57:27Z
lastUpdateTime: 2018-04-09T04:57:27Z
message: Deployment has minimum availability.
reason: MinimumReplicasAvailable
status: "True"
type: Available
observedGeneration: 4
readyReplicas: 2
replicas: 2
updatedReplicas: 2
[root@171 nginx]# cat nginx_service.yaml
apiVersion: v1
kind: Service
metadata:
creationTimestamp: 2018-04-09T11:34:09Z
labels:
run: nginx
name: nginx
namespace: default
resourceVersion: "140236"
selfLink: /api/v1/namespaces/default/services/nginx
uid: eb57a21b-3be9-11e8-b75a-000c29858eab
spec:
clusterIP: 10.99.59.56
ports:
- port: 80
protocol: TCP
targetPort: 80
selector:
app: nginx
sessionAffinity: None
type: ClusterIP
status:
loadBalancer: {}
[root@171 nginx]# cat nginx_ingress.yaml
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
creationTimestamp: 2018-04-09T11:39:48Z
generation: 1
name: test
namespace: default
resourceVersion: "140644"
selfLink: /apis/extensions/v1beta1/namespaces/default/ingresses/test
uid: b54bbda8-3bea-11e8-b75a-000c29858eab
spec:
rules:
- host: test.nginx.com
http:
paths:
- backend:
serviceName: nginx
servicePort: 80
status:
loadBalancer: {}
然会加载三个配置分件,分别生成deployment、ingress和服务Service:
kubectl create -f nginx-deploy.yaml --record
kubectl create -f nginx-service.yaml --record
kubectl create -f nginx-ingress.yaml --record
查看pod:
kubectl get pods -o wide | grep nginx
关注下pod的IP地址,这个时候我们已经可以在本地的集群内访问nginx了,运行以下命令测试:
curl http://10.244.1.19
然后查看下ingress和Service的状态:
kubectl get ing | grep nginx
kubectl get svc | grep nginx
我这里用的VM虚拟机,NAT网络模式,暂时只能在集群内部访问,想要通过本机和外网访问还需要配置下,将pod的ip段转发到本机master或者node的IP:
这里以master的IP地址为列,首先你需要查看下你虚拟机master的IP地址,我这里是192.168.3.131
然后通过route print查看自己电脑上vmnet8网卡对应的网卡接口编号:
我这里是15,我们需要将k8s的服务Service和pod网段的请求转发到我们的master虚拟机:
route add 10.99.0.0 MASK 255.255.0.0 192.168.3.131 IF 15
route add 10.244.0.0 MASK 255.255.0.0 192.168.3.131 IF 15
成功之后我们就可以通过pod和Service的IP地址在浏览器里访问了:
查看下Traefik的UI会看到对应的ingress已经显示了出啦:
可以看到Traefik的UI上多了一个名称为test.nginx.com的选项卡,这个名称是我们在Ingress.yaml中指定的hsot,我们是可以通过这个名称来直接路由请求的,但是需要配置下windows的hosts文件:
打开路径:C:\Windows\System32\drivers\etc ,找到hosts文件编辑:
我们刚才已经将nginx服务(Service)的访问转发到master虚拟机,所以我们需要配置下映射关系,test.nginx.com域名的请求转发到Service的IP,然后就可以访问了: