由于公司的基础环境为 Docker,有项目需要做 ZooKeeper 或者 Spring Cloud 的服务注册,服务注册的 IP 及端口均为 Docker 内部提供,所以需要搭建 Calico 网路来实现宿主机访问。
另测试环境的服务均为 IP + 端口的方式访问,一旦更换宿主机则导致无法调用的情况,所以需要配置域名来访问,而测试环境发布频繁,所以需要服务能自动注册及发现来生成域名。
实验架构网络
Consul 架构图
Calico 架构图
主机名 | IP | 系统 | 组件 |
---|---|---|---|
W708-ATMQZLPR-1 | 172.29.150.202 | Centos 7.2 | consul-Server,registrator,consul-template,nginx-ingress,nginx-host |
W708-ATMQZLPR-2 | 172.29.150.203 | Centos 7.2 | consul-Server,registrator,consul-template,nginx-ingress,nginx-host |
W708-ATMQZLPR-3 | 172.29.150.204 | Centos 7.2 | consul-Server,registrator,consul-template,nginx-ingress,nginx-host |
w708-payyhuat-3 | 172.29.150.199 | Centos 7.2 | consul-client,registrator |
前三台为 Server 服务器,实际上不需要安装 Registrator,此为测试环境,后面的实验过程也是在前 2 台上实现。
具体配置详见 Calico 搭建篇
注意:
CALICO_LIBNETWORK_LABEL_ENDPOINTS=true
,允许 Calico 策略读取 Docker 容器的 label 标签。以下所有的组件安装均为 Docker 容器
1.1 概述
Consul 是 Google 开源的一个使用 Go 语言开发的服务发现、配置管理中心服务。内置了服务注册与发现框架、分布一致性协议实现、健康检查、Key/Value 存储、多数据中心方案,不再需要依赖其他工具(比如 ZooKeeper 等)。服务部署简单,只有一个可运行的二进制的包。每个节点都需要运行 Agent,他有两种运行模式 Server 和 Client。每个数据中心官方建议需要 3 或 5 个 Server 节点以保证数据安全,同时保证 server-leader 的选举能够正确的进行。
1.2 安装配置
下载镜像
docker pull docker.io/consul:latest
创建 Consul 配置
vim /opt/platform/consul/server.json
{
"datacenter": "quark-consul",
"data_dir": "/consul/data",
"server": true,
"ui": true,
"bind_addr": "172.29.150.202",
"client_addr": "127.0.0.1",
"bootstrap_expect": 3,
"retry_join": ["172.29.150.202","172.29.150.203","172.29.150.204"],
"retry_interval": "10s",
"rejoin_after_leave": true,
"skip_leave_on_interrupt": true
}
1.3 配置说明
官方在启动容器的时候是将一部分配置作为 docker run
的参数,而我追求简洁以及配置落地,所以都写到了配置文件里了。
0.0.0.0
,如果有多块网卡,需要指定,否则启动报错127.0.0.1
;额外配置说明(可有可无)
默认端口说明
1.4 启动 consul-server
docker run -d \
--net=host \
--name consul \
-v /opt/platform/consul/config:/consul/config \
-v /opt/platform/consul/data:/consul/data \
consul agent
启动参数说明
这里需要将 config 和 data 挂载出来,以防容器删除的同时,数据被一并删除
1.5 命令
查看集群成员
docker exec consul consul member
查看节点身份
docker exec consul consul info
其他参数自己摸索吧,docker exec consul consul
能看到 help 信息
1.6 Web 访问
浏览器访问http://172.29.150.202:8500/ui
只要是 Server 端开启了 UI,任何一个 Server 都能访问 Web 界面。
2.1 概述
Consul Template 是 HashiCorp 基于 Consul 所提供的可扩展的工具,通过监听 Consul 中的数据变化,动态地修改一些配置文件中地模板。常用于在 Nginx、HAProxy 上动态配置健康状态下的客户端反向代理信息。
Consul Template 和 nginx 必须安装在同一台机器上,因为 Consul Template 需要动态修改 nginx 的配置文件 nginx.conf
,然后执行 nginx -s reload
命令进行路由更新,达到动态负载均衡的目的。
nginx-ingress 是我自己命名的(实现原理跟 k8s 的 ingress 一样),因为此 nginx 主要是负责访问 Calico 网络内的负载均衡,且 Calico 不支持 HTTP 协议的穿透,所以外部需要跟 ingress 通讯的话必须在中间再创建一个 nginx-host 作为转发,后面会介绍。
2.2 原理
2.3 创建 nginx-consul-template 镜像
1. 下载 nginx 镜像
docker pull docker.io/nginx:latest
2. 创建 nginx 脚本
官方及网上大部分的启动 nginx-consul-template 容器最后 ENTRYPOINT 都为 nginx -s reload
,但是因为在重制镜像的时候会将 nginx 镜像中 ENTRYPOINT 的 nginx -g 'daemon off' 给覆盖掉,导致容器在启动的时候 nginx 没有启动,而 nginx -s reload
会去读 /run/nginx.pid
,如果没有则r eload 失败,所以这里新建了一个 nginx 启动及重启的脚本。
# vim nginx.sh
#!/bin/bash
if nginx -t>/dev/null; then
if [[ -s /var/run/nginx.pid ]]; then
nginx -s reload
if [[ $? != 0 ]]; then
rm -f /var/run/nginx.pid
nginx -c /etc/nginx/nginx.conf
fi
else
nginx -c /etc/nginx/nginx.conf
fi
fi
这里做了 3 层判断,先检查 nginx 配置是否正确,然后查看检查 nginx.pid 是否存在且不为空。容器如果退出,会导致 nginx.pid
里面的 ID 号不对,再次启动 nginx 的时候,nginx -s reload
会报错,所以需要再判断 nginx -s reload
是否正确。
3. 创建 nginx-consul-template 的 docker file
# vim nginx-consul-template.df
FROM nginx
MAINTAINER Qingwen Zhang
RUN apt-get update && \
apt-get install --no-install-recommends --no-install-suggests -y unzip && \
rm -r /var/lib/apt/lists/*
ENV CONSUL_TEMPLATE_VERSION 0.19.4
ADD https://releases.hashicorp.com/consul-template/${CONSUL_TEMPLATE_VERSION}/consul-template_${CONSUL_TEMPLATE_VERSION}_linux_amd64.zip /tmp/consul-template.zip
ADD nginx.sh /tmp/nginx.sh
RUN chmod +x /tmp/nginx.sh
RUN unzip /tmp/consul-template.zip -d /usr/bin && \
chmod +x /usr/bin/consul-template && \
rm /tmp/consul-template.zip
RUN mkdir /etc/ctmpl
WORKDIR /etc/ctmpl
ENTRYPOINT ["/usr/bin/consul-template"]
4. 创建镜像
docker build -t 172.29.150.223:5000/nginx-consul-template -f /opt/dockerfile/nginx-consul-template.df .
5. 推送镜像到仓库
docker push 172.29.150.223:5000/nginx-consul-template
2.4 运行 nginx-consul-template
docker run -d \
--restart=always \
--net=calico \
--ip=10.233.49.100 \
--label org.projectcalico.label.role=nginx \
-v /opt/platform/nginx-calico/conf:/etc/nginx \
-v /opt/platform/nginx-calico/modules:/usr/lib/nginx/modules \
-v /opt/platform/nginx-calico/html:/usr/share/nginx/html \
-v /opt/platform/nginx-calico/logs:/var/log/nginx \
-v /opt/platform/nginx-calico/ctmpl:/etc/ctmpl \
--name=calico-nginx1-consul-template \
172.29.150.223:5000/nginx-consul-template \
-consul-addr=172.29.150.202:8500 -wait=5s \
-template="/etc/ctmpl/ctmpl:/etc/nginx/conf.d/app.conf:/tmp/nginx.sh"
启动参数说明
--ip:
nginx-host 反向代理的时候需要固定的 IP,所以这里需要指定 IP。
-v:
因为是 nginx 配置,所有需要将 nginx 可能需要保存的配置及日志等映射出来。
--label:
org.projectcalico.label.role 这里需要配置标签(label),Calico 的 policy 策略需要根据容器的label来做控制流量,后面有针对 policy 详述。
-consul-addr:
指定 Consul 地址。
-template:
ctmpl 为配置模板,app.conf 为生成的 nginx 配置,nginx.sh 为启动及重启 nginx 的脚本。
2.5 创建 ctmpl 模板
vim /opt/platform/nginx-calico/ctmpl
{
{range services}}{
{ if in .Tags "calico" }}{
{$name := .Name}}{
{$service := service .Name}}upstream {
{$name}} {
zone upstream-{
{$name}} 64k;
{
{range $service}} server {
{.Address}}:{
{.Port}} max_fails=3 fail_timeout=60 weight=1;
{
{end}}}
server {
listen 80;
charset utf-8;
server_name {
{$name|toLower|split "-"|join "."}}.flyclock.cn;
access_log /var/log/nginx/{
{.Name}}.log;
location / {
proxy_pass http://{
{$name}};
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_connect_timeout 10s;
proxy_send_timeout 150s;
proxy_read_timeout 150s;
proxy_next_upstream error timeout invalid_header http_404 http_502 http_504 http_500;
}
}
{
{end}}{
{end}}
模板说明
注意:registrator 在向 consul 注册的时候是把所有提供端口服务的容器信息都注册上去,包括了 host 及 bridge 网络下的容器,consul-template 会抓取 consul 上所有的服务信息,而 nginx-consul-template 是在 calico 网络,所以 nginx 只能反向代理到同网络下的服务。因此需要在开头的位置做一层判断过滤 { { if in .Tags "calico" }}
,只生成反向代理到带有 calico tag 容器的配置,而 calico 网络下的容器在启动的时候也必须添加 -e SERVICE_TAG=calico
,不然不会被解析nginx-ingress(calico网络)里面。
至于 ctmpl 的语法结构会在文末贴出官方 git 教程。
最终生成的 nginx 配置如下:
upstream nginx-test {
zone upstream-nginx-test 64k;
server 10.233.49.254:80 max_fails=3 fail_timeout=60 weight=1;
server 10.233.61.129:80 max_fails=3 fail_timeout=60 weight=1;
}
server {
listen 80;
charset utf-8;
server_name nginx.test.flyclock.cn;
access_log /var/log/nginx/nginx-test.log;
location / {
proxy_pass http://nginx-test;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_connect_timeout 10s;
proxy_send_timeout 150s;
proxy_read_timeout 150s;
proxy_next_upstream error timeout invalid_header http_404 http_502 http_504 http_500;
}
}
2.6 创建 Calico policy
Calico 网络有 2 种控制流量的方式,profile 跟 policy。
profile 设置思路是针对网络的,默认配置名称是跟创建网络名字一样。如果针对容器做策略,需要先创建策略,然后针对容器的网络 workloadEndpoint 来应用,而容器只要重启,则相应的workloadEndpoint 也会变化,所以不建议用 profile 来做。
policy 默认可以精细到具体容器,因为他是针对容器的 label 来做的,所以只需要在启动容器的时候添加 --label org.projectcalico.label.role
即容器的默认策略应用的是 policy 的。
vim nginx-policy.yaml
apiVersion: v1
kind: policy
metadata:
name: allow-tcp-80
spec:
selector: role == 'nginx'
types:
- ingress
- egress
ingress:
- action: allow
protocol: tcp
source:
nets:
- 10.233.0.0/16
- 172.0.0.0/8
destination:
ports:
- 80
egress:
- action: allow
配置说明
ingress 是入口,egress 是出口,我们这里需要外部的 nginx-host 反向代理到 Calico 网络的 nginx-ingress,所以只需要 ingress 放行指定 IP 的 TCP 80 即可。
3.1 前言
由于 Calico 网络不支持 HTTP 协议,所以即使你在 iptables 中配置了 NAT 路由,将访问宿主机 80 端口的请求都转发到 nginx-consul-template,外部也无法访问 nginx-ingress。于是我们需要额外启动一个 nginx(docker host 网络),来做反向代理到 nginx-ingress。
另如果你需要不同网卡下面的网络通讯的话,你只需要在 iptables 中添加 NAT 条目即可:
iptables -t nat -N expose-ports
iptables -t nat -A OUTPUT -j expose-ports
iptables -t nat -A PREROUTING -j expose-ports
iptables -t nat -A expose-ports -p tcp --destination 192.0.2.1 --dport 80 -j DNAT --to 192.168.7.4:8080
3.2 运行 nginx-host
docker run -d \
--net=host \
-v /opt/platform/nginx-host/conf:/etc/nginx \
-v /opt/platform/nginx-host/modules:/usr/lib/nginx/modules \
-v /opt/platform/nginx-host/html:/usr/share/nginx/html \
-v /opt/platform/nginx-host/logs:/var/log/nginx \
--name=nginx-host nginx
3.3 配置 nginx
vim /opt/platform/nginx-host/conf/conf.d/default.conf
upstream nginx-calico {
server 10.233.49.100:80;
}
server {
listen 80;
charset utf-8;
server_name *.flyclock.cn;
location / {
proxy_pass http://nginx-calico;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_connect_timeout 10s;
proxy_send_timeout 150s;
proxy_read_timeout 150s;
proxy_next_upstream error timeout invalid_header http_404 http_502 http_504 http_500;
}
}
Consul 的概念上面提过,不做复述
1.1 创建 client.json
vim /opt/platform/consul/config/client.json
{
"datacenter": "quark-consul",
"data_dir": "/consul/data",
"server": false,
"ui": false,
"bind_addr": "172.29.150.199",
"client_addr": "127.0.0.1",
"bootstrap_expect": 0,
"retry_join": ["172.29.150.202","172.29.150.203","172.29.150.204"],
"retry_interval": "10s",
"rejoin_after_leave": true,
"skip_leave_on_interrupt": true
}
配置说明
这里 Client 不需要开启 UI 及 Server,所以均为 false,以及 bootstrap_expect 设为 0 不参与 leader 节点竞争。
1.2 启动 consul-client
docker run -d \
--net=host \
--name consul \
-v /opt/platform/consul/config:/consul/config \
-v /opt/platform/consul/data:/consul/data \
consul agent
2.1 概述
一个由 Go 语言编写的,针对 Docker 使用的,通过检查本机容器进程在线或者停止运行状态,去注册服务的工具。所以我们要做的实验,所有的工具都是在 Docker上运行的,就是因为 Registrator 是通过检查 Docker 容器的状态来判断服务状态的,这样就和我们的代码实现完全解耦了,对上层透明化,无感知。它有如下特点
2.2 下载镜像
这里必须要注意:Registrator 的 lastest 版本已经2年没更新了,他的最新主板本是 master,一定要注意,因为旧的版本无法发现跟自己不是同一个网络的容器
docker pull docker.io/gliderlabs/registrator:master
2.3 启动 Registrator
docker run -d \
--name=registrator \
--net=host \
-v /var/run/docker.sock:/tmp/docker.sock \
gliderlabs/registrator:master \
consul://127.0.0.1:8500
启动参数说明
docker.sock
路径-e SERVICE_ID
参数,指定 Service ID,然后在注册前做判断。如果出现重复情况,可以尝试清空出现数据异常的 Consul 节点的 data 目录。查看网络信息及容器 workloadEndpoint
查看网络
docker network ls
NETWORK ID NAME DRIVER SCOPE
e8447d6e6ca4 bridge bridge local
b69fb4a79dfb calico calico global
b9b2cc4386d6 host host local
ecf16013a029 none null local
查看具体信息
docker network inspect b69fb4a79dfb
其中在 Containers 下就有容器的信息,其中 EndpointID 就是下面提到的 workloadEndpoint
创建指定 IP 地址段的 Calico 网络
docker network create --driver calico --ipam-driver calico-ipam --subnet=10.233.0.0/16 calico
清除无用 calico workloadEndpoint
容器在 calico 服务停止的情况下被删除了,calico 服务再次启动的时候注册到 etcd 里的数据并没会刷新掉被删除容器的信息,如果你启动的是固定IP的容器,则会提示 workloadEndpoint 信息冲突,需要手动去删除
查看
calicoctl get workloadEndpoint
NODE ORCHESTRATOR WORKLOAD NAME
W708-ATMQZLPR-1 libnetwork libnetwork 1b0a02b382530a28e517e2a5099e3cb9cfb1e3d143f4bc2dc60ad31d394c58bb
W708-ATMQZLPR-1 libnetwork libnetwork 517810dea92addc92d02cf37012d9b2945e329fb1e2aa4bf7275ac3bd626dcba
W708-ATMQZLPR-1 libnetwork libnetwork 694840734bffcb79db7b28ece11f2ea9802cce764ebe0d45c55269fc728b3bae
W708-ATMQZLPR-1 libnetwork libnetwork 6e23c48397e6819351f9e0723ee8224d7c59b784029e0bd987095bf51608b077
删除
calicoctl delete workloadEndpoint 8173e77ea4b8dd69f68d21d846e99b27e57140dfdca28346ceeea50d4abc7e84 --node=W708-ATMQZLPR-1 --orchestrator=libnetwork --workload=libnetwork
Docker image:https://hub.docker.com/r/library/consul/
Consul 配置:https://www.consul.io/docs/agent/options.html
Consul Service配置:https://www.consul.io/docs/agent/services.html
Consul HTTP API:https://blog.csdn.net/u010246789/article/details/51871051
Consul 填坑:https://my.oschina.net/u/553243/blog/1634206?p=1&temp=1526522296342#blog-comments-list
博客参考:
http://www.cnblogs.com/cuishuai/p/8194345.html
https://blog.csdn.net/mn960mn/article/details/51753893
https://kevinguo.me/2017/09/01/docker-consul-consul-template-registrator-nginx/#consul
https://www.jianshu.com/p/d8ac9ad495a7
https://blog.csdn.net/socho/article/details/75434733
GitHub(包涵启动及配置):https://github.com/hashicorp/consul-template
配置参考:https://blog.csdn.net/lizhenhe/article/details/80030051
博客参考:https://www.hi-linux.com/posts/36431.html
官网:https://gliderlabs.com/registrator/latest/
官网:https://www.projectcalico.org/
博客参考:http://cizixs.com/2017/10/19/docker-calico-network