原文連接node
對於HTTP服務來講,不一樣的URL地址常常對應到不一樣的後端服務,Ingress類型資源能夠知足此類需求。linux
簡單說,是一個代理,能夠根據配置轉發請求到指定的服務上。nginx
因爲K8S集羣擁有強大的副本控制能力,Pod隨時可能從一個節點上被驅逐到另外一個節點上,或者直接銷燬再來一個新的。git
然而伴隨着Pod的銷燬和重生,Pod的IP等信息不斷地在改變,此時使用K8S提供的Service機制能夠解決這一問題,Service經過標籤選定指定的Pod做爲後端服務,並監聽這些Pod的變化。github
在對外暴露服務時,使用Service的NodePort是一個方法json
當須要對外暴露的服務量比較多的時候,端口管理的問題便會暴露出來。後端
此時的一個處理方案是使用一個代理服務(例如Nginx)根據請求信息將請求轉發到不一樣的服務上去。api
每當有新服務加入,都須要對該服務的配置進行修改、升級,在服務數量逐漸變多後,該配置項目會變得愈來愈大,手工修改的風險也會逐漸增高。bash
那麼須要一個工具來簡化這一過程,但願能夠經過簡單的配置動態生成代理中複雜的配置,最好還能夠順手從新加載配置文件。markdown
K8S恰好也提供了此類型資源。
在使用普通的Service時,集羣中每一個節點的kube-proxy在監聽到Service和Endpoints的變化時,會動態的修改相關的iptables的轉發規則。 客戶端在訪問時經過iptables設置的規則進行路由轉發達到訪問服務的目的。
而Ingress則跳過了kube-proxy這一層,經過Ingress Controller中的代理配置進行路由轉發達到訪問目標服務的目的。
實際上能夠把IngressController看作一個擁有默認處理後端的代理,根據Ingress資源的配置動態修改代理的配置文件,以實現按照規則轉發請求的功能。
type Ingress struct { metav1.TypeMeta `json:",inline"` metav1.ObjectMeta `json:"metadata,omitempty"` // Ingess配置。 Spec IngressSpec `json:"spec,omitempty"` // Ingress資源當前狀態。 Status IngressStatus `json:"status,omitempty"` } type IngressSpec struct { // 默認的後端服務,當不匹配全部的Ingress規則的時候使用。 // 通常狀況默認後端都在Ingress控制器中配置,該字段不進行聲明配置。 // 若是沒有主機或路徑與 Ingress 對象中的 HTTP 請求匹配,則流量將路由到您的默認後端。 Backend *IngressBackend `json:"backend,omitempty"` // TLS配置。目前Ingress只支持443一種TLS端口。 // 若是列表中有多個不一樣的hosts,將會在ingress controller支持SNI的狀況下, // 經過使用SNI TLS擴展中聲明的主機名,在同個端口下使用多路複用。 TLS []IngressTLS `json:"tls,omitempty"` // Ingress的規則。未匹配到規則列表中規則的請求將會被轉發到默認後端上。 Rules []IngressRule `json:"rules,omitempty"` } type IngressBackend struct { // 服務名。 ServiceName string `json:"serviceName"` // 服務的端口。 ServicePort intstr.IntOrString `json:"servicePort"` } type IngressRule struct { // 域名。 // 不能使用IP地址,不能使用端口。對HTTP服務使用80端口,HTTPS服務使用443端口。 Host string `json:"host,omitempty"` // 域名下的具體轉發規則。 // 未定義的狀況下會將請求轉發至默認後端。 IngressRuleValue `json:",inline,omitempty"` } type IngressRuleValue struct { HTTP *HTTPIngressRuleValue `json:"http,omitempty"` } type HTTPIngressRuleValue struct { Paths []HTTPIngressPath `json:"paths"` } type HTTPIngressPath struct { // 匹配的路徑,必須以/爲開頭。 // 未定義的狀況下會將請求轉發至默認後端。 Path string `json:"path,omitempty"` // 處理請求的後端服務。 Backend IngressBackend `json:"backend"` } 複製代碼
具體的建立步驟爲
建立ServiceAccount、集羣角色、角色,並進行綁定操做。
最開始嘗試了未配置ServiceAccount的狀況,發現nginx-ingress-controller啓動時會報沒有權限。
# work @ ali in ~/k8s/ingress_newest [16:40:39] C:1 $ kubectl get pods -n ingress-nginx NAME READY STATUS RESTARTS AGE nginx-ingress-controller-5bd975597-7wcvh 0/1 CrashLoopBackOff 2 41s # work @ ali in ~/k8s/ingress_newest [16:40:42] $ kubectl logs nginx-ingress-controller-5bd975597-7wcvh -n ingress-nginx ------------------------------------------------------------------------------- NGINX Ingress controller Release: 0.28.0 Build: git-1f93cb8f3 Repository: https://github.com/kubernetes/ingress-nginx nginx version: nginx/1.17.7 ------------------------------------------------------------------------------- W0215 08:40:45.986921 6 flags.go:250] SSL certificate chain completion is disabled (--enable-ssl-chain-completion=false) W0215 08:40:45.987053 6 client_config.go:543] Neither --kubeconfig nor --master was specified. Using the inClusterConfig. This might not work. I0215 08:40:45.987390 6 main.go:193] Creating API client for https://10.96.0.1:443 I0215 08:40:46.009124 6 main.go:237] Running in Kubernetes cluster version v1.17 (v1.17.0) - git (clean) commit 70132b0f130acc0bed193d9ba59dd186f0e634cf - platform linux/amd64 F0215 08:40:46.014744 6 main.go:87] ✖ The cluster seems to be running with a restrictive Authorization mode and the Ingress controller does not have the required permissions to operate normally. 複製代碼
建立服務帳號、集羣角色、角色等內容,並進行相關綁定。 實際上對此部份內容目前也只是看的明白他在寫啥...具體爲何須要這些權限、爲何這樣綁定,留坑後面學習瞭解了權限相關的內容後再說。
# 後續的資源都在ingress-nginx空間內,此處須要提早建立好命名空間 apiVersion: v1 kind: Namespace metadata: name: 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 --- 複製代碼
該控制器將不一樣的請求根據URI轉發至不一樣的服務進行處理。
我的理解實際上在此位置的服務,只要包含一個代理程序,和一個監聽ingress資源變動動態修改該代理程序配置文件的程序便可。 例如此處使用的nginx代理,當集羣中Ingress資源發生變更時,動態修改nginx.conf配置,並從新加載配置文件,以實現轉發請求的目的。
for { // 監聽集羣中Ingress資源的變更 // 修改代理配置文件 // 從新加載配置文件 } 複製代碼
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.28.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 - name: https containerPort: 443 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: Service metadata: name: ingress-nginx-svc namespace: ingress-nginx labels: app.kubernetes.io/name: ingress-nginx app.kubernetes.io/part-of: ingress-nginx spec: type: NodePort ports: - name: http port: 80 targetPort: 80 protocol: TCP - name: https port: 443 targetPort: 443 protocol: TCP selector: app.kubernetes.io/name: ingress-nginx app.kubernetes.io/part-of: ingress-nginx --- 複製代碼
此時該Pod中的nginx有一份默認的配置文件。
其中定義了默認後端、健康檢查等請求內容。 實際上也能夠經過ingress-nginx-controller的`default-backend-service`參數來指定默認後端。
http { upstream upstream_balancer { # ... } server { server_name _ ; listen 80 default_server reuseport backlog=511 ; listen 443 default_server reuseport backlog=511 ssl http2 ; location / { # ... } # health checks in cloud providers require the use of port 80 location /healthz { access_log off; return 200; } location /nginx_status { allow 127.0.0.1; deny all; access_log off; stub_status on; } } ## end server _ # backend for when default-backend-service is not configured or it does not have endpoints server { listen 8181 default_server reuseport backlog=511; set $proxy_upstream_name "internal"; access_log off; location / { return 404; } } # default server, used for NGINX healthcheck and access to nginx stats server { listen 127.0.0.1:10246; set $proxy_upstream_name "internal"; keepalive_timeout 0; gzip off; access_log off; location /healthz { return 200; } # ... } } 複製代碼
搞一個簡單的服務來測試一下IngressController是否正常工做。
因爲默認的nginx配置中只有`/`一個location,因此此配置中的path直接使用了`/`。 可是能夠經過ingress-controller的nginx配置文件的變化來驗證ingress資源對其的影響。
apiVersion: apps/v1 kind: Deployment metadata: name: nginx spec: replicas: 1 selector: matchLabels: app: nginx template: metadata: labels: app: nginx spec: containers: - name: nginx image: nginx ports: - name: http containerPort: 80 --- apiVersion: v1 kind: Service metadata: name: nginx labels: app: nginx spec: ports: - port: 8080 targetPort: 80 selector: app: nginx --- apiVersion: extensions/v1beta1 kind: Ingress metadata: name: nginx-ingress spec: rules: - host: ngx.myingress.com #此service的訪問域名 http: paths: - path: / backend: serviceName: nginx servicePort: 8080 複製代碼
nginx配置文件發生了變化,多了一部分關於`ngx.myingress.com`的配置。
http { ## start server ngx.myingress.com server { server_name ngx.myingress.com ; listen 80 ; listen 443 ssl http2 ; set $proxy_upstream_name "-"; location / { # ... } } ## end server ngx.myingress.com } 複製代碼
綁定ngx.myingress.com
到節點IP,而後進行訪問,即可以看到對應的頁面了。