k8s version: 1.6.7 无CNI
[title]1. 创建Service Account[/title]
1 2 3 4 5 6 |
[root@docker1 complete-example]# more nginx-ingress-sa.yaml apiVersion: v1 kind: ServiceAccount metadata: name: nginx-ingress namespace: default |
kubectl create -f nginx-ingress-sa.yaml
[title]2. 绑定sa到role[/title]
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
[root@docker1 complete-example]# cat nginx-ingress-sa-role-binding.yaml kind: ClusterRoleBinding apiVersion: rbac.authorization.k8s.io/v1beta1 metadata: name: nginx-ingress namespace: default subjects: - kind: ServiceAccount namespace: default name: nginx-ingress roleRef: kind: ClusterRole name: cluster-admin apiGroup: rbac.authorization.k8s.io |
注意这里随意给了一个较高的角色
kubectl create -f nginx-ingress-sa-role-binding.yaml
上述工作是为了保证nginx controller pod获得权限与api server通信:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
Kubernetes Workstation +---------------------------------------------------+ +------------------+ | | | | | +-----------+ apiserver +------------+ | | +------------+ | | | | proxy | | | | | | | | | apiserver | | ingress | | | | ingress | | | | | | controller | | | | controller | | | | | | | | | | | | | | | | | | | | | | | | | service account/ | | | | | | | | | | kubeconfig | | | | | | | | | +<-------------------+ | | | | | | | | | | | | | | | | | +------+----+ kubeconfig +------+-----+ | | +------+-----+ | | |<--------------------------------------------------------| | | | | | +---------------------------------------------------+ +------------------+ |
[title]3. 创建nginx controller pod需要使用的缺省tls 证书及key[/title]
kubectl create -f default-server-secret.yaml
相关yaml文件从https://github.com/nginxinc/kubernetes-ingress/tree/master/examples/complete-example 获取
[title]4. 部署nginx ingress controller[/title]
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
[root@docker1 complete-example]# cat nginx-ingress-rc.yaml apiVersion: extensions/v1beta1 kind: DaemonSet metadata: name: nginx-ingress-ds labels: app: nginx-ingress-ctrl spec: template: metadata: labels: app: nginx-ingress-ctrl spec: serviceAccountName: nginx-ingress containers: - image: nginxdemos/nginx-ingress:1.0.0 name: nginx-ingress-lb ports: - containerPort: 80 hostPort: 80 - containerPort: 443 hostPort: 443 env: - name: POD_NAMESPACE valueFrom: fieldRef: fieldPath: metadata.namespace # Uncomment the lines below to enable extensive logging and/or customization of # NGINX configuration with configmaps args: #- -v=3 #- -nginx-configmaps=$(POD_NAMESPACE)/nginx-config - -default-server-tls-secret=$(POD_NAMESPACE)/default-server-secret |
注意这里使用的是daemonset方式部署,为了保证每个node上都存在一个nginx pod
[title]5. 创建相关测试用APP pod及其相关service[/title]
1 2 3 4 |
$ kubectl create -f tea-rc.yaml $ kubectl create -f tea-svc.yaml $ kubectl create -f coffee-rc.yaml $ kubectl create -f coffee-svc.yaml |
[title]6. 创建nginx 提供应用ssl访问时候所需的证书及key[/title]
1 |
$ kubectl create -f cafe-secret.yaml |
[title]7. 创建k8s中的ingress 资源[/title]
1 |
kubectl create -f cafe-ingress.yaml |
[title]8. 验证测试[/title]
1 2 3 |
[root@docker1 complete-example]# kubectl get ing NAME HOSTS ADDRESS PORTS AGE cafe-ingress cafe.example.com 80, 443 11d |
注意系统本没有显示 ingress 的 address,这可能是由于我的环境没有使用CNI缘故?但从node节点的主机IP上是可以访问到相关nginx发布的应用的.
1 2 3 4 5 6 |
[root@docker1 complete-example]# kubectl get pods NAME READY STATUS RESTARTS AGE coffee-rc-94c0j 1/1 Running 1 11d nginx-ingress-ds-hwhl3 1/1 Running 0 1h nginx-ingress-ds-j845z 1/1 Running 0 1h tea-rc-4501t 1/1 Running 1 11d |
测试环境为了节省资源,只设置coffee,tea应用分别只其一个pod.
docker inspect 某个具体ingress controller pod:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
"NetworkSettings": { "Bridge": "", "SandboxID": "849a063de3679beb132885677e95de4e953e5d9731940d614fc04982aa5a7f1f", "HairpinMode": false, "LinkLocalIPv6Address": "", "LinkLocalIPv6PrefixLen": 0, "Ports": { "443/tcp": [ { "HostIp": "0.0.0.0", "HostPort": "443" } ], "80/tcp": [ { "HostIp": "0.0.0.0", "HostPort": "80" } ] }, |
访问某个具体的ingress controller所在node的宿主IP:访问coffee目录获得如下应用显示请求被分往coffee pod
访问/tea目录,请求被分往tea pod:
当创建ingress resource时, ingress controller上日志显示:
1 |
I0924 13:05:24.593156 1 event.go:218] Event(v1.ObjectReference{Kind:"Ingress", Namespace:"default", Name:"cafe-ingress", UID:"efc09df3-9884-11e7-911f-000c29420d98", APIVersion:"extensions", ResourceVersion:"168360", FieldPath:""}): type: 'Normal' reason: 'AddedOrUpdated' Configuration for default/cafe-ingress was added or updated |
说明nginx controller获得相关ingress指定的配置更新.
[title]Ingress原理[/title]
Ingress (resource)是k8s中配置controller的具体规则实现,可以理解为k8s具备L7 LB实现(比如基于host,基于uri)。
Ingress controller监控ingress resource配置,并对LB进行配置。一般来说controller会和具体的software LB作为一个pod被部署,不同的SW LB需要不同的controller实现。真正执行这些规则来分发请求的是 SW LB,所以controller里可以是nginx也可以其它比如traefik。下图描述了ingress的原理(注意图中错误: nginx实际直接将请求发送给pod,不经过service):
nginx controller通过监视api server获取相关ingress、service、endpoint、secret、node、configmap对象,并在程序内部不断循环监视相关service是否有新的endpoints变化,一旦发生变化则自动更新nginx.tmpl 模板配置并产生新的配置文件进行reload
ingress resource里配置的是service名称,但nginx controller是直接将请求发送到相关pods.
nginx自动产生的一个配置示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 |
[root@docker1 complete-example]# kubectl exec nginx-ingress-ds-hwhl3 -- cat /etc/nginx/conf.d/default-cafe-ingress.conf upstream default-cafe-ingress-cafe.example.com-tea-svc { server 10.2.13.5:80; <<<<<<< pod地址 } upstream default-cafe-ingress-cafe.example.com-coffee-svc { server 10.2.13.4:80; <<<<<<< pod地址 } server { listen 80; listen 443 ssl; ssl_certificate /etc/nginx/secrets/default-cafe-secret; ssl_certificate_key /etc/nginx/secrets/default-cafe-secret; server_tokens on; server_name cafe.example.com; if ($scheme = http) { return 301 https://$host:443$request_uri; } location /tea { proxy_http_version 1.1; proxy_connect_timeout 60s; proxy_read_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-cafe-ingress-cafe.example.com-tea-svc; } location /coffee { proxy_http_version 1.1; proxy_connect_timeout 60s; proxy_read_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-cafe-ingress-cafe.example.com-coffee-svc; } } |
[title]ingress的一些问题[/title]
还不能支持较为复杂的LB特性,例如会话保持,nginx controller扩展了ingress可以做会话保持但必须使用nginx plus。
业务规则发生变化,会导致频繁修改ingress配置,且所变化都会引起nginx reload配置,这在大并发,复杂系统环境下可能会产生较大问题
外部访问的入口依赖使用controller所在node的宿主IP,且端口暴露在node IP上,对于多个应用需要同时使用相同端口时候会导致端口冲突
外部访问入口分散在多个node IP上,使得外部统一访问变得困难,且存在潜在的单点故障,一个node 失败,客户端只有重新发起到新的node节点的访问(虽然可以使用dns来轮询这些IP),因此有必要为这些入口访问点构建统一的虚拟IP(漂移IP),这可以通过在k8s环境外部使用其它高级LB来实现,比如F5。或者将多个提供访问的node节点构建为一个集群(比如使用keepalived),可参考 https://jimmysong.io/kubernetes-handbook/practice/edge-node-configuration.html
所以基本上ingress的方案还得需要一个外部LB来做统一的高容量请求入口,ingress只能作为k8s内部的二级LB(且功能有限)。与其这样,不如直接通过将pod暴露给外部LB来直接做负载均衡,可参考:https://www.myf5.net/post/2334.htm
其它缺点:
nginx无图形界面统一管理,nginx plus有 但是是商业版本。
ingress没有业务监控检查功能
只支持http L7
不能混合支持L4/L7 LB
不支持TLS的SNI,以及SSL re-encrypt
(2020.6修改,L4/L7.SNI,ssl passthrough 都能支持了)
文章评论