提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档


前言

        根据 kubernetes 中 Service 的定义和了解我们知道,如果 kubernetes 中的 pod 中容器想要对外部用户提供服务就需要将 pod 服务暴露至外部,让用户可以访问,而 Service 的表现形式为 ip 地址和端口号(ClusterIP:port)&(NodePort)即工作在四层 TCP/IP 层只能够通过 ip + 端口的方式访问,而在 ingress 当中可以使用七层协议(HTTP/HTTPS)的服务方式来实现负载均衡以及 k8s 集群内部服务和客户端之间的通信(既可以通过域名和主机名的方式),接下来将详细讲解 ingress-nginx 工作机制及概念;


一、ingress 是什么?

        ingress 在 kubernetes 中是一个具有七层协议(HTTP/HTTPS)的路由转发机制,通过策略以及结合具体提供转发服务的 Ingress Controller 来实现基于灵活的 ingress 策略定义的服务路由功能;

二、ingress-nginx 概念

        在 k8s 集群当中可以通过 Service 来对外暴露 k8s 集群当中的 pod 服务,从而使得外部请求能够访问 k8s 集群当中的 pod,而 Service 有多种暴露方式,常用的有 ClusterIP、NodePort.. ,如下通过 Service 和 ingress 做对比来更加了解 ingress-nginx 的概念:

        第一种暴露方式 clusterIP 针对集群内部的端口访问,通过标签的方式将 pod 和 svc 进行关联,访问 svc 时 svc 通过策略来将请求发送至各个 pod ,只限于集群内部访问;

        第二种暴露方式就是 NodePort ,该方式是基于 ClusterIP 暴露端口方式之上对集群外部进行暴露访问的一种方法,默认端口是从 30000 开始,此时集群外部就可以通过 master节点ip + 端口的方式对集群内部的 pod 服务进行访问,请求会先到达 NodePort 暴露的 ip + 端口,随后 NodePort 会和集群内的 ClusterIP 进行映射从而使得外部服务访问集群内的 pod 资源;

        第三种暴露方式就是 ingress 方式,该访问方式也是基于 ClusterIP 之上建立一个暴露方式, nodeport 只能够暴露 ip+端口(四层代理) 而 ingress-nginx 可以使用域名(七层代理)的方式对外暴露服务,ingress-nginx 就相当于是一个 nginx 服务的反向代理,当创建 ingress-nginx 之后会创建一个 nginx 服务(ingress-nginx 的 pod 容器),其中 Pod 中容器 nginx.conf 配置文件则记录的是对外暴露的域名以及监听端口是都是通过 ingress 的配置自动添加的,使用 location 中的 proxy-pass 来代理 k8s 集群中的 cluster 暴露的 ip,当外部请求访问到 ingress 暴露的域名时会反向代理到对应匹配的 svc 从而实现服务的访问;

三、 ingress-nginx 工作流程

        如下图,如果管理员修改了 ingress 配置则 ingress 会通过 kubernetes API Server 来监听修改的配置动作,API 会和 Store(协程)建立连接,由 Store 来监听资源变化的时间(informer 模式),最终会判断资源是否发生变化,当发生变化之后会将变更的资源写入至更新事件当中(updateChannel) 之后主程(NginxController) 会读取 updateChannel 当中的更新事件加载到主程(NginxController)并向同步队列(syncQueue)追加同步任务,之后同步队列协程(syncQueue)会拉取同步队列的信息,还有一种情况就是获取最新的 ingress/service 配置 nginx 服务必须的信息,也会加载到协程(syncQueue)当中,之后会对这些收集的信息资源进行判断是否需要 reload ,当有新配置时会触发 reload 重写 nginx 配置文件并构造 POST 数据,向 Lua Server 发送更新请求,如果判断不需要重载则直接构造 POST 数据,并向 LuaServer 发送更新请求;

四、Ingress-nginx 部署案例

1、创建 IngressContainer

[root@kube-master ~]# mkdir ingress
[root@kube-master ~]# cd ingress/
[root@kube-master ingress]# vim ingress-container.yaml
# 创建名称空间 nginx-ingress
---
apiVersion: v1
kind: Namespace
metadata:
  name: nginx-ingress


# 创建 SA,用于 IngressContainer 和 kube-apiServer 进行认证
---
apiVersion: v1
kind: ServiceAccount
metadata:
  name: nginx-ingress
  namespace: nginx-ingress


# 设置集群角色策略,是否允许对 ingress-container 中的资源(pod、configmaps等)进行用户授权
---
kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: nginx-ingress
rules:
- apiGroups:
  - ""
  resources:
  - services
  - endpoints
  verbs:
  - get
  - list
  - watch
- apiGroups:
  - ""
  resources:
  - secrets
  verbs:
  - get
  - list
  - watch
- apiGroups:
  - ""
  resources:
  - configmaps
  verbs:
  - get
  - list
  - watch
  - update
  - create
- apiGroups:
  - ""
  resources:
  - pods
  verbs:
  - list
  - watch
- apiGroups:
  - ""
  resources:
  - events
  verbs:
  - create
  - patch
  - list
- apiGroups:
  - extensions
  resources:
  - ingresses
  verbs:
  - list
  - watch
  - get
- apiGroups:
  - "extensions"
  resources:
  - ingresses/status
  verbs:
  - update
- apiGroups:
  - k8s.nginx.org
  resources:
  - virtualservers
  - virtualserverroutes
  - globalconfigurations
  - transportservers
  - policies
  verbs:
  - list
  - watch
  - get
- apiGroups:
  - k8s.nginx.org
  resources:
  - virtualservers/status
  - virtualserverroutes/status
  verbs:
  - update
---
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: nginx-ingress
subjects:
- kind: ServiceAccount
  name: nginx-ingress
  namespace: nginx-ingress
roleRef:
  kind: ClusterRole
  name: nginx-ingress
  apiGroup: rbac.authorization.k8s.io


# 创建 Secret 存储,用于存储加密证书信息,用于 SA 引入进行认证,类型是 Opaque;
---
apiVersion: v1
kind: Secret
metadata:
  name: default-server-secret
  namespace: nginx-ingress
type: Opaque
data:
  tls.crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUN2akNDQWFZQ0NRREFPRjl0THNhWFhEQU5CZ2txaGtpRzl3MEJBUXNGQURBaE1SOHdIUVlEVlFRRERCWk8KUjBsT1dFbHVaM0psYzNORGIyNTBjbTlzYkdWeU1CNFhEVEU0TURreE1qRTRNRE16TlZvWERUSXpNRGt4TVRFNApNRE16TlZvd0lURWZNQjBHQTFVRUF3d1dUa2RKVGxoSmJtZHlaWE56UTI5dWRISnZiR3hsY2pDQ0FTSXdEUVlKCktvWklodmNOQVFFQkJRQURnZ0VQQURDQ0FRb0NnZ0VCQUwvN2hIUEtFWGRMdjNyaUM3QlBrMTNpWkt5eTlyQ08KR2xZUXYyK2EzUDF0azIrS3YwVGF5aGRCbDRrcnNUcTZzZm8vWUk1Y2Vhbkw4WGM3U1pyQkVRYm9EN2REbWs1Qgo4eDZLS2xHWU5IWlg0Rm5UZ0VPaStlM2ptTFFxRlBSY1kzVnNPazFFeUZBL0JnWlJVbkNHZUtGeERSN0tQdGhyCmtqSXVuektURXUyaDU4Tlp0S21ScUJHdDEwcTNRYzhZT3ExM2FnbmovUWRjc0ZYYTJnMjB1K1lYZDdoZ3krZksKWk4vVUkxQUQ0YzZyM1lma1ZWUmVHd1lxQVp1WXN2V0RKbW1GNWRwdEMzN011cDBPRUxVTExSakZJOTZXNXIwSAo1TmdPc25NWFJNV1hYVlpiNWRxT3R0SmRtS3FhZ25TZ1JQQVpQN2MwQjFQU2FqYzZjNGZRVXpNQ0F3RUFBVEFOCkJna3Foa2lHOXcwQkFRc0ZBQU9DQVFFQWpLb2tRdGRPcEsrTzhibWVPc3lySmdJSXJycVFVY2ZOUitjb0hZVUoKdGhrYnhITFMzR3VBTWI5dm15VExPY2xxeC9aYzJPblEwMEJCLzlTb0swcitFZ1U2UlVrRWtWcitTTFA3NTdUWgozZWI4dmdPdEduMS9ienM3bzNBaS9kclkrcUI5Q2k1S3lPc3FHTG1US2xFaUtOYkcyR1ZyTWxjS0ZYQU80YTY3Cklnc1hzYktNbTQwV1U3cG9mcGltU1ZmaXFSdkV5YmN3N0NYODF6cFErUyt1eHRYK2VBZ3V0NHh3VlI5d2IyVXYKelhuZk9HbWhWNThDd1dIQnNKa0kxNXhaa2VUWXdSN0diaEFMSkZUUkk3dkhvQXprTWIzbjAxQjQyWjNrN3RXNQpJUDFmTlpIOFUvOWxiUHNoT21FRFZkdjF5ZytVRVJxbStGSis2R0oxeFJGcGZnPT0KLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQo=
  tls.key: LS0tLS1CRUdJTiBSU0EgUFJJVkFURSBLRVktLS0tLQpNSUlFcEFJQkFBS0NBUUVBdi91RWM4b1JkMHUvZXVJTHNFK1RYZUprckxMMnNJNGFWaEMvYjVyYy9XMlRiNHEvClJOcktGMEdYaVN1eE9ycXgrajlnamx4NXFjdnhkenRKbXNFUkJ1Z1B0ME9hVGtIekhvb3FVWmcwZGxmZ1dkT0EKUTZMNTdlT1l0Q29VOUZ4amRXdzZUVVRJVUQ4R0JsRlNjSVo0b1hFTkhzbysyR3VTTWk2Zk1wTVM3YUhudzFtMApxWkdvRWEzWFNyZEJ6eGc2clhkcUNlUDlCMXl3VmRyYURiUzc1aGQzdUdETDU4cGszOVFqVUFQaHpxdmRoK1JWClZGNGJCaW9CbTVpeTlZTW1hWVhsMm0wTGZzeTZuUTRRdFFzdEdNVWozcGJtdlFmazJBNnljeGRFeFpkZFZsdmwKMm82MjBsMllxcHFDZEtCRThCay90elFIVTlKcU56cHpoOUJUTXdJREFRQUJBb0lCQVFDZklHbXowOHhRVmorNwpLZnZJUXQwQ0YzR2MxNld6eDhVNml4MHg4Mm15d1kxUUNlL3BzWE9LZlRxT1h1SENyUlp5TnUvZ2IvUUQ4bUFOCmxOMjRZTWl0TWRJODg5TEZoTkp3QU5OODJDeTczckM5bzVvUDlkazAvYzRIbjAzSkVYNzZ5QjgzQm9rR1FvYksKMjhMNk0rdHUzUmFqNjd6Vmc2d2szaEhrU0pXSzBwV1YrSjdrUkRWYmhDYUZhNk5nMUZNRWxhTlozVDhhUUtyQgpDUDNDeEFTdjYxWTk5TEI4KzNXWVFIK3NYaTVGM01pYVNBZ1BkQUk3WEh1dXFET1lvMU5PL0JoSGt1aVg2QnRtCnorNTZud2pZMy8yUytSRmNBc3JMTnIwMDJZZi9oY0IraVlDNzVWYmcydVd6WTY3TWdOTGQ5VW9RU3BDRkYrVm4KM0cyUnhybnhBb0dCQU40U3M0ZVlPU2huMVpQQjdhTUZsY0k2RHR2S2ErTGZTTXFyY2pOZjJlSEpZNnhubmxKdgpGenpGL2RiVWVTbWxSekR0WkdlcXZXaHFISy9iTjIyeWJhOU1WMDlRQ0JFTk5jNmtWajJTVHpUWkJVbEx4QzYrCk93Z0wyZHhKendWelU0VC84ajdHalRUN05BZVpFS2FvRHFyRG5BYWkyaW5oZU1JVWZHRXFGKzJyQW9HQkFOMVAKK0tZL0lsS3RWRzRKSklQNzBjUis3RmpyeXJpY05iWCtQVzUvOXFHaWxnY2grZ3l4b25BWlBpd2NpeDN3QVpGdwpaZC96ZFB2aTBkWEppc1BSZjRMazg5b2pCUmpiRmRmc2l5UmJYbyt3TFU4NUhRU2NGMnN5aUFPaTVBRHdVU0FkCm45YWFweUNweEFkREtERHdObit3ZFhtaTZ0OHRpSFRkK3RoVDhkaVpBb0dCQUt6Wis1bG9OOTBtYlF4VVh5YUwKMjFSUm9tMGJjcndsTmVCaWNFSmlzaEhYa2xpSVVxZ3hSZklNM2hhUVRUcklKZENFaHFsV01aV0xPb2I2NTNyZgo3aFlMSXM1ZUtka3o0aFRVdnpldm9TMHVXcm9CV2xOVHlGanIrSWhKZnZUc0hpOGdsU3FkbXgySkJhZUFVWUNXCndNdlQ4NmNLclNyNkQrZG8wS05FZzFsL0FvR0FlMkFVdHVFbFNqLzBmRzgrV3hHc1RFV1JqclRNUzRSUjhRWXQKeXdjdFA4aDZxTGxKUTRCWGxQU05rMXZLTmtOUkxIb2pZT2pCQTViYjhibXNVU1BlV09NNENoaFJ4QnlHbmR2eAphYkJDRkFwY0IvbEg4d1R0alVZYlN5T294ZGt5OEp0ek90ajJhS0FiZHd6NlArWDZDODhjZmxYVFo5MWpYL3RMCjF3TmRKS2tDZ1lCbyt0UzB5TzJ2SWFmK2UwSkN5TGhzVDQ5cTN3Zis2QWVqWGx2WDJ1VnRYejN5QTZnbXo5aCsKcDNlK2JMRUxwb3B0WFhNdUFRR0xhUkcrYlNNcjR5dERYbE5ZSndUeThXczNKY3dlSTdqZVp2b0ZpbmNvVlVIMwphdmxoTUVCRGYxSjltSDB5cDBwWUNaS2ROdHNvZEZtQktzVEtQMjJhTmtsVVhCS3gyZzR6cFE9PQotLS0tLUVORCBSU0EgUFJJVkFURSBLRVktLS0tLQo=


# 创建 ConfigMap 用于对 IngressContainer 容器进行配置修改
---
kind: ConfigMap
apiVersion: v1
metadata:
  name: nginx-config
  namespace: nginx-ingress
data:


# 编辑 IngressContainer 容器创建,控制类型用的是 deployment;
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-ingress
  namespace: nginx-ingress
spec:
  replicas: 1
  selector:
    matchLabels:
      app: nginx-ingress
  template:
    metadata:
      labels:
        app: nginx-ingress
    spec:
      serviceAccountName: nginx-ingress     # 引入 SA 用于 pod 和 kube-apiServer 进行加密认证
      containers:
      - image: nginx/nginx-ingress:1.7.2
        imagePullPolicy: IfNotPresent
        name: nginx-ingress
        ports:
        - name: http
          containerPort: 80
          hostPort: 80
        - name: https
          containerPort: 443
          hostPort: 443
        env:                            # 定义变量
        - name: POD_NAMESPACE
          valueFrom:
            fieldRef:
              fieldPath: metadata.namespace
        - name: POD_NAME
          valueFrom:
            fieldRef:
              fieldPath: metadata.name
        args:                            # 通过变量引入 secret 和 configMap
          - -nginx-configmaps=$(POD_NAMESPACE)/nginx-config
          - -default-server-tls-secret=$(POD_NAMESPACE)/default-server-secret



# 保存退出后查看 nginx-ingress 名称空间下的所有资源
[root@kube-master ingress]# kubectl get cm,sa,deployment,secret -n nginx-ingress 
NAME                         DATA   AGE
configmap/kube-root-ca.crt   1      77m
configmap/nginx-config       0      77m

NAME                           SECRETS   AGE
serviceaccount/default         1         77m
serviceaccount/nginx-ingress   1         77m

NAME                            READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/nginx-ingress   1/1     1            1           77m

NAME                               TYPE                                  DATA   AGE
secret/default-server-secret       Opaque                                2      77m
secret/default-token-2rhp2         kubernetes.io/service-account-token   3      77m
secret/nginx-ingress-token-9k4tp   kubernetes.io/service-account-token   3      77m


2、创建 Service 和 Deployment(服务)

# 创建 deployment、Service
[root@kube-master ingress]# vim test-dep.yaml 
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx
spec:
  replicas: 3
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: myweb
        image: nginx
        imagePullPolicy: IfNotPresent
        ports:
        - containerPort: 80

---
apiVersion: v1
kind: Service
metadata:
  name: nginx-svc
spec:
  selector:
    app: nginx
  ports:
  - protocol: TCP
    port: 80
    targetPort: 80


# 验证是否创建成功
[root@kube-master ingress]# kubectl get pod,svc
NAME                     READY   STATUS    RESTARTS   AGE
pod/nginx-f8f495-8l9sd   1/1     Running   0          43m
pod/nginx-f8f495-hs49c   1/1     Running   0          43m
pod/nginx-f8f495-zhbvn   1/1     Running   0          43m

NAME                 TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)   AGE
service/kubernetes   ClusterIP   10.96.0.1      <none>        443/TCP   16d
service/nginx-svc    ClusterIP   10.96.74.181   <none>        80/TCP    43m

3、创建 Ingress 对外进行域名代理

# 创建 ingress 的剧本文件
[root@kube-master ingress]# vim test-ingress.yaml 
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: nginx-ingress-test                # 定义 ingress 名称
spec:
  rules:
  - host: www.zkj.com                     # 定义对外暴露的域名
    http:                                 # 协议为 http 协议
      paths:                              # 定义服务访问的路径
      - path: /backend                    # 路径指定 /backend
        pathType: ImplementationSpecific  # 定义路径类型为 ImplementationSpecific
        backend:                          # 定义后端代理
          service:                        # 定义代理的 svc 信息
            name: nginx-svc               # 指定 svc 的名称
            port:                         # 定义 svc 的端口
              number: 80


# 查看创建的 ingress 信息
[root@kube-master ingress]# kubectl describe ingress nginx-ingress-test 
Name:             nginx-ingress-test
Namespace:        default
Address:          
Default backend:  default-http-backend:80 (<error: endpoints "default-http-backend" not found>)
Rules:
  Host         Path  Backends
  ----         ----  --------
  www.zkj.com                  # 暴露的域名信息
                               # 代理的后端服务
               /backend   nginx-svc:80 (10.244.1.4:80,10.244.1.5:80,10.244.2.3:80)
Annotations:   <none>
Events:
  Type    Reason          Age                From                      Message
  ----    ------          ----               ----                      -------
  Normal  AddedOrUpdated  35s (x2 over 38m)  nginx-ingress-controller  Configuration for default/nginx-ingress-test was added or updated

4、查看 IngressContainer 容器中的 nginx 配置文件

# 查看 IngressContainer 容器信息
[root@kube-master ingress]# kubectl get pod -n nginx-ingress 
NAME                             READY   STATUS    RESTARTS   AGE
nginx-ingress-78c4c6db55-tgl4w   1/1     Running   0          3h18m


# 进入容器
[root@kube-master ~]# kubectl exec -it -n nginx-ingress nginx-ingress-78c4c6db55-tgl4w /bin/bash

nginx@nginx-ingress-78c4c6db55-tgl4w:/$ cd etc/nginx/conf.d/

# 查看配置文件
nginx@nginx-ingress-78c4c6db55-tgl4w:/etc/nginx/conf.d$ cat default-nginx-ingress-test.conf 



# 负载均衡 pod ip 地址
upstream default-nginx-ingress-test-www.zkj.com-nginx-svc-8080 {
	zone default-nginx-ingress-test-www.zkj.com-nginx-svc-8080 256k;
	random two least_conn;
	
	server 10.244.1.10:80 max_fails=1 fail_timeout=10s max_conns=0;
	
}


server {
	
	
	listen 80;
    server_tokens on;
    server_name www.zkj.com;        # 域名为 hosts 字段定义的域名


	location /backend {             # location 字段为 path 字段定义的路径
		
		
		proxy_http_version 1.1;
		

		proxy_connect_timeout 60s;
		proxy_read_timeout 60s;
		proxy_send_timeout 60s;
		client_max_body_size 1m;
		proxy_set_header Host $host;
		proxy_set_header X-Real-IP $remote_addr;
		proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
		proxy_set_header X-Forwarded-Host $host;
		proxy_set_header X-Forwarded-Port $server_port;
		proxy_set_header X-Forwarded-Proto $scheme;
		proxy_buffering on;


        # 定义反向代理策略		
		proxy_pass http://default-nginx-ingress-test-www.zkj.com-nginx-svc-8080;
		
		
	}
	
	
}

总结

        以上就是今天要讲的内容,本文仅仅简单介绍了 Ingress-nginx 的使用,而 Ingress-nginx 提供了七层协议访问通信功能,能够使得客户使用域名的方式来访问 kubernetes 集群内部容器服务。

Logo

开源、云原生的融合云平台

更多推荐