首页 > 代码库 > 如何利用Confd与Etcd对CoreOS中的服务进行动态重新配置
如何利用Confd与Etcd对CoreOS中的服务进行动态重新配置
提供:ZStack云计算
系列教程
本教程为CoreOS上手指南系列九篇中的第七篇。
内容介绍
CoreOS允许大家在各集群成员上的Docker容器内轻松运行服务。作为基本流程,我们通常需要启动某服务的一个或多个实例,而后利用etcd加以注册。
在本篇教程中,我们将探讨confd工具,其专门用于观察分布式键-值存储中的内容变化。其运行于Docker容器之风,且可用于触发配置修改与服务重载。
先决条件与既定目标
为了完成本篇教程,大家应当对CoreOS及其各组件拥有基本了解。
如果对这方面内容不太熟悉,大家请首先参阅以下几篇教程:
- 如何在DigitalOcean上设置一套CoreOS集群
- 如何在CoreOS集群上创建并运行一项服务
- 如何利用Fleet单元文件为CoreOS集群创建灵活服务
另外,要了解更多与管理工具相关的内容,则请参阅:
- 如何利用Fleet与Fleetctl管理CoreOS集群
- 如何使用Etcdctl与Etcd,CoreOS的分布式键-值存储机制
其中“如何创建灵活服务”一文特别重要,因为其中涉及的服务将作为本篇教程内的前端服务。
在今天的文章中,我们将探讨如何利用Nginx创建新的应用容器。其将作为反向代理服务于各个Apache实例。该Nginx容器将利用confd进行配置,负责观察各sidekick服务所负责的服务注册表。
我们将继续使用本系列教程的三节点集群:
- coreos-1
- coreos-2
- coreos-3
下面正式开始今天的内容。
配置后端Apache服务
我们首先从后端Apache服务开始。
登录至COreOS设备:
ssh -A core@ip_address
Apache容器设置
我们首先创建基本Apache容器。由于之前在其它教程中已经提到,因此这里只简要进行说明。
下面提取基础镜像并启动容器实例:
docker run -i -t ubuntu:14.04 /bin/bash
容器启动后,我们会面对一套bash会话。在这里,更新本地apt软件包目录并安装apahce2:
apt-get update
apt-get install apache2 -y
设置默认页面:
echo"<h1>Running from Docker on CoreOS</h1>" > /var/www/html/index.html
现在退出该容器:
exit
使用以下命令登录或创建Docker Hub账户:
docker login
这里需要提供用户名、密码以及邮箱地址。
接下来获取刚刚创建的实例的容器ID:
docker ps -l
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
1db0c9a40c0d ubuntu:14.04 "/bin/bash" 2 minutes ago Exited (0) 4 seconds ago jolly_pare
其中的高亮部分即为容器ID。将输出结果复制到我们自己的计算机上。
现在提交该容器ID、Docker Hub用户名称以及镜像名称。这里我们使用apahce作为名称:
docker commit 1db0c9a40c0duser_name/apache
将新镜像推送至Docker Hub:
docker push user_name/apache
现在即可在服务文件中使用此镜像了。
创建Apache服务模板单元文件
现在我们已经拥有了可用容器,接下来创建模板单元文件,保证fleet与systemd能够正确管理该服务。
在开始之前,首先设置一套目录结构:
cd ~
mkdir static templates instances
现在,我们可以在模板目录内构建自己的模板文件了:
vim templates/apache@.service
将以下内容粘贴至文件中。大家可以参阅创建灵活的fleet服务单元文件教程了解各选项的含义:
[Unit]Description=Apache web server service on port %i
# Requirements
Requires=etcd.serviceRequires=docker.serviceRequires=apache-discovery@%i.service
# Dependency ordering
After=etcd.serviceAfter=docker.serviceBefore=apache-discovery@%i.service[Service]
# Let processes take awhile to start up (for first run Docker containers)
TimeoutStartSec=0
# Change killmode from "control-group" to "none" to let Docker remove
# work correctly.
KillMode=none
# Get CoreOS environmental variables
EnvironmentFile=/etc/environment
# Pre-start and Start
## Directives with "=-" are allowed to fail without consequence
ExecStartPre=-/usr/bin/docker kill apache.%iExecStartPre=-/usr/bin/docker rm apache.%iExecStartPre=/usr/bin/docker pull user_name/apacheExecStart=/usr/bin/docker run --name apache.%i -p ${COREOS_PRIVATE_IPV4}:%i:80 \user_name/apache /usr/sbin/apache2ctl -D FOREGROUND
# Stop
ExecStop=/usr/bin/docker stop apache.%i[X-Fleet]
# Don‘t schedule on the same machine as other Apache instances
Conflicts=apache@*.service
我们这里需要修改以使用专有接口替代公共接口。由于我们的各Apache实例都会通过Nginx反射代理发送流量,因此这部分调整是必不可少的。注意,在DigitalOcean上使用专有接口的话,我们使用的各服务器必须具备“private networking”标记。
另外,注意变更user_name以引用我们的Docker Hub用户名,从而正确提取Docker文件。
创建sidekick模板单元文件
现在,我们需要以同样的方式处理sidekick服务。稍后我们会对内容进行调整以符合自身环境的实际情况。
打开该模板文件:
vim templates/apache-discovery@.service
在文件中使用以下信息:
[Unit]Description=Apache web server on port %i etcd registration
# Requirements
Requires=etcd.serviceRequires=apache@%i.service
# Dependency ordering and binding
After=etcd.serviceAfter=apache@%i.serviceBindsTo=apache@%i.service[Service]
# Get CoreOS environmental variables
EnvironmentFile=/etc/environment
# Start
## Test whether service is accessible and then register useful information
ExecStart=/bin/bash -c ‘ while true; do curl -f ${COREOS_PRIVATE_IPV4}:%i; if [ $? -eq 0 ]; then etcdctl set /services/apache/${COREOS_PRIVATE_IPV4} \‘${COREOS_PRIVATE_IPV4}:%i\‘ --ttl 30; else etcdctl rm /services/apache/${COREOS_PRIVATE_IPV4}; fi; sleep 20; done‘
# Stop
ExecStop=/usr/bin/etcdctl rm /services/apache/${COREOS_PRIVATE_IPV4}[X-Fleet]
# Schedule on the same machine as the associated Apache service
MachineOf=apache@%i.service
以上配置与之前教程中的内容有所区别。我们利用etcdctl set命令调整了部分值。相较于发送JSON对象,这里我们设置了简单的IP地址加端口的组合。通过这种方式,我们能够直接读取该值以掌握前往此服务的必要连接信息。
我们还调整了相关信息以指定在其它文件中已经使用的专有接口。
进行服务实例化
现在为这些服务创建两个实例。
首先是创建符号链接。前往刚刚创建的~/instances目录,同时链接至服务运行所在的端口。我们希望让两项服务分别运行在端口7777与端口8888上:
cd ~/instances
ln -s ../templates/apache@.service apache@7777.service
ln -s ../templates/apache@.service apache@8888.service
ln -s ../templates/apache-discovery@.service apache-discovery@7777.service
ln -s ../templates/apache-discovery@.service apache-discovery@8888.service
现在,我们可以将~/instances目录发送至fleet以启动这些服务:
fleetctl start ~/instances/*
在实例启动后(可能需要几分钟),大家应该能够看到sidekicks生成的etcd条目:
etcdctl ls --recursive /
/coreos.com
/coreos.com/updateengine
/coreos.com/updateengine/rebootlock
/coreos.com/updateengine/rebootlock/semaphore
/services
/services/apache
/services/apache/10.132.249.206/services/apache/10.132.249.212
如果大家查询这些条目的值,则会看到其IP地址与端口编号:
etcdctl get /services/apache/10.132.249.206
10.132.249.206:8888
大家可以使用curl以检索该页面,并确保其正常起效。注意,我们必须配置该服务使用专有网络才能保证其在设备内正常运作:
curl 10.132.249.206:8888
<h1>Running from Docker on CoreOS</h1>
现在我们已经设置完成了自己的后端基础设施。我们的下一项目标是熟悉confd,从而在Nginx每次变更及重新配置时在etcd中查看/services/apache的位置。
创建Nginx容器
我们继续以Ubuntu 14.04为系统平台启动Nginx容器。
安装软件
使用以下命令启动一套新容器:
docker run -i -t ubuntu:14.04 /bin/bash
更新我们的本地apt软件包缓存并安装Nginx。我们还需要安装curl,因为基础镜像中并不包含:
apt-get update
apt-get install nginx curl -y
现在我们可以前往发布页面以获取GitHub上的confd。我们还需要找到其最新稳定版本的链接。目前该版本为v0.5.0,但具体链接可能有所变化。
现在重新回到Docker容器,使用复制到的URL以下载该应用。我们将其存放在/usr/local/bin目录内。我们需要将confd选定为输出文件:
cd /usr/local/bin
curl -L https://github.com/kelseyhightower/confd/releases/download/v0.5.0/confd-0.5.0<^>-linux-amd64 -o confd
现在将该文件设置为可执行,从而在容器内加以使用:
chmod +x confd
我们还需要创建confd所能支持的配置结构,在/etc目录下进行:
mkdir -p /etc/confd/{conf.d,templates}
创建Confd配置文件以读取Etcd值
现在我们的应用已经安装完成,接下来配置confd。具体方式可以是创建配置文件,或者使用模板资源文件。
confd中的配置文件用于设置该服务以检查特定etcd值,同时在检测到变更时执行初始化操作。配置文件使用TOML文件格式,其易于使用且非常直观。
首先在配置目录中创建nginx.toml文件:
vi /etc/confd/conf.d/nginx.toml
在文件中添加以下信息:
[template]
# The name of the template that will be used to render the application‘s configuration file
# Confd will look in `/etc/conf.d/templates` for these files by default
src = "http://www.mamicode.com/nginx.tmpl"
# The location to place the rendered configuration file
dest = "/etc/nginx/sites-enabled/app.conf"
# The etcd keys or directory to watch. This is where the information to fill in
# the template will come from.
keys = [ "/services/apache" ]
# File ownership and mode information
owner = "root"mode = "0644"
# These are the commands that will be used to check whether the rendered config is
# valid and to reload the actual service once the new config is in place
check_cmd = "/usr/sbin/nginx -t"reload_cmd = "/usr/sbin/service nginx reload"
下面解释其中的部分关键内容:
DirectiveRequired?TypeDescription
src Yes String为用于渲染该信息的模板。如果其处于/etc/confd/templates位置之外,则使用完整路径。
dest Yes String为已渲染配置文件所在的位置。
keys Yes Array of strings为模板使用以实现正确渲染的etcd键。如果该模板被设定为处理子键,则其亦可为目录。
owner No String为作为渲染配置文件持有者的用户名称。
group No String为持有渲染配置文件的组。
mode No String为用于设定渲染文件的octal权限模式。
check_cmd No String用于检查渲染配置文件的语法。
reload_cmd No String命令用于重载该应用的配置。
prefix No String为etcd层次结构中的一部分,位于keys指令中的keys之前,用于确保.toml文件更为灵活。
我们创建的这个文件中包含大量重要内容,用于指定confd实例的功能实现方式。我们的Nginx容器所使用的模板存储于/etc/confd/templates/nginx.conf.tmpl内,用于渲染将被放置在/etc/nginx/sites-enabled/app.conf处的配置文件。该文件将被赋予0644权限组,并归属于root用户。
此confd应用将查找/services/apache节点中的变更。当变更出现时,confd会查询此节点中的新信息,而后为Nginx渲染新的配置。另外,它还能够对已有文件进行语法错误检查并重载Nginx服务。
现在我们的模板资源文件已经创建完成。
创建Confd模板文件
我们将使用confd项目GitHub说明文档内提供的模板文件。
创建的这个文件将在之前完成的配置文件内加以引用。将此文件放在我们的模板目录内:
vi /etc/confd/templates/nginx.tmpl
在文件中,我们需要重新创建标准Nginx反向代理配置文件。这里我们会使用部分Go模板化语法,用于替换confd从etcd中提取到的信息。
首先利用upstream服务器配置该块。此部分用于定义Nginx能够作为请求发送目标的服务器池。其格式如下:
upstreampool_name {
serverserver_1_IP:port_num;
serverserver_2_IP:port_num;
serverserver_3_IP:port_num;
}
这样我们就能将请求发送至pool_name处,而Nginx则会选择定义服务器之一来处理请求内容。
我们的模板文件负责解析etcd以获取Apache Web服务器的IP地址与端口编号。因此相较于以状态化方式定义upstream服务器,我们可以在所渲染的文件中动态填充这些信息。具体方式请参阅Go模板中的动态内容介绍。
要完成这一目标,我们使用以下内容作为配置块:
upstream apache_pool {
{{ range getvs "/services/apache/*" }}
server {{ . }};
{{ end }}
}
下面解释其具体含义。我们打开的块负责定义名为apache_pool的上游服务器池。在其中,我们使用双大括号以指定Go代码。
在这些大括号中,我们指定所需值的来源etcd端点。我们使用range使列表具备可迭代性。
我们将etcd中/services/apache位置下的全部条目发送至range块。而后,我们在利用“{{}}”中的一个点(.)来插入当前迭代中的键值。在range循环中,我们借此填充服务器池。最后,我们使用{{end}}指令作为循环结尾。
注意:记得在循环内的server指令后加上分号。如果不添加,则会造成配置无法生效。
在服务器池设置完成后,我们可以使用代理将全部连接引导至该池。需要注意的是access_log,这里我们暂时使用自定义格式:
upstream apache_pool {
{{ range getvs "/services/apache/*" }}
server {{ . }};
{{ end }}
}
server {
listen80 default_server;
listen [::]:80 default_server ipv6only=on;
access_log /var/log/nginx/access.log upstreamlog;
location / {
proxy_passhttp://apache_pool;
proxy_redirectoff;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
这会响应全部端口80上的连接,并将其发送至apache_pool位置的服务器池。
另外,我们还需要移除默认Nginx配置文件,从而保证不会出现冲突。这里我们移除指向默认配置的符号链接:
rm /etc/nginx/sites-enabled/default
接下来,我们要配置模板文件内所引用的日志格式。这部分内容必须位于配置中的http部分,且可用于主配置文件。将该文件打开:
vi /etc/nginx/nginx.conf
添加log_format指令以定义希望记录的信息。其会记录进行访问的客户端以及请求被发送到的后端服务器。我们以如下规程实现数据记录:
. . .
http {
### Basic Settings##log_format upstreamlog ‘[$time_local] $remote_addr passed to: $upstream_addr: $request Upstream Response Time: $upstream_response_time Request time: $request_time‘;
sendfileon;
. . .
完成后保存并退出。
创建脚本以运行Confd
我们需要创建一套脚本,负责利用模板资源文件并在合适的时间段内调用confd。
此脚本必须肩负以下两项职责,从而保证我们的服务能够正常运作:
- 必须根据当前后端基础设施状态对Nginx设置进行初始化,从而匹配容器启动操作。
- 必须持续观察etcd注册表中的Apache服务器变更,从而根据后端服务器可用状态重新配置Nginx。
这里我们直接使用Marcel de Graaf的GitHub页面。这套脚本非常适合我们的实际需求,只需要根据实际场景做出一点调整。
首先将该脚本与我们的confd可执行文件放在一起。我们将其命名为confd-watch:
vi /usr/local/bin/confd-watch
我们仍然从bash标题头开始进行解释。而后设置部分bash选项以保证在出现故障时,该脚本会立即失效。其会返回最后一条失效或者成功运行的命令值。
#!/bin/bash
set -eo pipefail
下面我们希望设置部分变量。通过使用bash参数,我们可以设置默认值但同时保留一定的灵活性,从而在调用脚本时能够覆盖掉其中的硬编码值。基本上,这意味着独立设置各连接地址,而后将其归纳成组以获取完整的地址。
参数替代部分使用以下语法:
${var_name:-default_value}。如果存在var_name或者为非空,则将其值作为属性; 否则采用default_value默认值。
我们已经在默认情况下将etcd设定为使用默认值。这样我们的脚本能够正常起效,但同时亦可在必要时通过定制化方式调用该脚本:
#!/bin/bash
set -eo pipefail
export ETCD_PORT=${ETCD_PORT:-4001}export HOST_IP=${HOST_IP:-172.17.42.1}export ETCD=$HOST_IP:$ETCD_PORT
现在使用confd对Nginx配置文件的初始版本进行渲染,各相关值读取自etcd。我们还将使用一条until循环以持续尝试构建初始配置。
该循环结构将在etcd不可用的情况下立即生效,或者在Nginx容器先于后端服务器被启动的情况下被激活。这样etcd会反复尝试,直到其最终生成有效的初始配置。
我们调用的实际confd命令会在执行一次后退出。因此我们可以等待5秒钟,直到后端服务器完成注册后再行尝试。我们利用默认或提交的参数接入完整的ETCD变量,而后使用模板资源文件以定义需要执行的操作:
#!/bin/bash
set -eo pipefail
export ETCD_PORT=${ETCD_PORT:-4001}export HOST_IP=${HOST_IP:-172.17.42.1}export ETCD=$HOST_IP:$ETCD_PORTecho"[nginx] booting container. ETCD: $ETCD"# Try to make initial configuration every 5 seconds until successful
until confd -onetime -node $ETCD -config-file /etc/confd/conf.d/nginx.toml; doecho"[nginx] waiting for confd to create initial nginx configuration"
sleep 5done
在初始配置设置完成后,脚本接下来需要以持续方式运行。我们要借此确保Nginx能够借此发现一切变更并保持更新。
这一次,我们设置连续轮询间隔,并将其无限期运行在后台进程内。我们提交同样的etcd连接信息与同样的模板资源文件,因为我们需要实际的目标与之前所提到的并无区别。
在将confd进程纳入后台后,我们可以使用现有配置文件启动Nginx了。由于此脚本将通过Docker的run命令接受调用,因此需要使其在前台运行在确保容器不会中途退出。要完成这一目标,我们可以追踪日志内容以访问全部记录到的信息:
#!/bin/bash
set -eo pipefail
export ETCD_PORT=${ETCD_PORT:-4001}export HOST_IP=${HOST_IP:-172.17.42.1}export ETCD=$HOST_IP:$ETCD_PORTecho"[nginx] booting container. ETCD: $ETCD."# Try to make initial configuration every 5 seconds until successful
until confd -onetime -node $ETCD -config-file /etc/confd/conf.d/nginx.toml; doecho"[nginx] waiting for confd to create initial nginx configuration."
sleep 5done# Put a continual polling `confd` process into the background to watch# for changes every 10 seconds
confd -interval 10 -node $ETCD -config-file /etc/confd/conf.d/nginx.toml &
echo"[nginx] confd is now monitoring etcd for changes..."# Start the Nginx service using the generated configecho"[nginx] starting nginx service..."
service nginx start
# Follow the logs to allow the script to continue running
tail -f /var/log/nginx/*.log
完成之后保存并退出。
最后,我们需要将此脚本设置为可执行:
chmod +x /usr/local/bin/confd-watch
退出该容器并返回主机系统:
exit
提交并推送容器
现在我们可以提交该容器并将其推送至Docker Hub,从而供全部设备进行获取。找到其容器ID:
docker ps -l
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
de4f30617499 ubuntu:14.04 "/bin/bash" 22 hours ago Exited (0) About a minute ago stupefied_albattani
其中的高亮字符串即为我们需要的容器ID。使用此ID、Docker Hub用户名以及镜像名称提交该容器。这里我们将其命名为nginx_lb:
docker commit de4f30617499user_name/nginx_lb
如果需要,请登录Docker Hub账户:
docker login
现在已经可以进行镜像提交了:
docker push user_name/nginx_lb
构建Nginx Static单元文件
下面我们需要构建一个单元文件,其负责启动我们创建完成的容器。在这里,我们使用fleet以控制此流程。
由于此文件没有现成模板可用,因此我们将在此前创建的~/static目录中从头进行创建:
vim static/nginx_lb.service
下面从标准的[Unit]部分开始,描述该服务并定义其依赖性与顺序:
[Unit]Description=Nginx load balancer for web server backends
# Requirements
Requires=etcd.serviceRequires=docker.service
# Dependency ordering
After=etcd.serviceAfter=docker.service
接下来,我们定义文件中的[Serivce]部分。在这里我们将超时设置为0,同时将killmode设置为无。我们需要再次引入环境文件,从而访问此容器运行所在主机的公共与专有IP地址。
之后,我们将清理环境以确保该容器的早期版本不再存在。现在提取刚刚创建的容器以确保其处于最新版本。
最后,启动此容器。在此过程中,我们需要启动容器,根据remove与kill命令中的引用内容为其命名,而后为其提供运行所在主机的公共IP地址并映射至端口80。我们调用此前创建的confd-watch脚本作为run命令:
[Unit]Description=Nginx load balancer for web server backends
# Requirements
Requires=etcd.serviceRequires=docker.service
# Dependency ordering
After=etcd.serviceAfter=docker.service[Service]
# Let the process take awhile to start up (for first run Docker containers)
TimeoutStartSec=0
# Change killmode from "control-group" to "none" to let Docker remove
# work correctly.
KillMode=none
# Get CoreOS environmental variables
EnvironmentFile=/etc/environment
# Pre-start and Start
## Directives with "=-" are allowed to fail without consequence
ExecStartPre=-/usr/bin/docker kill nginx_lbExecStartPre=-/usr/bin/docker rm nginx_lbExecStartPre=/usr/bin/docker pull user_name/nginx_lbExecStart=/usr/bin/docker run --name nginx_lb -p ${COREOS_PUBLIC_IPV4}:80:80 \user_name/nginx_lb /usr/local/bin/confd-watch
现在我们需要理清停止命令与fleet调度方向。我们希望该容器只在主机不再运行其它负载均衡实例或者后端Apache服务器时才进行初始化。这样一来,我们就能更为高效地进行服务负载分散:
[Unit]Description=Nginx load balancer for web server backends
# Requirements
Requires=etcd.serviceRequires=docker.service
# Dependency ordering
After=etcd.serviceAfter=docker.service[Service]
# Let the process take awhile to start up (for first run Docker containers)
TimeoutStartSec=0
# Change killmode from "control-group" to "none" to let Docker remove
# work correctly.
KillMode=none
# Get CoreOS environmental variables
EnvironmentFile=/etc/environment
# Pre-start and Start
## Directives with "=-" are allowed to fail without consequence
ExecStartPre=-/usr/bin/docker kill nginx_lbExecStartPre=-/usr/bin/docker rm nginx_lbExecStartPre=/usr/bin/docker pull user_name/nginx_lbExecStart=/usr/bin/docker run --name nginx_lb -p ${COREOS_PUBLIC_IPV4}:80:80 \user_name/nginx_lb /usr/local/bin/confd-watch
# Stop
ExecStop=/usr/bin/docker stop nginx_lb[X-Fleet]Conflicts=nginx.serviceConflicts=apache@*.service
完成后保存并退出。
运行Nginx负载均衡
现在我们拥有此前完成的两套Apache实例。下面进行检查:
fleetctl list-units
UNIT MACHINE ACTIVE SUB
apache-discovery@7777.service 197a1662.../10.132.249.206 active running
apache-discovery@8888.service 04856ec4.../10.132.249.212 active running
apache@7777.service 197a1662.../10.132.249.206 active running
apache@8888.service 04856ec4.../10.132.249.212 active running
大家也可以再次检查,确保其已经注册至etcd:
etcdctl ls --recursive /services/apache
/services/apache/10.132.249.206
/services/apache/10.132.249.212
我们现在可以启动Nginx服务了:
fleetctl start ~/static/nginx_lb.service
Unit nginx_lb.service launched on 96ec72cf.../10.132.248.177
整个启动过程可能需要耗费1分钟左右,具体取决于镜像的获取速度。启动完成后,如果使用fleetctl journal命令检查日志,则会看到来自confd的日志信息:
fleetctl journal nginx_lb.service
-- Logs begin at Mon 2014-09-15 14:54:05 UTC, end at Tue 2014-09-16 17:13:58 UTC. --
Sep 16 17:13:48 lala1 docker[15379]: 2014-09-16T17:13:48Z d7974a70e976 confd[14]: INFO Target config /etc/nginx/sites-enabled/app.conf out of sync
Sep 16 17:13:48 lala1 docker[15379]: 2014-09-16T17:13:48Z d7974a70e976 confd[14]: INFO Target config /etc/nginx/sites-enabled/app.conf has been updated
Sep 16 17:13:48 lala1 docker[15379]: [nginx] confd is monitoring etcd for changes...
Sep 16 17:13:48 lala1 docker[15379]: [nginx] starting nginx service...
Sep 16 17:13:48 lala1 docker[15379]: 2014-09-16T17:13:48Z d7974a70e976 confd[33]: INFO Target config /etc/nginx/sites-enabled/app.conf in sync
Sep 16 17:13:48 lala1 docker[15379]: ==> /var/log/nginx/access.log <==
Sep 16 17:13:48 lala1 docker[15379]: ==> /var/log/nginx/error.log <==
Sep 16 17:13:58 lala1 docker[15379]: 2014-09-16T17:13:58Z d7974a70e976 confd[33]: INFO /etc/nginx/sites-enabled/app.conf has md5sum a8517bfe0348e9215aa694f0b4b36c9b should be 33f42e3b7cc418f504237bea36c8a03e
Sep 16 17:13:58 lala1 docker[15379]: 2014-09-16T17:13:58Z d7974a70e976 confd[33]: INFO Target config /etc/nginx/sites-enabled/app.conf out of sync
Sep 16 17:13:58 lala1 docker[15379]: 2014-09-16T17:13:58Z d7974a70e976 confd[33]: INFO Target config /etc/nginx/sites-enabled/app.conf has been updated
可以看到,confd会从etcd中获取初始配置。其随后启动nginx。接下来的各行显示etcd条目已经被重新评估,同时生成新的配置文件。如果新生成的文件与原有文件的md5不符,则原有文件会被替换,服务也随之重载。
如此一来,我们的负载均衡服务最终将能够追踪Apache后端服务器。如果confd进行不断更新,则可能是因为我们的Apache实例刷新TTL的频率过高。这时,大家可以增加sidekick模板中的sleep与TTL值以解决这个问题。
要查看运行中的负载均衡机制,大家可以从运行Nginx服务的主机上查询/etc/environments文件。其中包含该主机的公共IP地址。如果大家希望进一步改善此配置,则可以考虑运行一项sidekick服务以将此信息注册至etcd:
fleetctl ssh nginx_lb cat /etc/environment
COREOS_PRIVATE_IPV4=10.132.248.177
COREOS_PUBLIC_IPV4=104.131.16.222
现在,如果我们通过浏览器前往公共IPv4,则会看到我们在Apache实例中配置的页面:
如果大家再次查看日志,应该会看到用于指定负责发送请求的后端服务器的相关信息:
fleetctl journal nginx_lb
. . .
Sep 16 18:04:38 lala1 docker[18079]: 2014-09-16T18:04:38Z 51c74658196c confd[28]: INFO Target config /etc/nginx/sites-enabled/app.conf in sync
Sep 16 18:04:48 lala1 docker[18079]: 2014-09-16T18:04:48Z 51c74658196c confd[28]: INFO Target config /etc/nginx/sites-enabled/app.conf in sync
Sep 16 18:04:48 lala1 docker[18079]: [16/Sep/2014:18:04:48 +0000] 108.29.37.206 passed to: 10.132.249.212:8888: GET / HTTP/1.1 Upstream Response Time: 0.003 Request time: 0.003
总结
可以看到,现在我们已经可以设置服务以检查etcd的配置细节。confd等工具能够持续提取各重要条目,从而极大简化这一实现流程。
在本示例当中,我们配置Nginx服务以使用etcd来生成其初始配置。我们也可以在后台设置以持续检查各项变更。这套体系与基于模板的动态配置相结合,将使我们实现后端服务器的不断更新。
本文来源自DigitalOcean Community。英文原文:How To Use Confd and Etcd to Dynamically Reconfigure Services in CoreOS By Justin Ellingwood
翻译:diradw
如何利用Confd与Etcd对CoreOS中的服务进行动态重新配置