利用ingress實現集群外部對kubernetes內部服務的訪問
由於Pod和Service是kubernetes集群範圍內的虛擬概念,所以集群外的客戶端系統無法通過Pod的IP地址或者Service的虛擬IP地址和虛擬端口號訪問到它們。為了讓外部客戶端能夠訪問到這些服務,可以將Pod或Service的端口號映射到宿主機。
1.將容器應用的端口號映射到物理機
1)設置容器級別的hostPort,將容器應用的端口號映射到物理機
2)設置Pod級別的hostNetwork=true,該Pod中所有容器的端口號都將被直接映射到物理機上
2.將Service的端口號映射到物理機
1)設置nodePort映射到物理機,同時設置Service的類型為NodePort
2)設置LoadBalancer映射到雲服務商提供的LoadBalancer地址
如果設置了Service的nodePort,那麽集群會在每一個節點都監聽設置的nodePort,外部客戶端可以通過任意nodeIP:Port的方式對集群服務進行訪問。但是當集群中服務較多,那麽需要管理的端口也會比較多,各個端口之間不能沖突,比較麻煩;另外,因為方式訪問形式為nodeIP:Port的方式,那麽對於一些HTTP服務,這種方式是無法做到根據URL路徑進行轉發的。ingress是kubernetes V1.1版本之後新增的資源對象,用於實現HTTP層業務路由機制。
實現ingress路由機制主要包括3個組件:
1)ingress是kubernetes的一個資源對象,用於編寫定義規則
2)反向代理負載均衡器,通常以Service的Port方式運行,接收並按照ingress定義的規則進行轉發,通常為nginx,haproxy,traefik等,本文使用nginx
3)ingress-controller,監聽apiserver,獲取服務新增,刪除等變化,並結合ingress規則動態更新到反向代理負載均衡器上,並重載配置使其生效
二.部署
本文使用谷歌提供的nginx-ingress-controller鏡像創建ingress-controller,並以Pod+Service方式運行,其中Service使用nodePort方式將80,443端口映射至物理機上
部署過程中使用到的文檔參考:https://github.com/kubernetes/ingress-nginx/tree/master/deploy
1.下載各所需的yaml文件
curl https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/namespace.yaml >namespace.yaml curl https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/default-backend.yaml>default-backend.yaml curl https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/configmap.yaml>configmap.yaml curl https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/tcp-services-configmap.yaml>tcp-services-configmap.yaml curl https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/udp-services-configmap.yaml > udp-services-configmap.yaml curl https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/without-rbac.yaml>without-rbac.yaml curl https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/rbac.yaml>rbac.yaml curl https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/with-rbac.yaml > with-rbac.yaml curl https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/provider/baremetal/service-nodeport.yaml >service-nodeport.yaml
2.啟動上述yaml文件
kubectl create -f namespace.yaml kubectl create -f configmap.yaml kubectl create -f default-backend.yaml kubectl create -f tcp-services-configmap.yaml kubectl create -f udp-services-configmap.yaml kubectl create -f rbac.yaml kubectl create -f with-rbac.yaml kubectl create -f service-nodeport.yaml
上述yaml文件中幾乎可以不用修改,僅default-backend.yaml以及with-rbac.yaml兩個文件需要簡單修改。
default-backend.yaml文件定義了默認的ingress服務,即客戶端訪問的URL地址不存在時,默認返回的頁面,這個服務使用任何應用實現都可以,只需要能夠返回一個404應答,並且提供/healthz路徑實現健康檢查,另外服務名稱需要設置為default-backend-service,因為該鏡像中nginx默認通過default-backend-service訪問默認backend
rabc.yaml是kubernetes實現鑒權的方式,本文不做介紹
with-rbac.yaml文件中定義了一個Deployment,運行ingress-controller;需要註意的是如果修改了yaml文件中使用的鏡像,部分參數可能需要更改,這個具體情況具體分析,本文不做說明
service-nodeport.yaml文件定義了一個服務,並且以nodePort方式監聽80以及443端口,為客戶端提供訪問入口。
上述文件修改後如下:
nginx-ingress]# cat namespace.yaml apiVersion: v1 kind: Namespace metadata: name: ingress-nginx ############################ nginx-ingress]# cat configmap.yaml kind: ConfigMap apiVersion: v1 metadata: name: nginx-configuration namespace: ingress-nginx labels: app: ingress-nginx ############################## nginx-ingress]# cat rbac.yaml apiVersion: v1 kind: ServiceAccount metadata: name: nginx-ingress-serviceaccount namespace: ingress-nginx --- apiVersion: rbac.authorization.k8s.io/v1beta1 kind: ClusterRole metadata: name: nginx-ingress-clusterrole rules: - apiGroups: - "" resources: - configmaps - endpoints - nodes - pods - secrets verbs: - list - watch - apiGroups: - "" resources: - nodes verbs: - get - apiGroups: - "" resources: - services verbs: - get - list - watch - apiGroups: - "extensions" resources: - ingresses verbs: - get - list - watch - apiGroups: - "" resources: - events verbs: - create - patch - apiGroups: - "extensions" resources: - ingresses/status verbs: - update --- apiVersion: rbac.authorization.k8s.io/v1beta1 kind: Role metadata: name: nginx-ingress-role namespace: 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 - create - update --- apiVersion: rbac.authorization.k8s.io/v1beta1 kind: RoleBinding metadata: name: nginx-ingress-role-nisa-binding namespace: 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 roleRef: apiGroup: rbac.authorization.k8s.io kind: ClusterRole name: nginx-ingress-clusterrole subjects: - kind: ServiceAccount name: nginx-ingress-serviceaccount namespace: ingress-nginx ############################# nginx-ingress]# cat tcp-services-configmap.yaml kind: ConfigMap apiVersion: v1 metadata: name: tcp-services namespace: ingress-nginx ############################# nginx-ingress]# cat udp-services-configmap.yaml kind: ConfigMap apiVersion: v1 metadata: name: udp-services namespace: ingress-nginx ############################# nginx-ingress]# cat service-nodeport.yaml apiVersion: v1 kind: Service metadata: name: ingress-nginx namespace: ingress-nginx spec: type: NodePort ports: - name: http port: 80 targetPort: 80 nodePort: 80 protocol: TCP - name: https port: 443 targetPort: 443 nodePort: 443 protocol: TCP selector: app: ingress-nginx ############################## nginx-ingress]# cat default-backend.yaml apiVersion: extensions/v1beta1 kind: Deployment metadata: name: default-http-backend labels: app: default-http-backend namespace: ingress-nginx spec: replicas: 1 selector: matchLabels: app: default-http-backend template: metadata: labels: app: default-http-backend spec: terminationGracePeriodSeconds: 60 containers: - name: default-http-backend # Any image is permissible as long as: # 1. It serves a 404 page at / # 2. It serves 200 on a /healthz endpoint #image: gcr.io/google_containers/defaultbackend:1.4 image: index.tenxcloud.com/google_containers/defaultbackend:1.0 livenessProbe: httpGet: path: /healthz port: 8080 scheme: HTTP initialDelaySeconds: 30 timeoutSeconds: 5 ports: - containerPort: 8080 resources: limits: cpu: 10m memory: 20Mi requests: cpu: 10m memory: 20Mi --- apiVersion: v1 kind: Service metadata: name: default-http-backend namespace: ingress-nginx labels: app: default-http-backend spec: ports: - port: 80 targetPort: 8080 selector: app: default-http-backend #################################### nginx-ingress]# cat with-rbac.yaml apiVersion: extensions/v1beta1 kind: Deployment metadata: name: nginx-ingress-controller namespace: ingress-nginx spec: replicas: 1 selector: matchLabels: app: ingress-nginx template: metadata: labels: app: ingress-nginx annotations: prometheus.io/port: '10254' prometheus.io/scrape: 'true' spec: serviceAccountName: nginx-ingress-serviceaccount containers: - name: nginx-ingress-controller #image: quay.io/kubernetes-ingress-controller/nginx-ingress-controller:0.15.0 #image: gcr.io/google_containers/nginx-ingress-controller:0.9.0-beta.2 image: index.tenxcloud.com/google_containers/nginx-ingress-controller:0.8.3 args: - /nginx-ingress-controller - --default-backend-service=$(POD_NAMESPACE)/default-http-backend - --nginx-configmap=$(POD_NAMESPACE)/nginx-configuration - --tcp-services-configmap=$(POD_NAMESPACE)/tcp-services - --udp-services-configmap=$(POD_NAMESPACE)/udp-services #- --annotations-prefix=nginx.ingress.kubernetes.io env: - name: POD_NAME valueFrom: fieldRef: fieldPath: metadata.name - name: POD_NAMESPACE valueFrom: fieldRef: fieldPath: metadata.namespace ports: - name: http containerPort: 80 - name: https containerPort: 443 livenessProbe: failureThreshold: 3 httpGet: path: /healthz port: 10254 scheme: HTTP initialDelaySeconds: 10 periodSeconds: 10 successThreshold: 1 timeoutSeconds: 1 readinessProbe: failureThreshold: 3 httpGet: path: /healthz port: 10254 scheme: HTTP periodSeconds: 10 successThreshold: 1 timeoutSeconds: 1 securityContext: runAsNonRoot: false
三,ingress規則編寫
下面是一個簡單的例子
nginx-ingress]# cat mytest.yaml apiVersion: extensions/v1beta1 kind: Ingress metadata: name: test-ingress annotations: ingress.kubernetes.io/ssl-redirect: "false" ##關閉強制使用HTTPS的設置 spec: rules: ## 根據URL路徑實現轉發,域名為 * - http: paths: - path: /demo backend: serviceName: mydemo servicePort: 8080 - path: /test backend: serviceName: mytest servicePort: 8080 nginx-ingress]# cat mytest.yaml apiVersion: extensions/v1beta1 kind: Ingress metadata: name: pand-ingress annotations: ingress.kubernetes.io/ssl-redirect: "false" spec: rules: ## 根據域名實現轉發 - host: www.mywebsite1.com http: paths: - backend: serviceName: mydemo servicePort: 8080 - host: www.mywebsite2.com http: paths: - backend: serviceName: mytest servicePort: 8080
創建上述ingress,在客戶端配置好域名解析,實現訪問
利用ingress實現集群外部對kubernetes內部服務的訪問