Docker 部署 Varnish 反向代理软件

容器化的好处是可以非常快速地进行部署并提供服务,越来越多的 Docker 云服务出现,平台也日趋完善,国内的服务商相当给力,给的资源和许多虚拟服务器运营商相比还好很多,许多创业公司提供了一定免费额度的 Docker 云,比如时速云,DaoCloud,灵雀云,阿里淘宝推出了一个基于 Docker 的阿里百川。那么如何用好这些服务?个人认为现阶段拿来搭建反向代理,加速和减轻服务器的压力是比较好的。

Varnish 是这几年比较热门的高效能的反向代理缓存软件,可以非常稳定地支撑高负载的网站,vcl语言强大,但在配置上对运维人员是有一个学习成本的困扰。我见过配置好的运维配置的vcl,非常简洁但逻辑清晰,也见过非常臃肿的vcl配置,非常难以理解且问题不断。比如:https://github.com/comotion/security.vcl 看的我真是头大。。。

这些天测试了国内四个比较有名气的 Docker 云(时速云,DaoCloud,灵雀云,阿里百川),全是在线代码构建的,但阿里百川在使用时会有一些要注意的,Dockerfile 和标准 Docker 有些区别,但构建方式还是大同小异的,感兴趣的童鞋也可以尝试一下。

Docker 代码构建仓库如下:

https://github.com/icodex/docker-varnish

里面就只有两个服务,一个是 TCPROXY 小型的 TCP 代理软件,用于解决其他 tcp 端口代理中继的问题,比如 TLS 443端口。bin 文件只在 Centos 7环境测试过,其他的发行版建议自己编译,代码仓库:

https://github.com/dccmx/tcproxy

简单说明一下使用方式,这里以时速云的平台操作进行演示,因为我在上面已经构建好了可以直接使用的镜像,搜索 Varnish 就可以找到,欢迎使用。

1. 首先注册并登陆时速云

2. 创建服务,创建时搜索关键字 varnish 的镜像

Varnish 4.x build with Docker 0

Varnish 4.x build with Docker 1

3. 选择适合自己的容器配置,进入高级设置设置正确的环境变量

Varnish 4.x build with Docker 2

Varnish-4.x-build-with-Docker-3-1

4. 最后部署启动即可

TenxCloud Build

环境变量的说明:

ENV VARNISH_CACHE_LIMIT "64M" #设置可接受最大缓存文件大小,超过64M 直接 pass 不缓存,小于64M 但大于32M(该值的一半) 的,仍会启用 HTTP Streaming 进行传输。小于32M 则正常传输(即等待 varnish 缓存完毕后再传输)
ENV VARNISH_CNF "" #备用配置,用于覆盖默认 varnish.vcl 配置,默认为空
ENV VARNISH_BACKEND "1.2.3.4:80;2.3.4.5:80;3.4.5.6:80;4.5.6.7:80" #后端服务器地址和端口,一般是后端的80端口,修改为你实际的后端服务器地址,支持多台后端轮询,用英文半角符号";"分隔
ENV VARNISH_FRONT "0.0.0.0:80" #Varnish 监听地址,默认为所有网络接口所有接口的80端口,如无必要不要更改
ENV VARNISHD_PARAMS "-s malloc,128M" #默认使用内存缓存,容量256MiB,具体根据实际容器配置
ENV TCPROXY "" #TCPROXY 服务后端指向,语法请参考 https://github.com/dccmx/tcproxy/blob/master/README.md

测试时,我用了一个免费的万网虚拟主机,上传了一张图片,然后分别在这四个平台进行部署,得到以下测试链接,嗯(⊙_⊙),资金上做到了零成本。

时速云,北京机房:http://apis-icodex.tenxapp.com/pic.jpg
DaoCloud,北京机房:http://varnish.daoapp.io/pic.jpg
灵雀云,上海 AWS 机房:http://apis-icodex.myalauda.cn/pic.jpg
阿里百川,杭州 BGP:http://apis.wx.jaeapp.com/pic.jpg

部署nginx前端优化模块ngx_pagespeed

ngx_pagespeed

ngx_pagespeed 是 Nginx 的一个扩展模块,主要的功能是针对前端页面而进行服务器端的优化,对前端设计人员来说,可以省去优化css、js以及图片的过程。ngx_pagespeed对nginx自身负载能力的提升基本是看不到的,甚至会因为进行服务器端的优化而使系统增加负载;但从减少客户请求数的角度去看,牺牲部分服务器性能还是值得的。ngx_pagespeed模块的主要功能如下:

图像优化:剥离元数据、动态调整,重新压缩
CSS和JavaScript压缩、合并、级联、内联
小资源内联
推迟图像和JavaScript加载
对HTML重写、压缩空格、去除注释等
提升缓存周期

提示:ngx_pagespeed模块目前仍处于开发阶段,功能上与mod_pagespeed相比稍有欠缺。但开源的力量不可小觑,Github上针对ngx_pagespeed Bugs的反馈更新很频繁,基本上都能很快得到解决,使用前务必考虑这点,不建议部署在生产环境。另,系统内GCC版本必须大于4.2。

ngx_pagespeed更新频率较高,建议及时更新到最新版本,而且最好先部署在本地环境中,经过一番测试稳定后再上线生产环境。主要测试方法参考这里:https://github.com/pagespeed/ngx_pagespeed/wiki/Testing

编译nginx和ngx_pagespeed,务必查看官方的材料:
ngx_pagespeed官方 http://ngxpagespeed.com/
Github https://github.com/pagespeed/ngx_pagespeed
Google Developers https://developers.google.com/speed/docs/mod_pagespeed/build_ngx_pagespeed_from_source
这里环境为nginx 1.9.6 和pagespeed 1.10.33.2,步骤如下:

# git clone git://github.com/pagespeed/ngx_pagespeed.git
# cd ngx_pagespeed/
# wget -c https://dl.google.com/dl/page-speed/psol/1.10.33.2.tar.gz
# rm -rf psol
# tar -zxvf 1.10.33.2.tar.gz # expands to psol/
# ./scripts/pagespeed_libraries_generator.sh > /usr/local/nginx/conf/pagespeed_libraries.conf

然后重新编译nginx,首先查看线上使用的编译参数,然后追加ngx_pagespeed模块进去,编译后覆盖到原来nginx的sbin路径,然后重启一下nginx就可以了。

# nginx version: nginx/1.9.6
built by gcc 4.8.3 20140911 (Red Hat 4.8.3-9) (GCC)
built with OpenSSL 1.0.2d 9 Jul 2015
TLS SNI support enabled
configure arguments: --user=www --group=www --prefix=/usr/local/nginx --sbin-path=/usr/sbin/nginx --pid-path=/var/run/nginx.pid --lock-path=/var/run/nginx.lock --error-log-path=/var/log/nginx/error.log --http-log-path=/var/log/nginx/access.log --with-file-aio --with-ipv6 --with-http_geoip_module --with-zlib=/usr/local/src/zlib-1.2.8 --with-openssl-opt=no-krb5 --with-openssl=/usr/local/src/openssl-1.0.2d --with-threads --with-http_v2_module --with-http_ssl_module --with-http_realip_module --with-http_sub_module --with-http_xslt_module --with-http_gunzip_module --with-http_gzip_static_module --with-http_stub_status_module --with-http_addition_module --with-http_image_filter_module --with-http_secure_link_module --with-http_flv_module --with-http_mp4_module --with-google_perftools_module --with-mail --with-mail_ssl_module --with-http_degradation_module --with-libatomic --add-module=/usr/local/src/ngx_pagespeed --with-pcre=/usr/local/src/pcre-8.37 --with-pcre-jit --with-ld-opt=-lrt --with-debug
# make # 只make,接下来不需要make install
# mv /usr/sbin/nginx /usr/sbin/nginx.old # 备份原来的执行文件
# cp objs/nginx /usr/sbin/nginx # 复制刚刚编译好的执行文件
# /usr/sbin/nginx -t # 测试配置文件
nginx: the configuration file /usr/local/nginx/conf/nginx.conf syntax is ok
nginx: configuration file /usr/local/nginx/conf/nginx.conf test is successful

测试通过,然后进行平滑升级nginx,首先发送USR2信号给nginx,然后再优雅退出旧的进程。

# kill -USR2 `cat /var/run/nginx.pid`
# kill -QUIT `cat /var/run/nginx.pid.oldbin`

另外32位系统编译时,需要在./configure 后面加上–with-cc-opt=’-DLINUX=2 -D_REENTRANT -D_LARGEFILE64_SOURCE -march=i686 -pthread’ 。强烈建议在64位系统下使用ngx_pagespeed模块,64位系统并不会比32位系统使用更多内存

安装ngx_pagespeed后第一件事情就去看Google官方帮助文件,必须了解清楚模块的运作和相应过滤器的功能,个人建议是不用开这么多过滤。还要记得打开日志记录以便于查看运行产生的错误,一般在nginx.conf的error处指定日志输出路径(如:error_log /var/log/nginx/error.log info;),nginx启动后在终端中查看日志输出。在你所打开的任何一个过滤器(EnableFilters)后,建议都做这个步骤检查pagespeed是否出错。

个人使用时发现默认的配置会和nginx的rewrite系统有一些不兼容的情况,特别是开启了lazyload_images rewrite_css rewrite_images rewrite_javascript之类的,那么html源码里面出现的ngx_pagespeed_static url地址一访问就会出现404 not found的错误,或者直接rewrite到index.php,那么你需要做一件事:在ngx_pagespeed公用配置里面添加一行,如下红字部分。重点:Discuz论坛不要开启lazyload_images这个过滤器,否则会出现不能显示帖子内的图片附件。

#  Ensure requests for pagespeed optimized resources go to the pagespeed
#  handler and no extraneous headers get set.
location ~ ".pagespeed.([a-z].)?[a-z]{2}.[^.]{10}.[^.]+" { add_header "" ""; }
location ~ "^/ngx_pagespeed_static/" { }
location ~ "^/ngx_pagespeed_beacon$" { }
location /ngx_pagespeed_statistics { allow 127.0.0.1; deny all; }
location /ngx_pagespeed_global_statistics { allow 127.0.0.1; deny all; }
location /ngx_pagespeed_message { allow 127.0.0.1; deny all; }
location /pagespeed_console { allow 127.0.0.1; deny all; }
if ($request_uri ~ "(ngx_pagespeed_([^.]+)/(.*)?)") { break; }

添加之后无需更改原有网站的rewrite规则,即可正常使用。

本站开启了ngx_pagespeed,然后用几个前端测试工具进行测试,在PageSpeed测试环节,本站得到了93分。测试结果可以点击下列地址查看:http://gtmetrix.com/reports/blog.icodex.org/jmELNaSS
http://www.webpagetest.org/result/130510_X8_4Z8/

PageSpeed Insights

总结:经过朋友和自己的多番测试,nginx部署安装前端优化模块ngx_pagespeed还是非常有必要的。
——————————————————– 分割线——————————————————– 继续阅读

如何在 Ubuntu 12.10 下重置Compiz及Unity

升级到Ubuntu 12.10Ubuntu 13.04 之后,如果Unity桌面出错了就无法按照12.04之前的方式执行$ unity –reset 进行重置。

现在有两种方法可以帮助解决重置的问题:
第一种是添加PPA源,安装unity-reset

$ sudo add-apt-repository ppa:amith/ubuntutools
$ sudo apt-get update
$ sudo apt-get install unity-reset

代码在这里查看:https://github.com/phanimahesh/unity-revamp

安装好了在终端执行

$ unity-reset

第二种,如果不想添加PPA源,可以使用dconf-tools Via:How to Reset Unity in Ubuntu 12.10 Quantal

$ sudo apt-get install dconf-tools

然后执行命令重置

$ dconf reset -f /org/compiz/

最后,重启或运行此命令使其生效

$ setsid unity

gif动画:

[技巧]让varnish 忽略大小写

在类unix主机上,文件系统是区分大小写的,但在网络上却需要忽略大小写,比如一些网友上传照片的时候,图片后缀名一般是大写的。这将会导致我们前端缓存服务无法缓存或进行重复缓存,影响效率。
如果使用nginx,在配置location时,可以用~*忽略大小写,例如:
location ~* .(ftpquota|htaccess|htpasswd)?$ { # ~*表示忽略大小写
deny all;
}

配置squid的acl时,可以用-i忽略大小写,例如:
acl domain dstdomain -i icodex.org (-i表示忽略大小写)
http_access deny domain

而在varnish的vcl语法中,可以用(?i)的正则表达式忽略大小写,例如:
if (req.http.referer !~ "(?i)icodex.org") { # (?i)表示忽略大小写
error 404;
}

配置Varnish不缓存特定大小的内容

最近使用的一台Varnish服务器,经常发现把内存资源和磁盘IO资源占满的情况,后面找原因,发现Varnish把一些大文件缓存了,例如一些压缩档。记得以前用Squid时是有相应设置项的,可以不缓存文件大小超过1M的文件。经过Google搜索了一番,发现有篇文章的方法不错,用变通的方法(vcl_fetch 不支持 pass 语法,但支持 restart)解决了我的困扰,遂写日志以记之。

sub vcl_recv {
  /** ... vcl_recv example from above ... */
  /* Bypass cache for large files.  The x-pipe header is
     set in vcl_fetch when a too large file is detected. */
  if (req.http.x-pipe && req.restarts > 0) {
    remove req.http.x-pipe;
    return (pipe);
  }
  /** ... vcl_recv example from above ... */
}
sub vcl_fetch {
  /* Don't try to cache too large files.  It appears
     Varnish just crashes if we don't filter them. */
  if (beresp.http.Content-Length ~ "[0-9]{7,}") {
    set req.http.x-pipe = "1";
    return (restart);
  }
}
sub vcl_pipe {
  set bereq.http.connection = "close";
}

本文参考了:http://devblog.seomoz.org/2011/05/how-to-cache-http-range-requests/
https://www.varnish-cache.org/lists/pipermail/varnish-misc/2010-November/004968.html