首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Varnish:使用Nginx + Docker时后端获取失败

Varnish:使用Nginx + Docker时后端获取失败
EN

Stack Overflow用户
提问于 2017-08-24 00:39:27
回答 1查看 2.1K关注 0票数 1

我有点迷茫,因为我在docker-compose容器中使用的时候遇到了一个带有Varnish的503-error。

varnishlog返回以下内容:

代码语言:javascript
复制
varnish_1  | *   << BeReq    >> 3
varnish_1  | -   Begin          bereq 2 pass
varnish_1  | -   Timestamp      Start: 1503505759.849314 0.000000 0.000000
varnish_1  | -   BereqMethod    GET
varnish_1  | -   BereqURL       /
varnish_1  | -   BereqProtocol  HTTP/1.1
varnish_1  | -   BereqHeader    Host: localhost
varnish_1  | -   BereqHeader    Pragma: no-cache
varnish_1  | -   BereqHeader    Cache-Control: no-cache
varnish_1  | -   BereqHeader    Upgrade-Insecure-Requests: 1
varnish_1  | -   BereqHeader    User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.101 Safari/537.36
varnish_1  | -   BereqHeader    Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8
varnish_1  | -   BereqHeader    Accept-Encoding: gzip, deflate, br
varnish_1  | -   BereqHeader    Accept-Language: de,de-DE;q=0.8,en-US;q=0.6,en;q=0.4
varnish_1  | -   BereqHeader    X-Forwarded-For: 172.18.0.1, 172.18.0.1
varnish_1  | -   BereqHeader    Via: varnish-default
varnish_1  | -   BereqHeader    startedAt: 1503505759.849
varnish_1  | -   BereqHeader    X-Varnish: 3
varnish_1  | -   VCL_call       BACKEND_FETCH
varnish_1  | -   VCL_return     fetch
varnish_1  | -   FetchError     no backend connection
varnish_1  | -   Timestamp      Beresp: 1503505759.849366 0.000052 0.000052
varnish_1  | -   Timestamp      Error: 1503505759.849370 0.000056 0.000004
varnish_1  | -   BerespProtocol HTTP/1.1
varnish_1  | -   BerespStatus   503
varnish_1  | -   BerespReason   Service Unavailable
varnish_1  | -   BerespReason   Backend fetch failed
varnish_1  | -   BerespHeader   Date: Wed, 23 Aug 2017 16:29:19 GMT
varnish_1  | -   BerespHeader   Server: Varnish
varnish_1  | -   VCL_call       BACKEND_ERROR
varnish_1  | -   BerespHeader   Content-Type: text/html; charset=utf-8
varnish_1  | -   BerespHeader   Retry-After: 5
varnish_1  | -   VCL_return     deliver
varnish_1  | -   Storage        malloc Transient
varnish_1  | -   ObjProtocol    HTTP/1.1
varnish_1  | -   ObjStatus      503
varnish_1  | -   ObjReason      Backend fetch failed
varnish_1  | -   ObjHeader      Date: Wed, 23 Aug 2017 16:29:19 GMT
varnish_1  | -   ObjHeader      Server: Varnish
varnish_1  | -   ObjHeader      Content-Type: text/html; charset=utf-8
varnish_1  | -   ObjHeader      Retry-After: 5
varnish_1  | -   Length         278
varnish_1  | -   BereqAcct      0 0 0 0 0 0
varnish_1  | -   End

这是我的default.vcl的内容:

代码语言:javascript
复制
# varnish version 4
vcl 4.0;
import std;
import directors;

# backend start

backend default {
  .host = "web";
  .port = "80";
  .connect_timeout = 30s;
  .first_byte_timeout = 600s;
  .between_bytes_timeout = 1s;
  .probe = {
    .url = "/robots.txt";
    .interval = 10s;
    .timeout = 5s;
    .window = 5;
    .threshold = 3;
  }
}

# backend end


#############
# Housekeeping

# init start
sub vcl_init {
  new magento2 = directors.fallback();
  magento2.add_backend(default);
}
# init end

sub vcl_fini {
  return (ok);
}

#############
# Client side

acl purge {
    "web";
    "php";
    "localhost";
}

sub vcl_recv {
  call custom_ctrl;

  if (req.method == "PURGE") {
      if (client.ip !~ purge) {
          return (synth(405, "Method not allowed"));
      }
      if (!req.http.X-Magento-Tags-Pattern) {
          return (synth(400, "X-Magento-Tags-Pattern header required"));
      }
      ban("obj.http.X-Magento-Tags ~ " + req.http.X-Magento-Tags-Pattern);
      return (synth(200, "Purged"));
  }

  /* We do not support SPDY or HTTP/2.0 */
  if (req.method == "PRI") {
    return (synth(405));
  }

  if (req.restarts == 0) {
    /* set X-Forwarded-For */
    if (req.http.X-Forwarded-For) {
      set req.http.X-Forwarded-For = req.http.X-Forwarded-For + ", " + client.ip;
    } else {
      set req.http.X-Forwarded-For = client.ip;
    }
    /* set Via */
    if (req.http.Via) {
      set req.http.Via = req.http.Via + ", varnish-default";
    } else {
      set req.http.Via = "varnish-default";
    }
    set req.http.startedAt = std.time2real(now, 0.0);
  }



  /* backend selector */
  if (req.url ~ "^/max") {
    set req.backend_hint = magento2.backend();
  }

  if (req.method != "GET" &&
    req.method != "HEAD" &&
    req.method != "PUT" &&
    req.method != "POST" &&
    req.method != "TRACE" &&
    req.method != "OPTIONS" &&
    req.method != "DELETE") {
      /* Non-RFC2616 or CONNECT which is weird. */
      return (pipe);
  }

  /* Implementing websocket support (https://www.varnish-cache.org/docs/4.0/users-guide/vcl-example-websockets.html) */
  if (req.http.Upgrade ~ "(?i)websocket") {
    return (pipe);
  }


  if (req.method != "GET" && req.method != "HEAD") {
    /* We only deal with GET and HEAD by default */
    return (pass);
  }

  /* Not cacheable */
  if (req.http.Authorization) {
    return (pass);
  }

  # no cache request
  if (req.http.Cache-Control == "no-cache" || req.url ~ "cache-control=no-cache") {
    return (pass);
  }

  # Send Surrogate-Capability headers to announce ESI support to backend
  # set req.http.Surrogate-Capability = "key=ESI/1.0";

  # sort the query string
  set req.url = std.querysort(req.url);

  # Bypass shopping cart, checkout and search requests
  if (req.url ~ "/checkout" || req.url ~ "/catalogsearch") {
      return (pass);
  }

  # normalize url in case of leading HTTP scheme and domain
  set req.url = regsub(req.url, "^http[s]?://", "");

  # Cookies
  std.collect(req.http.Cookie);

  # Compression filter. See https://www.varnish-cache.org/trac/wiki/FAQ/Compression
  if (req.http.Accept-Encoding) {
      if (req.url ~ "\.(jpg|jpeg|png|gif|gz|tgz|bz2|tbz|mp3|ogg|swf|flv)$") {
          # No point in compressing these
          unset req.http.Accept-Encoding;
      } elsif (req.http.Accept-Encoding ~ "gzip") {
          set req.http.Accept-Encoding = "gzip";
      } elsif (req.http.Accept-Encoding ~ "deflate" && req.http.user-agent !~ "MSIE") {
          set req.http.Accept-Encoding = "deflate";
      } else {
          # unkown algorithm
          unset req.http.Accept-Encoding;
      }
  }
  # Remove Google gclid parameters to minimize the cache objects
  set req.url = regsuball(req.url,"\?gclid=[^&]+$",""); # strips when QS = "?gclid=AAA"
  set req.url = regsuball(req.url,"\?gclid=[^&]+&","?"); # strips when QS = "?gclid=AAA&foo=bar"
  set req.url = regsuball(req.url,"&gclid=[^&]+",""); # strips when QS = "?foo=bar&gclid=AAA" or QS = "?foo=bar&gclid=AAA&bar=baz"

  # static files are always cacheable. remove SSL flag and cookie
  if (req.url ~ "^/(pub/)?(media|static)/.*\.(ico|css|js|jpg|jpeg|png|gif|tiff|bmp|mp3|ogg|svg|swf|woff|woff2|eot|ttf|otf)$") {
    unset req.http.Https;
    unset req.http.X-Forwarded-Proto;
    unset req.http.Cookie;
  }

  return (hash);
}


sub vcl_pipe {
  # By default Connection: close is set on all piped requests, to stop
  # connection reuse from sending future requests directly to the
  # (potentially) wrong backend. If you do want this to happen, you can undo
  # it here.
  # unset bereq.http.connection;
  if (req.http.upgrade) {
    set bereq.http.upgrade = req.http.upgrade;
  }
  return (pipe);
}


sub vcl_pass {
  return (fetch);
}


sub vcl_hash {

  if (req.http.host) {
    hash_data(req.http.host);
  } else {
    hash_data(server.ip);
  }

  if (req.http.cookie ~ "X-Magento-Vary=") {
    hash_data(regsub(req.http.cookie, "^.*?X-Magento-Vary=([^;]+);*.*$", "\1"));
  }

  # For multi site configurations to not cache each other's content
  if (req.http.host) {
    hash_data(req.http.host);
  } else {
    hash_data(server.ip);
  }

  # To make sure http users don't see ssl warning
  if (req.http.X-Forwarded-Proto) {
    hash_data(req.http.X-Forwarded-Proto);
  }

  return (lookup);
}


sub vcl_purge {
  return (synth(200, "Purged"));
}


sub vcl_hit {
  if (obj.ttl > 0s) {
    # A pure unadultered hit, deliver it
    return (deliver);
  }
  # backend is healthy
  if (std.healthy(req.backend_hint)) {
    # set the stale
    if(obj.ttl + std.duration(std.integer(regsub(obj.http.Cache-Control, "[\s\S]*m-stale=(\d)+[\s\S]*", "\1"), 2) + "s", 2s) > 0s){
      return (deliver);
    }
  } else if (obj.ttl + obj.grace > 0s) {
    # Object is in grace, deliver it
    # Automatically triggers a background fetch
    return (deliver);
  }

  # fetch & deliver once we get the result
  return (miss);
}


sub vcl_miss {
  return (fetch);
}


sub vcl_deliver {
  # Happens when we have all the pieces we need, and are about to send the
  # response to the client.
  #
  # You can do accounting or modifying the final object here.
  set resp.http.X-Hits = obj.hits;
  set req.http.varnishUse = now - std.real2time(std.real(req.http.startedAt, 0.0), now);
  if (resp.http.Server-Timing) {
    if (std.real(req.http.varnishUse, 0) > 0) {
      set resp.http.Server-Timing = "9=" + req.http.varnishUse + ";Varnish," + resp.http.Server-Timing;
    } else {
      set resp.http.Server-Timing = "9=0.000;Varnish," + resp.http.Server-Timing;
    }
  } else {
    if (std.real(req.http.varnishUse, 0) > 0) {
      set resp.http.Server-Timing = "9=" + req.http.varnishUse + ";Varnish";
    } else {
      set resp.http.Server-Timing = "9=0.000;Varnish";
    }
  }
  return (deliver);
}



# custom control
sub custom_ctrl{
  #响应healthy检测
  if(req.url == "/ping"){
    return(synth(701));
  }
  if(req.url == "/varnish/version") {
    return(synth(702));
  }
}


sub vcl_synth {
  if (resp.status == 701) {
    synthetic("pong");
  } elsif (resp.status == 702) {
    synthetic("2017-08-20T16:27:55.780Z");
  }
  set resp.http.Cache-Control = "no-store, no-cache, must-revalidate, max-age=0";
  set resp.status = 200;
  set resp.http.Content-Type = "text/plain; charset=utf-8";
  return (deliver);
}


###############
# Backend Fetch

sub vcl_backend_fetch {
  return (fetch);
}



sub vcl_backend_response {
  if (bereq.uncacheable) {
    return (deliver);
  }

  if (beresp.http.content-type ~ "text") {
      set beresp.do_esi = true;
  }

  # cache only successfully responses and 404s
  if (beresp.status != 200 && beresp.status != 404) {
      set beresp.ttl = 0s;
      set beresp.uncacheable = true;
      return (deliver);
  } elsif (beresp.http.Cache-Control ~ "private") {
      set beresp.uncacheable = true;
      set beresp.ttl = 86400s;
      return (deliver);
  }

  if (beresp.http.X-Magento-Debug) {
      set beresp.http.X-Magento-Cache-Control = beresp.http.Cache-Control;
  }

  # validate if we need to cache it and prevent from setting cookie
  # images, css and js are cacheable by default so we have to remove cookie also
  if (beresp.ttl > 0s && (bereq.method == "GET" || bereq.method == "HEAD")) {
      unset beresp.http.set-cookie;
      if (bereq.url !~ "\.(ico|css|js|jpg|jpeg|png|gif|tiff|bmp|gz|tgz|bz2|tbz|mp3|ogg|svg|swf|woff|woff2|eot|ttf|otf)(\?|$)") {
          set beresp.http.Pragma = "no-cache";
          set beresp.http.Expires = "-1";
          set beresp.http.Cache-Control = "no-store, no-cache, must-revalidate, max-age=0";
          set beresp.grace = 1m;
      }
  }

  # the response body is text, do gzip (judge by response header Content-Type)
  if (beresp.http.Content-Type ~ "text" || beresp.http.Content-Type ~ "application/javascript" || beresp.http.Content-Type ~ "application/json") {
    set beresp.do_gzip = true;
  }

  # The following scenarios set uncacheable
  if (beresp.ttl <= 0s ||
    beresp.http.Set-Cookie ||
    beresp.http.Surrogate-Control ~ "no-store" ||
    (!beresp.http.Surrogate-Control &&
      beresp.http.Cache-Control ~ "no-cache|no-store|private") ||
    beresp.http.Vary == "*"){
    # Hit-For-Pass
    set beresp.uncacheable = true;
    set beresp.ttl = 300s;
    set beresp.grace = 0s;
    return (deliver);
  }

  # Pause ESI request and remove Surrogate-Control header
  if (beresp.http.Surrogate-Control ~ "ESI/1.0") {
    unset beresp.http.Surrogate-Control;
    set beresp.do_esi = true;
  }

  return (deliver);
}

您可能想知道为什么在配置中会有.host = "web" -这是因为docker-compose神奇地为链接服务的docker-compose.yml文件中的每个节点创建了配置,在我的例子中是web作为nginx实例的服务名。

我能够从varnish容器ping web,所以链接是正常的。此外,这也是码头容器的首选用途。

nginx正在监听端口80 (就像内部的清漆)。我之前在8080上试过nginx,但它一直在侦听tcp:80,没有错误输出,所以我试着把两个服务都映射到80端口,它似乎工作得很好;但是,如果我把nginx切换到8080端口,问题就存在了。请记住,如果您在Dockerfile文件中为web-container使用FROM nginx,nginx将始终侦听端口80,因此这也可能不是问题。

很乐意提供更多信息。

EN

回答 1

Stack Overflow用户

发布于 2017-08-24 00:49:07

这个Github问题的答案为我解决了这个问题。看起来,这个调查产生了一些问题。我不知道为什么,但是使用问题本身中标记的较小的配置文件是有效的。

https://github.com/magento/magento2/issues/10165

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/45845170

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档