K8S应用服务暴露的几种方式
上一篇文章中介绍了如何在K8S平台中基于SideCar模式部署一个Java应用。但此时我们部署的Java服务只能在集群内部通过Pod IP进行访问,无法暴露到公网对外提供服务。在K8S中,有以下方式可以将我们的应用服务对外进行暴露:
通过Service暴露应用服务
- NodePort
apiVersion: v1
kind: Service
metadata:
name: app-svc
labels:
app: demo-app
spec:
type: NodePort
ports:
- port: 80 //service 集群IP的端口
targetPort: 8062 //service管理的后端应用的端口
nodePort: 30062 //service在集群内所有节点上暴露的端口
selector:
app: demo-app //选择器,选择关联的POD标签
集群外的服务可以通过集群的任一节点的公网IP和NodePort访问应用服务。但基于以下的几点原因,不建议在生产环境使用NodePort方式暴露服务:
- 增加部署管理难度: 服务部署时需要关注NodePort是否已经被占用,即使不指定端口,使用K8S随机分配的端口,这样也造成服务部署混乱,不便于管理。
- 安全问题: 集群暴露多个公网IP、端口给集群外部,容易产生安全问题。
- 增加客户端开发成本: 客户端需要维护多个IP,当某个节点宕机无法提供服务时,需要客户端去处理这种错误,增加客户端开发成本,导致强耦合。
apiVersion: v1
kind: Service
metadata:
name: app-svc
labels:
app: demo-app
spec:
type: LoadBalancer
ports:
- port: 80
targetPort: 8062
selector:
app: demo-app
当云服务商提供了负载均衡器时,就会把负载均衡的IP写入service的的external-ip中。否则此时service会一直处于pending状态。
因为客户端通过LoadBalancer访问服务,通过LB提供了负载均衡机制,解决了客户端需要维护多个IP的问题。并且集群内部不再需要暴露公网IP和端口,提升了集群的安全性。
通过Ingress暴露服务
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: app-ingress
spec:
tls: //开启tls
- hosts:
- mydomain.com //需要开启tls的域名
secretName: demo-tls //挂载的secret
rules:
- host: mydomain.com
http:
paths:
- path: /bar
backend:
serviceName: app-svc //Ingress关联的service
servicePort: 80 //service端口
通过在k8S中部署Ingress Controller,并编写相应的Ingress规则并可以将我们的服务暴露。与LoadBalancer相比,其优势在于所有服务都可以通过一个公网IP暴露,通过域名和路径转发到不同的服务,是一个反向代理机制。而LoadBalancer机制则是每个服务都需要一个携带公网IP的LoadBalancer。
Service工作机制
Pod中承载的是我们具体的后端服务,我们通过定义Deployment中的spec.replicas属性,说明有几个Pod能同时提供服务。而Service便是对这一组Pod的抽象,通过Service中的spec.selector属性,确定service管理的Pod所具有的标签。Pod的IP、端口组成了EndPoint。Service通过API Server动态监听所管理的POD的创建、销毁等事件,并将可提供服务的POD信息写入EndPoints中。
Ingress工作机制
为了实现服务的反向代理,K8S集群中必须部署Ingress Contoller。目前使用较多的是Ingress-Nginx。我们编写的Ingress规则会被解析为相应的Nginx规则,并写入到了Nginx Pod的nginx.conf文件中。例如我们上文中的Ingress规则,会被大致翻译为这样的nginx配置,Ingress中的host被写入Nginx的server块,path被写入location块。
参考资料
- K8S官网 kubernetes.io/docs/concep…
- Kubernetes In Action Chapter5(Services: enabling clients to discover and talk to pods)