1.介绍
Consul 是一款服务网络平台,主要实现服务注册、服务发现、服务网格、服务网关、安全网络以及配置管理等多类服务,非常适合做为微服务架构的底层网络平台。
配置中心其实就是一个 KV 存储,我们如果做配置中心的话其实主要就是用 KV 存储部分,但是为了以后的可扩展性,我们可能会使用各种服务网格的能力,因此选择 Consul 相比 etcd 来说是可以使用很多扩展的功能,不需要自己再进行额外的开发了。
2.部署架构
Consul 推荐的部署方式是采用多个可用区实现部署,因为采用 Raft 一致性的算法,所以一般部署奇数个节点,官方建议生产环境部署 5 节点,分布于 3 个可用区,每个可用区内最多两个节点,这样可以承受两个节点或者 1 个可用区的丢失。多个可用区一般是多个机房,如果没有条件也可以部署在 1~2 个可用区内,如果只有 1 个机房,那么这里的可用区可以看作是机架,尽量使服务分布于不同的机架,这样可以容忍最多两个机架完全丢失。
对于小型环境建议将 Consul 代理部署在多个物理服务器上,至少运行 3 个节点,如下图所示:
这样可以允许 1 个节点故障,从而具备一定的容错性。
3.安装配置
3.1.前提准备
我们下面以 3 个节点为例进行部署,机器列表如下:
172.16.0.5 ec1
172.16.0.6 ec2
172.16.0.7 ec3
每个节点的操作系统都是 Ubuntu 22.04,不过我们这里选择使用二进制的安装包进行安装,和具体哪个平台的关系不大,访问下载链接:https://developer.hashicorp.com/consul/downloads 下载安装包,最新的稳定版安装包名称为:consul_1.16.1_linux_amd64.zip,也就是我们当前安装 Consul 的版本是:1.16.1
3.2.安装到节点
我们在每个节点上都通过相同的步骤进行安装:
# 解压并放到 PATH 下
unzip consul_1.16.1_linux_amd64.zip
mv consul /usr/local/bin/
# 查看版本
consul --version
# 开启命令自动提示 可以用 tab 看到多级命令
consul -autocomplete-install
complete -C /usr/local/bin/consul consul
# 创建用户
useradd --system --home /etc/consul.d --shell /bin/false consul
# 创建数据目录并授权
mkdir --parents /data/consul
chown --recursive consul:consul /data/consul
# 创建证书目录
mkdir -p /etc/consul.d/certs
这样的话每个机器都安装上了,我们这里的数据目录放在 /data/consul 下,生产环境部署时一般放到单独的数据盘下面。
3.3.生成密钥和证书
然后我们在其中一个节点,比如第一个节点生成 GOSSIP 密钥,用于客户端之间通信的加密,客户端通信采用对称加密,因此每个节点都需要使用相同的密钥:
consul keygen
生成之后会返回密钥的 base64 编码,我们将这串密钥保存好,等下配置要用。
然后我们生成用于 RPC 加密的 TLS 证书,这个用于在客户端和服务端之间通信进行加密,首先需要生成 CA,同样是在第一个节点执行:
# 进入证书目录
cd /etc/consul.d/certs/
consul tls ca create
执行之后会输出:
==> Saved consul-agent-ca.pem
==> Saved consul-agent-ca-key.pem
这样就生成了 consul-agent-ca.pem
和 consul-agent-ca-key.pem
,前者是公钥,后者是私钥,然后我们基于 CA 创建证书:
consul tls cert create -server -dc dc1 -domain consul
由于我们是 1 个集群,因此数据中心指定为 dc1
,这样执行之后默认会生成 dc1-server-consul-0.pem
和 dc1-server-consul-0-key.pem
证书文件。
因为接下来我们将采用客户端证书自动生成的方式,所以我们不用再手动生成客户端证书了,然后我们将生成好的 CA 和证书发送到另外两个节点:
scp -r /etc/consul.d/certs/ ec2:/etc/consul.d/
scp -r /etc/consul.d/certs/ ec3:/etc/consul.d/
其实我们这里也可以只发送 consul-agent-ca-key.pem
即可,证书可以在每个节点基于 CA 单独生成,这里全部发送过去其实是为了操作简单,每个节点都是采用相同的证书。
3.4.集群配置
现在我们开始在第 1 个节点上编写配置文件:
touch /etc/consul.d/consul.hcl
chmod 640 /etc/consul.d/consul.hcl
然后我们编辑 /etc/consul.d/consul.hcl
写入下面的配置:
datacenter = "dc1"
data_dir = "/data/consul"
encrypt = "AU4FQ/rbbxqMQXRN5vA1QP1UHoDb8lubANa9llmXOEQ="
tls {
defaults {
ca_file = "/etc/consul.d/certs/consul-agent-ca.pem"
cert_file = "/etc/consul.d/certs/dc1-server-consul-0.pem"
key_file = "/etc/consul.d/certs/dc1-server-consul-0-key.pem"
verify_incoming = true
verify_outgoing = true
}
internal_rpc {
verify_server_hostname = true
}
}
auto_encrypt {
allow_tls = true
}
retry_join = ["172.16.0.6", "172.16.0.7"]
acl {
enabled = true
default_policy = "deny"
enable_token_persistence = true
}
其中的配置需要注意的有:
datacenter
和上面生成证书时配置一致,即:dc1
data_dir
配置我们实际的数据目录,即:/data/consul
encrypt
就是刚才生成的 gossip 密钥值- 证书的路径注意配置正确
retry_join
配置自动发现的节点,这样初始化的时候就不需要手动加入了。
配置好之后保存并退出。
然后继续创建服务配置文件:
touch /etc/consul.d/server.hcl
chmod 640 /etc/consul.d/server.hcl
然后编辑 /etc/consul.d/server.hcl
添加内容如下:
server = true
bootstrap_expect = 3
bind_addr = "172.16.0.5"
client_addr = "0.0.0.0"
performance {
raft_multiplier = 1
}
connect {
enabled = true
}
addresses {
grpc = "127.0.0.1"
}
ports {
grpc = 8502
grpc_tls = 8503
http = 8500
}
其中需要注意的配置有:
server
设置为 true 表示处于服务模式。bootstrap_expect
表示预期的节点数量,这里配置为 3bind_addr
表示服务绑定的地址,默认不配置也可以,默认值是:0.0.0.0
client_addr
表示客户端绑定的地址,也就是 HTTP 和 DNS 绑定的地址,这个默认是127.0.0.1
,因此必须要设置下。addresses.grpc
表示绑定 gRPC API 的地址,由于我们使用了 TLS 的 gRPC,因此这里为了安全改为了127.0.0.1
ports
下面配置端口,其中grpc
默认是 8502,grpc_tls
默认是 8503,http
默认是 8500
配置好之后保存并退出。
然后我们同步配置文件到另外的节点:
scp /etc/consul.d/*.hcl ec2:/etc/consul.d/
scp /etc/consul.d/*.hcl ec3:/etc/consul.d/
然后所有节点都重新设置下配置目录的权限:
# 所有节点都执行
chown --recursive consul:consul /etc/consul.d
然后我们分别在 ec2 和 ec3 上修改配置,主要是改几个和 IP 相关的:
ec2 上面修改 consul.hcl,修改 retry_join
改为另外两个节点的:
retry_join = ["172.16.0.5", "172.16.0.7"]
然后修改 server.hcl,修改 bind_addr
:
bind_addr = "172.16.0.6"
同样修改 ec3 上面的 consul.hcl:
retry_join = ["172.16.0.5", "172.16.0.6"]
修改 server.hcl:
bind_addr = "172.16.0.7"
最后修改完毕都保存一下。
我们需要选 1 个节点启动 Web UI 服务,一般不用每个节点都启动,这里选择第一个节点 ec1 编辑 server.hcl
配置,添加内容如下:
ui_config {
enabled = true
}
添加后保存配置。
3.5.服务启动
然后在每个机器上都创建 service 服务文件:/etc/systemd/system/consul.service
填写内容如下:
[Unit]
Description="HashiCorp Consul - A service mesh solution"
Documentation=https://www.consul.io/
Requires=network-online.target
After=network-online.target
ConditionFileNotEmpty=/etc/consul.d/consul.hcl
[Service]
EnvironmentFile=-/etc/consul.d/consul.env
User=consul
Group=consul
ExecStart=/usr/local/bin/consul agent -config-dir=/etc/consul.d/
ExecReload=/bin/kill --signal HUP $MAINPID
KillMode=process
KillSignal=SIGTERM
Restart=on-failure
LimitNOFILE=65536
[Install]
WantedBy=multi-user.target
每个机器都填写好并且保存,然后启动前先验证下配置文件的正确性:
consul validate /etc/consul.d/
如果校验失败会提示错误,比如上面的 grpc_tls
配置文档没写,但是校验不通过,因此这些报错都需要根据具体的提示进行修改,最终校验通过说明配置基本没有问题。
然后我们在所有节点上依次启动服务:
systemctl start consul
启动后查看状态和日志是否正常:
systemctl status consul
journalctl -u consul.service -f
有个别的报错一般没什么影响,比如离线环境可能远程更新会报错,以及个别连接断开的问题。在全部启动之前每个启动的节点都会等待发现的节点启动,直到所有的节点完全启动集群运行就正常了。
如果需要也可以设置开机自动启动:
systemctl enable consul
3.6.生成访问密钥
启动之后我们需要生成 SecretID 用于客户端或者 UI 的访问:
consul acl bootstrap
这个命令只能执行 1 次后续无法继续执行,创建后返回的内容要保存好,之后访问时都会用到,具体还可以设置访问策略,这里就不再详细说了,放到后续的使用文档中再来整理。
然后需要设置环境变量,建议添加到用户环境变量配置中:
# 这个 token 就是上面生成的 SecretID
export CONSUL_HTTP_TOKEN="d8004e40-7621-fb51-14de-48d9339e65e0"
然后可以查看集群的状态:
consul info
# 查看集群节点
consul members
然后我们还可以访问 Web UI,地址为:http://172.16.0.5:8500,访问之后输入上面的 token 就可以登录上去,然后就可以通过页面进行服务、Key/Value 相关的操作了。
我们如果使用 HTTP API 访问,需要在 Header 里面加上 X-Consul-Token
,比如:
curl --header "X-Consul-Token: d8004e40-7621-fb51-14de-48d9339e65e0" http://127.0.0.1:8500/v1/kv/a/b
和使用 cli 访问是类似的,比如:
consul kv get a/b
这样 Consul 集群就基本上安装完毕了。
3.7.Web UI 开启 HTTPS 配置
到上面已经部署完成了,不过默认情况下 Consul 是采用 HTTP 方式访问 Web UI 或者 API,如果有需要也可以开启 HTTPS 访问的方式,我们首先修改 Web UI 配置节点的配置文件:/etc/consul.d/consul.hcl
修改 tls
块下面的配置如下:
tls {
defaults {
ca_file = "/etc/consul.d/certs/consul-agent-ca.pem"
cert_file = "/etc/consul.d/certs/dc1-server-consul-0.pem"
key_file = "/etc/consul.d/certs/dc1-server-consul-0-key.pem"
verify_incoming = false
verify_outgoing = true
}
internal_rpc {
verify_server_hostname = true
verify_incoming = true
}
}
我们将 defaults 中 verify_incoming
的值改为 false
,这样就不会拒绝 HTTPS 和 RPC 连接了,然后我们在 internal_rpc
中再添加 verify_incoming = true
的配置表示对 RPC 进行验证,这样就可以只对 HTTPS 放行了,然后我们保存配置文件。
如果我们只想 Web UI 通过 HTTPS 访问,而不使用 HTTPS API 访问其他节点,那么这个配置不需要同步,但是如果我们需要在所有的节点都想通过 HTTPS API 的方式访问服务,那么每个节点都需要按照上面进行同步修改,否则除了 Web UI 无法通过其他节点无法访问。
然后编辑 /etc/consul.d/server.hcl
配置文件,在 ports
中添加 HTTPS 访问端口:
ports {
grpc = 8502
grpc_tls = 8503
http = 8500
https = 8501
}
这里推荐使用约定的 8501 作为 HTTPS 的端口,与此同时 HTTP 也同时开着,如果我们想关闭 HTTP 需要设置如下:
ports {
grpc = 8502
grpc_tls = 8503
http = -1
https = 8501
}
这样就只提供 HTTPS 访问了,然后保存配置并且同步到所有的节点,以保证都开启一致的服务,也就是每个节点都需要开启 HTTPS。
上面两个配置修改完成后,所有节点依次重启 Consul 服务,然后通过 HTTPS 访问 Web UI 就可以了。
如果使用命令行方式访问,需要指定本地公钥签名的位置或者放到根证书目录中,否则 curl 认为不安全会报错:
curl --header "X-Consul-Token: d8004e40-7621-fb51-14de-48d9339e65e0" --cacert /etc/consul.d/certs/consul-agent-ca.pem https://127.0.0.1:8501/v1/kv/a/b
这样 HTTPS 服务就开启成功了。
Reference:
- 集群安装
- https://developer.hashicorp.com/consul/tutorials/production-deploy/security
- https://developer.hashicorp.com/consul/tutorials/security-operations/tls-encryption-openssl-secure#configure-the-consul-ui-for-https