背景
1. 随着时间的积累,网络管理服务日趋复杂,运维同学很难完全弄清楚各个迭代版本的差异,而研发同学对于现网管理服务的部署细节也不是完全清楚,服务的交付成为一个痛苦的过程。
2. 因为网络管理服务的配置往往是跟机房相关的,新增一个机房需要对现网所有服务的配置文件进行修改。可想而知,新增一个机房需要投入多大的人力,而且容易出错。
3. 变更失败时,服务回退需要同时回退二进制文件,对应版本的配置文件以及其他依赖项,也是比较容易出错。
4. 服务的迁移也是需要将同一个服务的二进制文件,配置文件以及其他依赖项同时部署到新机器上
随着服务规模扩大,数量增多,研发和运维之间的矛盾会变得非常突出。本质是因为服务运行成功与部署成功之间存在一条沟,受到很多条件限制。
所以我们尝试用容器的方法将服务及其运行环境放到一起,简化部署过程,使得部署成功尽量等价于运行成功。
工作流
研发:gitlab + jenkins + 配置中心
运维:维护docker-compose.yml
研发->运维:docker镜像ID
说明:
1. 对于研发而言所有的docker镜像的编译配置都放在jenkins中
2. 配置中心:放置服务实际的配置+各服务的配置模版,服务的配置文件是编译docker镜像时动态生成,而非直接由研发提供。新增机房时无需提供新的配置文件,只需要在配置中心增加新机房配置,所有的服务都能够自动生成对应机房的配置。
3. docker-compose.yml:启动docker的配置文件,详见: Docker Compose
例子
以部门的一个服务unet3manager为例,服务由一个so文件+配置文件组成。
1. jenkins配置
主要看第二个shell命令
1) wiwo_cfg承担了配置中心的功能。build_images.sh是编译镜像的脚本;run.sh中集成了 所有机房相关的配置,将会根据模版生成配置文件;templates是各服务的配置文件模版。
2) build_image.sh和Dockerfile代码如下所示。最终将unet3manager.so、run.sh和配置文件模版放到了容器中。
cat build_image.sh
---#!/bin/bashsub_sys=$1module=$2tag=$3typeset -l module_low
module_low=${module}sed -i "s#%{sub_sys}#${sub_sys}#g" Dockerfile
sed -i "s#%{module}#${module}#g" Dockerfile
url="preugistry.XX/YY/${module_low}:${tag}"docker build -t ${url} .
docker push ${url}cat Dockerfile
---
FROM image_id
ADD run.sh root/
RUN mkdir -p root/%{sub_sys}/%{module}
COPY *.so /root/%{sub_sys}/%{module}/
COPY templates /root/templates
3) 最后给出docker镜像的ID。
如果$BUILD_NUMBER=42,则编译出来的镜像ID为: preugistry.XX/YY/unet3manager:42
2. 配置中心(run.sh+templates)
1) run.sh : 容器启动后的第一个命令,负责生成配置文件,启动服务。
脚本结构如下:(为了方便描述,只抽取出部分示意配置)
# 解析输入:/root/run.sh --azid=XX --module=YY# 获取参数, 过程省略# azid=XX# module=XX# 获取环境变量, 过程省略# serviceip=XX # serviceport=XX# 机房级别的变量case "$azid" in666888)
_zone="pre"
_zoneid="666888"
_regionid="666888"
_ns_unet_setr="${NS_UNET}/set${_regionid}"
_ns_unet_setz="${NS_UNET}/set${_zoneid}"
_ns_ulb_setr="${NS_ULB}/set${_regionid}"
# _unet3manager
_unet3manager_conf_lan_gw_ip="10.21.0.1"
# 其他配置 <...省略...>
;;4001)
;;
*)
echo "wrong azid name: ${azid}"
exit 1
;;
esac
echo ${_name_unet3manager:="${_ns_unet_setr}/UNet3Manager"}###### 找到服务模版 ##########cd /root
file=$module".conf"cp -f "templates/${file}.template" $file####### 环境变量 ##########sed -i "s#%{listen_ip}#${serviceip}#" $file
sed -i "s#%{listen_port}#${serviceport}#" $file####### 通用变量 ##########sed -i "s#%{name_unet3manager}#${_name_unet3manager}#" $file####### 各业务相关配置替换 ##########sed -i "s#%{unet3manager_conf_lan_gw_ip}#${_unet3manager_conf_lan_gw_ip}#"
$file###### 启动服务 ########mv -f $file /root/XX/conf
XX_start -c /root/XX/conf/$file
2) templates: 配置文件模版%{变量}的方法指代一个实际变量,运行时由run.sh根据配置信息生成实际的配置文件,unet3mananger配置文件如下:
$ cat templates/unet3manager.conf.template
[common]
subsys = usdn
module = UNet3Manager
[network]
listen-pair = 0.0.0.0:%{listen_port}:${HOME}/@{common.subsys}/@{common.module}/@{common.module}.so
client-pair = *:*:${HOME}/@{common.subsys}/@{common.module}/@{common.module}.so:
listen-ip = %{listen_ip}
listen-port = %{listen_port}
[log]
level = %{log_level}
maxsize = 10M
[name]
myname = %{unet3manager_name_myname}
udatabase = %{name_udatabase}
uvroutermanager = %{name_uvroutermanager}
unet3manager = %{name_unet3manager_notexist}
[plugin]
zookeeper = ${HOME}/aioplug/aioplug_zookeeper/aioplug_zookeeper.so
[zookeeper]
server = %{zookeeper_server}
[conf]
region_id = %{unet3manager_conf_region_id}
lan_gw_ip = %{unet3manager_conf_lan_gw_ip}
[mode]
pnat_only = %{unet3manager_mode_pnat_only}
3. 启动docker:运维同学拿到docker镜像之后,修改docker-compose.yml再重启docker就可以完成部署。
unet3manager:
image: preugistry.XX/YY/unet3manager:42
command: /root/run.sh --azid=666888 --module=unet3manager
container_name: unet3manager_ins1
ports:
- "192.168.153.97:XX:XX"
volumes:
- /var/log:/var/log
environment:
- SERVICEIP=192.168.153.97
- SERVICEPORT=7250
restart: always
CIO之家 www.ciozj.com 公众号:imciow