我正在使用 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/