在travis ci中使用docker镜像(没有Dockerfile或构建容器)

时间:2018-01-17 15:09:15

标签: docker travis-ci gitlab-ci

TL; DR

故事很长:将这样一个多图像gitlab-CI文件翻译成travis-CI的正确方法是什么?特别是一种允许脚本比裸命令更复杂的方法。

长版

使用gitlab CI,可以在不同的docker映像中运行不同的CI作业,而不知道docker CLI和docker文件,如下所示:

build_jessie-gcc48:
  image: debian:jessie
  before_script:
    - apt-get update
    - apt-get install -y git cmake g\+\+-4.8 ninja-build
  script:
    - BUILDDIR=$(mktemp -d)
    - cd ${BUILDDIR}
    - SOMEVAR=somevalue cmake -G Ninja -DCMAKE_C_COMPILER=gcc-4.8 -DCMAKE_CXX_COMPILER=g++-4.8 ${CI_PROJECT_DIR}
    - cmake --build builddir

build_stretch-gcc63:
  image: debian:stretch
  before_script:
    - apt-get update
    - apt-get install -y git cmake g\+\+-6 ninja-build
  script:
    - BUILDDIR=$(mktemp -d)
    - cd ${BUILDDIR}
    - cmake -G Ninja -DCMAKE_C_COMPILER=gcc-6 -DCMAKE_CXX_COMPILER=g++-6 ${CI_PROJECT_DIR}
    - cmake --build .

即。我的脚本大多是普通的shell代码,我可以cd并分配/使用变量。我想知道如何用travis做同样的事情。 This帖子建议使用docker CLI,但有一些我觉得这种方法不方便的事情:

  • 学习使用CLI,为不同的图像指定名称,这些图像在不需要的地方带来了复杂性。
  • 向每一行添加docker exec IMAGENAME会使yml
  • 混乱
  • 使用变量会添加另一层解析它们(应该在docker镜像内部还是外部解析变量?)
  • 使用cd更改目录不会"只是工作" (它是内置的shell而不是可执行文件,对吧?
  • 需要重新克隆或装载已签出的存储库

所以我目前的方法看起来像这样:

language: c++
services:
  - docker

jobs:
  include:
    - script:
      - docker pull debian:jessie
      - docker run -itd --name JESSIE -v ${TRAVIS_BUILD_DIR}:/repo.git debian:jessie
      - docker exec JESSIE apt-get update
      - docker exec JESSIE apt-get install -y git cmake g\+\+-4.8 ninja-build
      - docker exec JESSIE bash -c 'cd $(mktemp -d) && \
                                    SOMEVAR=somevalue cmake -G Ninja -DCMAKE_C_COMPILER=gcc-4.8 -DCMAKE_CXX_COMPILER=g++-4.8 /repo.git && \
                                    cmake --build .'
    - script:
      - docker pull debian:stretch
      - docker run -itd --name STRETCH -v ${TRAVIS_BUILD_DIR}:/repo.git debian:stretch
      - docker exec STRETCH apt-get update
      - docker exec STRETCH apt-get install -y git cmake g\+\+-6 ninja-build
      - docker exec STRETCH bash -c 'cd $(mktemp -d) && \
                                     cmake -G Ninja -DCMAKE_C_COMPILER=gcc-6 -DCMAKE_CXX_COMPILER=g++-6 /repo.git && \
                                     cmake --build .'

这涉及一些尝试和错误,因为bash -c apt-get没有成功,因为bash(?)不知道apt-get。 (而且这项工作甚至失败了,因为变量赋值会导致bash SOMEVAR=somevalue command not found出错,并且cmake虽然刚刚安装,但未找到logouttime = mm.fetchone() 。所以我通常不会觉得这就是使用它的方式。

1 个答案:

答案 0 :(得分:3)

我不知道为什么SOMEVAR=somevalue不起作用,因为语法看起来很好并且应与docker exec CONTAINER bash -c '…'

兼容

无论如何,我有一个建议来写你的.travis.yml,它不那么冗长,更接近于GitLab CI conf文件的措辞:它依赖于所谓的block style YAML。< / p>

所有步骤都在同一个bash命令中运行,因此您可以分配变量并重复使用它们。

以下是我建议的相应.travis.yml

sudo: required

language: cpp

services:
  - docker

jobs:
  include:
    - script: |
        docker run --name JESSIE -it -v ${TRAVIS_BUILD_DIR}:/repo.git debian:jessie /bin/bash -c '
        export PS4='\''+ \e[33;1m($0 @ line $LINENO) \$\e[0m '\'' # quotes must be escaped
        set -e # exit on failure
        set -x # trace for debug
        apt-get update
        apt-get install -y git cmake g\+\+-4.8 ninja-build
        cd $(mktemp -d)
        SOMEVAR=somevalue cmake -G Ninja -DCMAKE_C_COMPILER=gcc-4.8 -DCMAKE_CXX_COMPILER=g++-4.8 /repo.git
        cmake --build .'
    - script: |
        docker run --name STRETCH -it -v ${TRAVIS_BUILD_DIR}:/repo.git debian:stretch /bin/bash -c '
        export PS4='\''+ \e[33;1m($0 @ line $LINENO) \$\e[0m '\'' # quotes must be escaped
        TRAVIS_EVENT_TYPE="$1"
        set -e # exit on failure
        set -x # trace for debug
        echo "Build triggered by ${TRAVIS_EVENT_TYPE}"
        apt-get update
        apt-get install -y git cmake g\+\+-6 ninja-build
        cd $(mktemp -d)
        cmake -G Ninja -DCMAKE_C_COMPILER=gcc-6 -DCMAKE_CXX_COMPILER=g++-6 /repo.git
        cmake --build .' bash "${TRAVIS_EVENT_TYPE}"

一些相关的评论:

  • 根据doc的建议,我添加了sudo: required(并用cpp替换了c ++)。
  • 单引号'在脚本的第一行和最后一行的末尾是必需的。
  • 我删除了docker pull debian:jessie命令,因为它应该由docker run […] debian:jessie […]
  • 自动触发
  • 使用绑定挂载(通过传递选项-v ${TRAVIS_BUILD_DIR}:/repo.git)是个好主意!
  • 如果要在测试后立即删除容器,也可以将--rm标记传递给docker run(除非您想在后续的Travis CI命令中检查或重新使用容器)。如果您传递--rm标记,则当然应删除--name JESSIE选项。
  • 我删除了-d标记,因为现在不需要在后台运行容器,因为只有一个docker run而没有docker exec。此外,它确保传递给docker run的Bash命令的输出将显示在Travis CI日志中(因为它们不在后台运行)。
  • 在这样的CI上下文中建议使用Bash选项set -e,而选项set -x则不那么重要(可以用set -v替换为类似目的而不是详细程度),并且重新定义PS4的行有助于使用set -x获得改进的黄色提示。另请注意,如果您愿意,可以将-e-x选项直接传递给bash(即,您可以将bash -c 'set -e; […]'替换为bash -e -c '[…]')。
  • 最后,我修改了第二个脚本,以举例说明如何将其他变量(此处为Travis CI env变量TRAVIS_EVENT_TYPE)从Travis传递到Docker / Bash上下文。 实际上,实现这一目标的一种更简单的方法是使用选项-e

    docker run […] -e TRAVIS_EVENT_TYPE="${TRAVIS_EVENT_TYPE}" debian:jessie /bin/bash […]
    

注意:我自己没有测试过这个解决方案,因为手动没有cmake项目;但是如果你有一些反馈意见或者看到这个主题的问题,请随时告诉我。