为了真实近似模拟线上,下面的配置都是一个服务一个docker-compose.yml文件。
consul
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 1version: '3.3'
2services:
3 consul:
4 image: consul
5 container_name: consul_server
6 network_mode: bridge
7 ports:
8 - 8300:8300
9 - 8301:8301
10 - 8301:8301/udp
11 - 8302:8302
12 - 8302:8302/udp
13 - 8400:8400
14 - 8500:8500
15 - 53:53/udp
16 command: consul agent -data-dir=/tmp/consul -server -bootstrap -domain=zhenhe.li -client=0.0.0.0
17
18
19
2018-04-22 23:06 做出更改:
1.镜像image由原来的progrium/consul 修改为官方的consul, 原因是原来的镜像中consul版本过低没有新特性。官方目前是1.0.7
2.参数变更为 consul agent 开头,同时新版本中要求参数要加入 -client=x.x.x.x 否则默认127.0.0.1 不允许外部ip 访问
新特性包含critical服务定时清除,允许Tags定义覆盖,增加Meta属性(非常有用,在后面的 template 中使用):
请求示例:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 1{
2 "ID": "redis1",
3 "Name": "redis",
4 "Tags": [
5 "primary",
6 "v1"
7 ],
8 "Address": "127.0.0.1",
9 "Port": 8000,
10 "Meta": {
11 "redis_version": "4.0"
12 },
13 "EnableTagOverride": false,
14 "Check": {
15 "DeregisterCriticalServiceAfter": "90m",
16 "HTTP": "http://localhost:5000/health",
17 "Interval": "10s"
18 }
19}
20
响应示例:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 1{
2 "redis1": {
3 "ID": "redis1",
4 "Service": "redis",
5 "Tags": ["primary", "v1"],
6 "Address": "127.0.0.1",
7 "Meta": {
8 "redis_version": "4.0"
9 },
10 "Port": 8000,
11 "EnableTagOverride": false,
12 "CreateIndex": 0,
13 "ModifyIndex": 0
14 }
15}
16
**
registrator
1
2
3
4
5
6
7
8
9
10
11
12
13 1version: '3.3'
2services:
3 registrator:
4 image: gliderlabs/registrator
5 container_name: docker_consul_registrator
6 network_mode: bridge
7 external_links:
8 - consul_server:consul
9 volumes:
10 - /var/run/docker.sock:/tmp/docker.sock
11 command: consul://consul:8500
12
13
上述配置文件中。 network_mode 使用的bridge ,这其中也踩过坑。网上有很多示例是host, 意思是docker 可以与宿主机共有一网套络,就是说进入容器执行ifconfig与宿主机看到的可能是一样的,暴露的端口也占用宿主机端口。后来反复测试发现在mac os中,network_mode=host 这个配置不能达到上述要求。最终在一篇讨论看到结论:Should docker run –net=host work?
讨论中说network_mode=host在linux中可以正常运行,有时间我验证一下。
nginx+consul-template, 这个网上或docker hub上有别人已经做好了,但是模板ctmpl文件都是根据自己的环境编写的,有可能不符合自己的要求,所以这一步还是要自己去pull nginx镜像,加入最新版consul-template,然后commit, push到hub上或自己的仓库中使用。
之所以要用自己的镜像,一个非常重要的原因是consul-template版本还是变更非常快的,它要随着consul版本的变更而变更Struct,用来解析最新的nodes, services等等json结构。 举例,我们本例中会用到的Meta属性就是目前网上现有的consul-template-nginx镜像中包含的consul-template所不能解析的。
自己基于官方nginx 镜像加入最新版的 consul-template,加入自己的ctmpl 模板文件
自定义consul-template-nginx
Dockerfile
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 1FROM nginx
2MAINTAINER LiZhenhe <zhenhe.li@vcg.com>
3
4RUN apt-get update && \
5 apt-get install --no-install-recommends --no-install-suggests -y unzip && \
6 rm -r /var/lib/apt/lists/*
7
8
9ENV CONSUL_TEMPLATE_VERSION 0.19.4
10ADD https://releases.hashicorp.com/consul-template/${CONSUL_TEMPLATE_VERSION}/consul-template_${CONSUL_TEMPLATE_VERSION}_linux_amd64.zip /tmp/consul-template.zip
11
12RUN unzip /tmp/consul-template.zip -d /usr/bin && \
13 chmod +x /usr/bin/consul-template && \
14 rm /tmp/consul-template.zip
15RUN mkdir /etc/ctmpl
16COPY ctmpl /etc/ctmpl
17WORKDIR /etc/ctmpl
18
19ENTRYPOINT ["/usr/bin/consul-template"]
20
ctmpl模板文件, 内容还需要改造。这个模板来自网上,稍后,我基于这个模板加入Meta进行多域名解析的改造,适应我们现在线上环境的需求
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 1{{range services}}
2 upstream {{.Name}} {
3 least_conn;{{range service .Name}}
4 server {{.Address}}:{{.Port}};{{end}}
5 }
6{{end}}
7
8server {
9 listen 80;
10 proxy_set_header Host $host;
11 proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
12 {{range services}}
13 location {{.Name}} {
14 proxy_read_timeout 180;
15 proxy_pass http://{{.Name}}/{{.Name}};
16 }
17 {{end}}
18}
19
线上使用Tags,但不严谨, 应该使用Meta最为严谨安全
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30 1{{range services}}
2 {{$name := .Name}}
3 {{$service := service .Name}}
4 {{$tags := .Tags}}
5
6 upstream {{$name}} {
7 zone upstream-{{$name}} 64k;
8 {{range $service}}
9 server {{.Address}}:{{.Port}} max_fails=3 fail_timeout=60 weight=1;
10 {{else}}
11 server 127.0.0.1:65535;
12 {{end}}
13 }
14 server {
15 listen 80;
16 listen 443;
17 charset utf-8;
18 server_name {{range $tags }} {{.}} {{else}}localhost{{end}};
19 access_log /var/log/nginx/{{$name}}.log;
20 location / {
21 proxy_pass http://{{$name}};
22 proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
23 proxy_set_header Host $host;
24 proxy_set_header X-Real-IP $remote_addr;
25 client_max_body_size 1000m;
26 proxy_buffering off;
27 }
28 }
29{{end}}
30
注意这个ctmpl文件要与上面的Dockerfile放在同上目录下。
执行docker build -t="zhenheli/consul-template-nginx" -f Dockfile .来构建镜像
consul-template-nginx
1
2
3
4
5
6
7
8
9
10
11
12 1version: '3'
2services:
3 consul-template:
4 container_name: consul-template-nginx
5 image: zhenheli/consul-template-nginx
6 network_mode: bridge
7 external_links:
8 - consul_server:consul
9 command: -consul-addr=consul:8500 -wait=5s -template="/etc/ctmpl/ctmpl:/etc/nginx/conf.d/app.conf:nginx -s reload"
10 ports:
11 - 80:80
12
最终由于spring-cloud-consul-client版本过低也无法提供nodeMeta, 退回到使用tags, 不过为了安全起见, 制定了一个规则,
以vcg_domain:开头的才看作是要获取的域名的tag,具体实现如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 1{{range services}} {{$name := .Name}} {{$service := service .Name}} {{$tags := .Tags}}
2upstream {{$name}} {
3zone upstream-{{$name}} 64k;
4{{range $service}}server {{.Address}}:{{.Port}} max_fails=3 fail_timeout=60 weight=1;
5{{else}}server 127.0.0.1:65535;{{end}}
6}
7server {
8 listen 80;
9 listen 443;
10 charset utf-8;
11 access_log /var/log/nginx/{{.Name}}.log;
12 server_name {{range $tag := .Tags}} {{if $tag|contains "vcg_domain:"}} {{$tag|replaceAll "vcg_domain:" ""}}{{else}}localhost{{end}}{{else}}localhost{{end}};
13 location / {
14 proxy_pass http://{{.Name}};
15 proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
16 proxy_set_header Host $host;
17 proxy_set_header X-Real-IP $remote_addr;
18 client_max_body_size 1000m;
19 proxy_buffering off;
20 }
21} {{end}}
22