kubernetes集群内的服务, 在集群外是无法访问的, 想访问的话, 必须通过一种方式将请求代理进集群内部, ingress就是最为常用的手段, ingress也有许多开源方案,这里以ingress-nginx为例.Nginx Ingress 也是本人最常用集群外对访问方式.
首先会将nginx ingress部署到集群中,然后会聊了聊它的使用方式.
原理
Nginx ingress 本质上就是nginx+Lua, 所以使用过nginx的,其实对它的原理一看就明白.
首先看一下Nginx 的 反向代理模式
在 k8s 系统中,后端服务的变化是十分频繁的,单纯依靠人工来更新nginx 的配置文件几乎不可能,nginx-ingress 由此应运而生。Nginx-ingress 通过监视 k8s 的资源状态变化实现对 nginx 配置文件的自动更新
同样一看便知, 对于使用nginx ingress来说,知道它是怎么样的工作方式感觉就可以了,源码之类的其实没必要过多去解读.
总结 : Ingress-nginx分为3部分:
- nginx-ingress-controller: 通过与 Kubernetes API 交互,动态的去感知集群中 Ingress 规则变化,然后读取它,按照自定义的规则,规则就是写明了哪个域名对应哪个service,生成一段 Nginx 配置,再写到 Nginx-ingress-control的 Pod 里,这个 Ingress Contronler 的pod里面运行着一个nginx服务,控制器会把生成的nginx配置写入/etc/nginx.conf文件中,然后 reload 一下 使用配置生效。以此来达到动态更新问题
- Nginx: 反向代理服务
- Ingress: ingress资源对象
部署
DaemonSet
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 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92
| apiVersion: extensions/v1beta1 kind: DaemonSet metadata: labels: app: ingress-nginx name: nginx-ingress-controller namespace: ingress-nginx spec: revisionHistoryLimit: 10 selector: matchLabels: app: ingress-nginx template: metadata: annotations: prometheus.io/port: "10254" prometheus.io/scrape: "true" labels: app: ingress-nginx spec: affinity: nodeAffinity: requiredDuringSchedulingIgnoredDuringExecution: nodeSelectorTerms: - matchExpressions: - key: beta.kubernetes.io/os operator: NotIn values: - windows containers: - 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: apiVersion: v1 fieldPath: metadata.name - name: POD_NAMESPACE valueFrom: fieldRef: apiVersion: v1 fieldPath: metadata.namespace image: rancher/nginx-ingress-controller:0.21.0-rancher3 imagePullPolicy: IfNotPresent livenessProbe: failureThreshold: 3 httpGet: path: /healthz port: 10254 scheme: HTTP initialDelaySeconds: 10 periodSeconds: 10 successThreshold: 1 timeoutSeconds: 1 name: nginx-ingress-controller ports: - containerPort: 80 hostPort: 80 name: http protocol: TCP - containerPort: 443 hostPort: 443 name: https protocol: TCP readinessProbe: failureThreshold: 3 httpGet: path: /healthz port: 10254 scheme: HTTP periodSeconds: 10 successThreshold: 1 timeoutSeconds: 1 volumeMounts: - mountPath: /etc/localtime name: host-time readOnly: true dnsPolicy: ClusterFirst hostNetwork: true serviceAccount: nginx-ingress-serviceaccount serviceAccountName: nginx-ingress-serviceaccount terminationGracePeriodSeconds: 30 volumes: - hostPath: path: /etc/localtime name: host-time
|
Default http backend
在新版的nginx ingress中,强制需要部署一个默认的后端, 用于处理无法匹配上的请求,就是一个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
| apiVersion: v1 kind: Service metadata: labels: app: default-http-backend name: default-http-backend namespace: ingress-nginx spec: ports: - port: 80 protocol: TCP targetPort: 8080 selector: app: default-http-backend sessionAffinity: None type: ClusterIP --- apiVersion: extensions/v1beta1 kind: Deployment metadata: annotations: labels: app: default-http-backend name: default-http-backend namespace: ingress-nginx spec: selector: matchLabels: app: default-http-backend template: metadata: labels: app: default-http-backend spec: containers: - image: rancher/nginx-ingress-controller-defaultbackend:1.4-rancher1 imagePullPolicy: IfNotPresent livenessProbe: failureThreshold: 3 httpGet: path: /healthz port: 8080 scheme: HTTP initialDelaySeconds: 30 periodSeconds: 10 successThreshold: 1 timeoutSeconds: 5 name: default-http-backend ports: - containerPort: 8080 protocol: TCP resources: limits: cpu: 10m memory: 20Mi requests: cpu: 10m memory: 20Mi
|
Ingress Rule
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| apiVersion: extensions/v1beta1 kind: Ingress metadata: name: fxxk namespace: default spec: rules: - host: fxxk.com http: paths: - backend: serviceName: auth servicePort: 8082 path: /fxxk - backend: serviceName: auth2 servicePort: 8899 path: /client/v1
|
规则使用还是比较清晰的, 一看就明白, ingress支持很多个域名, 最终都会转换成nginx里的server的标准配置.
最后将上述资源apply 到集群中即可.
支持TCP/UDP
其实在Nginx 1.9之后的版本就已经支持了TCP转发了, 因此Nginx Ingress默认也是可以直接使用TCP转发的, 使用了Nginx Ingress这么久,从来都没有关注过这个点
查看了官方文档,使用也比较简单
首先,需要在nginx ingress controller 的daemonset中容器的启动参数增加对TCP/UDP的配置
1 2 3 4 5 6 7 8 9
| spec: containers: - 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
|
--tcp-services-configmap
指定包含tcp的规则的cm, tcp-services这个名字也可以自定义,具体格式下面再说
--udp-services-configmap
指定包含udp的规则的cm
当然,这个configmap可以在其它的namespace下, 比如放在 default的话,则是defalt/tcp-services
来看一下这个tcp-services的cm的内容,非常简单:
1 2 3 4 5 6 7 8
| apiVersion: v1 data: "9000": clickhouse-operator/clickhouse-1box:9000 kind: ConfigMap metadata: name: tcp-services namespace: ingress-nginx
|
要关注的只有data
字段,格式为: out_port: namespaces/svc_name:port
, 即out_port为需要对外暴露的tcp端口, 这个例子表示,需要对外暴露9000端口,通过9000端口进来的TCP请求请转发到ns: clickhouse-operator下的svc: clickhouse-1box的9000端口上
总共就需要这2步,就能够实现对外接收tcp请求了,是不是非常方便.
最后来看看在nginx pod中生成的配置,其实就是转换成了nginx 的stram
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
|
server { preread_by_lua_block { ngx.var.proxy_upstream_name="tcp-clickhouse-operator-clickhouse-1box-9000"; }
listen 9000;
proxy_timeout 600s; proxy_pass upstream_balancer;
}
|
Annotation/Configmap
nginx本身强大的原因之一在于它的很多参数都是可以设置的, 在nginx ingress中也是如此,通过增加configmap及annotation可以自定义非常多的选项, 甚至可以使用自定义模板
比如: 我需要自定义nginx的日志,或者调整一些参数配置,那么就可以使用一个nginx-config的cm, 然后在daemonset中指定使用这个cm即可.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| apiVersion: v1 data: client-body-buffer-size: 10m error-log-level: error http-redirect-code: "301" log-format-upstream: '{"time": "$time_iso8601", "remote_addr": "$proxy_protocol_addr", "x-forward-for": "$proxy_add_x_forwarded_for", "request_id": "$request_id", "remote_user": "$remote_user", "bytes_sent": $bytes_sent, "request_time": $request_time, "status": $status, "vhost": "$host", "request_proto": "$server_protocol", "path": "$uri", "request_query": "$args", "request_length": $request_length, "request_method": "$request_method", "http_referrer": "$http_referer", "http_user_agent": "$http_user_agent" }' proxy-body-size: 10m kind: ConfigMap metadata: labels: app: ingress-nginx name: nginx-configuration namespace: ingress-nginx
|
其它的一些常用配置可参考以下:
annotations列表
configmap列表
问题
- controller启动时提示以下提示:
解决:
nginx-ingress-controller的daemonset中的启动命令中指定了ingress-class, 所以需要相对应
所以最好不要指定ingress-class, 不然以后想增加的时候都会需要与这个对应
- 关于
--annotations-prefix=nginx.ingress.kubernetes.io
在编写ingress规则时经常需要定义一些annotations, annotations-prefix支持使用自定义前缀, 默认值为nginx.ingress.kubernetes.io
,一般情况下不建议修改, 官方支持的annotations列表可参考
参考文章: