Kubernetes實現Ingress服務發佈

Ingress原理 

  在K8S中,暴露一個http服務一般有兩種方式,一是通過Service暴露端口的方式讓外部以及集羣內部的node來訪問到http相關頁面內容,二是通過Ingress負載均衡的方式,將由外部網絡域名訪問通過Ingress的Nginx節點反代到後端指定Service下的Pod節點中的http服務。

Service的模式結構如下:

  service -> label selector -> pods

  31217 -> app1 selector -> app1 1234

  31218 -> app2 selector -> app2 3456

  31218 -> app2 selector -> app2 4567

  訪問流程:

【PREROUTING鏈】
-m comment --comment "kubernetes service portals" -j KUBE-SERVICES

【KUBE-SERVICES鏈】
-d 10.16.0.10/32 -p udp -m comment --comment "kube-system/kube-dns:dns cluster IP" -m udp --dport 53 -j KUBE-SVC-TCOU7JCQXEZGVUNU

【KUBE-SVC-TCOU7JCQXEZGVUNU鏈】
-m comment --comment "kube-system/kube-dns:dns" -j KUBE-SEP-L5MHPWJPDKD7XIFG

【KUBE-SEP-L5MHPWJPDKD7XIFG鏈】
-p udp -m comment --comment "kube-system/kube-dns:dns" -m udp -j DNAT --to-destination 10.0.0.46:53

 注意:目前有三種訪問方式

①名稱空間,通過kube-proxy

②iptables,不需要直接通過kube-proxy所以效率更高

③通過ipvs進行,效率是最高的

目前默認使用的是②


  用戶通過訪問由service層生成的ClusterIP以及隨機端口,訪問到由該service指定的唯一標誌label,指向內部挑選出來的Pod節點

  向service ip 10.16.0.10:53發送udp請求,查找路由表,把數據包轉發給網橋docker0,在數據包進入docker0網橋時,數據包經過

  PREROUTING鏈,然後跳至KUBE-SERVICES鏈,KUBE-SERVICES鏈中一條匹配此數據包的規則,跳至KUBE-SVC-*鏈KUBE-SVC-*

  不做任何操作,跳至KUBE-SEP-*鏈KUBE-SEP-*裏對此數據包作了DNAT到10.0.0.46:53,其中10.0.0.46即爲kube-dns的pod ip

  查找與10.0.0.46匹配的路由,轉發數據包到flannel.1,再交由flanneld進程進行封裝轉發出去。


Ingress模式結構如下:

圖片.png

  ingress -> service -> label selector -> pods           

                www.app1.com -> app1-service -> app1 selector -> app1 1234

80   ->     www.app2.com -> app2-service -> app2 selector -> app2 3456    

                www.app3.com -> app3-service -> app3 selector -> app3 4567

  Ingress負載均衡由三種組件組成

  ①Nginx

  ②Ingress Controller

  ③Ingress

  Nginx用於對外提供訪問,內部記錄了由Ingress Controller向kube-apiserver拿到的實時的service的endpoint到nginx配置文件中,

關聯的Service下的Pod節點的IP,端口信息,讓Nginx在訪問域名時能夠反代到指定Service下屬的Pod節點上。Ingress則是用於在

Nginx中生成虛擬主機的配置端,如指定Service下屬的Pod節點的upstream上下文等配置信息。


Ingress負載均衡實現

基於http:

  部署Ingress基本環境

  Master節點上配置

  官方文檔:https://github.com/kubernetes/ingress-nginx/tree/master/deploy

  下載yaml文件

   curl https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/namespace.yaml | kubectl apply -f -
   curl https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/default-backend.yaml | kubectl apply -f -
   curl https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/tcp-services-configmap.yaml | kubectl apply -f -
   curl https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/udp-services-configmap.yaml | kubectl apply -f -
   curl https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/rbac.yaml | kubectl apply -f -
   namespace.yaml:創建一個網絡名稱空間供Ingress使用

   default-backend.yaml:創建一個在Nginx默認的虛擬主機配置。

   tcp-services-configmap.yaml:使得Nginx能代理tcp,存放tcp四層負載均衡配置。

   udp-services-configmap.yaml:使得Nginx能代理udp,存放udp四層負載均衡配置。

   rbac.yaml:啓用rbac角色,將角色綁定到指定的 ServiceAccount。

  啓用Ingress配置的yaml,default-backend.yaml需要更改鏡像爲國內鏡像

  # kubectl create -f namespace.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


  創建nginx,Ingress-controller

  編輯yaml文件

[root@node-1 ingress]# cat deployment.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
      hostNetwork: true
      containers:
        - name: nginx-ingress-controller
          image: lizhenliang/nginx-ingress-controller:0.9.0
          args:
            - /nginx-ingress-controller
            - --default-backend-service=$(POD_NAMESPACE)/default-http-backend
            - --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
  name: nginx-ingress-controller
  namespace: ingress-nginx
spec:
  replicas: 1
  selector:
    matchLabels:
      app: ingress-nginx
  template:
    metadata:
      labels:
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
      hostNetwork: true
      containers:
        - name: nginx-ingress-controller
          image: lizhenliang/nginx-ingress-controller:0.9.0
          args:
            - /nginx-ingress-controller
            - --default-backend-service=$(POD_NAMESPACE)/default-http-backend
            - --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

  啓用nginx-ingress-controller:kubectl create -f deployment.yaml

  查看:

  圖片.png

  創建ingress配置文件,用於定義Ingress中需要的關聯Service,在這裏我創建兩個web服務,nginx與apache

  # kubectl run --image=nginx:1.10 nginx --replicas=1 #定義deployment

  # kubectl expose deployment nginx --port=80  #定義service,暴露端口

  # kubectl run --image=httpd httpd --replicas=1

  # kubectl expose deployment httpd --port=80

指定Ingress中需要關聯的service

[root@node-1 ingress]# cat ingress-test.yaml
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: http-test
spec:
  rules:
  - host: nginx-wjq.com
    http:
      paths:
      - backend:
          serviceName: nginx
          servicePort: 80
  - host: httpd-wjq.com
    http:
      paths:
      - backend:
          serviceName: httpd
          servicePort: 80


 #kubectl create -f ingress-test.yaml

 

這個時候查看nginx-ingress-controller的pod就會發現Ingress組件已經自動同步了相關的虛擬主機配置,ingress-controller去獲取到了Service後端的Pod

圖片.png

一下是創建了nginx,httpd的service後,自動同步到nginx中的配置

圖片.png

同步了httpd-wjq.com域名的虛擬主機在nginx中

圖片.png

同步了nginx-wjq.com域名的虛擬主機在nginx中

圖片.png

查看ingress-controller在哪個pod主機上,就可以通過那個主機對外的物理IP訪問到Nginx從而訪問到對應域名service的Pod應用

圖片.png

可以配置ingress-controller在兩個node物理主機上,修改replicas爲2

[root@node-1 ingress]# kubectl edit deployment nginx-ingress-controller -n ingress-nginx -o yaml

圖片.png


瀏覽器訪問

  需要在本地物理機的host文件中添加域名解析

  192.168.175.130 nginx-wjq.com
  192.168.175.130 httpd-wjq.com

圖片.png

圖片.png



基於https:

  創建密鑰對:

  使用cfssl創建私人CA

  # cfssl print-defaults csr > ca-csr.json  ##創建默認的csr json文件

  修改ca-csr.json

[root@node-1 https]# cat ca-csr.json
{
    "CN": "wujunqi", ##CA名稱
    "key": {
        "algo": "rsa",
        "size": 2048
    },
    "names": [
        {
            "C": "CN",
            "L": "shenzhen",
            "ST": "shenzhen"
        }
    ]
}
 

創建私人CA參數,有效期之類的,默認是一年,無需修改

  # cfssl print-defaults config > ca-config.json

生成CA密鑰對:

  # cfssl gencert  --initca ca-csr.json | cfssljson -bare ca

創建出ca.pem以及ca-key.pem

再根據兩個密鑰對創建出針對於域名的相關密鑰證書

  在創建一個證書請求文件,針對於某一訪問域名

  # cfssl print-defaults csr > server-csr.json

  # cat server-csr.json

  [root@node-1 https]# cat server-csr.json
  {
      "CN": "www.wujunqi.com",
      "key": {
          "algo": "rsa",
          "size": 2048
      },
      "names": [
          {
              "C": "CN",
              "L": "shenzhen",
              "ST": "shenzhen"
          }
      ]
  }

  由私人CA針對該證書請求文件創建對應的密鑰對

  # cfssl gencert -ca=ca.pem -ca-key=ca-key.pem --config=ca-config.json --prefile=www server-csr.json | cfssljson -bare server

  至此,需要的密鑰創建完成

  創建在集羣中使用的TLS

  # kubectl create secret tls wujunqi-https --key server-key.pem --cert server.pem

  查看tls

  # kubectl get secret

  圖片.png

  創建Ingress使用TLS進行訪問,指定Service,讓ingress-controller關聯到Service後端的Pod

[root@node-1 ingress]# cat https.yaml
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: https-test
spec:
  tls:
  - hosts:
    - www.wujunqi.com
    secretName: wujunqi-https
  rules:
    - host: www.wujunqi.com
      http:
        paths:
        - backend:
            serviceName: nginx
            servicePort: 80


創建Ingress:

  # kubectl create -f https.yaml

查看Ingress:

  圖片.png

這時候就可以進行訪問了,將物理主機的host文件中添加域名解析

  192.168.175.130 www.wujunqi.com

圖片.png



  

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章