环境深度容器化建设

原创:陈斌 张少华


本期导读

1.为提升部署效率持续集成测试环境从胖docker向深度容器化的改进;

2.架构采用Rancher + Harbor,网络采用pipework为容器配置固定的IP地址;

物理架构

在测试环境建设过程中由于模块数量快速增加,为了提高部署效率和稳定性我们在容器化的基础上进行了深度容器化的探索,深度容器化采用了Rancher + Harbor的架构,该架构有非常优良的性能,非常适合以pod为单位进行子系统级别测试环境建设。

网络配置

如上图所示,每一个Node节点对应现在的一套测试环境,拥有独立的ip。

其实现原理为Node节点是Dind生成容器,创建后使用pipework为容器配置固定的IP地址,之后可在Node中启动多个Pod,分享使用Node的IP地址。

对比Cattle和K8S使用过程中的差异

由于我们测试需求的特殊性,目前Rancher上面的服务群并不需要频繁的做升级,而是会频繁的创建和释放。Cattle的稳定性和易用性要优于K8S,但是K8S提供了更加强大的周边功能包括资源管理、监控、配置管理等。

Cattle:

(1)多服务应用,每个项目都作为独立的服务受Rancher管理,升级比较方便。缺点是需要以应用(stack)为单位进行扩展和调度,因为我们其实是把一个应用里的多个容器包在一起对外提供服务。

扩展方式 :stack-copy、或者通过模板创建(效率略低于主从容器方式)。

(2)主从容器,一个容器作为主容器,添加多个从容器,耦合关系更紧密,优点是以服务(service)为单位进行扩展和调度。

扩展方式:由于资源对象的编号,直接scale即可。

缺点:

当需要对该服务做升级时,会重启所有容器,从容器越多,升级越慢。因为升级的最小操作单元就是服务。

当在服务中使用负载均衡时,而该服务又拥有从服务的时候,你需要使用主服务作为负载均衡器的目标。从服务不能成为目标。

从服务不能使用links/external_links来创建服务别名。

内部访问:Cattle提供了内部DNS解析,直接以容器名访问。

K8S:

多容器Pod

以Pod为单位进行调度,一个Pod里面启动多个容器,类似于Cattle的主从容器方式,但是差异在于网络。

扩展方式:scale(效率不高)。

内部访问:Pod内的所有容器共享网络namespace,其实就是都通过-net=container(Pod创建时有一个sleep容器) 共享了同一个网络,所以端口不能冲突,容器直接以localhost(或者127.0.0.1)访问。

缺点:

扩展效率低下。

容器之间的相互通信不是十分稳定。

优点:有一系列的强大的利于编排的功能,比如 initContainer、HPA、PV等都是非常好的特性。

CI 工作流

数据库组件容器化


Mysql容器化

我们测试环境使用的mysql版本是5.6.41,所以我们制作mysql-5.6.41的镜像,制作过程比较简单

(1)拉取官方镜像启动,环境变量必须要设置。

docker run -p 3300:3306 --name mysql  -e MYSQL_ROOT_PASSWORD=root123 -d docker.io/mysql:5.6.41

(2)利用docker cp 将我们的配置文件复制到该容器中

docker cp ${PWD}/my.cnf mysql:/etc/mysql/

(3)利用docker commit命令 将修改部分提交,

docker commit mysql 192.168.1.251:7003/qa/mysql:5.6.41-private

(4)推送到Harbor

docker push 192.168.1.251:7003/qa/mysql:5.6.41-private

(5)启动试一下:

docker run -p3301:3306 -e MYSQL_ROOT_PASSWORD=root@123 -e TZ=Asia/Shanghai --name mysql-p -d -v /home/demo/data2:/var/lib/mysql 192.168.1.251:7003/qa/mysql:5.6.41-private

(6)客户端连接,使用我们启动时指定的root的密码,然后查看一下配置是否正确,找一个我们配置文件里的自定义选型比对一下:

(7)没问题,完成。注意数据卷的使用,不要把数据放在容器内部,这部分,具体使用还要再做规划。

Mongo容器化(3.6.4)

先看下咱们的配置文件,没有什么特殊配置,可以直接拉取官方镜像启动,然后看下mongo镜像的启动参数:

环境变量:


配置文件默认在 /etc下,启动时 使用–config /etc/mongo/mongo.conf 来指定自定义配置,这里不需要。我们只需要直接启动官方镜像,把数据文件映射出来即可。

docker run -p 27000:27017 -v /home/demo/mongodata:/data --name mongo-p -d -e MONGO_INITDB_ROOT_USERNAME=admin -e MONGO_INITDB_ROOT_PASSWORD=admin -e TZ=Asia/Shanghai 192.168.1.251:7003/qa/mongo:3.6.4

客户端连接一下试试:

Redis容器化(3.2.12)

其实原理跟mysql类似,这里简单写了个Dockerfile,因为redis启动必须指定配置文件

FROM docker.io/redis:3.2.12

MAINTAINER xxx@xxx.com

COPY redis.conf /usr/redis.conf

CMD [ "redis-server", "/usr/redis.conf" ]

对配置文件做了一点修改,把日志文件去掉了,在容器里,我们一般都是使用docker logs 查看日志,需要把日志输出出来,而不是写入文件里。

docker build -t 192.168.1.251:7003/qa/redis:3.2.12 .

docker run -p 6300:6379 -v /home/demo/redisdata2:/data -e TZ=Asia/Shanghai --name redis-p -d 192.168.1.251:7003/qa/redis:3.2.12

连接成功,注意这里没设置密码验证。如果想要加上密码,也非常简单,redis支持一系列的command line,使用方式跟在配置文件里面的key值完全一样,比如这里我们要加上密码验证,只需要在docker 启动命令最后加上 


(注意docker run的启动参数是有顺序的,在镜像名字后面的内容都认为是command,平时启动镜像,一般的参数都写在镜像名字之前)

应用容器化


S2I 对接生产

由于生产使用OpenShift,原有的镜像构建流水线做出的镜像虽然比较简单易用,但无法与OpenShift兼容,所以借助OpenShift提供的镜像构建工具 s2i 去做镜像。缺陷就是目前这个基础镜像太大了。

本地构建方式:

(1)安装s2i,并拉取基础镜像到本地

(2)拉取代码,并切换到项目根目录,例如:/home/work/dev/projects/hydra

(3)执行s2i构建:s2i build . 192.168.1.251:7003/qa/python:2.7-oc hydra -e GIT_REPO_NAME=hydra (必填:通过这个环境变量来指定项目名称,并且会影响到代码在容器中的路径)

(4)启动镜像:通过上面的命令,构建出了一个名字为 hydra,tag为latest的镜像,要启动这个镜像,也非常简单,需要指定几个环境变量

- env:

- name: GIT_REPO_NAME

value: hydra

- name: INI_CMD

value: (测试环境一般不需要这个变量)

- name: RUN_CMD

value: make start_test

- name: RUN_CMD_DIR

value: /data/home/work/hydra/

应用修改:

(1)测试时同一个Pod里面启动多个容器,所以nginx 不能启动会有端口冲突。uwsgi启动需要将socket替换为http-socket并且端口不能冲突,由于日志管理不便,暂时舍弃。

(2)Makefile 添加用于测试环境的启动和初始化的命令

启动命令(RUN_CMD):start_test,先做make local_config操作,然后做启动操作,直接runserver启动即可

初始化命令(INI_CMD):测试一般不需要,线上一般会复制nginx配置

(3)以hydra 的修改为例子:

修改tools/config_templates/gen_config.py  直接vim编辑,将class LocalSettings(object) 这个类里的localhost全部替换为127.0.0.1,因为localhost不走物理网卡,一些数据库连接会直接在容器内部找socket,导致连不上。

Makefile 根据需要启动的服务类型添加了两个target:

start_test:local_config

        DJANGO_SETTINGS_MODULE="hydra.settings" python manage.py runserver 0.0.0.0:19010 --noreload

start_celery-hydra_upload-1_test:local_config

        DJANGO_SETTINGS_MODULE="hydra.settings" PYTHONPATH="." /data/home/work/hydra/.venv/bin/celery worker -A async_tasks -Q hydra,hydra_loan_notify,hydra_repay_notify -P eventlet -c 200 -l info --

logfile=/tmp/celery.log --without-heart

启动hydra:分别传入不同的RUN_CMD来启动两个服务,例如:make start_test

应用接入方式


配置修改

总体方式是——根据该项目依赖的外部服务,将配置修改为通过环境变量读取,由于之前的不规范,大部分项目都涉及如下三个文件的修改:

(1)Makefile 增加 docker_config,以hydra为例:

 (2)修改tools/config_templates/gen_config.py 

 (3)修改tools/config_templates/local_settings.py.tmpl 配置模板里面全局替换一下

项目根目录添加启动脚本:

entrypoint.sh 原因:部分项目需要在启动之前先生成配置文件

根据不同项目框架 操作不同:

django项目:

#!/bin/bash

make docker_config

python manage.py runserver 0.0.0.0:8080 --noreload

flask项目:

#!/bin/bash

make docker_config

gunicorn -k gevent -c gunicorn_dev.py yin.app:app

容器化现存问题


日志采集

需求:

(1)持久化存储

将日志文件持久化存储,按hostname区分。一个pod里面通常会有小到几个大到几十个容器,统一把日志挂载到其中的stubs容器中,然后再挂载的pv上面。

缺点:

1.查看不方便,动态pv不能根据名字区分出来是哪个deploy的日志。

2.多个replicaSet副本的日志都绑到了同一个目录下,文件众多,查找不便。

备选方案一:阿里云logtail(收费)

备选方案二:efk 

备选方案三:graylog

当前采取的方式是:

在stubs容器中安装了ssh服务,然后通过rsync去同步case日志。

在释放资源之前,利用kubectl cp 持久化存储服务日志。

去除依赖

目前自动化体系,对基础库的每日构建、stubs更新等依赖严重。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 202,529评论 5 475
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,015评论 2 379
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,409评论 0 335
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,385评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,387评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,466评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,880评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,528评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,727评论 1 295
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,528评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,602评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,302评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,873评论 3 306
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,890评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,132评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,777评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,310评论 2 342