Consul-Template
Consul-Template简介
Consul-Template是基于Consul的自动替换配置文件的应用。在Consul-Template没出现之前,大家构建服务发现系统大多采用的是Zookeeper、Etcd+Confd这样类似的系统。
Consul官方推出了自己的模板系统Consul-Template后,动态的配置系统可以分化为Etcd+Confd和Consul+Consul-Template两大阵营。Consul-Template的定位和Confd差不多,Confd的后端可以是Etcd或者Consul。
Consul-Template提供了一个便捷的方式从Consul中获取存储的值,Consul-Template守护进程会查询Consul实例来更新系统上指定的任何模板。当更新完成后,模板还可以选择运行一些任意的命令。
Consul-Template的使用场景
Consul-Template可以查询Consul中的服务目录、Key、Key-values等。这种强大的抽象功能和查询语言模板可以使Consul-Template特别适合动态的创建配置文件。例如:创建Apache/Nginx Proxy Balancers、Haproxy Backends、Varnish Servers、Application Configurations等。
Consul-Template特性
- Quiescence:Consul-Template内置静止平衡功能,可以智能的发现Consul实例中的更改信息。这个功能可以防止频繁的更新模板而引起系统的波动。
- Dry Mode:不确定当前架构的状态,担心模板的变化会破坏子系统?无须担心。因为Consul-Template还有Dry模式。在Dry模式,Consul-Template会将结果呈现在STDOUT,所以操作员可以检查输出是否正常,以决定更换模板是否安全。
- CLI and Config:Consul-Template同时支持命令行和配置文件。
- Verbose Debugging:即使每件事你都做的近乎完美,但是有时候还是会有失败发生。Consul-Template可以提供更详细的Debug日志信息。
Consul-template目录规划
- Consul-template安装目录
/opt/consul-template-VERSION
(VERSION为版本号),安装完成后软链接到/opt/consul-template
。 - Consul-template二进制程序目录
/opt/consul-template/bin
- Consul-template配置文件目录为
/opt/consul-template/conf
- Consul-template模板目录为
/opt/consul-template/ctmpl
- Consul-template日志目录为
/opt/consul-template/logs
完整目录结构如下:
~]# tree -C /opt/consul-template
/opt/consul-template
├── bin
├── conf
├── ctmpl
└── logs
Consul-Template安装
创建相应目录
~]# mkdir -p /opt/consul-template-0.19.5
~]# ln -s /opt/consul-template-0.19.5/ /opt/consul-template
~]# mkdir -p /opt/consul-template-0.19.5/{bin,conf,ctmpl,logs}
下载程序包并解压
官网下载地址:
私有镜像下载地址:
下载软件包:
~]# wget https://mirrors.xlhy1.com/source-code/consul-template_0.19.5_linux_amd64.tgz
解压
~]# tar xf consul-template_0.19.5_linux_amd64.tgz -C consul-template/bin/
导出环境变量
~]# echo 'export PATH=$PATH:/opt/consul-template/bin' > /etc/profile.d/consul-template.sh
~]# source /etc/profile.d/consul-template.sh
Consul-Template常用命令
-consul-auth= 设置基本的认证用户名和密码。
-consul-addr= 设置Consul实例的地址。
-max-stale= 查询过期的最大频率,默认是1s。
-dedup 启用重复数据删除,当许多consul template实例渲染一个模板的时候可以降低consul的负载。
-consul-ssl 使用https连接Consul。
-consul-ssl-verify 通过SSL连接的时候检查证书。
-consul-ssl-cert SSL客户端证书发送给服务器。
-consul-ssl-key 客户端认证时使用的SSL/TLS私钥。
-consul-ssl-ca-cert 验证服务器的CA证书列表。
-consul-token= 设置Consul API的token。
-syslog 把标准输出和标准错误重定向到syslog,syslog的默认级别是local0。
-syslog-facility= 设置syslog级别,默认是local0,必须和-syslog配合使用。
-template= 增加一个需要监控的模板,格式是:'templatePath:outputPath(:command)',多个模板则可以设置多次。
-wait= 当呈现一个新的模板到系统和触发一个命令的时候,等待的最大最小时间。如果最大值被忽略,默认是最小值的4倍。
-retry= 当在和consul api交互的返回值是error的时候,等待的时间,默认是5s。
-config= 配置文件或者配置目录的路径。
-pid-file= PID文件的路径。
-log-level= 设置日志级别,可以是"debug","info", "warn" (default), and "err"。
-dry Dump生成的模板到标准输出,不会生成到磁盘。
-once 运行consul-template一次后退出,不以守护进程运行。
Consul-Template模板语法
Consul Template解析以Go Template格式编写的文件。 如果您不熟悉语法,请阅读Go的文档和示例。 除Go提供的模板功能外,Consul Template还提供以下功能:
API函数
datacenters
在Consul目录中查询所有数据中心
{{ datacenters }}
例如:
{{ range datacenters }}
{{ . }}{{ end }}
可以指定一个可选的布尔值,指示Consul Template忽略不可访问或没有当前领导者的数据中心。启用此选项需要执行O(N + 1)操作,因此不建议在性能较高的环境中使用。
// Ignores datacenters which are inaccessible
{{ datacenters true }}
file
读取并输出磁盘上本地文件的内容。如果无法读取文件,则会发生错误。当文件更改时,Consul Template将获取更改并重新呈现模板。
{{ file "" }}
例如:
{{ file "/path/to/my/file" }}
呈现
file contents
这不会处理嵌套模板。
key
查询Consul获取给定键路径的值。如果密钥不存在,Consul Template将阻止呈现,直到密钥存在。要避免阻塞,请使用keyOrDefault
或keyExists
。
{{ key "@" }}
<DATACENTER>
属性是可选的;如果省略,则使用本地数据中心。
例如:
{{ key "service/redis/maxconns" }}
呈现
15
keyExists
查询Consul获取给定键路径的值。如果密钥存在,则返回true,否则返回false。与密钥不同,如果密钥不存在,则此功能不会阻止。这对于控制流量很有用。
{{ keyExists "@" }}
<DATACENTER>
属性是可选的;如果省略,则使用本地数据中心。
例如:
{{ if keyExists "app/beta_active" }}
# ...
{{ else }}
# ...
{{ end }}
keyOrDefault
查询Consul获取给定键路径的值。如果密钥不存在,则将使用默认值。与密钥不同,如果密钥不存在,则此功能不会阻止。
{{ keyOrDefault "@" "" }}
<DATACENTER>
属性是可选的;如果省略,则使用本地数据中心。
例如:
{{ keyOrDefault "service/redis/maxconns" "5" }}
呈现
5
请注意,Consul Template使用多阶段执行。在评估的第一阶段,Consul Template将没有来自Consul的数据,因此将始终回退到默认值。从Consul的后续读取将在下一个模板传递中从Consul(如果密钥存在)中提取实际值。这很重要,因为这意味着由于keyOrDefault中缺少key,Consul Template永远不会“阻止”模板的呈现。即使密钥存在,如果Consul尚未返回密钥的数据,也将使用默认值。
ls
查询给定键路径上所有顶级kv对的Consul。
{{ ls "@" }}
<DATACENTER>
属性是可选的;如果省略,则使用本地数据中心。
例如:
{{ range ls "service/redis" }}
{{ .Key }}:{{ .Value }}{{ end }}
呈现
maxconns:15
minconns:5
node
查询目录中节点的Consul。
{{node "@"}}
<NAME>
属性是可选的;如果省略,则使用本地代理节点。
<DATACENTER>
属性是可选的;如果省略,则使用本地数据中心。
例如:
{{ with node }}
{{ .Node.Address }}{{ end }}
呈现
10.5.2.6
要查询其他节点:
{{ with node "node1@dc2" }}
{{ .Node.Address }}{{ end }}
呈现
10.4.2.6
要访问TaggedAddresses或Meta等地图数据,请使用Go的文本/模板地图索引。
nodes
查询目录中所有节点的Consul。
{{ nodes "@~" }}
<DATACENTER>
属性是可选的;如果省略,则使用本地数据中心。
<NEAR>
属性是可选的;如果省略,则以词法顺序指定结果。如果提供了节点名称,则结果按照提供的节点的最短往返时间排序。如果提供_agent,则结果按照到本地代理的最短往返时间排序。
例如:
{{ range nodes }}
{{ .Address }}{{ end }}
呈现
10.4.2.13
10.46.2.5
要通过最短的自行车时间查询不同的数据中心和订单:
{{ range nodes "@dc2~_agent" }}
{{ .Address }}{{ end }}
要访问TaggedAddresses或Meta等地图数据,请使用Go的文本/模板地图索引。
secret
查询Vault以获取给定路径上的密钥。
{{ secret "" "" }}
<DATA>
属性是可选的;如果省略,请求将是一个文件库读取(HTTP GET)请求。如果提供,请求将是一个vault write
(HTTP PUT/POST)请求。
例如:
{{ with secret "secret/passwords" }}
{{ .Data.wifi }}{{ end }}
呈现
FORWARDSoneword
要访问版本化的秘密值(对于K/V版本2后端):
{{ with secret "secret/passwords?version=1" }}
{{ .Data.data.wifi }}{{ end }}
省略?version
参数时,将获取最新版本的secret。引用秘密值时请注意嵌套的.Data.data语法。
使用Vault版本0.10.0/0.10.1时,secret路径必须以“data”为前缀,即上述示例的secrt/data/passwords。对于0.10.1之后的Vault版本,这不是必需的,因为consul-template将检测正在使用的KV后端版本。版本2 KV后端在0.10.0之前不存在,因此这些是唯一受影响的版本。
使用write生成PKI证书的示例:
{{ with secret "pki/issue/my-domain-dot-com" "common_name=foo.example.com" }}
{{ .Data.certificate }}{{ end }}
参数必须是key = value对,并且每对必须是函数的自己的参数:
请注意,Vault不支持阻止查询。因此,如果secret被更改,Consul Template将不会立即重新加载,就像Consul的键值存储一样。 Consul Template将在原始secret的租约期限的一半时间内获取新secret。例如,Vault的通用secret后端中的大多数项目都有默认的30天租约。这意味着Consul Template将每15天更新一次secret。因此,建议在生成初始密钥时使用较小的租约期限,以迫使Consul Template更频繁地续订。
在使用将与Vault交互的模板时,还要考虑启用error_on_missing_key。默认情况下,Consul Template使用Go的模板语言。访问不存在的结构字段或映射键时,默认为打印“”。这可能不是理想的行为,尤其是在处理密码或其他数据时。因此,建议您设置:
template {
error_on_missing_key = true
}
您还可以使用if或with block来防止空值。
{{ with secret "secret/foo"}}
{{ if .Data.password }}
password = "{{ .Data.password }}"
{{ end }}
{{ end }}
secrets
查询Vault以获取给定路径上的机密列表。并非所有端点都支持列表。
{{ secrets "" }}
例如:
{{ range secrets "secret/" }}
{{ . }}{{ end }}
呈现
bar
foo
zip
要迭代并列出Vault中通用secret后端中的每个secret:
{{ range secrets "secret/" }}
{{ with secret (printf "secret/%s" .) }}{{ range $k, $v := .Data }}
{{ $k }}: {{ $v }}
{{ end }}{{ end }}{{ end }}
service
根据健康状况查询服务Consul。
{{ service ".@~|" }}
<TAG>
属性是可选的;如果省略,将查询所有节点。
<DATACENTER>
属性是可选的;如果省略,则使用本地数据中心。
<NEAR>
属性是可选的;如果省略,则以词法顺序指定结果。如果提供了节点名称,则结果按照提供的节点的最短往返时间排序。如果提供_agent,则结果按照到本地代理的最短往返时间排序。
<FILTER>
属性是可选的;如果省略,则仅返回健康服务。提供过滤器允许客户端过滤服务。
例如:
上面的示例是在“east-aws”数据中心查询Consul的健康“网络”服务。标记和数据中心属性是可选的。要查询当前数据中心的“Web”服务的所有节点(无论标记):
{{ range service "web" }}
server {{ .Name }}{{ .Address }}:{{ .Port }}{{ end }}
使用名为“web”的逻辑服务呈现所有健康节点的IP地址:
server web01 10.5.2.45:2492
server web02 10.2.6.61:2904
要访问NodeTaggedAddresses或NodeMeta等地图数据,请使用Go的文本/模板地图索引。
默认情况下,仅返回健康服务。要列出所有服务,请传递“any”过滤器:
{{ service "web|any" }}
这将返回注册到代理的所有服务,无论其状态如何。
要按特定的运行状况集过滤服务,请指定以逗号分隔的运行状况列表:
{{ service "web|passing,warning" }}
这将根据Consul中定义的节点和服务级别检查返回被视为“passing”或“warning”的服务。请注意,逗号表示“or”,而不是“and”。
注意:以下内容存在架构差异:
{{ service "web" }}
{{ service "web|passing" }}
前者将返回Consul认为“健康”和通过的所有服务。后者将返回在Consul代理注册的所有服务并执行客户端过滤。作为一般规则,如果您只想要健康的服务,请不要单独使用“传递”参数 - 而只是省略第二个参数。
services
查询目录中所有服务的Consul。
{{ services "@" }}
<DATACENTER>
属性是可选的;如果省略,则使用本地数据中心。
例如:
{{ range services }}
{{ .Name }}: {{ .Tags | join "," }}{{ end }}
呈现
node01 tag1,tag2,tag3
tree
查询给定键路径上所有kv对的Consul。
{{ tree "@" }}
<DATACENTER>
属性是可选的;如果省略,则使用本地数据中心。
例如:
{{ range tree "service/redis" }}
{{ .Key }}:{{ .Value }}{{ end }}
呈现
minconns 2
maxconns 12
nested/config/value "value"
不像ls,tree
返回所有key前缀,就像Unix tree
命令
Scratch
暂存器(或简称“stcatch”)在模板的上下文中可用于存储临时数据或计算。 Scratch数据不在模板之间共享,也不在调用之间缓存。
scratch.Key
如果数据存在于命名键的暂存器中,则返回布尔值。即使该键的数据为“nil”,仍然会返回true。
{{ scratch.Key "foo" }}
scratch.Get
返回指定键的暂存器中的值。如果数据不存在,则返回“nil”。
{{ scratch.Get "foo" }}
scratch.Set
将给定值保存在给定键上。如果该密钥已存在,则会被覆盖。
{{ scratch.Set "foo" "bar" }}
scratch.SetX
此行为与Set完全相同,但如果值已存在则不会覆盖。
{{ scratch.SetX "foo" "bar" }}
scratch.MapSet
将值保存在map中的命名键中。如果该密钥已存在,则会被覆盖。
{{ scratch.MapSet "vars" "foo" "bar" }}
scratch.MapSetX
此行为与MapSet完全相同,但如果值已存在则不会覆盖。
{{ scratch.MapSetX "vars" "foo" "bar" }}
scratch.MapValues
返回指定映射中所有值的排序列表(按键)。
{{ scratch.MapValues "vars" }}
辅助函数
与API函数不同,辅助函数不查询远程服务。这些函数对于解析数据,格式化数据,执行数学等非常有用。
base64Decode
接受base64编码的字符串并返回解码的结果,如果给定的字符串不是有效的base64字符串,则返回错误。
{{ base64Decode "aGVsbG8=" }}
呈现
hello
base64Encode
接受一个字符串并返回一个base64编码的字符串。
{{ base64Encode "hello" }}
呈现
aGVsbG8=
base64URLDecode
接受base64编码的URL安全字符串并返回解码结果,如果给定字符串不是有效的base64 URL安全字符串,则返回错误。
{{ base64Encode "hello" }}
呈现
aGVsbG8=
byKey
接受tree
调用返回的对的列表,并创建一个按顶级目录对对进行分组的映射。
例如:
groups/elasticsearch/es1
groups/elasticsearch/es2
groups/elasticsearch/es3
services/elasticsearch/check_elasticsearch
services/elasticsearch/check_indexes
使用以下模板
{{ range $key, $pairs := tree "groups" | byKey }}{{ $key }}:
{{ range $pair := $pairs }} {{ .Key }}={{ .Value }}
{{ end }}{{ end }}
呈现
elasticsearch:
es1=1
es2=1
es3=1
请注意,最顶层的键是从Key值中删除的。剥离后没有前缀的键将从列表中删除。
结果对被键控为一个映射,因此可以按键查找单个值:
{{ $weights := tree "weights" }}
{{ range service "release.web" }}
{{ $weight := or (index $weights .Node) 100 }}
server {{ .Node }} {{ .Address }}:{{ .Port }} weight {{ $weight }}{{ end }}
byTag
获取service
或services
函数返回的服务列表,并创建一个按标记对服务进行分组的映射。
{{ range $tag, $services := service "web" | byTag }}{{ $tag }}
{{ range $services }} server {{ .Name }} {{ .Address }}:{{ .Port }}
{{ end }}{{ end }}
contains
确定针是否在可迭代元素内。
{{ if .Tags | contains "production" }}
# ...
{{ end }}
containsAll
如果所有针都在可迭代元素内,则返回true,否则返回false。如果针列表为空,则返回true。
{{ if containsAll $requiredTags .Tags }}
# ...
{{ end }}
containsAny
如果任何针在可迭代元素内,则返回true,否则返回false。如果针列表为空,则返回false。
{{ if containsAny $acceptableTags .Tags }}
# ...
{{ end }}
containsNone
如果没有针在可迭代元素内,则返回true,否则返回false。如果针列表为空,则返回true。
{{ if containsNone $forbiddenTags .Tags }}
# ...
{{ end }}
containsNotAll
如果某些针不在可迭代元素内,则返回true,否则返回false。如果针列表为空,则返回false。
{{ if containsNotAll $excludingTags .Tags }}
# ...
{{ end }}
env
读取当前进程可访问的给定环境变量。
{{ env "CLUSTER_ID" }}
可以链接此函数来操作输出:
{{ env "CLUSTER_ID" | toLower }}
读取给定的环境变量,如果它不存在或为空,则使用默认值ex 12345
.
{{ or (env "CLUSTER_ID") "12345" }}
executeTemplate
执行并返回已定义的模板。
{{ define "custom" }}my custom template{{ end }}
This is my other template:
{{ executeTemplate "custom" }}
And I can call it multiple times:
{{ executeTemplate "custom" }}
Even with a new context:
{{ executeTemplate "custom" 42 }}
Or save it to a variable:
{{ $var := executeTemplate "custom" }}
explode
从tree
或ls
调用获取结果并将其转换为深度嵌套的映射以进行解析/遍历。
{{ tree "config" | explode }}
注意:在爆炸后,您将丢失有关密钥对的所有元数据。您还可以访问深层嵌套值:
{{ with tree "config" | explode }}
{{ .a.b.c }}{{ end }}
您需要在Consul中拥有关于数据的合理格式。有关更多信息,请参阅Go的文本/模板包。
indent
通过在每行前面添加N个空格来缩进文本块。
{{ tree "foo" | explode | toYAML | indent 4 }}
in
确定针是否在可迭代元素内。
{{ if in .Tags "production" }}
# ...
{{ end }}
loop
接受不同的参数,并根据这些参数区分其行为。
如果给出一个整数的循环,它将返回一个从零开始并循环到但不包括给定整数的goroutine:
{{ range loop 5 }}
# Comment{{end}}
如果给定两个整数,则此函数将返回从第一个整数开始并循环到但不包括第二个整数的goroutine:
{{ range $i := loop 5 8 }}
stanza-{{ $i }}{{ end }}
这将呈现:
stanza-5
stanza-6
stanza-7
注意:由于函数返回goroutine而不是切片,因此无法获取索引和元素。换句话说,以下内容无效:
# Will NOT work!
{{ range $i, $e := loop 5 8 }}
# ...{{ end }}
join
将给定的字符串列表作为管道并将其连接到提供的字符串上:
{{ $items | join "," }}
trimSpace
获取提供的输入并修剪所有空格,制表符和换行符:
{{ file "/etc/ec2_version" | trimSpace }}
parseBool
获取给定的字符串并将其解析为布尔值:
{{ "true" | parseBool }}
这可以与键和条件检查结合使用,例如:
{{ if key "feature/enabled" | parseBool }}{{ end }}
parseFloat
获取给定的字符串并将其解析为base-10 float64:
{{ "1.2" | parseFloat }}
parseInt
获取给定的字符串并将其解析为base-10 int64:
{{ "1" | parseInt }}
这可以与其他助手结合使用,例如:
{{ range $i := loop key "config/pool_size" | parseInt }}
# ...{{ end }}
parseJSON
获取给定的输入(通常是键中的值)并将结果解析为JSON:
{{ with $d := key "user/info" | parseJSON }}{{ $d.name }}{{ end }}
注意:Consul Template会多次评估模板,并且在第一次评估时,键的值将为空(因为尚未加载任何数据)。这意味着模板必须防止空响应。
parseUint
获取给定的字符串并将其解析为base-10 int64:
{{ "1" | parseUint }}
plugin
获取插件和可选有效负载的名称并执行Consul Template插件。
{{ plugin "my-plugin" }}
这通常与用于自定义的JSON过滤器结合使用:
{{ tree "foo" | explode | toJSON | plugin "my-plugin" }}
regexMatch
将参数作为正则表达式,如果在给定字符串上匹配则返回true,否则返回false。
{{ if "foo.bar" | regexMatch "foo([.a-z]+)" }}
# ...
{{ else }}
# ...
{{ end }}
regexReplaceAll
将参数作为正则表达式,并将所有出现的正则表达式替换为给定的字符串。与go一样,您可以使用$1之类的变量来引用替换字符串中的子表达式。
{{ "foo.bar" | regexReplaceAll "foo([.a-z]+)" "$1" }}
replaceAll
将参数作为字符串取代,并用给定的字符串替换给定字符串的所有匹配项。
{{ "foo.bar" | replaceAll "." "_" }}
此功能也可以与其他功能链接:
{{ service "web" }}{{ .Name | replaceAll ":" "_" }}{{ end }}
split
在提供的分隔符上拆分给定的字符串:
{{ "foo\nbar\n" | split "\n" }}
这可以与链接和管道与其他功能结合使用:
{{ key "foo" | toUpper | split "\n" | join "," }}
timestamp
以字符串(UTC)形式返回当前时间戳。如果没有给出参数,则结果是当前的RFC3339时间戳:
{{ timestamp }} // e.g. 1970-01-01T00:00:00Z
如果给出了可选参数,则它用于格式化时间戳。魔术参考日期Mon Jan 2 15:04:05 -0700 MST 2006可用于根据需要格式化日期:
{{ timestamp "2006-01-02" }} // e.g. 1970-01-01
作为一种特殊情况,如果可选参数是“unix”,则以秒为单位的unix时间戳将作为字符串返回。
{{ timestamp "unix" }} // e.g. 0
toJSON
从tree
或ls
调用获取结果并将其转换为JSON对象。
{{ tree "config" | explode | toJSON }}
呈现
{"admin":{"port":"1234"},"maxconns":"5","minconns":"2"}
注意:Consul将所有KV数据存储为字符串。因此,true为“true”,1为“1”,等等。
toJSONPretty
从tree
或ls
调用获取结果并将其转换为漂亮打印的JSON对象,缩进两个空格.
{{ tree "config" | explode | toJSONPretty }}
呈现
{
"admin": {
"port": "1234"
},
"maxconns": "5",
"minconns": "2",
}
注意:Consul将所有KV数据存储为字符串。因此,true为“true”,1为“1”,等等。
toLower
将参数作为字符串并将其转换为小写。
{{ key "user/name" | toLower }}
toTitle
将参数作为字符串并将其转换为标题。
{{ key "user/name" | toTitle }}
toTOML
从tree
或ls
调用获取结果并将其转换为TOML对象。
{{ tree "config" | explode | toTOML }}
呈现
maxconns = "5"
minconns = "2"
[admin]
port = "1134"
注意:Consul将所有KV数据存储为字符串。因此,true为“true”,1为“1”,等等。
toUpper
将参数作为字符串并将其转换为大写。
{{ key "user/name" | toUpper }}
toYAML
从tree
或ls
调用获取结果并将其转换为漂亮打印的YAML对象,缩进两个空格。
{{ tree "config" | explode | toYAML }}
renders
admin:
port: "1234"
maxconns: "5"
minconns: "2"
注意:Consul将所有KV数据存储为字符串。因此,true为“true”,1为“1”,等等。
数学函数
浮点数和整数值可以使用以下函数。
add
返回两个值的总和。
{{ add 1 2 }} // 3
这也可以与管道功能一起使用。
{{ 1 | add 2 }} // 3
subtract
返回第一个值与第二个值的差值。
{{ subtract 2 5 }} // 3
这也可以与管道功能一起使用。
{{ 5 | subtract 2 }} // 3
请仔细注意参数的顺序。
multiply
返回两个值的乘积。
{{ multiply 2 2 }} // 4
这也可以与管道功能一起使用。
{{ 2 | multiply 2 }} // 4
divide
返回第一个值的第二个值的除法。
{{ divide 2 10 }} // 5
这也可以与管道功能一起使用。
{{ 10 | divide 2 }} // 5
请仔细注意顺序或参数。
modulo
返回第一个值的第二个模的模数。
{{ modulo 2 5 }} // 1
这也可以与管道功能一起使用。
{{ 5 | modulo 2 }} // 1
请仔细注意参数的顺序。
Consul-Template使用
在进行以下测试前,你首先得有一个Consul集群。
命令行方式
输出已注册服务的名称和tag
注册服务
-
创建一个服务文件
]# cd /opt/consul/conf/ ]# cat hi-linux.json { "service": { "name": "hi-linux", "tags": ["web"], "port": 8000, "check": { "http": "http://10.114.0.61:8000", "interval": "10s" } } }
-
通过consul reload进行热注册
/opt/consul/bin/consul reload -http-addr=127.0.0.1:8500 Configuration reload triggered
-
验证服务是否注册成功
]# curl http://127.0.0.1:8500/v1/catalog/service/hi-linux [{"ID":"f177c224-86ca-eb08-75e4-3f52cb3db538","Node":"consul-client-1","Address":"10.114.0.61","Datacenter":"aliyun","TaggedAddresses":{"lan":"10.114.0.61","wan":"10.114.0.61"},"NodeMeta":{"consul-network-segment":""},"ServiceKind":"","ServiceID":"hi-linux","ServiceName":"hi-linux","ServiceTags":["web"],"ServiceAddress":"","ServiceWeights":{"Passing":1,"Warning":1},"ServiceMeta":{},"ServicePort":8000,"ServiceEnableTagOverride":false,"ServiceProxyDestination":"","ServiceProxy":{},"ServiceConnect":{},"CreateIndex":138042,"ModifyIndex":138068}]
使用Consul-Template渲染
-
创建模板文件
]# cd /opt/consul-template/ctmpl/ [root@UAT_PUB_Third_Platform_1 ctmpl]# cat hi-linux.ctmpl {{ range services }} {{ .Name }} {{ range .Tags }} {{ . }}{{ end }} {{ end }}
-
调用模板文件生成查询结果
]# consul-template \ -consul-addr=http://10.114.0.61:8500 \ -template="/opt/consul-template/ctmpl/hi-linux.ctmpl:./hi-linux.conf" \ -once
命令说明:
- -consul-addr:指定Consul API接口,默认端口8500。
- -template:模板参数,第一个参数是模板文件位置,第二个参数是结果输出位置。
- -once:只运行一次就退出。
-
查看模板渲染结果
]# cat hi-linux.conf consul hi-linux web
根据已注册的服务动态生成Nginx配置文件
-
新建Nginx配置模板文件
]# cd /opt/consul-template/ctmpl/ ]# cat nginx.conf.cfmpl {{ range services }} {{ $name := .Name }} {{ $service := service .Name }} upstream {{ $name }} { zone upstream-{{ $name }} 64k; {{ range $service }}server {{ .Address }}:{{ .Port }} max_fails=3 fail_timeout=60 weight=1; {{ else }}server 127.0.0.1:65535; # force a 502{{ end }} } {{ end }} server { listen 80 default_server; location / { root html; index index.html; } location /stub_status { stub_status; } {{ range services }} {{ $name := .Name }} location /{{ $name }} { proxy_pass http://{{ $name }}; } {{ end }} }
-
调用模板文件生成Nginx配置文件
]# consul-template \ -consul-addr=http://10.114.0.61:8500 \ -template="/opt/consul-template/ctmpl/nginx.conf.ctmpl:/usr/local/nginx/conf/vhosts/service.conf" \ -once
-
查看模板渲染结果
]# cat /usr/local/nginx/conf/vhosts/service.conf upstream consul { zone upstream-consul 64k; server 10.114.0.59:8300 max_fails=3 fail_timeout=60 weight=1; server 10.114.0.60:8300 max_fails=3 fail_timeout=60 weight=1; } upstream hi-linux { zone upstream-hi-linux 64k; server 10.114.0.61:8000 max_fails=3 fail_timeout=60 weight=1; } server { listen 80 default_server; location / { root html; index index.html; } location /stub_status { stub_status; } location /consul { proxy_pass http://consul; } location /hi-linux { proxy_pass http://hi-linux; } }
-
如果想生成后自动加载配置,可以这样
]# consul-template \ -consul-addr=http://10.114.0.61:8500 \ -template="/opt/consul-template/ctmpl/nginx.conf.ctmpl:/usr/local/nginx/conf/vhosts/service.conf:/etc/init.d/nginx reload" \ -once
运行Consul-Template作为一个服务
上面两个例子都是consul-template运行一次后就退出了,如果想运行为一个服务可以这样:
~]# consul-template \
-consul-addr=http://10.114.0.61:8500 \
-template="/opt/consul-template/ctmpl/nginx.conf.ctmpl:/usr/local/nginx/conf/vhosts/service.conf:/etc/init.d/nginx reload"
查询Consul实例同时渲染多个模板,然后重启相关服务。如果API故障则每30s尝试检测一次值,consul-template运行一次后退出。
]# consul-template \
-consul-addr=http://10.114.0.61:8500 \
-retry 30s \
-once \
-template="nginx.ctmpl:/etc/nginx/nginx.conf:service nginx restart" \
-template="redis.ctmpl:/etc/redis/redis.conf:service redis restart" \
-template="haproxy.ctmpl:/etc/haproxy/haproxy.conf:service haproxy restart"
查询一个实例,Dump模板到标准输出。主要用作测试模板输出。
]# consul-template \
-consul-addr=http://10.114.0.61:8500 \
-template="/opt/consul-template/ctmpl/nginx.conf.ctmpl:/usr/local/nginx/conf/vhosts/service.conf" \
-once \
-dry
配置文件方式
以上参数除了在命令行使用也可以直接配置在文件中,下面看看Consul-Template的配置文件,简称HCL(HashiCorp Configuration Language),它是和JSON兼容的。
consul {
# 指定要随请求传递的基本身份验证信息
auth {
enabled = true
username = "test"
password = "test"
}
# Consul代理的地址。默认127.0.0.1:8500
address = "127.0.0.1:8500"
# 连接Consul时使用的ACL令牌。如果未在Consul群集上启用ACL,则无需设置此选项。此选项也可通过环境变量CONSUL_TOKEN获得。
token = "abcd1234"
# 控制从Consul返回错误时的重试行为。 Consul Template具有高度容错能力,这意味着它不会在失败时退出。相反,它使用指数退避和重试功能来等待群集变得可用
retry {
# 这启用了重试。默认情况下启用重试,因此这是多余的。
enabled = true
# 指定了在放弃之前尝试的次数。每次尝试都会增加指数退避睡眠时间。将此值设置为零将实现无限次重试。
attempts = 12
# 重试尝试之间休眠的基本时间量。每次重试都会睡眠的指数比此基数长2。对于5次重试,睡眠时间为:250ms, 500ms, 1s, 2s, 然后是4s.
backoff = "250ms"
# 重试尝试之间休眠的最长时间。当max_backoff设置为零时,重试尝试之间的指数睡眠没有上限。如果max_backoff设置为10s且退避设置为1s,则睡眠时间为:1s, 2s, 4s, 8s, 10s, 10s, ...
max_backoff = "1m"
}
# 此块配置用于连接Consul服务器的SSL选项。
ssl {
# 启用了SSL。为SSL指定任何选项也将启用它。
enabled = true
# 启用了SSL对等验证。默认值为“true”,它将检查全局CA链以确保给定的证书有效。如果您使用的是未添加到CA链的自签名证书,则可能需要禁用SSL验证。
verify = false
# 用于进行身份验证的证书的路径。如果仅提供证书,则假定其包含证书和要转换为X509证书的密钥。如果同时指定了证书和密钥,Consul Template将自动将它们组合成X509证书。
cert = "/path/to/client/cert"
key = "/path/to/client/key"
# 这是证书颁发机构用作CA的路径。这对于自签名证书或使用其自己的内部证书颁发机构的组织非常有用。
ca_cert = "/path/to/ca"
# 这是PEM编码的CA证书文件目录的路径。如果同时指定了'ca_cert`和`ca_path`,则首选`ca_cert`。
ca_path = "path/to/certs/"
# 设置用于验证的SNI服务器名称。
server_name = "my-server.com"
}
}
# 这是侦听触发重载事件的信号。默认值如下所示。将此值设置为空字符串将导致CT不侦听任何重载信号。
reload_signal = "SIGHUP"
# 这是听取触发优雅停止的信号。默认值如下所示。将此值设置为空字符串将导致CT不侦听任何正常停止信号。
kill_signal = "SIGINT"
# 这是允许“陈旧”数据的最大间隔。默认情况下,只有Consul leader才会回复查询;对follower的任何要求都会转发给leader。在具有许多请求的大型群集中,这不是可扩展的,因此只要最后复制的数据在这些边界内,此选项允许任何关注者响应查询。值越高,群集负载越少,但更有可能产生过时的数据。
max_stale = "10m"
# 日志级别
log_level = "warn"
# 存储PID文件的路径,该文件将包含Consul Template进程的进程ID。
pid_file = "/path/to/pid"
# 这是静止计时器;它定义了等待群集达到一致状态的最小和最大时间量,在渲染模板之前。这对于具有大量抖动的系统很有用,因为它会减少模板渲染的次数。
wait {
min = "5s"
max = "10s"
}
# 表示Vault的配置部分的开始。本节中包含的所有值均与Vault有关。
vault {
# Vault leader的地址. 协议(http(s))部分是必需的
address = "https://vault.service.consul:8200"
# 这是定期秘密续租和秘密重新获得之间的宽限期。更新密钥时,如果剩余租约小于或等于配置的宽限,则Consul Template将请求新凭证。这可以防止Vault在到期时撤消凭据,并且Consul Template具有陈旧的凭据。注意:如果将此值设置为高于默认TTL或最大TTL的值,则Consul Template将始终读取新密码!对于可预测的行为,这也应该小于或约为TTL的1/3。
grace = "5m"
# 与Vault服务器通信时使用的令牌。与其他与Vault集成的工具一样,Consul Template假设您为Vault提供了一个Vault令牌;它没有通过Vault的auth方法生成令牌的合并逻辑。也可以通过环境变量VAULT_TOKEN指定该值。
token = "abcd1234"
# 这告诉Consul Template,提供的令牌实际上是一个包装的令牌,应该在使用之前使用Vault的cubbyhole响应包装解包。
unwrap_token = true
# 此选项告知Consul Template自动续订给定的Vault令牌。如果您不熟悉Vault的体系结构,则Vault会定期更新令牌,否则它们将被撤销。 Consul Template将在令牌的租约期限的一半时间自动续订令牌。默认值为true,但如果要使用带外进程续订Vault令牌,则可以禁用此选项。请注意,即使此选项设置为false,也始终会更新模板中指定的密码(例如,使用{{secret}})。此选项仅适用于顶级Vault令牌本身。
renew_token = true
# 介绍了连接Vault的重试选项。
retry {
# ...
}
# 用于连接Vault服务器的SSL选项。
ssl {
# ...
}
}
# 定义连接到syslog服务器以进行日志记录的配置。
syslog {
# 启用syslog日志记录。指定任何其他选项也会启用syslog日志记录。
enabled = true
# 发送日志到syslog facility
facility = "LOCAL5"
}
# 定义了重复数据删除模式的配置。
deduplicate {
# 实现了重复数据删除模式。指定任何其他选项还可以启用重复数据删除模式。
enabled = true
# 这是Consul的KV 存储中路径的前缀,其中重复数据删除模板将被预先渲染和存储。
prefix = "consul-template/dedup/"
}
# 定义了exec模式的配置。
exec {
# 这是作为子进程执行的命令。每个Consul Template流程只能有一个命令。
command = "/usr/bin/app"
# 这是在杀死命令之前等待的随机展开。默认值为0(无等待),但是大型群集应考虑设置splay值以防止所有子进程在数据发生更改时同时重新加载。当此值设置为非零时,Consul Template将在重新加载或终止子进程之前等待一段随机时间直到splay值。这可以用于防止在没有正常重新加载的应用程序上出现雷鸣般的群体问题。
splay = "5s"
env {
# 这指定子进程是否不应继承父进程的环境。默认情况下,子项将具有对父项的环境变量的完全访问权限。将此设置为true将仅将`custom_env`中指定的值发送到子进程。
pristine = false
# 这将在下面显示的表单中指定其他自定义环境变量,以注入子项的运行时环境。如果自定义环境变量与系统环境变量共享其名称,则自定义环境变量优先。即使指定了原始,白名单或黑名单,也都是有价值的,这个选项中的s被赋予子进程。
custom = ["PATH=$PATH:/etc/myapp/bin"]
# 指定了一个环境变量列表,专门包含在公共变量列表中。如果指定,则仅将与给定模式匹配的那些环境变量公开给子进程。这些字符串使用Go的glob函数进行匹配,因此允许使用通配符。
whitelist = ["CONSUL_*"]
# 这指定了一个环境变量列表,它们在暴露给子进程的环境变量列表中专门禁止。如果指定,则任何与给定模式匹配的环境变量都不会向子进程公开,即使它们已列入白名单。此选项中的值优先于白名单中的值。这些字符串使用Go的glob函数进行匹配,因此允许使用通配符。
blacklist = ["VAULT_*"]
}
# 定义了在监视模板中发生更改时将发送到子进程的信号。信号将仅在进程启动后发送,并且只有在所有相关模板至少呈现一次后才会启动该进程。默认值为nil,它告诉Consul Template停止子进程并生成一个新进程而不是向其发送信号。这对于遗留应用程序或无法在没有完全重新加载时无法正确重新加载其配置的应用程序非常有用。
reload_signal = ""
# 定义义了当Consul Template正常关闭时发送到子进程的信号。应用程序应该开始优雅的清理。如果应用程序没有在`kill_timeout`之前终止,它将被终止(实际上是“kill -9”)。默认值为“SIGTERM”。
kill_signal = "SIGINT"
# 定义了在Consul Template退出时等待子进程正常终止的时间。在此指定时间之后,子进程将被强制终止(实际上是“kill -9”)。默认值为“30s”。
kill_timeout = "2s"
}
# 义模板的配置。与其他块不同,可以多次指定此块以配置多个模板。也可以直接通过CLI配置模板。
template {
# 这是磁盘上用作输入模板的源文件。这通常称为“Consul Template template”。如果不使用`contents`选项,则需要此选项。
source = "/path/on/disk/to/template.ctmpl"
# 这是源模板将呈现的磁盘上的目标路径。如果父目录不存在,Consul Template将尝试创建它们,除非create_dest_dirs为false。
destination = "/path/on/disk/where/template/will/render.txt"
# 此选项告诉Consul Template如果它们不存在,则创建目标路径的父目录。默认值是true。
create_dest_dirs = true
# 此选项允许在配置文件中嵌入模板的内容,而不是将“source”路径提供给模板文件。这对于短模板很有用。此选项与`source`选项互斥。
contents = "{{ keyOrDefault \"service/redis/maxconns@east-aws\" \"5\" }}"
# 这是在呈现模板时运行的可选命令。该命令仅在生成的模板更改时运行。该命令必须在30秒内返回(可配置),并且必须具有成功的退出代码。 Consul Template不是流程监视器或init系统的替代品。
command = "restart service foo"
# 这是等待可选命令返回的最长时间。默认值为30秒。
command_timeout = "60s"
# 访问不存在的结构或映射字段/键时退出并出错。访问不存在的字段时,默认行为将打印“”。强烈建议您在从Vault中检索机密时将其设置为“true”。
error_on_missing_key = false
# 这是呈现文件的权限。如果未指定此选项,Consul Template将尝试匹配目标路径上已存在的文件的权限。如果该路径中不存在任何文件,则权限为0644。
perms = 0600
# 此选项在写入新模板之前备份先前在目标路径上呈现的模板。它只保留一个备份。此选项对于防止在没有回滚策略的情况下意外更改数据非常有用。
backup = true
# 这些是在模板中使用的分隔符。默认值为“{{”和“}}”,但对于某些模板,使用不与输出文件本身冲突的不同分隔符可能更容易。
left_delimiter = "{{"
right_delimiter = "}}"
# 这是在将新模板渲染到磁盘并触发命令之前要等待的“最小(:最大)”,用冒号(`:`)分隔。 如果省略可选的最大值,则假定它是所需最小值的4倍。 这是一个带有单位后缀(“5s”)的数字时间。 没有默认值。 模板的等待值优先于任何全局配置的等待。
wait {
min = "2s"
max = "10s"
}
}
注意: 上面的选项不都是必选的,可根据实际情况调整。为了更加安全,token也可以从环境变量里读取,使用CONSUL_TOKEN和VAULT_TOKEN。强烈建议你不要把token放到未加密的文本配置文件中。
接下来我们看一个简单的实例,生成Nginx配置文件并重新加载:
]# cd /opt/consul-template/conf/
]# cat nginx.conf.hcl
consul {
address = "10.114.0.61:8500"
}
reload_signal = "SIGHUP"
kill_signal = "SIGINT"
max_stale = "10m"
log_level = "warn"
pid_file = "/var/run/consul-template-nginx.pid"
wait {
min = "5s"
max = "10s"
}
syslog {
enabled = true
facility = "LOCAL5"
}
template {
source = "/opt/consul-template/ctmpl/nginx.conf.ctmpl"
destination = "/usr/local/nginx/conf/vhosts/server.conf"
create_dest_dirs = true
#contents = "{{ keyOrDefault \"service/redis/maxconns@east-aws\" \"5\" }}"
command = "service nginx reload"
command_timeout = "60s"
error_on_missing_key = false
perms = 0600
backup = true
left_delimiter = "{{"
right_delimiter = "}}"
wait {
min = "2s"
max = "10s"
}
}
注:nginx.conf.ctmpl模板文件内容还是和前面的一样。
执行以下命令就可渲染文件了:
]# consul-template -config "/opt/consul-template/conf/nginx.conf.hcl"
2019/02/26 17:28:12 [DEBUG] (logging) enabling syslog on LOCAL5
Reloading nginx: [ OK ]