三种方式:k8s 集群向外暴露服务的方式一共有 NodePort, Ingress,LoadBalancer 这三种,每种方式都有各自的优缺点。
NodePort方式:这种方式是将K8S中的Pod或Service等资源的端口映射到主机上,从而在集群外部可以通过使用 主机IP:Port 的方式来访问Pod或Service,尽管这种方式使用起来比较简单,但并不适用于大量服务的情况,否则会导致主机上开的端口较多,不便于管理。
LoadBalancer方式:这种方式是结合云提供商的LB来使用,但是如果使用的LB较多,产生大量费用的问题也不容忽视。
Ingress方式:这种方式是K8S官方比较推荐的对外暴露服务的方式,也是在生产环境中使用较多的方式。
简单介绍:Ingress Contoller 是一个 pod 服务,封装了一个 web 前端负载均衡器,同时在其基础上实现了动态感知 Ingress 的变化,并根据 Ingress 的定义动态生成前端 web 负载均衡器的配置文件。比如 Nginx Ingress Controller 本质上就是一个 Nginx,只不过它能根据 Ingress 资源的定义动态生成 Nginx 的配置文件,并且动态 Reload 配置文件。Ingress Controller 的作用是作为集群服务的统一入口,并根据路由转发规则将请求负载均衡地转发到各个服务。
常见实现:Ingress Controller 有多种实现,除了常见的基于Nginx或基于Haproxy的实现之外,还有很多种其它的实现。
# 部署命令
kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/nginx-0.30.0/deploy/static/mandatory.yaml
apiVersion: v1
kind: Namespace
metadata:
name: ingress-nginx
labels:
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
---
kind: ConfigMap
apiVersion: v1
metadata:
name: nginx-configuration
namespace: ingress-nginx
labels:
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
---
kind: ConfigMap
apiVersion: v1
metadata:
name: tcp-services
namespace: ingress-nginx
labels:
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
---
kind: ConfigMap
apiVersion: v1
metadata:
name: udp-services
namespace: ingress-nginx
labels:
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: nginx-ingress-serviceaccount
namespace: ingress-nginx
labels:
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
---
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRole
metadata:
name: nginx-ingress-clusterrole
labels:
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
rules:
- apiGroups:
- ""
resources:
- configmaps
- endpoints
- nodes
- pods
- secrets
verbs:
- list
- watch
- apiGroups:
- ""
resources:
- nodes
verbs:
- get
- apiGroups:
- ""
resources:
- services
verbs:
- get
- list
- watch
- apiGroups:
- ""
resources:
- events
verbs:
- create
- patch
- apiGroups:
- "extensions"
- "networking.k8s.io"
resources:
- ingresses
verbs:
- get
- list
- watch
- apiGroups:
- "extensions"
- "networking.k8s.io"
resources:
- ingresses/status
verbs:
- update
---
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: Role
metadata:
name: nginx-ingress-role
namespace: ingress-nginx
labels:
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
rules:
- apiGroups:
- ""
resources:
- configmaps
- pods
- secrets
- namespaces
verbs:
- get
- apiGroups:
- ""
resources:
- configmaps
resourceNames:
# Defaults to "-"
# Here: "-"
# 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
labels:
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: 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
labels:
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: nginx-ingress-clusterrole
subjects:
- kind: ServiceAccount
name: nginx-ingress-serviceaccount
namespace: ingress-nginx
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-ingress-controller
namespace: ingress-nginx
labels:
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
spec:
replicas: 1
selector:
matchLabels:
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
template:
metadata:
labels:
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
annotations:
prometheus.io/port: "10254"
prometheus.io/scrape: "true"
spec:
# wait up to five minutes for the drain of connections
terminationGracePeriodSeconds: 300
serviceAccountName: nginx-ingress-serviceaccount
nodeSelector:
kubernetes.io/os: linux
containers:
- name: nginx-ingress-controller
image: quay.io/kubernetes-ingress-controller/nginx-ingress-controller:0.30.0
args:
- /nginx-ingress-controller
- --configmap=$(POD_NAMESPACE)/nginx-configuration
- --tcp-services-configmap=$(POD_NAMESPACE)/tcp-services
- --udp-services-configmap=$(POD_NAMESPACE)/udp-services
- --publish-service=$(POD_NAMESPACE)/ingress-nginx
- --annotations-prefix=nginx.ingress.kubernetes.io
securityContext:
allowPrivilegeEscalation: true
capabilities:
drop:
- ALL
add:
- NET_BIND_SERVICE
# www-data -> 101
runAsUser: 101
env:
- name: POD_NAME
valueFrom:
fieldRef:
fieldPath: metadata.name
- name: POD_NAMESPACE
valueFrom:
fieldRef:
fieldPath: metadata.namespace
ports:
- name: http
containerPort: 80
protocol: TCP
- name: https
containerPort: 443
protocol: TCP
livenessProbe:
failureThreshold: 3
httpGet:
path: /healthz
port: 10254
scheme: HTTP
initialDelaySeconds: 10
periodSeconds: 10
successThreshold: 1
timeoutSeconds: 10
readinessProbe:
failureThreshold: 3
httpGet:
path: /healthz
port: 10254
scheme: HTTP
periodSeconds: 10
successThreshold: 1
timeoutSeconds: 10
lifecycle:
preStop:
exec:
command:
- /wait-shutdown
---
apiVersion: v1
kind: LimitRange
metadata:
name: ingress-nginx
namespace: ingress-nginx
labels:
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
spec:
limits:
- min:
memory: 90Mi
cpu: 100m
type: Container
部署文件:本文中Nginx Ingress Controller是以Deployment的方式进行部署的,所以还需要部署一个Service,以便能够从外部访问Nginx Ingress Controller。在K8S集群的Master节点上创建一个名称为 nginx-ingress-service.yaml 的部署文件,该部署文件定义了部署的Service使用NodePort的服务暴露方式,将Service的80端口映射到主机的30080端口(基于http协议访问),将Service的443端口映射到主机的30443端口(基于https协议问题),文件内容如下所示。
apiVersion: v1
kind: Service
metadata:
name: nginx-ingress-service
namespace: ingress-nginx
labels:
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
spec:
selector:
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
type: NodePort
ports:
- name: http
port: 80
targetPort: 80
nodePort: 30080
protocol: TCP
- name: https
port: 443
targetPort: 443
nodePort: 30443
protocol: TCP
执行部署:在K8S集群所在的Master节点中执行以下命令,即可部署Service,执行结果如下图所示:
kubectl apply -f nginx-ingress-service.yaml
查看部署结果:执行部署成功之后,执行以下命令即可查看到部署的Service的详细信息,执行结果如下图所示:
kubectl get service -n ingress-nginx
部署Deployment:在K8S集群的Master节点上创建一个名称为 nginx-deployment.yaml 的部署文件,该部署文件定义了创建Nginx应用的Pod数量为2,以及使用的镜像为nginx:1.7.9,文件内容如下所示:
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
labels:
app: nginx
spec:
replicas: 2
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.7.9
部署Service:为了暴露Nginx应用服务,还需要部署一个Service,以便用户访问经由Nginx Ingress Controller之后,能够路由到Nginx应用服务所在的Pod。在K8S集群的Master节点中创建一个名称为 nginx-service.yaml 的部署文件,该部署文件定义了在K8S集群内部通过端口号80来访问该Service,以及该Service对外暴露的端口号也为80,文件内容如下所示:
apiVersion: v1
kind: Service
metadata:
name: nginx-service
labels:
app: nginx
spec:
selector:
app: nginx
ports:
- port: 80
targetPort: 80
执行部署:在K8S集群所在的Master节点中执行以下命令,即可部署Nginx应用服务,执行结果如下图所示:
kubectl apply -f nginx-deployment.yaml
kubectl apply -f nginx-service.yaml
查看部署结果:执行部署成功之后,执行以下命令即可查看到部署的Nginx应用的详细信息,执行结果如下图所示:
kubectl get pods
kubectl get services
部署Deployment:在K8S集群的Master节点上创建一个名称为 tomcat-deployment.yaml 的部署文件,该部署文件定义了创建Tomcat应用的Pod数量为2,以及使用的镜像为tomcat:9.0,文件内容如下所示:
apiVersion: apps/v1
kind: Deployment
metadata:
name: tomcat-deployment
labels:
app: tomcat
spec:
replicas: 2
selector:
matchLabels:
app: tomcat
template:
metadata:
labels:
app: tomcat
spec:
containers:
- name: tomcat
image: tomcat:9.0
部署Service:为了暴露Tomcat应用服务,还需要部署一个Service,以便用户访问经由Nginx Ingress Controller之后,能够路由到Tomcat应用服务所在的Pod。在K8S集群的Master节点中创建一个名称为 tomcat-service.yaml 的部署文件,该部署文件定义了在K8S集群内部通过端口号8080来访问该Service,以及该Service对外暴露的端口号也为8080,文件内容如下所示:
apiVersion: v1
kind: Service
metadata:
name: tomcat-service
labels:
app: tomcat
spec:
selector:
app: tomcat
ports:
- port: 8080
targetPort: 8080
执行部署:在K8S集群所在的Master节点中执行以下命令,即可部署Tomcat应用服务,执行结果如下图所示:
kubectl apply -f tomcat-deployment.yaml
kubectl apply -f tomcat-service.yaml
查看部署结果:执行部署成功之后,执行以下命令即可查看到部署的Tomcat应用的详细信息,执行结果如下图所示:
kubectl get pods
kubectl get services
部署文件:上面部署了Nginx和Tomcat这两个应用服务,还需要部署Ingress规则,才能根据Ingress规则来实现把用户对Nginx Ingress Controller的访问请求转发到对应的应用服务。在K8S集群所在的Master节点上创建一个名称为 ingress-web.yaml 的部署文件,该部署文件中定义了对nginx.app.com域名的请求全部转发给名称为nginx-service的服务(即Nginx应用服务)且该服务的端口号为80,而对tomcat.app.com域名的请求全部转发给名称为tomcat-service的服务(即Tomcat应用服务)且该服务的端口号为8080,文件的内容如下所示:
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
name: ingress-web
spec:
rules:
- host: nginx.app.com
http:
paths:
- backend:
serviceName: nginx-service
servicePort: 80
- host: tomcat.app.com
http:
paths:
- backend:
serviceName: tomcat-service
servicePort: 8080
执行部署:在K8S集群所在的Master节点中执行以下命令,即可部署Ingress规则,执行结果如下图所示:
kubectl apply -f ingress-web.yaml
查看部署结果:执行部署成功之后,执行以下命令即可查看到部署的Ingress规则的详细信息,执行结果如下图所示:
kubectl get ingress
获取IP地址:上面部署的Ingress规则中指定,对域名 nginx.app.com 的请求全部转发到名称为 nginx-service 的应用服务,对域名 tomcat.app.com 的请求全部转发到名称为 tomcat-service 的应用服务,而本文所在的K8S集群中没有配置DNS服务,所以无法对这两个域名进行解析,因此,采用在宿主机中修改hosts文件,将这两个域名映射到Nginx Ingress Controller所在的K8S集群节点的IP地址。通过在K8S集群的Master节点中执行以下两条命令即可以查看到Nginx Ingress Controller所在的K8S集群节点的IP地址,本文中对应的IP地址为192.168.1.122。
# 查看 Nginx Ingress Controller 部署在哪个节点
kubectl get pod -n ingress-nginx -o wide
# 查看节点的详情信息
kubectl get nodes -o wide
配置域名:由于本文的宿主机是Windows系统,所以需要在 C:\Windows\System32\drivers\etc\hosts 文件中添加以下域名映射配置: