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