β

docker 打包系统设计

nosa.me 139 阅读

最近一周我写完了 docker 打包系统,这是我使用 go 写的第一个系统,多多加油。

打包系统的输入是 git project 和 branch (还有 timeout ),输出是可以 run 的 image,中间打出的 app package 也可以另行保存。相比之前的虚拟机打包,有几个好处:

1. 可以在 git project 变化时自动触发打包,避免人为触发。虽然基于虚拟机打包也可以做到自动触发,但是对于环境沉重的虚拟机来说,我们之前的打包系统只是在上面打 app package,环境是我们事先部署好的;

检查「git project 变化」这点不难,以我们使用的 Gerrit 为例,可以这样:

ssh -p 29418 -i key_path user@git.xxx.com "gerrit stream-events"

比如获取到了下面的事件:


{
    "type": "ref-updated",
    "submitter": {
        "name": "Zhou xxx",
        "email": "zhouxxx@xxx.com",
        "username": "zhouxxx"
     },
     "refUpdate": {
         "oldRev": "f612a09551f848c22cc6b758ab6844c9afd73b00",
         "newRev": "c6f8b2214afcaa83d11a109703c31227e9ac4068",
         "refName": "master",
         "project": "projectName"
     }
}

匹配需要的 type 然后拿到 project 和 refName。

2. 解决虚拟机打包环境共用和资源争用的问题,这点显而易见。由于一个 git project 可能有多个 service,而且每个 service 依赖的环境可能不一样,所以对每一个 service 维护一个基础镜像(我们叫做 build image)。而且,代码变化之后 project 下面的所有 service 都要重新打包。

我们定义了一个 dockerfiles project 来专门存放 Dockerfile 等配置,目录结构如下:

dockerfiles/{project1,project2…}/{service1,service2…}/{Dockerfile,Buildfile…}

1. 对于一个 project,它有哪些 service 根据 dockerfiles/project/ 下面的目录名称来获取;

2. 上面说了每一个 service 都依赖一个 build image,考虑到 service 的 project 可能很大导致 git clone 耗时,build image 需要包含 project 代码。build image 去除 project 代码的部分我叫做 build base image(比如 centos6-java6-maven),它包含一些基础打包工具(比如 maven),相应的,build image 的名称格式是 service:build base image,比如 wdstack:centos6-java8-maven;

3. build base image 在 Buildfile 中定义,Buildfile 中还需要定义 build cmd,也就是打 app package 的命令;

4. Dockerfile 是用于打 run image 的,它依赖的 FROM 指令后面的 image 我们叫做 run base image,比如 centos6-java8-tomcat8,run image 的格式我定义为 service-branch:run base image,比如 wdstack-release_20151128:centos6-java8-tomcat8。

打 run image 的命令类似:


docker build --rm=true -t dockerRegistry/wdstack-release_20151128:centos6-java8-tomcat8 . && \
docker push dockerRegistry/wdstack-release_20151128:centos6-java8-tomcat8

5. 很显然,我们需要做两件事,第一件是在 build image 上面 build app package,build image 各不相同,由于我们使用 kubernetes,所以调用 kubernetes API 创建基于 build image 的 pod ( container ),build cmd 需要包含在 command ( entrypoint ) 中以便执行。

第二件事是打 run image,这个过程在任何 docker 中都可以进行,如果在打包系统运行的本地打,需要获取上面 build cmd 打出的 app package,这一点不容易,所以我选择在上面的 container 中打 run image。

所以,command 还要包括打 run image 的命令。

6. 既然两件事都要在同一个 container 中做,前面打出的 app package 如何给后面的 Dockerfile 使用?这里我定义了个目录,叫做 /PACKAGE_DIR,build cmd 打出的包需要在 /PACKAGE_DIR 中,Dockerfile 中可以直接使用 /PACKAGE_DIR 中的文件,比如:

COPY /PACKAGE/wdstack.tgz /

RUN tar xvzf /wdstack.tgz -C /wdstack

7. 事实上在做第一件事之前,还需要获取 branch 的最新代码,类似:

git fetch origin -p && git checkout branch && git pull

8. Dockerfile 同级目录还可以放置其他文件,供 Dockerfile 使用。

下面来整理一下整个过程。

1. 输入 project 和 branch (还可以指定 timeout );

2. 获取 dockerfiles project 最新配置,并获取 project 的所有 service;

3. 开始对每一个 service 执行打包;

4. 根据 Buildfile 获取 service 的 build base image 和 build cmd;

5. 检查 build image,名称为 service:build base image,如果 image 不存在,则创建;如果存在,则通过 git pull 更新。

build image 需要包括 project 和 dockerfiles 两个项目。

6. 调用 kubernetes API 创建基于 build image 的 pod,command 部分要写入 获取 branch 最新代码 + build cmd + 打 run image 代码。timeout 在此处用于控制 pod 执行时间。

7. 把信息存入数据库。

Related posts:

  1. build docker image in docker
  2. kubernetes 搭建
作者:nosa.me
未来不会有sa
原文地址:docker 打包系统设计, 感谢原作者分享。

发表评论