docker - 如何在 docker traefik 中终止 SSL 以使用 Varnish

标签 docker varnish traefik

我正在使用 docker traefik 并在该 Varnish 后面进行缓存,而我的网站在 Varnish 后面。
这是我的网站和 Varnish 服务的 docker-compose:

version: "3.7"


services:
  dev-ui-service:
    image: mywebsite.ui:latest
    networks:
      - localnetwork

  varnish:
    image: myvarnish:latest
    deploy:
      labels:
        - "traefik.enable=true"
        - "traefik.http.routers.ui.rule=Host(`mydomain.com`)"
        - "traefik.http.routers.ui.entrypoints=web"
        - "traefik.http.services.ui.loadbalancer.server.port=80"
        - "traefik.http.routers.ui-secured.rule=Host(`mydomain.com`)"
        - "traefik.http.routers.ui-secured.entrypoints=web-secured"
        - "traefik.http.routers.ui-secured.tls.certresolver=mytlschallenge"
        - "traefik.docker.network=traefik-proxy"
      mode: replicated
      replicas: 1
      resources:
        limits:
          cpus: '0.5'
          memory: 200M
        reservations:
          cpus: '0.2'
          memory: 20M
    networks:
      - localnetwork
      - traefik-proxy
    depends_on:
      - dev-ui-service

networks:
  localnetwork:
  traefik-proxy:
    external: true
这是我的 default.vcl 文件:
vcl 4.0;
backend default {
  .host = "dev-ui-service";
  .port = "4200";
}

# If you don't include below, header Age in response to client always be 0

sub vcl_deliver {
  # Display hit/miss info
  if (obj.hits > 0) {
    set resp.http.V-Cache = "HIT";
  }
  else {
    set resp.http.V-Cache = "MISS";
  }
  set resp.http.Access-Control-Allow-Origin = "*";
  set resp.http.Access-Control-Allow-Headers = "Accept,Authorization,Cache-Control,Content-Type,DNT,If-Modified-Since,Keep-Alive,Origin,User-Agent,X-Mx-ReqToken,X-Requested-With";
  set resp.http.Allow = "GET, POST";
  set resp.http.Access-Control-Allow-Credentials = "true";
  set resp.http.Access-Control-Allow-Methods = "GET, POST, PUT, DELETE, OPTIONS, PATCH";
  set resp.http.Access-Control-Expose-Headers = "X-Pagination-Total, X-Pagination-Page, X-Pagination-Limit";
}
sub vcl_backend_response {
  if (beresp.status == 200) {
    unset beresp.http.Cache-Control;
    set beresp.http.Cache-Control = "public; max-age=200";
    set beresp.ttl = 200s;
  }
  set beresp.http.Served-By = beresp.backend.name;
  set beresp.http.V-Cache-TTL = beresp.ttl;
  set beresp.http.V-Cache-Grace = beresp.grace;
}
一切都很好,但 Varnish 不支持 https 所以来自 https MISS 的所有请求。
当请求从 traefik 发送到 Varnish 时,如何终止 SSL?

最佳答案

内置 VCL 行为
您的 VCL 扩展了 vcl_deliver 的标准行为。和 vcl_backend_response子程序。因为您没有为 vcl_recv 提供任何逻辑, 将使用 Varnish 的内置 VCL 行为。
事实上,Varnish 总是使用内置的 VCL,除非有问题的子程序被覆盖。
https://github.com/varnishcache/varnish-cache/blob/6.0/bin/varnishd/builtin.vcl
为什么是小姐?

If we look at the built-in VCL for `vcl_recv`, you'll see that there are some caching rules in place:

sub vcl_recv {
    if (req.method == "PRI") {
        /* This will never happen in properly formed traffic (see: RFC7540) */
        return (synth(405));
    }
    if (!req.http.host &&
      req.esi_level == 0 &&
      req.proto ~ "^(?i)HTTP/1.1") {
        /* In HTTP/1.1, Host is required. */
        return (synth(400));
    }
    if (req.method != "GET" &&
      req.method != "HEAD" &&
      req.method != "PUT" &&
      req.method != "POST" &&
      req.method != "TRACE" &&
      req.method != "OPTIONS" &&
      req.method != "DELETE" &&
      req.method != "PATCH") {
        /* Non-RFC2616 or CONNECT which is weird. */
        return (pipe);
    }

    if (req.method != "GET" && req.method != "HEAD") {
        /* We only deal with GET and HEAD by default */
        return (pass);
    }
    if (req.http.Authorization || req.http.Cookie) {
        /* Not cacheable by default */
        return (pass);
    }
    return (hash);
}

当满足以下条件时,会发生缓存未命中:
  • GET 以外的请求方法或 HEAD
  • 该请求包含一个 Authorization标题
  • 该请求包含 Cookie标题

  • The most likely situation is that the requests that cause a MISS contain a cookie.


    如何将失误变成命中
    假设cookies是问题,你应该在vcl_recv里面写一些VCL逻辑并确定保留哪些 cookie 以及应删除哪些 cookie。
    大多数跟踪 cookie 对服务器端没有影响,可以删除。
    其他 cookie 由应用程序使用,无法删除。
    如果特定的 URL 资源需要 cookie 值,您可以使用 return(pass)以确保 Varnish 不会缓存它。
    不需要 cookie 值的其他页面可以剥离这些 cookie 以确保缓存命中。
    对于需要 cookie,但 cookie 值具有较低且可控变化的页面,您可以使用缓存变化并将 cookie 值缓存在 vcl_hash 中。 .

    Again, I'm assuming that cookies are the reason why the cache miss occurs.


    如何优化 TLS 终止
    Varnish 的开源版本不支持原生 TLS,因此需要终止。
    Varnish 通过支持 PROXY protocol 来促进 TLS 终止。 .显然 Traefik supports it as well .
    您可以通过打开一个额外的监听端口在 Varnish 级别启用 PROXY 协议(protocol)。
    而简化的仅 HTTP varnishd命令可能如下所示:
    varnishd -a :80 -f /etc/varnish/default.vcl
    
    由代理供电的 varnishd命令可能如下所示:
    varnishd -a :80 -a :8443,PROXY -f /etc/varnish/default.vcl
    
    如您所见,我在端口 8443 上添加了一个额外的监听接口(interface)仅支持代理流量。端口 80对于常规 HTTP 流量仍然有效。
    然后,您可以配置 Traefik 以终止 TLS 并将流量路由到 Varnish。如果您在 Traefik 上启用 PROXY 协议(protocol),Varnish 将能够利用该协议(protocol)。
    在 VCL 中,您可以使用以下 VCL 片段检测 HTTP/HTTPS 请求:
    vcl 4.1;
    
    import proxy;
    
    sub vcl_recv {
        if (proxy.is_ssl()) {
            set req.http.X-Forwarded-Proto = "https";
        } else {
            set req.http.X-Forwarded-Proto = "http";
        }
    }
    
    然后你可以返回 Vary: X-Forwarded-Proto应用程序中的响应 header ,以创建基于协议(protocol)的缓存变体。
    PROXY 协议(protocol)的另一个优点是 X-Forwarded-For header 始终包含原始客户端的客户端 IP 地址,无论跳数如何。

    关于docker - 如何在 docker traefik 中终止 SSL 以使用 Varnish ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/67457581/

    相关文章:

    amazon-web-services - AWS Docker 部署

    docker - 当未打开端口8080时,Traefik仪表板不显示

    magento - Varnish 缓存清空 Magento 中的购物车

    url - 我可以使用 Varnish 重新格式化我的 URL 参数吗

    centos - 坚持配置 Varnish

    docker - ACME 证书超时与 traefik

    docker - 运行 docker traefik v2.0 以使用自签名证书的问题

    nginx - docker + Nginx : Getting proxy_pass to work

    docker - Newman 报告生成在本地工作,但不是来自 CI

    构建 docker 镜像的文件所有权