本文描述一个 C++ 程序的自动化构建过程,涉及:
1、制作适用于 c++ 简单程序的基础镜像。
2、使用 CICD 进行编译和构建,并发布。在此过程,涉及到邮件通知。

本文示例在简单应用场合中有实践意义,即不使用如 jenkins 这样重型工具,如果信任现成免费的私有的服务,可将自动化工作迁移到公网,否则内建局域网服务或使用公有云搭建。

技术总结

  • 下载原始镜像
  • 在原始镜像的容器中,添加必要的文件,一般有链接器、动态库
  • 重新制作镜像,提交远程仓库。
  • 不同编译器,其依赖动态库,链接器不同,建议镜像的库,与宿主机一致。
  • 注意:不同程序依赖的动态库不同,在宿主机上用ldd命令可查看详情。

制作镜像

下载原始镜像

注:源码为 C++,使用 C++11 特性,选 alpine,其 C 库不是 glibc。选 busybox 64版本。在 64 位系统直接执行:

docker pull busybox

即可得到 64 位的版本。
运行 busybox:

docker run --name -it bar busybox sh

拷贝文件

基于 ubuntu 1604 64bit制作。标的程序为:

ldd test
        linux-vdso.so.1 =>  (0x00007ffe173f3000)
        libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007f506d62a000)
        libstdc++.so.6 => /usr/lib/x86_64-linux-gnu/libstdc++.so.6 (0x00007f506d2a8000)
        libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007f506cf9e000)
        libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007f506cd88000)
        libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f506c9be000)
        /lib64/ld-linux-x86-64.so.2 (0x0000558004458000)

容器执行:

mkdir -p  /lib64 /lib/x86_64-linux-gnu/ /usr/lib/gcc/x86_64-linux-gnu/5
date > /etc/version

宿主机执行:

docker cp /lib64/ld-linux-x86-64.so.2 bar:/lib64
docker cp /lib/x86_64-linux-gnu/ld-2.23.so bar:/lib/x86_64-linux-gnu/
docker cp /lib/x86_64-linux-gnu/libpthread.so.0 bar:/lib/x86_64-linux-gnu/
docker cp /lib/x86_64-linux-gnu/libpthread-2.23.so bar:/lib/x86_64-linux-gnu/
docker cp -a /usr/lib/x86_64-linux-gnu/libstdc++.so.6  bar:/lib/x86_64-linux-gnu/
docker cp -a /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.21  bar:/lib/x86_64-linux-gnu/
docker cp -a /lib/x86_64-linux-gnu/libm.so.6  bar:/lib/x86_64-linux-gnu/
docker cp -a /lib/x86_64-linux-gnu/libm-2.23.so  bar:/lib/x86_64-linux-gnu/
docker cp -a /lib/x86_64-linux-gnu/libc.so.6  bar:/lib/x86_64-linux-gnu/
docker cp -a /lib/x86_64-linux-gnu/libc-2.23.so  bar:/lib/x86_64-linux-gnu/
docker cp -a /lib/x86_64-linux-gnu/libgcc_s.so.1  bar:/lib/x86_64-linux-gnu/
docker cp -a /usr/lib/gcc/x86_64-linux-gnu/5/libgcc_s.so bar:/usr/lib/gcc/x86_64-linux-gnu/5/

在宿主机重新制作基础镜像:

docker commit bar registry.cn-hangzhou.aliyuncs.com/latelee/busybox:rt64

验证:

# 一窗口:
docker run -it --rm --name footest registry.cn-hangzhou.aliyuncs.com/latelee/busybox:rt64 sh
# 二窗口:
docker cp test footest:/
# 一窗口 即容器执行:
/test

验证正确后,上传:

docker push registry.cn-hangzhou.aliyuncs.com/latelee/busybox:rt64

使用

前面制作的镜像是基于ubuntu 16.04 64bit的运行时库,GCC版本为5.4,如此制作,是因为 busybox并没有带必备的动态库和链接器。在编译C++程序时,最好使用相同版本的编译器,如果使用不同版本的库,则还需要额外再制作。当然,如果嫌麻烦,可直接使用ubuntu的镜像,但体积较大,可权衡取舍。

编译后,假定得到test程序,将其拷贝到镜像中即可,Dockerfile可参考如下内容:

From registry.cn-hangzhou.aliyuncs.com/latelee/busybox:rt64

LABEL maintainer="Late Lee"

COPY test /
COPY config.yaml /

CMD ["/test"]

再制作镜像,上传到仓库,完成。

CICD 配置

上述步骤可自动化完成。将C++代码托管在 github 上,再利用 github 自带的 Actions 执行 CI 脚本,在该脚本中完成需要的操作。完整脚本如下:

name: C/C++ CI

on:
  push:
    branches: [ master ]
  pull_request:
    branches: [ master ] 

jobs:
  build:

    runs-on: ubuntu-16.04

    steps:
    - uses: actions/checkout@v2
    - name: make
      run: |
        make -C test/ -f Makefile_bin -j
        cp test/a.out test
    - name: ls
      run: ls * -lh
    - name: Publish to ali Registry
      uses: elgohr/Publish-Docker-Github-Action@master
      with:
        name: registry.cn-hangzhou.aliyuncs.com/latelee/ci_test:latest
        username: ${{ secrets.DOCKER_USER }}
        password: ${{ secrets.DOCKER_PASSWORD }}
        registry: registry.cn-hangzhou.aliyuncs.com
        dockerfile: Dockerfile

释义:使用 ubuntu-16.04系统,先用官方的actions/checkout下载代码,再编译,再利用现成的推送方案elgohr/Publish-Docker-Github-Action,并指定仓库名称、地址、账号密码,等等。当提交代码到仓库时,会自动编译、构建并上传到阿里云仓库。注意,为安全起见,账号和密码使用 secrets,需要在仓库中额外设置。

工程仓库

后续整理提供。