码蚁

打码改变人生

Docker 优雅解决容器配置文件

Posted at — Jan 9, 2017

容器配置文件是 Docker 内部比较棘手的问题,下面我将通过 etcd 优雅进行配置文件传递。

前言

在 Docker Container 概念中,如果还是把配置文件和镜像捆绑在一起的话,就失去了配置文件动态配置的意义了,一般应用配置传递有以下方式:

  1. 通过 ENV 传递,简单易用,但配置复杂的话就不好传递。
  2. 通过 Volume 挂载宿主机文件,此方法解决了配置复杂不好传递的问题,但如果在集群中,容器漂移到其他宿主机就找不到配置文件,缺乏横向扩展性。

其实最好的方式用 Zookeeper 或者 etcd 来存放配置数据,创建容器时通过 ENV 传递配置文件的 KEY,应用启动前用 KEY 拉取配置文件,然后启动应用,完美弥补上面方法的弊端。

etcd 简介

etcd 是一个应用在分布式环境下的 key/value 存储服务。利用 etcd 的特性,应用程序可以在集群中共享信息、配置或作服务发现,etcd 会在集群的各个节点中复制这些数据并保证这些数据始终正确。

实际上,etcd 作为一个受到 ZooKeeper 与 doozer 启发而催生的项目,除了拥有与之类似的功能外,更专注于以下四点:

etcd 集群搭建

这里下载 etcd,首先编辑配置文件「环境为 CentOS 7」:

# 节点名称,集群各个节点名称不能重复
ETCD_NAME=etcd1
# 数据目录
ETCD_DATA_DIR="/var/lib/etcd/etcd1"
# 集群节点之间通讯端口
ETCD_LISTEN_PEER_URLS="http://10.211.55.7:2380"
# 监听接受客户端请求地址
ETCD_LISTEN_CLIENT_URLS="http://0.0.0.0:2379"
# 集群通讯 宣告本节点地址
ETCD_INITIAL_ADVERTISE_PEER_URLS="http://10.211.55.7:2380"
# 集群成员
ETCD_INITIAL_CLUSTER="etcd1=http://10.211.55.7:2380,etcd2=http://10.211.55.8:2380,etcd3=http://10.211.55.9:2380"
# 表示这是在从无到有搭建 etcd 集群
ETCD_INITIAL_CLUSTER_STATE="new"
# 集群的识别码
ETCD_INITIAL_CLUSTER_TOKEN="k8s-etcd"
# 客户端 宣告地址
ETCD_ADVERTISE_CLIENT_URLS="http://10.211.55.7:2379"

注意:ETCD_INITIAL_CLUSTER_STATE 初始化的时候全部为 new。ETCD_INITIAL_CLUSTER_TOKEN 是集群的识别码,集群中每个节点都需要一样。ETCD_ADVERTISE_CLIENT_URLS 集群提供给客户端访问的 URL 需要暴露出来,不能是 127.0.0.1。ETCD_LISTEN_CLIENT_URLS 暴露自己的同时最好新增一个 127.0.0.1 的监听地址,便于 etcdctl 调用,当然用 0.0.0.0 也是可以的。ETCD_INITIAL_CLUSTER初始化时各个节点的集群信息。

使用 Systemd 守护进程:

$ vi /usr/lib/systemd/system/etcd.service

[Unit]
Description=Etcd Server
After=network.target
After=network-online.target
Wants=network-online.target

[Service]
Type=notify
WorkingDirectory=/app/docker/etcd/
# 配置文件路径
EnvironmentFile=-/app/docker/etcd/etcd.conf
# 程序目录及参数
ExecStart=/app/docker/etcd/etcd --name=${ETCD_NAME} \
           --data-dir=${ETCD_DATA_DIR} \
           --listen-peer-urls=${ETCD_LISTEN_PEER_URLS} \
           --listen-client-urls=${ETCD_LISTEN_CLIENT_URLS} \
           --initial-advertise-peer-urls=${ETCD_INITIAL_ADVERTISE_PEER_URLS} \
           --initial-cluster=${ETCD_INITIAL_CLUSTER} \
           --initial-cluster-state=${ETCD_INITIAL_CLUSTER_STATE} \
           --initial-cluster-token=${ETCD_INITIAL_CLUSTER_TOKEN} \
           --advertise-client-urls=${ETCD_ADVERTISE_CLIENT_URLS}
Restart=on-failure
LimitNOFILE=65536

[Install]
WantedBy=multi-user.target

重新载入 Systemd,扫描新的或有变动的单元:

$ systemctl daemon-reload

启动 etcd:

$ systemctl start etcd.service

开机自动 etcd:

$ systemctl enable etcd.service

关闭 etcd:

$ systemctl stop etcd.service

取消开机自启:

$ systemctl disable etcd.service

Python 交互工具

配置文件为便于存放,使用了 UrlEncode 进行转码。

工具地址在这里,支持 Python2 和 Python3,使用方法:

# 把本文文件 ./crmapp.conf 上传到 etcd,KEY 为 logstash/crmapp.conf,并进行 UrlEncode 编码
$ python etcd_python.py -H 10.78.170.65:2379 -t put -k logstash/crmapp.conf -v ./crmapp.conf -e
# 下载 KEY 为 logstash/crmapp.conf 到 ./crmapp.conf,并进行 UrlEncode 解码
$ python etcd_python.py -H 10.78.170.65:2379 -t get -k logstash/crmapp.conf -v ./crmapp.conf -d

Docker 中实现

使用 Dockerfile 时:

CMD ["/bin/bash", "-c", "/usr/bin/python /app/logstash-2.1.3/get_conf.py -H $CONF_HOSTS -t get -k $CONF_KEY -v $CONF_FILE -d && /app/logstash-2.1.3/bin/logstash -f $CONF_FILE"]

启动容器时我们需要使用 ENV 传递 etcd 集群地址,配置文件 KEY,配置文件路径就行了,这样我们就通过 ENV 完美解决了配置文件的问题。

comments powered by Disqus