nginx-proxy 自动反向代理
docker 使得部署应用非常的方便,真正的让在单机部署多个应用成为一键化操作。然而,如果单机中有多个应用需要对外提供服务,用 docker 有时候感觉并不是那么优雅。
如果在单机中需要部署多个应用,而这些应用需要占用同一个端口,比如多个 web 应用同时需要 80/443 端口,或者希望对于来自同一个域名的流量进行 load balance,希望这些流量可以被分发到不同的容器上。这些常见的场景,目前操作起来并不方便。
对于上述场景,常见的做法就是在本地部署一个 nginx,每当有 docker 容器更新的时候,便修改 nginx 的配置文件,使满足需求。
方法很简单,但是繁琐,如果有工具可以把这些操作自动化,那么在使用 docker 的时候,是不是可以节省很多精力。在 daocloud hub 里,的确有这么一样工具,即是 nginx-proxy。这是一个会自动获取容器配置并做好反向代理和负责均衡的 nginx。
部署 nginx-proxy
首先需要把共享使用的端口预留给 proxy,比如 80、443 端口,这样,就可以让打在这两个端口上的流量由 proxy 来分配。其次,因为 proxy 需要获取 docker 容器的配置进行对 nginx 的配置文件修改,因此,需要把 docker.sock
映射到容器中。
docker 启动命令
docker run -d -p 80:80 -v /var/run/docker.sock:/tmp/docker.sock:ro daocloud.io/daocloud/nginx-proxy
建议使用 compose 来配置,yml文件如下:
proxy:
image: daocloud.io/daocloud/nginx-proxy:0.3.6
privileged: false
restart: always
ports:
- 443:443
- 80:80
volumes:
- /var/run/docker.sock:/tmp/docker.sock:ro
反向代理
对于配置好 proxy 的主机,每当在主机上启动一个容器的时候,proxy 都会自动检查该容器是否含有 VIRTUAL_HOST
这个环境变量,当检查到某个刚启动的容器含有这个环境变量时,便会自动修改配置文件,使得这个来自 环境变量描述的域名 的流量会被打在这个容器上。
那么,在启动容器的时候,只需要添加一个环境变量,比如:
hypo_blog:
image: daocloud.io/cmss/hypo-blog:master-796038f
privileged: false
restart: always
ports:
- '4000'
environment:
- VIRTUAL_HOST=blog.ihypo.net
负载均衡
当有多个容器含有相同的 VIRTUAL_HOST
的时候,proxy 便会自动做好负载均衡,如果使用 daocloud 的话:
只需要在容器界面调整容器个数,proxy 会自动做好 load balance。
如果进入 proxy 容器中查看的话,也可以看到生成的配置文件:
upstream blog.ihypo.net {
# dao_hypo_blog_2
server 192.168.0.6:4000;
# dao_hypo_blog_1
server 192.168.0.4:4000;
}
其他
nginx-proxy 的使用非常简单,还支持多域名,多端口,https 等,可以参考镜像的 README
参考
https://github.com/jwilder/nginx-proxy
http://jasonwilder.com/blog/2014/03/25/automated-nginx-reverse-proxy-for-docker/
KMP算法next数组活用之前后缀问题
确切的说这是一篇解题报告(SDUTOJ 2784:http://acm.sdut.edu.cn/sdutoj/problem.php?action=showproblem&problemid=2784)。
前置技能 KMP字符串匹配算法: KMP字符串匹配算法
正如题目中描述:
你的任务是找出一个字串s,s既是String的前缀,又是String的后缀,并且s也出现在String的中间部分(既不是前缀,也不是后缀),s的长度越长越好。
很明显这是一道KMP算法周边题目,说是KMP算法是因为需要计算next数组,说是周边是因为这并不是一道匹配类型的题目。
正如《KMP字符串匹配算法》所说,next数组的目的是保存的匹配过的 S 串中还有多少直接等于 T 串的。但实际上,next中的数值的含义在不同的使用场景还有很多种理解。
比如求前后缀的题目中,我们就可以把next中的数组看做在next[i](next[i]!=0 and next[i] != -1)出,存在重复的字段String[0,next[i]]。
而对于这个题目,对于长度为len-1的字符串,那么next数组的长度为len。
如果在next数组中,如果next[len]为0,这可以说明不存在后缀和前缀相同的情况。如果next[len]不为0,这说明前缀和后缀相同,但是还不能说明中间存在这一循环体。
如果next[len]不为0,而且存在和next[len]一样的值,也就是说在在字符串中间出现了循环题,也就可以断定存在符合题目要求的字符串,而长度就是next[len](也就是后缀和前缀共同的长度)。
但如果串是一个循环串,比如像"papapapa"这种,那么next是递增的。因此不能用上段的方式判断十分满足题目要求。
因此需要判断出去最短循环节之后时候还是循环串。而除去最短循环串,便是String[0,next[len]]。因此,在该串的基础上进行判断,也就是判断next[next[i]]十分还是一个有效的值(非0和非-1),如果有效,说明依然存在字段重复。
因此这个题目就非常清楚了:只需要寻找next[i] == next[len]和判断 next[next[len]] != 0 且 next[next[len]] != -1。
把KMP相关算法封装,这个题目的核心代码就变成了:
/**
* SDUTOJ 2748
* Created by hypo on 15-11-15.
*/
class TestString{
private String str;
private int[] next;
//初始化 顺便获得next数组
public TestString(String str) {
this.str = str;
next = getNext();
}
//获取next数组
private int[] getNext(){
char[] chars = this.str.toCharArray();
int len = chars.length;
int[] next = new int[len + 1];
int k = -1, i = 0;
next[0] = -1;
while(i < len){
if(k == -1 || chars[k] == chars[i]){
i++;
k++;
next[i] = k;
}else{
k = next[k];
}
}
return next;
}
//获得结果 null表示不符合题目要求
public String getAns(){
int len = this.str.length();
if(next[len] == 0){
return null;
}
for(int i = 0;i < len;i++){
if(this.next[i] == next[len]){
return this.str.substring(0,next[len]);
}
}
if (next[next[len]] != 0 && next[next[len]] != -1)
{
return this.str.substring(0,next[next[len]]);
}
return null;
}
}
Copyright © 2020 Powered by MWeb, Theme used GitHub CSS.