kubernetes-handbook/11-ingress解析.md

317 lines
15 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

## 前言
这是kubernete官方文档中[Ingress Resource](https://kubernetes.io/docs/concepts/services-networking/ingress/)的翻译,后面的章节会讲到使用[Traefik](https://github.com/containous/traefik)来做Ingress controller文章末尾给出了几个相关链接。
**术语**
在本篇文章中你将会看到一些在其他地方被交叉使用的术语,为了防止产生歧义,我们首先来澄清下。
- 节点Kubernetes集群中的一台物理机或者虚拟机。
- 集群位于Internet防火墙后的节点这是kubernetes管理的主要计算资源。
- 边界路由器:为集群强制执行防火墙策略的路由器。 这可能是由云提供商或物理硬件管理的网关。
- 集群网络一组逻辑或物理链接可根据Kubernetes[网络模型](https://kubernetes.io/docs/admin/networking/)实现群集内的通信。 集群网络的实现包括Overlay模型的 [flannel](https://github.com/coreos/flannel#flannel) 和基于SDN的[OVS](https://kubernetes.io/docs/admin/ovs-networking/)。
- 服务使用标签选择器标识一组pod成为的Kubernetes[服务](https://kubernetes.io/docs/user-guide/services/)。 除非另有说明否则服务假定在集群网络内仅可通过虚拟IP访问。
## 什么是Ingress
通常情况下service和pod仅可在集群内部网络中通过IP地址访问。所有到达边界路由器的流量或被丢弃或被转发到其他地方。从概念上讲可能像下面这样
```
internet
|
------------
[ Services ]
```
Ingress是授权入站连接到达集群服务的规则集合。
```
internet
|
[ Ingress ]
--|-----|--
[ Services ]
```
你可以给Ingress配置提供外部可访问的URL、负载均衡、SSL、基于名称的虚拟主机等。用户通过POST Ingress资源到API server的方式来请求ingress。 [Ingress controller](https://kubernetes.io/docs/concepts/services-networking/ingress/#ingress-controllers)负责实现Ingress通常使用负载平衡器它还可以配置边界路由和其他前端这有助于以HA方式处理流量。
## 先决条件
在使用Ingress resource之前有必要先了解下面几件事情。Ingress是beta版本的resource在kubernetes1.1之前还没有。你需要一个`Ingress Controller`来实现`Ingress`,单纯的创建一个`Ingress`没有任何意义。
GCE/GKE会在master节点上部署一个ingress controller。你可以在一个pod中部署任意个自定义的ingress controller。你必须正确地annotate每个ingress比如 [运行多个ingress controller](https://github.com/kubernetes/ingress/tree/master/controllers/nginx#running-multiple-ingress-controllers) 和 [关闭glbc](https://github.com/kubernetes/ingress/blob/master/controllers/gce/BETA_LIMITATIONS.md#disabling-glbc).
确定你已经阅读了Ingress controller的[beta版本限制](https://github.com/kubernetes/ingress/blob/master/controllers/gce/BETA_LIMITATIONS.md)。在非GCE/GKE的环境中你需要在pod中[部署一个controller](https://github.com/kubernetes/ingress/tree/master/controllers)。
## Ingress Resource
最简化的Ingress配置
```yaml
1: apiVersion: extensions/v1beta1
2: kind: Ingress
3: metadata:
4: name: test-ingress
5: spec:
6: rules:
7: - http:
8: paths:
9: - path: /testpath
10: backend:
11: serviceName: test
12: servicePort: 80
```
*如果你没有配置Ingress controller就将其POST到API server不会有任何用处*
**配置说明**
**1-4行**跟Kubernetes的其他配置一样ingress的配置也需要`apiVersion``kind`和`metadata`字段。配置文件的详细说明请查看[部署应用](https://kubernetes.io/docs/user-guide/deploying-applications), [配置容器](https://kubernetes.io/docs/user-guide/configuring-containers)和 [使用resources](https://kubernetes.io/docs/user-guide/working-with-resources).
**5-7行**: Ingress [spec](https://github.com/kubernetes/community/blob/master/contributors/devel/api-conventions.md#spec-and-status) 中包含配置一个loadbalancer或proxy server的所有信息。最重要的是它包含了一个匹配所有入站请求的规则列表。目前ingress只支持http规则。
**8-9行**每条http规则包含以下信息一个`host`配置项比如for.bar.com在这个例子中默认是*`path`列表(比如:/testpath每个path都关联一个`backend`(比如test:80)。在loadbalancer将流量转发到backend之前所有的入站请求都要先匹配host和path。
**10-12行**:正如 [services doc](https://kubernetes.io/docs/user-guide/services)中描述的那样backend是一个`service:port`的组合。Ingress的流量被转发到它所匹配的backend。
**全局参数**为了简单起见Ingress示例中没有全局参数请参阅资源完整定义的[api参考](https://releases.k8s.io/master/pkg/apis/extensions/v1beta1/types.go)。 在所有请求都不能跟spec中的path匹配的情况下请求被发送到Ingress controller的默认后端可以指定全局缺省backend。
## Ingress controllers
为了使Ingress正常工作集群中必须运行Ingress controller。 这与其他类型的控制器不同,其他类型的控制器通常作为`kube-controller-manager`二进制文件的一部分运行,在集群启动时自动启动。 你需要选择最适合自己集群的Ingress controller或者自己实现一个。 示例和说明可以在[这里](https://github.com/kubernetes/ingress/tree/master/controllers)找到。
## 在你开始前
以下文档描述了Ingress资源中公开的一组跨平台功能。 理想情况下所有的Ingress controller都应该符合这个规范但是我们还没有实现。 GCE和nginx控制器的文档分别在[这里](https://github.com/kubernetes/ingress/blob/master/controllers/gce/README.md)和[这里](https://github.com/kubernetes/ingress/blob/master/controllers/nginx/README.md)。**确保您查看控制器特定的文档,以便您了解每个文档的注意事项。**
## Ingress类型
### 单Service Ingress
Kubernetes中已经存在一些概念可以暴露单个service查看[替代方案](https://kubernetes.io/docs/concepts/services-networking/ingress/#alternatives)但是你仍然可以通过Ingress来实现通过指定一个没有rule的默认backend的方式。
ingress.yaml定义文件
```Yaml
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: test-ingress
spec:
backend:
serviceName: testsvc
servicePort: 80
```
使用`kubectl create -f`命令创建然后查看ingress
```bash
$ kubectl get ing
NAME RULE BACKEND ADDRESS
test-ingress - testsvc:80 107.178.254.228
```
`107.178.254.228`就是Ingress controller为了实现Ingress而分配的IP地址。`RULE`列表示所有发送给该IP的流量都被转发到了`BACKEND`所列的Kubernetes service上。
### 简单展开
如前面描述的那样kubernete pod中的IP只在集群网络内部可见我们需要在边界设置一个东西让它能够接收ingress的流量并将它们转发到正确的端点上。这个东西一般是高可用的loadbalancer。使用Ingress能够允许你将loadbalancer的个数降低到最少例如假如你想要创建这样的一个设置
```
foo.bar.com -> 178.91.123.132 -> / foo s1:80
/ bar s2:80
```
你需要一个这样的ingress
```yaml
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后
```bash
$ kubectl get ing
NAME RULE BACKEND ADDRESS
test -
foo.bar.com
/foo s1:80
/bar s2:80
```
只要服务s1s2存在Ingress controller就会将提供一个满足该Ingress的特定loadbalancer实现。 这一步完成后您将在Ingress的最后一列看到loadbalancer的地址。
### 基于名称的虚拟主机
Name-based的虚拟主机在同一个IP地址下拥有多个主机名。
```
foo.bar.com --| |-> foo.bar.com s1:80
| 178.91.123.132 |
bar.foo.com --| |-> bar.foo.com s2:80
```
下面这个ingress说明基于[Host header](https://tools.ietf.org/html/rfc7230#section-5.4)的后端loadbalancer的路由请求
```Yaml
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
```
**默认backend**一个没有rule的ingress如前面章节中所示所有流量都将发送到一个默认backend。你可以用该技巧通知loadbalancer如何找到你网站的404页面通过制定一些列rule和一个默认backend的方式。如果请求header中的host不能跟ingress中的host匹配并且/或请求的URL不能与任何一个path匹配则流量将路由到你的默认backend。
### TLS
你可以通过指定包含TLS私钥和证书的[secret](https://kubernetes.io/docs/user-guide/secrets)来加密Ingress。 目前Ingress仅支持单个TLS端口443并假定TLS termination。 如果Ingress中的TLS配置部分指定了不同的主机则它们将根据通过SNI TLS扩展指定的主机名假如Ingress controller支持SNI在多个相同端口上进行复用。 TLS secret中必须包含名为`tls.crt`和`tls.key`的密钥这里面包含了用于TLS的证书和私钥例如
```Yaml
apiVersion: v1
data:
tls.crt: base64 encoded cert
tls.key: base64 encoded key
kind: Secret
metadata:
name: testsecret
namespace: default
type: Opaque
```
在Ingress中引用这个secret将通知Ingress controller使用TLS加密从将客户端到loadbalancer的channel
```yaml
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: no-rules-map
spec:
tls:
- secretName: testsecret
backend:
serviceName: s1
servicePort: 80
```
请注意各种Ingress controller支持的TLS功能之间存在差距。 请参阅有关[nginx](https://github.com/kubernetes/ingress/blob/master/controllers/nginx/README.md#https)[GCE](https://github.com/kubernetes/ingress/blob/master/controllers/gce/README.md#tls)或任何其他平台特定Ingress controller的文档以了解TLS在你的环境中的工作原理。
Ingress controller启动时附带一些适用于所有Ingress的负载平衡策略设置例如负载均衡算法后端权重方案等。更高级的负载平衡概念例如持久会话动态权重尚未在Ingress中公开。 你仍然可以通过[service loadbalancer](https://github.com/kubernetes/contrib/tree/master/service-loadbalancer)获取这些功能。 随着时间的推移我们计划将适用于跨平台的负载平衡模式加入到Ingress资源中。
还值得注意的是尽管健康检查不直接通过Ingress公开但Kubernetes中存在并行概念例如[准备探查](https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-probes/),可以使你达成相同的最终结果。 请查看特定控制器的文档,以了解他们如何处理健康检查([nginx](https://github.com/kubernetes/ingress/blob/master/controllers/nginx/README.md)[GCE](https://github.com/kubernetes/ingress/blob/master/controllers/gce/README.md#health-checks))。
## 更新Ingress
假如你想要向已有的ingress中增加一个新的Host你可以编辑和更新该ingress
```Bash
$ kubectl get ing
NAME RULE BACKEND ADDRESS
test - 178.91.123.132
foo.bar.com
/foo s1:80
$ kubectl edit ing test
```
这会弹出一个包含已有的yaml文件的编辑器修改它增加新的Host配置。
```yaml
spec:
rules:
- host: foo.bar.com
http:
paths:
- backend:
serviceName: s1
servicePort: 80
path: /foo
- host: bar.baz.com
http:
paths:
- backend:
serviceName: s2
servicePort: 80
path: /foo
..
```
保存它会更新API server中的资源这会触发ingress controller重新配置loadbalancer。
```bash
$ kubectl get ing
NAME RULE BACKEND ADDRESS
test - 178.91.123.132
foo.bar.com
/foo s1:80
bar.baz.com
/foo s2:80
```
在一个修改过的ingress yaml文件上调用`kubectl replace -f`命令一样可以达到同样的效果。
## 跨可用域故障
在不通云供应商之间,跨故障域的流量传播技术有所不同。 有关详细信息请查看相关Ingress controller的文档。 有关在federation集群中部署Ingress的详细信息请参阅[federation文档]()。
## 未来计划
- 多样化的HTTPS/TLS模型支持如SNIre-encryption
- 通过声明来请求IP或者主机名
- 结合L4和L7 Ingress
- 更多的Ingress controller
请跟踪[L7和Ingress的proposal](https://github.com/kubernetes/kubernetes/pull/12827),了解有关资源演进的更多细节,以及[Ingress repository](https://github.com/kubernetes/ingress/tree/master)了解有关各种Ingress controller演进的更多详细信息。
## 替代方案
你可以通过很多种方式暴露service而不必直接使用ingress
- 使用[Service.Type=LoadBalancer](https://kubernetes.io/docs/user-guide/services/#type-loadbalancer)
- 使用[Service.Type=NodePort](https://kubernetes.io/docs/user-guide/services/#type-nodeport)
- 使用[Port Proxy](https://github.com/kubernetes/contrib/tree/master/for-demos/proxy-to-service)
- 部署一个[Service loadbalancer](https://github.com/kubernetes/contrib/tree/master/service-loadbalancer) 这允许你在多个service之间共享单个IP并通过Service Annotations实现更高级的负载平衡。
## 参考
[Kubernetes Ingress Resource](https://kubernetes.io/docs/concepts/services-networking/ingress/)
[使用NGINX Plus负载均衡Kubernetes服务](http://dockone.io/article/957)
[使用 NGINX 和 NGINX Plus 的 Ingress Controller 进行 Kubernetes 的负载均衡](http://www.cnblogs.com/276815076/p/6407101.html)
[Kubernetes : Ingress Controller with Træfɪk and Let's Encrypt](https://blog.osones.com/en/kubernetes-ingress-controller-with-traefik-and-lets-encrypt.html)
[Kubernetes : Træfɪk and Let's Encrypt at scale](https://blog.osones.com/en/kubernetes-traefik-and-lets-encrypt-at-scale.html)
[Kubernetes Ingress Controller-Træfɪk](https://docs.traefik.io/user-guide/kubernetes/)
[Kubernetes 1.2 and simplifying advanced networking with Ingress](http://blog.kubernetes.io/2016/03/Kubernetes-1.2-and-simplifying-advanced-networking-with-Ingress.html)