概述
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協議的穿透,所以外部需要跟inress,通訊的話必須在中間再創建一個nginx-host作為轉發,后面會介紹。
原理
通過 Nginx 自身實現負載均衡和請求轉發;
通過 Consul-template 的 config 功能實時監控 Consul 集群節點的服務和數據的變化;
實時的用 Consul 節點的信息替換 Nginx 配置文件的模板,並重新加載配置文件;
下載nginx鏡像
docker pull docker.io/nginx:latest
創建nginx腳本
官方及網上大部分的啟動nginx-consul-template容器最后ENTRYPOINT都為nginx -sreload,但是因為在重制鏡像的時候會將nginx鏡像中ENTRYPOINT的nginx -g 'daemonoff'給覆蓋掉,導致容器在啟動的時候nginx沒有啟動,而nginx -s reload會去讀/run/nginx.pid,如果沒有則reload失敗,所以這里新建了一個nginx啟動及重啟的腳本。
#!/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是否正確
創建nginx-consul-template的docker file
vim nginx-consul-template.df
FROM nginx
MAINTAINER Qingwen Zhang <qingwenzhang@quarkfinance.com>
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"]
創建鏡像
docker build -t 172.16.4.92/service/nginx-consul-template -f /opt/dockerfile/nginx-consul-template.df . docker push 172.16.4.92/service/nginx-consul-template
創建ctmpl模板
mkdir -p /opt/platform/nginx-calico && cd /opt/platform/nginx-calico && mkdir -p conf modules html logs ctmpl
vim /opt/platform/nginx-calico/ctmpl/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 "."}}.test.com;
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}}
運行nginx-consul-template
docker pull 172.16.4.92/service/nginx-consul-template docker run -d \ --restart=always \ --net=calico \ --ip=10.233.2.1 \ --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.16.4.92/service/nginx-consul-template \ -consul-addr=172.16.150.25:8500 -wait=5s \ -template="/etc/ctmpl/ctmpl:/etc/nginx/conf.d/app.conf:/tmp/nginx.sh"
創建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
calicoctl apply -f nginx-policy.yaml calicoctl get policy
ingress是入口,egress是出口,我們這里需要外部的nginx-host反向代理到calico網絡的nginx-ingress,所以只需要ingress放行指定IP的tcp 80即可。
