k8s部署微服務專案實戰--react前端+springboot/python後端-第四節 前端專案部署總結以及引入ingress解決兩個問題
通過前面兩節的學習,我們已經可以將一個簡單的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應該是類似於下圖:
訪問成功,說明前端的請求正確傳送到了後端。
至此,前端部署完全結束。