写点什么

使用 Docker Configs 存储配置信息

作者:yombo
  • 2021 年 12 月 30 日
  • 本文字数:2836 字

    阅读完需:约 9 分钟

使用Docker Configs存储配置信息

在使用 configs 之前,在编排容器时,对于容器运行所需要的参数我都是通过环境变量的方式去配置的;所以在 compose.yml 中可以看到大量代码片段

 environment:       - "A=a"       - "B=b"
复制代码

这种方式虽然目前没有太大的问题,在工程实践上也没有太大的困难;但似乎仍有可以改进的地方,于是我把所有的环境变量配置,从 compose.yml 抽离成一个个独立的 envfile,使用 env_file 进行管理,于是可以该为这样的方式

env_file:       - ./env_files/configs.env # 引用外部配置文件的方式配置容器运行时的系统环境变量
复制代码

但这样还是有些弊端,比如我们现在要修改配置的话,修改完配置文件,还需要重新执行下容器编排文件。因为容器编排文件里是对所有容器的定义,这就会导致一些不涉及修改配置的其他服务也要跟着重启。虽然我们可以把每个服务单独维护一个编排文件,但这样就又失去了编排文件的意义。 那么,既然我们使用的是 Docker Swarm 方式来编排容器。从 Docker 的视角,如何管理配置呢?


简单的说,什么是 Docker Configs

Configs 允许存储一些非敏感信息,比如在容器运行之外的一些配置文件。这种方式可以保证 docker 镜像更加通用,而不需要将配置文件或者是环境变量绑定到容器。对于敏感信息,比如数据库账号之类的,建议使用secrets与 secrets 不同之处在于,configs 并没有对数据进行加密,而是直接把配置文件挂载到容器的文件系统中。同时允许任何时刻删除或者添加 configs,也可以共享 configs;为了支持更高灵活性,configs 内容可以是普通的字符串或者是二进制内容,当然二进制要保证大小在 512kb 之内

Docker 是如何管理 Configs

当你添加一个 config 到 swarm 时,Docker 会通过把 config 发送到 swarm manager;这个配置被加密存储在 Raft log 中,同时 swarm 集群中的各个 manager node 是共享这个 configs 信息,以确保所有的 manager node 都是同样的 configs 信息,即便在某个 manager node 被重置后,获取到的 configs 信息依旧如此

如果我们授权某个正在运行的 service 访问 config,config 信息会被以文件的形式挂载到容器里,请注意这里要与 volumes 区分。volumes 是把宿主机文件系统中的文件,挂载到容器中;而 config 相当于是把 swarm 的配置信息以文件的形式存放在容器中,两者本质上的差异还是比较明显的。默认情况下,挂载到容器里的 configs 信息,会存储在容器路径 /<config-name> 下;

一个 node 是否可以使用 configs,取决于这个 node 是否为 swarm manager 角色,或者有被授权访问 configs 的 service 运行在该 node 上。当容器任务停止运行时,共享给它的配置将从该容器的内存文件系统中卸载,并从节点的内存中刷新。

如果 node 与 swarm 失去了连接,已经访问 configs 的 service 仍然可以访问,只是不能够接受 configs 的更新,直到 node 恢复了与 swarm 的连接

如果要更新 stack,一定要更新 compose-file,然后重新执行 docker stack deploy -c <new-compose-file> <stack-name> 如果在 compose-file 中使用了一个新的 config,service 则会使用最新的 config,请注意 config 是不可以修改的,所以不能修改已经创建的 config,而是应该创建一个 config

运用到 Springboot

如一开始我介绍的,通过注入环境变量的方式,动态改变 springboot 程序运行状态的方式,是很常见的方式;一般来说,如果把 springboot 容器化后,我们考虑的便是如何能够通过参数的方式切换 springboot 运行的 profile 比如:

docker run --name application_name -e "SPRING_ACTIVE_PROFILES=**" <image>
复制代码

如果像我一样,好奇 springboot 如何映射环境变量,可以参考链接:

但上述方式,且不说优雅与否;从我的经验来看,要求管理 docker 的人或多或少的了解些要运行的 springboot 程序定义了那些 profiles,乃至知道关键配置属性是什么,才知道如何去声明环境变量,以注入到容器的环境中,这样就显得 docker 并不是那么灵活。

我们已经知道可以通过 docker config 创建配置信息,这些配置信息本身存储在 Docker Swarm 中(可以假设 Docker Swarm 中也有一个类似 k8s 的 etcd,是否如此我还不清楚),当容器引用某个 config 时,config 会以文件的形式存在于容器内的文件系统中,默认情况下 Linux 环境存在于容器内路径 /<config-name>

所以,我们可以通过环境变量的方式改变 springboot 启动时读取配置文件的路径,按照我们所指定的路径去读取配置文件,然后启动;这样我们就可以将 springboot 容器与配置完全分离,也便于我们版本管理配置;

docker run --name application_name -e "SPRING_CONFIG_LOCATION=/config-name" <image>
复制代码

如何更新 Docker Config

在使用 Docker Config 的方式成功部署后,遇到一个最迫切的问题就是:

我该如何让服务使用更新后的配置文件

Docker Config 被设计为版本化的。这是 Docker 设计时就决定了的。假设有个服务正在使用 myconfig 在运行,同时有另外一个服务也在使用 myconfig 在运行,这时候如果我们因为任意一个服务需要去修改配置,在没有强制版本控制的情况下,我们很可能是直接更新 myconfig 这个配置。这样的话,服务间就会因为共用同一个 config 而产生耦合。糟糕的话,我们本来是想修改服务 1 的,结果不但服务没有正确按照新配置启动,反而导致另外一个服务也没法正在运行了。参考:Let me try explaining why I think versioning is important;

如何操作

方式一,创建新的 docker config

  1. 很好理解,就是创建一个新的 docker config,配置文件内容修改后,就使用修改后的文件创建一个新的 docker config

docker config create new_config ./config.yaml
复制代码

2. 既然已经创建了一个新的 docker config,那么只需要让服务使用这个 config,并且重新启动就可以了

docker service update --force --config-rm old_config \ --config-add source=new_config,target=/bootstrap.yaml
复制代码

方式二,动态 docker config name

如果说更新服务的方式是 docker stack deploy ,或许有时候真的是要把整个 stack 更新一下呢。如果使用的 docker config 名称是固定的,像下面这样

services:  nginx:    configs:      - source: nginx.conf        target: /etc/nginx/nginx.confconfigs:  nginx.conf:    file: /etc/nginx/nginx.conf
复制代码

重复执行 docker stack deploy 可能会报错,错误信息可能是 :

Error response from daemon: rpc error: code = InvalidArgument desc = only updates to Labels are allowed

既然如此,那就让 docker config 的名字,随着 docker stack deploy 的执行而变化吧。我们把编排文件改成下面这个样子

services:  nginx:    configs:      - source: nginx.conf-${env.CONFIG_VERSION}        target: /etc/nginx/nginx.confconfigs:  nginx.conf-${env.CONFIG_VERSION}:    file: /etc/nginx/nginx.conf
复制代码

deploy 命令改为

CONFIG_VERSION=$(date +%s) docker stack deploy --compose-file docker-stack.yml stackname
复制代码

References


发布于: 刚刚
用户头像

yombo

关注

还未添加个人签名 2017.12.20 加入

还未添加个人简介

评论

发布
暂无评论
使用Docker Configs存储配置信息