术语
在本篇文章中你将会看到一些在其他地方被交叉使用的术语,为了防止产生歧义,我们首先来澄清下。
- 节点:Kubernetes集群中的一台物理机或者虚拟机。
- 集群:位于Internet防火墙后的节点,这是kubernetes管理的主要计算资源。
- 边界路由器:为集群强制执行防火墙策略的路由器。 这可能是由云提供商或物理硬件管理的网关。
- 集群网络:一组逻辑或物理链接,可根据Kubernetes网络模型实现群集内的通信。 集群网络的实现包括Overlay模型的 flannel 和基于SDN的OVS。
- 服务:使用标签选择器标识一组pod成为的Kubernetes服务。 除非另有说明,否则服务假定在集群网络内仅可通过虚拟IP访问。
什么是 Ingress?
通常情况下,service 和 pod 的 IP 仅可在集群内部访问。集群外部的请求需要通过负载均衡转发到 service 在 Node 上暴露的 NodePort 上,然后再由 kube-proxy 通过边缘路由器 (edge router) 将其转发给相关的 Pod 或者丢弃。如下图所示
internet | ------------ [Services]
而 Ingress 就是为进入集群的请求提供路由规则的集合,如下图所示
//这张图说明了ingress 的数据处理流程,客户端通过 service 暴露的端口进去集群,然后数据转发到ingress , ingress 调度到 pods 。这时ingress 通过 kuberneters API 监听pods 对应service 变化,动态修改ingress nginx 配置
Ingress 可以给 service 提供集群外部访问的 URL、负载均衡、SSL 终止、HTTP 路由等。为了配置这些 Ingress 规则,集群管理员需要部署一个 Ingress controller,它监听 Ingress 和 service 的变化,并根据规则配置负载均衡并提供访问入口。
Ingress的组成部分
Nginx:实现负载均衡到pod的集合
Ingress Controller:从集群api获取services对应pod的ip到nginx配置文件中
Ingress:为nginx创建虚拟主机
1.创建ingress-nginx controller 引擎
标准安装 ingress controller 配置文件: https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/static/mandatory.yaml
//需要先创建 ingress-controller ,选择引擎为 nginx 的nginx-ingress-controller
//这一步安装了 ingeess-controller pod
[root@kube ~]# kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/static/mandatory.yaml namespace/ingress-nginx created configmap/nginx-configuration created configmap/tcp-services created configmap/udp-services created serviceaccount/nginx-ingress-serviceaccount created clusterrole.rbac.authorization.k8s.io/nginx-ingress-clusterrole created role.rbac.authorization.k8s.io/nginx-ingress-role created rolebinding.rbac.authorization.k8s.io/nginx-ingress-role-nisa-binding created clusterrolebinding.rbac.authorization.k8s.io/nginx-ingress-clusterrole-nisa-binding created deployment.apps/nginx-ingress-controller created [root@kube ~]# [root@kube ~]# [root@kube ~]# [root@kube ~]# kubectl get namespace NAME STATUS AGE default Active 41d ingress-nginx Active 8s kube-node-lease Active 41d kube-public Active 41d kube-system Active 41d new-namespace Active 6d19h [root@kube ~]#
[root@kube test]# kubectl get pods -n ingress-nginx //检查nginx-ingress-controller 是否创建成功 -n 为指定 namesapce 为 inrgess-nginx NAME READY STATUS RESTARTS AGE nginx-ingress-controller-7995bd9c47-5qkr4 1/1 Running 0 6h4m [root@kube test]#
[root@kube test]# kubectl get pods --all-namespaces -l app.kubernetes.io/name=ingress-nginx --watch //检查是否创建成功 NAMESPACE NAME READY STATUS RESTARTS AGE ingress-nginx nginx-ingress-controller-7995bd9c47-5qkr4 1/1 Running 0 6h53m
2. 创建 ingress-nginx service
本次测试使用的ingress-nginx 是在NodePort 方式发布,因此需要先定义nodeport 类型的service 作为流量入口
[root@kube test]# cat ingress-service.yaml apiVersion: v1 kind: Service metadata: name: ingress-nginx namespace: ingress-nginx labels: app.kubernetes.io/name: ingress-nginx app.kubernetes.io/part-of: ingress-nginx spec: type: NodePort ports: - name: http port: 80 targetPort: 80 protocol: TCP nodePort: 30080 //在所有被允许的 node 上都暴露了相关的端口 - name: https port: 443 targetPort: 443 protocol: TCP nodePort: 30443 selector: app.kubernetes.io/name: ingress-nginx app.kubernetes.io/part-of: ingress-nginx [root@kube test]# kubectl apply -f ingress-service.yaml service/ingress-nginx created [root@kube test]# kubectl get service -n ingress-nginx NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE ingress-nginx NodePort 10.107.89.78 <none> 80:30080/TCP,443:30443/TCP 2m27s [root@kube test]#
3.创建被调度的 service 资源
[root@kube test]# cat ingress-demo.yaml apiVersion: v1 kind: Service //service 部分 metadata: name: myapp-ingress namespace: default spec: selector: app: myapp-ingress ports: - name: http port: 80 targetPort: 80 --- apiVersion: apps/v1 kind: Deployment //deployment 部分 metadata: name: my-ingress namespace: default spec: replicas: 2 selector: matchLabels: app: myapp-ingress release: canary-ingress template: //pods 部分 metadata: labels: app: myapp-ingress release: canary-ingress spec: containers: - name: myapp-pod image: nginx:1.7.9 ports: - name: http containerPort: 80 [root@kube test]#
4.发布 ingress 资源
[root@kube test]# cat ingress-my-ingress.yaml apiVersion: extensions/v1beta1 kind: Ingress metadata: name: testname-ingress spec: rules: - host: zy.ingress.com http: paths: - path: backend: serviceName: myapp-ingress servicePort: 80 [root@kube test]# [root@kube test]# [root@kube test]# kubectl apply -f ingress-my-ingress.yaml ingress.extensions/test-ingress created [root@kube test]# kubectl get ingress NAME HOSTS ADDRESS PORTS AGE test-ingress * 80 20s [root@kube test]# kubectl describe ingress test-ingress Name: test-ingress Namespace: default Address: Default backend: myapp-ingress:80 (10.244.1.17:80,10.244.2.39:80) Rules: Host Path Backends ---- ---- -------- * * myapp-ingress:80 (10.244.1.17:80,10.244.2.39:80) Annotations: kubectl.kubernetes.io/last-applied-configuration: {"apiVersion":"extensions/v1beta1","kind":"Ingress","metadata":{"annotations":{},"name":"test-ingress","namespace":"default"},"spec":{"backend":{"serviceName":"myapp-ingress","servicePort":80}}} Events: Type Reason Age From Message ---- ------ ---- ---- ------- Normal CREATE 69s nginx-ingress-controller Ingress default/test-ingress [root@kube test]#
[root@kube test]# kubectl describe test-ingress //修改了yaml 文件 ,添加了host error: the server doesn't have a resource type "test-ingress" [root@kube test]# kubectl describe ingress test-ingress Name: test-ingress Namespace: default Address: Default backend: default-http-backend:80 (<none>) Rules: Host Path Backends ---- ---- -------- zy.ingress.com myapp-ingress:80 (10.244.1.17:80,10.244.2.39:80) Annotations: kubectl.kubernetes.io/last-applied-configuration: {"apiVersion":"extensions/v1beta1","kind":"Ingress","metadata":{"annotations":{},"name":"test-ingress","namespace":"default"},"spec":{"rules":[{"host":"zy.ingress.com","http":{"paths":[{"backend":{"serviceName":"myapp-ingress","servicePort":80},"path":null}]}}]}} Events: Type Reason Age From Message ---- ------ ---- ---- ------- Normal CREATE 37m nginx-ingress-controller Ingress default/test-ingress Normal UPDATE 12m nginx-ingress-controller Ingress default/test-ingress [root@kube test]#
检查:
[root@kube test]# kubectl exec -n ingress-nginx -it nginx-ingress-controller-7995bd9c47-5qkr4 -- /bin/bash www-data@nginx-ingress-controller-7995bd9c47-5qkr4:/etc/nginx$ cat nginx.conf ..................................... ## start server zy.ingress.com server { server_name zy.ingress.com ; listen 80; set $proxy_upstream_name "-"; set $pass_access_scheme $scheme; set $pass_server_port $server_port; set $best_http_host $http_host; set $pass_port $pass_server_port; ....................................
[root@kube test]# curl http://10.2.61.22:30080/ //在后续添加了 Host 字段因此用ip 访问失败 <html> <head><title>404 Not Found</title></head> <body> <center><h1>404 Not Found</h1></center> <hr><center>openresty/1.15.8.1</center> </body> </html> [root@kube test]# curl http://zy.ingress.com:30080/ //换成域名成功 <!DOCTYPE html> <html> <head> <title>Welcome to nginx!</title> <style> body { 35em; margin: 0 auto; font-family: Tahoma, Verdana, Arial, sans-serif; } </style> </head> <body> <h1>Welcome to nginx!</h1> <p>If you see this page, the nginx web server is successfully installed and working. Further configuration is required.</p> <p>For online documentation and support please refer to <a href="http://nginx.org/">nginx.org</a>.<br/> Commercial support is available at <a href="http://nginx.com/">nginx.com</a>.</p> <p><em>Thank you for using nginx.</em></p> </body> </html> [root@kube test]#
5.Ingress 类型
单服务 Ingress
多服务的 Ingress
虚拟主机 Ingress
TLS Ingress
单服务 Ingress
单服务 Ingress 即该 Ingress 仅指定一个没有任何规则的后端服务。
apiVersion: extensions/v1beta1 kind: Ingress metadata: name: test-ingress spec: backend: serviceName: testsvc servicePort: 80
注:单个服务还可以通过设置
Service.Type=NodePort
或者Service.Type=LoadBalancer
来对外暴露。
多服务的 Ingress
路由到多服务的 Ingress 即根据请求路径的不同转发到不同的后端服务上,比如
foo.bar.com -> 178.91.123.132 -> / foo s1:80
/ bar s2:80
可以通过下面的 Ingress 来定义:
apiVersion: extensions/v1beta1 kind: Ingress metadata: name: test spec: rules: - host: foo.bar.com http: paths: - path: /foo backend: serviceName: s1 servicePort: 80 - path: /bar backend: serviceName: s2 servicePort: 80
使用 kubectl create -f
创建完 ingress 后:
$ kubectl get ing NAME RULE BACKEND ADDRESS test - foo.bar.com /foo s1:80 /bar s2:80
虚拟主机 Ingress
虚拟主机 Ingress 即根据名字的不同转发到不同的后端服务上,而他们共用同一个的 IP 地址,如下所示
foo.bar.com --| |-> foo.bar.com s1:80
| 178.91.123.132 |
bar.foo.com --| |-> bar.foo.com s2:80
下面是一个基于 Host header 路由请求的 Ingress:
apiVersion: extensions/v1beta1 kind: Ingress metadata: name: test spec: rules: - host: foo.bar.com http: paths: - backend: serviceName: s1 servicePort: 80 - host: bar.foo.com http: paths: - backend: serviceName: s2 servicePort: 80
注:没有定义规则的后端服务称为默认后端服务,可以用来方便的处理 404 页面。
TLS Ingress
TLS Ingress 通过 Secret 获取 TLS 私钥和证书 (名为 tls.crt
和 tls.key
),来执行 TLS 终止。如果 Ingress 中的 TLS 配置部分指定了不同的主机,则它们将根据通过 SNI TLS 扩展指定的主机名(假如 Ingress controller 支持 SNI)在多个相同端口上进行复用。
定义一个包含 tls.crt
和 tls.key
的 secret:
apiVersion: v1 data: tls.crt: base64 encoded cert tls.key: base64 encoded key kind: Secret metadata: name: testsecret namespace: default type: Opaque Ingress 中引用 secret: apiVersion: extensions/v1beta1 kind: Ingress metadata: name: no-rules-map spec: tls: - secretName: testsecret backend: serviceName: s1 servicePort: 80
注意,不同 Ingress controller 支持的 TLS 功能不尽相同。 请参阅有关 nginx,GCE 或任何其他 Ingress controller 的文档,以了解 TLS 的支持情况。