通过前面两节的学习,我们已经可以将一个简单的react项目部署到k8s中,总结起来其实就是下面的几步:
1. 创建react项目
2. 打包生成build文件夹(或者其他命名的文件夹)
3. 上传到服务器中(只要是安装了docker的linux服务器都可以,推荐上传到k8s的master节点中)
4. 准备Dockerfile和nginx.conf文件
5. docker build生成image并且同步到其他节点中(或者上传到本地或远程仓库中)
6. 准备部署文件即yaml文件,通常包括deployment.yaml和service.yaml
7. 运行kubectl apply -f xxx.yaml即可。
但同时我们提出了两个问题:
第一:大部分的前端访问应该是通过域名的形式访问,即http://domainName/webgui/smartocr/index.html来访问。
第二:前端微服务需要访问后端微服务,如果是通过nodeIP+nodePort的方式访问也没有问题,但是,如果是按照serviceName:servicePort的方式访问(而此种方式正是微服务部署所提倡的),当前的解决方案一定是访问不通的。
第一个问题好理解,就是要使用域名访问,跟我们访问www.baidu.com之类的是一个道理;第二个问题稍微有点不好理解,为什么通过nodeIP+nodePort的方式访问没有问题而通过serviceName:servicePort的方式访问就不行了呢?这是因为我们在前端发送类似于http://basemanage-be:8000/smartocr/BaseManage/cases这种serviceName+servicePort的方式调用后端微服务,实际上这个url是浏览器发出来的,而浏览器发出来的这个url是通过这个浏览器所在的本机上的dns来解析的,毫无疑问这肯定时解析不了的,因此请求无法发送给后端微服务。而通过nodeIP+nodePort的方式不需要通过本机的dns解析,因此没有问题。
好了,问题清楚了,那为什么可以通过在k8s中配置ingress来解决呢?
首先,ingress本身就可以解决需要对外暴露的微服务的域名访问问题,通过设置host和hostPath,我们的前端可以使用域名访问。
其次,对于处理前端请求的这个后端微服务,我们可以将其设置为另一个host和hostPath,这样所有前端发给后端的请求就类似于http://backend.com/smartocr/BaseManage/cases, 因为配置了ingress,因此该请求会被ingress处理,继而找到对应的后端服务进行处理。
OK,话不多说,看看怎么配置ingress,网上配置ingress的文章很多,总结下来就是先创建ingress controller,然后创建ingress rule:
首先创建ingress controller,这里使用的是nginx-ingress,这个mandatory.yaml文件我是从网上找的,不需要任何改动,拿过去直接就能用:
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 "<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 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: hostNetwork: true nodeSelector: nginx: "nginx" # 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
其次是创建ingress rule,需要注意的一点是Ingress rule的命名空间一定要和你的微服务的命名空间相同,负责它找不到你的微服务:
ingress_rule.yaml
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: ingress-myapp
annotations:
kubernetes.io/ingress.class: "nginx"
nginx.ingress.kubernetes.io/use-regex: "true"
nginx.ingress.kubernetes.io/ssl-redirect: "false"
spec:
rules:
- host: smartocr.com
http:
paths:
- path: /webgui/smartocr/
backend:
serviceName: service-basemanage
servicePort: 7070
- host: backend.com
http:
paths:
- path: /smartocr/BaseManage/
backend:
serviceName: service-basemanage-be
servicePort: 5555
注意看标红的host: backend.com,这就是处理前端请求的后端微服务service-basemanage-be的域名,所以后续你看到的url应该是类似于下图:
访问成功,说明前端的请求正确发送到了后端。
至此,前端部署完全结束。