Docker+Jenkins持续集成环境(4):使用etcd+confd实现容器服务注册与发现
前面我们已经通过jenkins+docker搭建了基本的持续集成环境,实现了服务的自动构建和部署,但是,我们遇到一个问题,jenkins构建出来的镜像部署后,需要通过ip:port去访问,有什么更好的方法吗?肯定是通过域名啊!前提是你注册一个域名,或者修改机器hosts文件。 本文介绍通过引入etcd+confd实现部署服务的自动注册,自动生成nginx配置文件,实现每个服务独立域名访问。
配置域名
假设你的域名是: example.com,那么我们可以规划
- dev.$servicename.example.com作为开发环境,
- test.$servicename.example.comz作为服务的测试环境。
配置步骤:
- 首先将*.example.com 指向一台nginx服务器
- 增加vhost配置文件,假设86.6,86.8,86.11 是docker swarm集群中的机器,服务的名称为allinoneservice,那么我们可以增加一个配置文件nginx_vhosts/service.conf:
upstream test_service_allinoneservice {
server 192.168.86.11:10091;
server 192.168.86.6:10091;
server 192.168.86.8:10091;
}
server {
listen 80;
server_name test.allinoneservice.example.com;
location / {
proxy_redirect off;
proxy_set_header Host $host;
proxy_read_timeout 300;
proxy_set_header X-Real-IP $http_x_forwarded_for;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_pass http://test_service_allinoneservice;
}
}
- 修改nginx配置文件nginx.conf,在最后一个大括号前,将刚新建的配置文件包含进去: include nginx_vhosts/*.conf;
- 重启nginx,就可以通过test.allinoneservice.example.com访问服务了
通过服务注册自动生成配置文件
第一步里,我们需要手动编写配置文件,有更好的方式吗?答案是通过服务注册+confd,自动生成配置文件。
docker 安装etcd集群
首先,docker安装etcd作为注册中心,我们安装一个包含3个实例的集群,编写docker-compose.yml:
version: '3'
services:
etcd0:
image: 192.168.86.8:5000/etcd
ports:
- "2379:2379"
volumes:
- etcd0:/etcd_data
command:
- /usr/local/bin/etcd
- -name
- etcd0
- --data-dir
- /etcd_data
- -advertise-client-urls
- http://etcd0:2379
- -listen-client-urls
- http://0.0.0.0:2379
- -initial-advertise-peer-urls
- http://etcd0:2380
- -listen-peer-urls
- http://0.0.0.0:2380
- -initial-cluster
- etcd0=http://etcd0:2380,etcd1=http://etcd1:2380,etcd2=http://etcd2:2380
etcd1:
image: 192.168.86.8:5000/etcd
ports:
- "2380:2379"
volumes:
- etcd1:/etcd_data
command:
- /usr/local/bin/etcd
- -name
- etcd1
- --data-dir
- /etcd_data
- -advertise-client-urls
- http://etcd1:2379
- -listen-client-urls
- http://0.0.0.0:2379
- -initial-advertise-peer-urls
- http://etcd1:2380
- -listen-peer-urls
- http://0.0.0.0:2380
- -initial-cluster
- etcd0=http://etcd0:2380,etcd1=http://etcd1:2380,etcd2=http://etcd2:2380
etcd2:
image: 192.168.86.8:5000/etcd
ports:
- "2381:2379"
volumes:
- etcd2:/etcd_data
command:
- /usr/local/bin/etcd
- -name
- etcd2
- --data-dir
- /etcd_data
- -advertise-client-urls
- http://etcd2:2379
- -listen-client-urls
- http://0.0.0.0:2379
- -initial-advertise-peer-urls
- http://etcd2:2380
- -listen-peer-urls
- http://0.0.0.0:2380
- -initial-cluster
- etcd0=http://etcd0:2380,etcd1=http://etcd1:2380,etcd2=http://etcd2:2380
volumes:
etcd0:
etcd1:
etcd2:
注意,上面的image: 192.168.86.8:5000/etcd 是用的私有仓库,大家可以使用官方版本quay.io/coreos/etcd
然后启动etcd:
docker stack deploy -c docker-compose.yml etcd
服务注册
etcd注册就简单了,可以通过etcd的rest api,例如:
curl http://192.168.86.11:2379/v2/keys/services/test/allinoneservice/service1 -XPUT -d value="192.168.86.8:10091"
所以,我们修改一下jenkins里的docker部署脚本,服务部署后自动向etcd注册,由于是swarm集群,因此我们可以注册多个ip。
echo "start remove old service"
docker service rm ${service_name}-${env}
echo "start create new service with latest builded image"
docker service create --name ${service_name}-${env} --replicas ${replicas} --publish ${service_port}:${docker_expose_port} 192.168.86.8:5000/${service_name}-${env}
echo "publish service to nginx"
curl http://192.168.86.11:2379/v2/keys/services/${env}/${service_name}/service1 -XPUT -d value="192.168.86.8:${service_port}"
curl http://192.168.86.11:2379/v2/keys/services/${env}/${service_name}/service2 -XPUT -d value="192.168.86.11:${service_port}"
curl http://192.168.86.11:2379/v2/keys/services/${env}/${service_name}/service3 -XPUT -d value="192.168.86.6:${service_port}"
注意,上面的service_name是jenkins参数化构建里定义的参数:
通过confd生成nginx配置文件
confd 是一个配置文件生成工具,可以从etcd、consul等注册中心读取数据根据模板生成配置文件,并在配置发生变化后自动更新配置文件,还能自动重启服务,是服务自动发现的居家必备良药。
首先讲下怎么安装,根据官方文档:
wget https://github.com/kelseyhightower/confd/releases/download/v0.14.0/confd-0.14.0-linux-amd64
mkdir -p /opt/confd/bin
mv confd-0.14.0-linux-amd64 /opt/confd/bin/confd
chmod +x /opt/confd/bin/confd
export PATH="$PATH:/opt/confd/bin"
为了方便使用,最好修改下/etc/profile,加入export PATH="$PATH:/opt/confd/bin",然后source /etc/profile让配置生效。
然后编写confd配置文件/etc/confd/conf.d/myapp-nginx.toml:
[template]
src = "nginx.conf.tmpl"
dest = "/opt/third_party/nginx_vhosts/service.conf"
keys = [
"/services/dev",
"/services/test",
]
reload_cmd = "/opt/third_party/sbin/nginx -s reload"
上面配置了,会读取的keys,以及dest目标配置文件地址,和配置文件更新后的reload_cmd,用于重启nginx
接着编写模板文件
{{range $dir := lsdir "/services/test"}}
upstream test_service_{{base $dir}} {
{{$custdir := printf "/services/test/%s/*" $dir}}{{range getvs $custdir}}
server {{.}};
{{end}}
}
server {
listen 80;
server_name test.{{base $dir}}.iflyresearch.com;
location / {
proxy_redirect off;
proxy_set_header Host $host;
proxy_read_timeout 300;
proxy_set_header X-Real-IP $http_x_forwarded_for;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_pass http://test_service_{{base $dir}};
}
}
{{end}}
上面的模板比较简单,通过lsdir指令读取服务列表,然后通过range getvs获取服务对应的负载地址。
然后启动confd,需要指定etcd的地址:
nohup confd -backend etcd -node http://192.168.86.11:2379 &
搞定!
延伸阅读
Jenkins+Docker 搭建持续集成环境:
作者:Jadepeng 出处:jqpeng的技术记事本--http://www.cnblogs.com/xiaoqi 您的支持是对博主最大的鼓励,感谢您的认真阅读。 本文版权归作者所有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- Nginx系列:图片过滤处理
- Nginx系列:几款负载均衡第三方插件的安装与使用
- 「高并发通信框架Netty4 源码解读(三)」NIO缓冲区Buffer详解
- UML类图符号:各种关系说明以及举例
- 「高并发通信框架Netty4 源码解读(四)」NIO缓冲区之字节缓冲区ByteBuffer详解
- 「influxDB 原理与实践(三)」连续查询
- 为什么使用OPA而不是原生的Pod安全策略?
- 浅入浅出 Java ConcurrentHashMap
- 「高并发通信框架Netty4 源码解读(五)」NIO通道Channel详解
- 图解一致性哈希算法,全网(小区局域网)最通俗易懂
- 「高并发通信框架Netty4 源码解读(六)」NIO通道之Socket通道
- 「高并发通信框架Netty4 源码解读(番外篇)」NIO实现大文件传输
- 「高并发通信框架Netty4 源码解读(七)」NIO通道之Selector选择器
- Python与seo工具脚本,360/搜狗相关搜索词采集源码参考
- 逐行阅读Spring5.X源码(八)Mybatis是如何利用MapperScan完成扫描的?