K8S學習筆錄 - 使用Ingress暴露服務

原文連接node

對於HTTP服務來講,不一樣的URL地址常常對應到不一樣的後端服務,Ingress類型資源能夠知足此類需求。linux

什麼是Ingress

簡單說,是一個代理,能夠根據配置轉發請求到指定的服務上。nginx

爲何須要Ingress資源

因爲K8S集羣擁有強大的副本控制能力,Pod隨時可能從一個節點上被驅逐到另外一個節點上,或者直接銷燬再來一個新的。git

然而伴隨着Pod的銷燬和重生,Pod的IP等信息不斷地在改變,此時使用K8S提供的Service機制能夠解決這一問題,Service經過標籤選定指定的Pod做爲後端服務,並監聽這些Pod的變化。github

在對外暴露服務時,使用Service的NodePort是一個方法json

問題1 - 如何管理端口

當須要對外暴露的服務量比較多的時候,端口管理的問題便會暴露出來。後端

此時的一個處理方案是使用一個代理服務(例如Nginx)根據請求信息將請求轉發到不一樣的服務上去。api

問題2 - 如何管理轉發配置

每當有新服務加入,都須要對該服務的配置進行修改、升級,在服務數量逐漸變多後,該配置項目會變得愈來愈大,手工修改的風險也會逐漸增高。bash

那麼須要一個工具來簡化這一過程,但願能夠經過簡單的配置動態生成代理中複雜的配置,最好還能夠順手從新加載配置文件。markdown

K8S恰好也提供了此類型資源。

Ingress的工做方式

在使用普通的Service時,集羣中每一個節點的kube-proxy在監聽到Service和Endpoints的變化時,會動態的修改相關的iptables的轉發規則。 客戶端在訪問時經過iptables設置的規則進行路由轉發達到訪問服務的目的。

而Ingress則跳過了kube-proxy這一層,經過Ingress Controller中的代理配置進行路由轉發達到訪問目標服務的目的。

ingress-worlflow

實際上能夠把IngressController看作一個擁有默認處理後端的代理,根據Ingress資源的配置動態修改代理的配置文件,以實現按照規則轉發請求的功能。

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"`
}
複製代碼

部署使用Ingress

具體的建立步驟爲

  1. 建立RBAC,爲IngressController提供指定權限
  2. 建立IngressController,處理、分發請求到不一樣的服務
  3. 建立Ingess資源

建立RBAC資源

建立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.
複製代碼

建立服務帳號、集羣角色、角色等內容,並進行相關綁定。 實際上對此部份內容目前也只是看的明白他在寫啥...具體爲何須要這些權限、爲何這樣綁定,留坑後面學習瞭解了權限相關的內容後再說。

github.com/kubernetes/…

# 後續的資源都在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

---
複製代碼

建立Ingress Controller

該控制器將不一樣的請求根據URI轉發至不一樣的服務進行處理。

我的理解實際上在此位置的服務,只要包含一個代理程序,和一個監聽ingress資源變動動態修改該代理程序配置文件的程序便可。 例如此處使用的nginx代理,當集羣中Ingress資源發生變更時,動態修改nginx.conf配置,並從新加載配置文件,以實現轉發請求的目的。

for {
    // 監聽集羣中Ingress資源的變更
    // 修改代理配置文件
    // 從新加載配置文件
}
複製代碼

github.com/kubernetes/…

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;
        }

        # ...
    }
}
複製代碼

建立Ingress資源

搞一個簡單的服務來測試一下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,而後進行訪問,即可以看到對應的頁面了。

相關文章
相關標籤/搜索