文章目录

  • ingress-nginx 的模板解读
  • server 段
  • SERVER template
  • 测试修改 ingress-nginx template
  • 测试访问 ingress-nginx 的静态资源


  • version: nginx-ingress-controller:0.29.0

ingress-nginx 的模板解读

本文简单介绍了 ingress-nginx template,并稍做修改,像原生一样使用 ingress-nginx 来处理静态资源的请求。

根据Custom NGINX template中的说明,其模板位于 /etc/nginx/template/nginx.tmpl

使用 kubectl cp 将其cp到外面进行查看。

server 段

# server 段中使用了 template 语句,所有的虚拟主机都是用 SERVER 模板生成的

{{ range $server := $servers }}
...
{{ template "SERVER" serverConfig $all $server }}
...
{{ end}}


# 其中 serverConfig 是一个函数在 internal/ingress/controller/template/template.go 中

"serverConfig": func(all config.TemplateConfig, server *ingress.Server) interface{} {
        return struct{ First, Second interface{} }{all, server}
}

# 函数的作用就是把 $all $server 变成一个结构体,分别对应 First, Second
# 所以在 {{ define "SERVER" }} 中的前两行也只是得到 $all $server 这两个值
{{ $all := .First }}
{{ $server := .Second }}

全局变量 $all$servers

# all 就是 .
{{ $all := . }}

# $server 是遍历 $servers 的
{{ range $server := $servers }}

# $servers 是 .Servers
{{ $servers := .Servers }}

SERVER template

# SERVER 开始 775 行,
# 这里的 path 是遍历 server.Locations ,即使没有 / 时也会自动加上,这个是实践出来的, 而其他的 location 就是 ingress 中的 path 了, 每一个 host 会生成一个虚拟主机的配置,即一个 server 段

{{ range $location := $server.Locations }} 
...
{{ $path := buildLocation $location $enforceRegex }}
...
location {{ $path }}
...
{{ end }}

测试修改 ingress-nginx template

现在的目的是修改 location {{ $path }} 处,为其增加一个判断,如果 nginx.ingress.kubernetes.io/server-snippet 中有 location / {} 的配置时,就跳过 location / 的生成。这样可以使用自己指定的 location /,就可以实现 ingress-nginx 处理静态请求了。

要不然的话,使用 nginx.ingress.kubernetes.io/app-root: /test 是生成一个 302 的跳转:

如创建ingress资源如下:

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  labels:
    app: test1
    env: test
    tier: frontend
  name: test1
  namespace: default
  annotations:
    nginx.ingress.kubernetes.io/server-alias: test2.mytest.com
    # 这里使用此注释指向 /test1
    nginx.ingress.kubernetes.io/app-root: /test1/
    nginx.ingress.kubernetes.io/server-snippet: |
          listen 8032;
          # 这里定义了静态资源的location
          location /test1 {
             root /data/apps/opt/web;
             index index.html;
          }
  spec:
    rules:
    - host: test1.mytest.com
      http:
        paths:
        - backend:
            serviceName: sample-app
            servicePort: 8080
          path: /sample

生成的nginx配置如下:

# SERVER template 中的定义
if ($uri = /) {
    return 302 {{ $location.Rewrite.AppRoot }};
}

# 渲染后的结果
if ($uri = /) {                                                    
    return 302 $scheme://$http_host/test1/;                     
}

访问效果如下:

# curl -i -H 'host: test1.mytest.com' http://10.111.32.9
HTTP/1.1 302 Moved Temporarily
Date: Mon, 28 Sep 2020 05:30:13 GMT
Content-Type: text/html
Content-Length: 138
Connection: keep-alive
Location: http://test1.mytest.com/test1/

HTTP/1.1 200 OK
Server: nginx/1.17.8
Date: Mon, 28 Sep 2020 05:30:13 GMT
Content-Type: text/html
Content-Length: 15
Last-Modified: Mon, 28 Sep 2020 04:45:25 GMT
Connection: keep-alive
ETag: "5f716a65-f"
Accept-Ranges: bytes

<h1>test1</h1>

或者自己使用 rewrite 生成一个规则,也都是类似的情况,反正你的 / 不能直接处理静态请求。

其默认加载的函数中有 contains: strings.Contains, 但是这个函数并不完全准确,比如说 location / { 中多一个空格的话,就会检测失败。

  • 如果 location / { 中间的空格多了,是不行的
  • 这种判断太粗糙了,如果是 # location / 也是会被匹配到的,然而实际上这是注释的

在 location 前添加判断

{{ if contains $server.ServerSnippet "location / {" }}
        {{ if eq $path "/" }}
            {{ $path = "/nolocation" }}
        {{ end }}
{{ end }}
location {{ $path }} {
...
}

这样过后,如果有如下的ingress资源,那么就可以正常的处理 / 的请求了(静态资源需要自己预先挂载)

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  labels:
    app: test1
    env: test
    tier: frontend
  name: test1
  namespace: default
  annotations:
    nginx.ingress.kubernetes.io/server-alias: test2.mytest.com
    #nginx.ingress.kubernetes.io/app-root: /test1
    nginx.ingress.kubernetes.io/server-snippet: |
          listen 8032;
          location / {
             root /data/apps/opt/web;
             index index.html;
          }
spec:
  rules:
  - host: test1.mytest.com
    http:
      paths:
      - backend:
          serviceName: sample-app
          servicePort: 8080
        path: /sample

测试访问 ingress-nginx 的静态资源

# 使用虚拟主机
# curl -i -H 'host: test1.mytest.com' http://10.111.32.9
HTTP/1.1 200 OK
Server: nginx/1.17.8
Date: Mon, 28 Sep 2020 05:59:13 GMT
Content-Type: text/html
Content-Length: 15
Last-Modified: Mon, 28 Sep 2020 04:45:25 GMT
Connection: keep-alive
ETag: "5f716a65-f"
Accept-Ranges: bytes

<h1>test1</h1>

# 使用端口
# curl -i  http://10.111.32.9:8032
HTTP/1.1 200 OK
Server: nginx/1.17.8
Date: Mon, 28 Sep 2020 05:59:21 GMT
Content-Type: text/html
Content-Length: 15
Last-Modified: Mon, 28 Sep 2020 04:45:25 GMT
Connection: keep-alive
ETag: "5f716a65-f"
Accept-Ranges: bytes

<h1>test1</h1>

参考

  • : K8S 源码探秘 之 nginx-ingress 工作原理分析
  • https://kubernetes.github.io/ingress-nginx/user-guide/nginx-configuration/custom-template/ : Custom NGINX template