K8s Ingress

什么是Ingress

Ingress是k8s以http或https的方式,使用nginx,根据URL规则(这些URL可在集群外访问),将请求转发给对应的service。

使用Ingress的前置条件

需要在k8s中运行ingress controller。使用RKE安装的K8s集群已经支持使用Ingress。

Ingress的描述文件

一个Ingress描述文件的例子如下:

apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
  name: test-ingress
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: /
spec:
  rules:
  - http:
      paths:
      - path: /testpath
        backend:
          serviceName: test
          servicePort: 80

此时,我们访问集群节点的/testpath这个URL,k8s会把请求转发给test服务。

Ingress规则

每一条Ingress规则包含如下信息:

  • host(可选):需要填写域名。如果配置了此项,Ingress规则仅对这个host生效。如果没有配置,这条规则对所有的host生效。这里判断标准是Request header里头HOST的值。
  • paths列表:列出了所有URL路径和后台service以及端口的对应关系。
  • backend:需要指明和path对应的服务和端口号,这样访问这个path的时候,请求会被转发到backend服务中。

查看Ingress的信息

执行

[root@k8s ~]# kubectl get ingress
NAME           HOSTS   ADDRESS           PORTS   AGE
test-ingress   *       192.168.100.128   80      97m

可以得到类似的输出。我们可以通过ADDRESS一栏的地址访问ingress对应的服务。

Ingress使用例子

单服务Ingress

单服务的Ingress只有一个backend。甚至我们可以不用写rules,仅仅指定一个default backend。例子如下:

apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
  name: test-ingress
spec:
  backend:
    serviceName: testsvc
    servicePort: 80

在这个例子中,testsvc是一个default backend。

不匹配所有规则的请求会被转发到default backend。因此使用这种配置方式配置单服务Ingress比较简便。

多服务Ingress

apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
  name: simple-fanout-example
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: /
spec:
  rules:
  - host: foo.bar.com
    http:
      paths:
      - path: /foo
        backend:
          serviceName: service1
          servicePort: 4200
      - path: /bar
        backend:
          serviceName: service2
          servicePort: 8080

配置达到的效果解释如下:

  • 一个请求头HOST为foo.bar.com到达该节点,如果请求URL为/foo,请求会被转发给service1的4200端口。
  • 一个请求头HOST为foo.bar.com到达该节点,如果请求URL为/bar,请求会被转发给service2的8080端口。

基于域名的虚拟主机

Ingress使用多个host的例子:

spec:
  rules:
  - host: foo.example.com
    http:
      paths:
      - path: /
        backend:
          serviceName: foo
          servicePort: 80
  - host: bar.example.com
    http:
      paths:
      - path: /
        backend:
          serviceName: bar
          servicePort: 80

k8s会判断请求头的host的内容。如果是foo.example.com访问foo服务,如果是bar.example.com则访问bar服务。

下面这个例子和上述的类似,只是如果请求头没有HOST,会被转发给service3。

apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
  name: name-virtual-host-ingress
spec:
  rules:
  - host: first.bar.com
    http:
      paths:
      - backend:
          serviceName: service1
          servicePort: 80
  - host: second.foo.com
    http:
      paths:
      - backend:
          serviceName: service2
          servicePort: 80
  - http:
      paths:
      - backend:
          serviceName: service3
          servicePort: 80

TLS支持

Ingress支持加密链接的访问模式。

配置步骤如下:

  1. 生成TLS证书。
$ openssl genrsa -out tls.key 2048
$ openssl req -new -x509 -key tls.key -out tls.cert -days 360 -subj /CN=kubia.example.com
  1. 创建一个Secret
kubectl create secret tls tls-secret --cert=tls.cert --key=tls.key
  1. 创建一个Ingress,使用上一步创建出的Secret
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: kubia
spec:
  tls:
  - hosts:
    - kubia.example.com
    secretName: tls-secret
  rules:
    - host: kubia.example.com
      http:
        paths:
        - path: /
          backend:
            serviceName: kubia-nodeport
            servicePort: 80

注意:tls配置的hosts需要和TLS证书中CN的值一致。

Ingress Path Rewrite

通常来说访问service内部的URL和它对应的Ingress入口URL是不同的。为了满足这个要求,Kubernetes提供了Path Rewrite(路径重写)。可以通过正则表达式语法,配置Ingress入口URL和访问service URL的对应关系。

配置Path Rewrite的方法为在Ingress中的annotations配置项中,增加如下配置:

nginx.ingress.kubernetes.io/rewrite-target: rewrite规则

下面讲解几个path rewrite规则示例:

apiVersion: networking.extensions/v1beta1
kind: Ingress
metadata:
  name: ingress-echo-with-rewrite
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: /
spec:
  rules:
  - host: rewrite.example
    http:
      paths:
      - path: /svc1/
        backend:
          serviceName: svc1
          servicePort: 80

这个配置会将http://rewrite.example/svc1/xxx重写为访问svc1的/路径。/svc1/xxx会全被改写为/,即原始URL/svc1后面的东西统统会被丢掉。

如何在访问svc1的时候去掉/svc1前缀,但又不会丢掉前缀之后的内容呢?下面的例子可以满足这个要求:

apiVersion: networking.extensions/v1beta1
kind: Ingress
metadata:
  name: ingress-echo-with-rewrite
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: /$1
spec:
  rules:
  - host: rewrite.example
    http:
      paths:
      - path: /svc1/(.*)
        backend:
          serviceName: svc1
          servicePort: 80

上面的rewrite规则将http://rewrite.example/svc1/xxx重写为访问svc1的/xxx

其中$1path中的第一个捕获组的内容。意思为将URL/svc1部分去掉,剩下的部分保留,用于访问svc1。

按照官方文档的说法,我们可以在rewrite规则中使用$1$2$n来获取path配置项中的第1个,第二个乃至第n个捕获组。

参考链接

使用OpenSSL生成自签名SSL证书
Ingress Path Rewrite官网示例

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容