Sign inSign up

flagshipio/varnish

By flagshipio

•Updated almost 4 years ago

Varnish image with flagship module built-in

Image
0

381

flagshipio/varnish repository overview

⁠Quick reference

⁠What is varnish

Varnish is an HTTP accelerator designed for content-heavy dynamic web sites as well as APIs. In contrast to other web accelerators, such as Squid, which began life as a client-side cache, or Apache and nginx, which are primarily origin servers, Varnish was designed as an HTTP accelerator. Varnish is focused exclusively on HTTP, unlike other proxy servers that often support FTP, SMTP and other network protocols.

⁠How to use this image.

⁠Basic usage

Create a default.vcl file

# specify the VCL syntax version to use
vcl 4.0;

import std;
import cookie;
import blob;
import header;

# import vmod_flagship to perfom experimentation and feature flag in varnish
import flagship;

# we won't use any static backend, but Varnish still need a default one
backend default none;

# initiate the flagship instance
sub vcl_init {
  flagship.init(envID=std.getenv("FS_ENV_ID"), apiKey=std.getenv("FS_API_KEY"), pollingInterval=std.integer(std.getenv("FS_POLLING_INTERVAL"), 10), logLevel=std.getenv("FS_LOG_LEVEL"), trackingEnabled=std.integer(std.getenv("FS_TRACKING_ENABLED"), 0));
}

sub vcl_recv {
	unset req.http.x-cache;

  # the visitor ID
  set req.http.X-VISITOR-ID = "" + req.xid;

  # initialize the visitor context
  set req.http.X-VISITOR-CONTEXT = "";

  # fillout the chrome device as context for example
  if (req.http.User-Agent ~ "Chrome") {
      set req.http.X-VISITOR-CONTEXT  = "device:chrome";
  } else if (req.http.User-Agent ~ "Mozilla.*Firefox*") {
      set req.http.X-VISITOR-CONTEXT  = "device:firefox";
  } else {
      set req.http.X-VISITOR-CONTEXT  = "device:edge";
  }

  if (req.url ~ "^/") {
    return (synth(200, "Flagship"));
  }

  return(hash);
}

sub vcl_hash {
  # this is where we should call flagship code to compute flag values
  set req.http.X-FS-FLAGVALUES = flagship.compute_flags(req.http.X-VISITOR-ID, req.http.X-VISITOR-CONTEXT);
    
  # you can also call flagship to get flag
  set req.http.X-FS-FLAGSTRING = flagship.get_flag_string(req.http.X-VISITOR-ID, req.http.X-VISITOR-CONTEXT, "color", "white", 1);
      
  # you can also call flagship to get flag
  set req.http.X-FS-FLAGBOOL = flagship.get_flag_bool(req.http.X-VISITOR-ID, req.http.X-VISITOR-CONTEXT, "IsVIP", 0, 1);

  # you can also call flagship to get flag
  set req.http.X-FS-FLAGNUMBER = flagship.get_flag_number(req.http.X-VISITOR-ID, req.http.X-VISITOR-CONTEXT, "price", 9.99, 1);

  # the builtin.vcl will take care of also varying cache on those flag values
  hash_data(req.http.X-FS-FLAGVALUES);
      
}

# Log cache miss, hit, pass, pipe & synth in header
sub vcl_hit {
	set req.http.x-cache = "hit";
}

sub vcl_miss {
	set req.http.x-cache = "miss";
}

sub vcl_pass {
	set req.http.x-cache = "pass";
}

sub vcl_pipe {
	set req.http.x-cache = "pipe uncacheable";
}

sub vcl_synth {
	set resp.http.Content-Type = "text/html; charset=utf-8";
  set resp.http.Retry-After = "5";
  set resp.body = {"<!DOCTYPE html>
<html>
  <head>
    <title>"} + resp.reason + {"</title>
  </head>
  <body>
    <h1>"} + resp.reason + {"</h1>
    <p>Visitor ID: "} + req.http.X-VISITOR-ID + {"</p>
    <p>Visitor context: "} + req.http.X-VISITOR-CONTEXT + {"</p>
    <p>Flagship getAllFlags: "} + req.http.X-FS-FLAGVALUES + {"</p>
  </body>
</html>
"};

  return (deliver);
}

# This function is used when a request is sent by our backend
sub vcl_backend_response {
  # If we find our layout cookie we copy it to a header and then we remove it so we can cache the page
  # Later after we deliver the page from cache we set the cookie from the header and then remove that header
  if ( beresp.http.Set-Cookie ) {
    set beresp.http.fs-cookie = beresp.http.Set-Cookie;
    unset beresp.http.Set-Cookie;
  }
}

sub vcl_deliver {

  if(resp.http.fs-cookie){
    set resp.http.Set-Cookie = resp.http.fs-cookie;
    unset resp.http.fs-cookie;
  }

  # Add flagship values to cookie if set
  if (req.http.X-FS-FLAGVALUES) {
    header.append(resp.http.Set-Cookie,"FS-FLAGVALUES=" + blob.transcode(encoded=req.http.X-FS-FLAGVALUES, encoding=URL) + "; Domain=localhost");
  } 

  if (obj.uncacheable) {
		set resp.http.x-cache = req.http.x-cache + " uncacheable" ;
	} else {
		set resp.http.x-cache = req.http.x-cache + " cached" ;
	}
}

Then run:

# we need the configuration file at /etc/varnish/default.vcl,
# our workdir has to be mounted as tmpfs to avoid disk I/O,
# and we'll use port 8080 to talk to our container (internally listening on 80)
docker run -it -p 8080:80 -t --name varnish-standalone \
 -v /path/to/default.vcl:/etc/varnish/default.vcl:ro \
 --tmpfs /var/lib/varnish/varnishd:exec \
 -e "FS_ENV_ID=ENV_ID" \
 -e "FS_API_KEY=API_KEY" \
 -e "FS_POLLING_INTERVAL=50" \
 -e "FS_LOG_LEVEL=debug" \
 -e "FS_TRACKING_ENABLED=0" \
 flagshipio/varnish:7.2

From there, you can visit localhost:8080 in your browser and see the example homepage.

⁠Reloading the configuration

The images all ship with varnishreload⁠ which allows you to easily update the running configuration without restarting the container (and therefore losing your cache). At its most basic, you just need this:

# update the default.vcl in your container
docker cp new_default.vcl running_container:/etc/varnish/default.vcl
# run varnishreload
docker exec running_container varnishreload

Note that varnishreload also supports reloading other files (it doesn't have to be default.vcl), labels (l), and garbage collection of old labeles (-m) among others. To know more, run

docker run varnish varnishreload -h

⁠License

Apache License.⁠

Tag summary

Content type

Image

Digest

sha256:0556564c4…

Size

207.9 MB

Last updated

almost 4 years ago

docker pull flagshipio/varnish:7.2