本文描述一个 C++ 程序的自动化构建过程,涉及:
1、制作适用于 c++ 简单程序的基础镜像。
2、使用 CICD 进行编译和构建,并发布。在此过程,涉及到邮件通知。
本文示例在简单应用场合中有实践意义,即不使用如 jenkins 这样重型工具,如果信任现成免费的私有的服务,可将自动化工作迁移到公网,否则内建局域网服务或使用公有云搭建。
技术总结
- 下载原始镜像
- 在原始镜像的容器中,添加必要的文件,一般有链接器、动态库
- 重新制作镜像,提交远程仓库。
- 不同编译器,其依赖动态库,链接器不同,建议镜像的库,与宿主机一致。
- 注意:不同程序依赖的动态库不同,在宿主机上用
ldd
命令可查看详情。
制作镜像
下载原始镜像
注:源码为 C++,使用 C++11 特性,选 alpine,其 C 库不是 glibc。选 busybox 64版本。在 64 位系统直接执行:
即可得到 64 位的版本。
运行 busybox:
1
| docker run --name -it bar busybox sh
|
拷贝文件
基于 ubuntu 1604 64bit制作。标的程序为:
1 2 3 4 5 6 7 8
| 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)
|
容器执行:
1 2
| mkdir -p /lib64 /lib/x86_64-linux-gnu/ /usr/lib/gcc/x86_64-linux-gnu/5 date > /etc/version
|
宿主机执行:
1 2 3 4 5 6 7 8 9 10 11 12
| 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/
|
在宿主机重新制作基础镜像:
1
| docker commit bar registry.cn-hangzhou.aliyuncs.com/latelee/busybox:rt64
|
验证:
1 2 3 4 5 6
| # 一窗口: docker run -it --rm --name footest registry.cn-hangzhou.aliyuncs.com/latelee/busybox:rt64 sh # 二窗口: docker cp test footest:/ # 一窗口 即容器执行: /test
|
验证正确后,上传:
1
| docker push registry.cn-hangzhou.aliyuncs.com/latelee/busybox:rt64
|
使用
前面制作的镜像是基于ubuntu 16.04 64bit的运行时库,GCC版本为5.4,如此制作,是因为 busybox并没有带必备的动态库和链接器。在编译C++程序时,最好使用相同版本的编译器,如果使用不同版本的库,则还需要额外再制作。当然,如果嫌麻烦,可直接使用ubuntu的镜像,但体积较大,可权衡取舍。
编译后,假定得到test程序,将其拷贝到镜像中即可,Dockerfile可参考如下内容:
1 2 3 4 5 6 7 8
| 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 脚本,在该脚本中完成需要的操作。完整脚本如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| 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,需要在仓库中额外设置。
工程仓库
后续整理提供。