如何利用Confd与Etcd对CoreOS中的服务进行动态重新配置

Posted ZStack上海云轴

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了如何利用Confd与Etcd对CoreOS中的服务进行动态重新配置相关的知识,希望对你有一定的参考价值。

提供:ZStack云计算

系列教程

本教程为CoreOS上手指南系列九篇中的第七篇。

内容介绍

CoreOS允许大家在各集群成员上的Docker容器内轻松运行服务。作为基本流程,我们通常需要启动某服务的一个或多个实例,而后利用etcd加以注册。

在本篇教程中,我们将探讨confd工具,其专门用于观察分布式键-值存储中的内容变化。其运行于Docker容器之风,且可用于触发配置修改与服务重载。

先决条件与既定目标

为了完成本篇教程,大家应当对CoreOS及其各组件拥有基本了解。

如果对这方面内容不太熟悉,大家请首先参阅以下几篇教程:

另外,要了解更多与管理工具相关的内容,则请参阅:

其中“如何创建灵活服务”一文特别重要,因为其中涉及的服务将作为本篇教程内的前端服务。

在今天的文章中,我们将探讨如何利用nginx创建新的应用容器。其将作为反向代理服务于各个Apache实例。该Nginx容器将利用confd进行配置,负责观察各sidekick服务所负责的服务注册表。

我们将继续使用本系列教程的三节点集群:

  • coreos-1
  • coreos-2
  • coreos-3

下面正式开始今天的内容。

配置后端Apache服务

我们首先从后端Apache服务开始。

登录至COreOS设备:

ssh -A [email protected]_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/[email protected]

将以下内容粘贴至文件中。大家可以参阅创建灵活的fleet服务单元文件教程了解各选项的含义:

[Unit]Description=Apache web server service on port %i

# Requirements
Requir[email protected]%i.service

# Dependency ordering
[email protected]%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
[email protected]*.service

我们这里需要修改以使用专有接口替代公共接口。由于我们的各Apache实例都会通过Nginx反射代理发送流量,因此这部分调整是必不可少的。注意,在DigitalOcean上使用专有接口的话,我们使用的各服务器必须具备“private networking”标记。

另外,注意变更user_name以引用我们的Docker Hub用户名,从而正确提取Docker文件。

创建sidekick模板单元文件

现在,我们需要以同样的方式处理sidekick服务。稍后我们会对内容进行调整以符合自身环境的实际情况。

打开该模板文件:

vim templates/[email protected]

在文件中使用以下信息:

[Unit]Description=Apache web server on port %i etcd registration

# Requirements
[email protected]%i.service

# Dependency ordering and binding
[email protected]%[email protected]%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
[email protected]%i.service

以上配置与之前教程中的内容有所区别。我们利用etcdctl set命令调整了部分值。相较于发送JSON对象,这里我们设置了简单的IP地址加端口的组合。通过这种方式,我们能够直接读取该值以掌握前往此服务的必要连接信息。

我们还调整了相关信息以指定在其它文件中已经使用的专有接口。

进行服务实例化

现在为这些服务创建两个实例。

首先是创建符号链接。前往刚刚创建的~/instances目录,同时链接至服务运行所在的端口。我们希望让两项服务分别运行在端口7777与端口8888上:

cd ~/instances
ln -s ../templates/[email protected] [email protected]
ln -s ../templates/[email protected] [email protected]
ln -s ../templates/[email protected] [email protected]
ln -s ../templates/[email protected] [email protected]

现在,我们可以将~/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 = "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][email protected]*.service

完成后保存并退出。

运行Nginx负载均衡

现在我们拥有此前完成的两套Apache实例。下面进行检查:

fleetctl list-units

UNIT                MACHINE             ACTIVE  SUB
[email protected]   197a1662.../10.132.249.206  active  running
[email protected]   04856ec4.../10.132.249.212  active  running
[email protected]     197a1662.../10.132.249.206  active  running
[email protected]     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中的服务进行动态重新配置的主要内容,如果未能解决你的问题,请参考以下文章

基于etcd+confd对监控prometheus的服务注册发现

如何利用fleet单元文件为CoreOS集群创建高灵活性服务

通过Etcd+Confd自动管理Haproxy(多站点)

如何在 coreOS 上将 etcd 值添加到我的 systemd 服务中?

confd+etcd完成后端服务器的自动检测

Confd实现Nginx配置文件自动管理