• Post author:
  • Post category:Kubernetes
  • Post comments:0评论
基于 Kubernetes 1.22 版本

一、基础概念

  Ingress 用于管理对集群中服务的外部访问,它可以提供负载均衡、SSL 加密和基于名称的虚拟主机。它可以将不同 URL 的访问请求转发到后端不同的 Service ,以实现 HTTP 层的业务路由机制,流量路由由 Ingress 资源上定义的规则控制。
  使用 Ingress 进行负载分发时, Ingress 控制器将基于 Ingress 规则将客户端请求直接转发到 Service 对应的后端 Endpoint (即 Pod )上,这样会跳过 kube-proxy 的转发功能, kube-proxy 不再起作用。如果 Ingress Controller 提供的是对外服务,则实际上实现的是边缘路由器的功能。
  在使用 Ingress 工作之前,集群必须有一个 Ingress 控制器在运行。常用的有 Nginx、HAProxy、Istio、Traefik 等,这里我选择 Nginx-Ingress。
  Ingress 官方文档:https://kubernetes.io/docs/concepts/services-networking/ingress/
  Nginx-Ingress 相关文档:https://kubernetes.github.io/ingress-nginx/https://github.com/kubernetes/ingress-nginx

二、基本使用

安装 Nginx-Ingress:

# 安装 Nginx-Ingress 控制器
[root@master ~]# kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/main/deploy/static/provider/baremetal/deploy.yaml

# 检查安装是否成功
[root@master ~]# kubectl get pods -n ingress-nginx
NAME                                        READY   STATUS      RESTARTS   AGE
ingress-nginx-admission-create--1-8m7rj     0/1     Completed   0          33s
ingress-nginx-admission-patch--1-j8sdk      0/1     Completed   1          33s
ingress-nginx-controller-644555766d-2mc5c   1/1     Running     0          33s

测试:

# 创建一个简单的 Web 服务器和相关的服务:
[root@master ~]# kubectl create deployment nginx-test --image=nginx --port=80
deployment.apps/nginx created
[root@master ~]# kubectl expose deployment nginx-test 
service/nginx exposed

# 定义一个ingress
[root@master ~]# vim nginx-test-ingress.yaml 
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: ngix-test-ingress
spec:
  ingressClassName: nginx
  rules:
  - host: www.test.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: nginx-test
            port:
              number: 80

[root@master ~]# kubectl apply -f nginx-test-ingress.yaml 
ingress.networking.k8s.io/ngix-test-ingress created   
[root@master ~]# kubectl get ingress ngix-test-ingress 
NAME                CLASS   HOSTS          ADDRESS   PORTS   AGE
ngix-test-ingress   nginx   www.test.com             80      8s
[root@master ~]# kubectl get svc -n ingress-nginx
NAME                                 TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)                      AGE
ingress-nginx-controller             NodePort    10.1.34.184    <none>        80:30912/TCP,443:30820/TCP   130m
ingress-nginx-controller-admission   ClusterIP   10.1.189.224   <none>        443/TCP                      130m


三、定义详解

Ingress 定义说明官方文档:https://kubernetes.io/docs/reference/kubernetes-api/service-resources/
我们来详解下上述例子中 Igress 定义:

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: ngix-test-ingress
spec:
  ingressClassName: nginx       # Ingress控制器名称
  rules:                        # Ingress主机规则列表,如果未指定或没有规则匹配,则所有流量都将发送到默认后端。
  - host: www.test.com          # 主机名称
    http:                       # 指向后端的http选择器列表
      paths:                    # 将请求映射到后端的路径集合
      - path: /                 # 路径
        pathType: Prefix        # 路径类型
        backend:                # 后端,定义了流量将转发到的服务端点
          service:              # 服务名称
            name: nginx-test
            port:               # 服务端口
              number: 80

1、路径

  注意 Ingress path 定义需要与后端真实 Service 提供的 path 一致,否则将会转发到一个不存在的 path 上引发 404 错误。
  路径类型(pathType):

• Prefix:基于 URL 路径前缀按 / 分割的匹配。匹配区分大小写,并按路径元素逐个进行。路径元素是指路径中由 / 分隔符分割的标签列表
• Exact:精确匹配 URL 路径并区分大小写。
• ImplementationSpecific:对于这种路径类型,匹配取决于 IngressClass 类型。可以将其视为单独的路径类型,或将其视为与 Prefix 或 Exact 路径类型相同。

路径匹配示例:

路径类型 路径 请求路径 是否匹配
Prefix / (all paths) Yes
Exact /foo /foo Yes
Exact /foo /bar No
Exact /foo /foo/ No
Exact /foo/ /foo No
Prefix /foo /foo, /foo/ Yes
Prefix /foo/ /foo, /foo/ Yes
Prefix /aaa/bb /aaa/bbb No
Prefix /aaa/bbb /aaa/bbb Yes
Prefix /aaa/bbb/ /aaa/bbb Yes,忽略尾部斜杠
Prefix /aaa/bbb /aaa/bbb/ Yes,匹配尾部斜杠
Prefix /aaa/bbb /aaa/bbb/ccc Yes,匹配子路径
Prefix /aaa/bbb /aaa/bbbxyz No,不匹配字符串前缀
Prefix /, /aaa /aaa/ccc Yes,匹配/aaa前缀
Prefix /, /aaa, /aaa/bbb /aaa/bbb Yes,匹配/aaa/bbb前缀
Prefix /, /aaa, /aaa/bbb /ccc Yes,匹配/前缀
Prefix /aaa /ccc No,使用默认后端
Mixed /foo (Prefix), /foo (Exact) /foo Yes,Exact优先匹配

  在某些情况下,一个 Ingress 中的多个路径会匹配一个请求。在这些情况下,最长的匹配路径将首先获得优先权。如果两个路径仍然相等匹配,则优先于具有确切路径类型的路径而不是前缀路径类型。
  主机可以是精确匹配(例如"foo.bar.com")或通配符(例如"*.foo.com")。精确匹配要求 HTTP host 标头与 host 字段匹配。通配符匹配要求 HTTP host 标头等于通配符规则的后缀。

主机 主机头 是否匹配
.foo.com bar.foo.com 基于共享后缀的匹配
.foo.com baz.bar.foo.com 不匹配,通配符仅涵盖单个 DNS 标签
*.foo.com foo.com 不匹配,通配符仅涵盖单个 DNS 标签

四、Ingress 策略配置

  创建两个不同版本的Web服务器和相关的服务用于以下示例测试,为了方便就不配置后端服务的 path 了,以版本区分(默认的 404 页面会显示 Nginx 服务器的版本号)。

[root@master ingress]# kubectl create deployment service1 --image=nginx:1.18.0 --port=80
[root@master ingress]# kubectl create deployment service2 --image=nginx:1.20.0 --port=80
[root@master ingress]# kubectl expose deployment service1 
[root@master ingress]# kubectl expose deployment service2

[root@master ingress]# kubectl get service
NAME         TYPE        CLUSTER-IP    EXTERNAL-IP   PORT(S)   AGE
service1     ClusterIP   10.1.34.114   <none>        80/TCP    7m20s
service2     ClusterIP   10.1.111.52   <none>        80/TCP    7m19s

[root@master ingress]# kubectl get svc -n=ingress-nginx
NAME                                 TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)                      AGE
ingress-nginx-controller             NodePort    10.1.34.184    <none>        80:30912/TCP,443:30820/TCP   6d22h
ingress-nginx-controller-admission   ClusterIP   10.1.189.224   <none>        443/TCP                      6d22h

1、基于URL的相同虚拟主机

  即同一虚拟主机下,将不同 URL 路径被转发到不同的服务上。这种配置常用于一个网站通过不同的路径提供不同的服务,例如:

# 定义ingress
[root@master ingress]# vim url.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: url-test
spec:
  ingressClassName: nginx
  rules:
  - host: foo.bar.com
    http:
      paths:
      - path: /18
        pathType: Prefix
        backend:
          service:
            name: service1
            port:
              number: 80
      - path: /20
        pathType: Prefix
        backend:
          service:
            name: service2
            port:
              number: 80

[root@master ingress]# kubectl apply -f url.yaml
[root@master ingress]# kubectl get ingress
NAME       CLASS   HOSTS         ADDRESS      PORTS   AGE
url-test   nginx   foo.bar.com   10.0.0.102   80      10m

[root@master ~]# curl -sH 'Host:foo.bar.com' http://10.0.0.100:30912/18 | grep nginx
<hr><center>nginx/1.18.0</center>
[root@master ~]# curl -sH 'Host:foo.bar.com' http://10.0.0.100:30912/20 | grep nginx
<hr><center>nginx/1.20.0</center>

2、基于名称的虚拟主机

即不同的虚拟主机被转发到不同的服务上。这种配置常用于一个网站通过不同虚拟主机提供不同的服务,例如:

[root@master ingress]# vim name.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: name-test
spec:
  ingressClassName: nginx
  rules:
  - host: foo.bar.com
    http:
      paths:
      - pathType: Prefix
        path: "/"
        backend:
          service:
            name: service1
            port:
              number: 80
  - host: bar.foo.com
    http:
      paths:
      - pathType: Prefix
        path: "/"
        backend:
          service:
            name: service2
            port:
              number: 80

[root@master ingress]# kubectl apply -f name.yaml        
[root@master ingress]# kubectl get ingress
NAME        CLASS   HOSTS                     ADDRESS   PORTS   AGE
name-test   nginx   foo.bar.com,bar.foo.com             80      21s

[root@master ingress]# curl -sH 'Host:foo.bar.com' http://10.0.0.100:30912/version | grep nginx
<hr><center>nginx/1.18.0</center>
[root@master ingress]# curl -sH 'Host:bar.foo.com' http://10.0.0.100:30912/version | grep nginx
<hr><center>nginx/1.20.0</center>

3、无虚拟主机

  没有在规则中定义任何虚拟主机,则可以匹配到 Ingress 控制器 IP 地址的任何 Web 流量,而无需基于名称的虚拟主机。
  以下将没有在请求中定义主机名的 IP 地址的任何流量(即没有提供请求标头)到转发 service1。

[root@master ingress]# vim no.yaml 
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: noname-test
spec:
  ingressClassName: nginx
  rules:
  - http:
      paths:
      - pathType: Prefix
        path: "/"
        backend:
          service:
            name: service1
            port:
              number: 80

[root@master ingress]# kubectl  get ingress
NAME          CLASS   HOSTS   ADDRESS      PORTS   AGE
noname-test   nginx   *       10.0.0.102   80      8s

[root@master ingress]# curl -s 10.0.0.100:30912/1 | grep nginx
<hr><center>nginx/1.18.0</center>

五、TLS

我们可以给 Ingress 中的域名设置 TLS 安全证书,使得 Ingress 可以提供 HTTPS 安全访问。
设置的步骤如下:

• 准备好证书文件。 
• 将证书保存到 Kubemetes 的一个 Secret 资源对象上。
• 将该 Secret 对象设置到 Ingress 中。

  Ingress 资源仅支持单个 TLS 端口 443,并假设 TLS 在入口点终止(服务及其 Pod 的流量为明文)。
  如果 Ingress 中的 TLS 配置部分指定了不同的主机,它们会根据通过 SNI TLS 扩展指定的主机名(前提是 Ingress 控制器支持 SNI)在同一端口上复用。
  TLS Secret 必须包含已命名的密钥 tls.crt、tls.key,其中包含用于 TLS 的证书和私钥。
  Secret 定义方式:

1、命令定义
kubectl create secret tls secret-test --key tls.key --cert tls.crt

2、文件定义
apiVersion: v1
kind: Secret
metadata:
  name: testsecret-tls
  namespace: default
data:
  tls.crt: base64 encoded cert
  tls.key: base64 encoded key
type: kubernetes.io/tls

1、单域名

创建自签名证书文件

[root@master ingress]# openssl req -x509 -nodes -days 3650 -newkey rsa:2048 -keyout tls-test-www.key -out tls-test-www.crt -subj "/CN=www.test.com"
[root@master ingress]# ll tls*
-rw-r--r-- 1 root root 1103 Nov 22 23:45 tls-test-www.crt
-rw-r--r-- 1 root root 1708 Nov 22 23:45 tls-test-www.key

选项说明:
-x509:输出x509结构而不是证书
-nodes:不要加密输出密钥
-days:-x509生成的证书有效的天数。
-newkey:生成大小为多少位的RSA密钥
-keyout:要将密钥发送到的文件
-out:输出到的文件
-subj:设置或修改请求主题

创建Secret

[root@master ingress]# kubectl create secret tls test-www --key tls-test-www.key --cert tls-test-www.crt
[root@master ingress]# kubectl get secrets 
NAME                  TYPE                                  DATA   AGE
test-www              kubernetes.io/tls                     2      34s

定义ingress

[root@master ingress]# vim tls-single.yaml 
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: tls-single
spec:
  ingressClassName: nginx
  tls:
  - hosts:
    - www.test.com
    secretName: test-www
  rules:
  - host: www.test.com
    http:
      paths:
      - pathType: Prefix
        path: "/"
        backend:
          service:
            name: service1
            port:
              number: 80

[root@master ingress]# kubectl apply -f tls-single.yaml 
[root@master ingress]# kubectl get ingress
NAME         CLASS   HOSTS          ADDRESS   PORTS     AGE
tls-single   nginx   www.test.com             80, 443   10s

[root@master ingress]# curl -skH 'Host:www.test.com' 'https://10.0.0.100:30820/1' | grep nginx
<hr><center>nginx/1.18.0</center>


2、多域名

(1)单域名证书

创建自签名证书和 Secret:

[root@master ingress]# openssl req -x509 -nodes -days 3650 -newkey rsa:2048 -keyout tls-test-login.key -out tls-test-login.crt -subj "/CN=login.test.com"
[root@master ingress]# kubectl create secret tls test-login --key tls-test-login.key --cert tls-test-login.crt

[root@master ingress]# kubectl get secrets
NAME                  TYPE                                  DATA   AGE
test-login            kubernetes.io/tls                     2      3s
test-www              kubernetes.io/tls                     2      9m24s

定义ingress:

[root@master ingress]# vim tls-multiple1.yaml 
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: tls-multiple1
spec:
  ingressClassName: nginx
  tls:
  - hosts:
    - www.test.com
    secretName: test-www
  - hosts:
    - login.test.com
    secretName: test-login
  rules:
  - host: www.test.com
    http:
      paths:
      - pathType: Prefix
        path: "/"
        backend:
          service:
            name: service1
            port:
              number: 80
  - host: login.test.com
    http:
      paths:
      - pathType: Prefix
        path: "/"
        backend:
          service:
            name: service2
            port:
              number: 80

[root@master ingress]# kubectl apply -f tls-multiple1.yaml 
[root@master ingress]# kubectl get ingress
NAME            CLASS   HOSTS                         ADDRESS   PORTS     AGE
tls-multiple1   nginx   www.test.com,login.test.com             80, 443   6s

[root@master ingress]# curl -skH 'Host:www.test.com' 'https://10.0.0.100:30820/1' | grep nginx
<hr><center>nginx/1.18.0</center>
[root@master ingress]# curl -skH 'Host:login.test.com' 'https://10.0.0.100:30820/1' | grep nginx
<hr><center>nginx/1.20.0</center>


(2)多域名证书

创建自签名多域名证书:

1、创建多域名配置文件
[root@master ingress]# cat test.conf 
[req]
req_extensions = v3_req
distinguished_name = req_distinguished_name
prompt = no

[req_distinguished_name]
commonName = *.test.com

[v3_req]
basicConstraints = CA:FALSE
keyUsage = nonRepudiation, digitalSignature, keyEncipherment
subjectAltName = @alt_names

[alt_names]
DNS.1 = www.test.com
DNS.2 = login.test.com

2、生成csr文件
# 创建私钥
[root@master cert]# openssl genrsa -out test.key 2048

# 生成csr文件
[root@master cert]# openssl req -new -nodes -key test.key -out test.csr -config test.conf

3、生成自签名证书
[root@master cert]# openssl x509 -req -days 3650 -in test.csr -signkey test.key -out test.cert -extensions v3_req -extfile test.conf
Signature ok
subject=/CN=*.test.com
Getting Private key

[root@master cert]# openssl x509 -text -noout -in test.cert | grep -i dns
                DNS:www.test.com, DNS:login.test.com

4、私钥/CSR/证书匹配校验
# 输出Modulus值要相同
openssl x509 -noout -modulus -in test.cert  
openssl rsa -noout -modulus -in test.key
openssl req -noout -modulus -in test.csr

定义ingress:

[root@master ingress]# kubectl create secret tls test --key cert/test.key --cert cert/test.cert

[root@master ingress]# vim tls-multiple2.yaml 
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: tls-multiple2
spec:
  ingressClassName: nginx
  tls:
  - hosts:
    - www.test.com
    - login.test.com
    secretName: test
  rules:
  - host: www.test.com
    http:
      paths:
      - pathType: Prefix
        path: "/"
        backend:
          service:
            name: service1
            port:
              number: 80
  - host: login.test.com
    http:
      paths:
      - pathType: Prefix
        path: "/"
        backend:
          service:
            name: service2
            port:
              number: 80

[root@master ingress]# kubectl apply -f tls-multiple2.yaml
[root@master ingress]# kubectl get ingress
NAME            CLASS   HOSTS                         ADDRESS      PORTS     AGE
tls-multiple2   nginx   www.test.com,login.test.com   10.0.0.102   80, 443   12s

[root@master ingress]# curl -skH 'Host:www.test.com' 'https://10.0.0.100:30820/1' | grep nginx
<hr><center>nginx/1.18.0</center>
[root@master ingress]# curl -skH 'Host:login.test.com' 'https://10.0.0.100:30820/1' | grep nginx
<hr><center>nginx/1.20.0</center>

参考文章:

https://kubernetes.io/docs/
《Kubernetes 权威指南》

发表评论

验证码: − 3 = 1