上一篇文章《如何在Jenkins中跑多个Docker(MySQL、Redis等)?》讲解了用 Dockerfile 跑 Jenkins,解决了“CircleCI 的 Dockerfile 和 config.yml 重复,违反 DRY”的问题。

但也面临一个新问题:

  • Jenkins 每次跑测试都要先进行 docker build,很慢。

解决办法很简单:把 Jenkins 构建的 Docker 镜像存起来,下次直接拉取。

检查 Docker image 是否存在远端镜像服务器

$ DOCKER_CLI_EXPERIMENTAL=enabled docker manifest inspect sinkcup/laravel-demo:asdf
no such manifest: docker.io/sinkcup/laravel-demo:asdf
$ echo $?
1

把 Jenkins 构建的 Docker 镜像存起来

sh "docker login -u $DOCKER_USER -p $DOCKER_PASSWORD $DOCKER_SERVER"
md5 = sh(script: "md5sum Dockerfile | awk '{print \$1}'", returnStdout: true).trim()
imageAndTag = "${DOCKER_SERVER}${DOCKER_PATH_PREFIX}laravel-demo:dev-${md5}"
dockerNotExists = sh(script: "DOCKER_CLI_EXPERIMENTAL=enabled docker manifest inspect $imageAndTag > /dev/null", returnStatus: true)
def testImage = null
if (dockerNotExists) {
    testImage = docker.build("$imageAndTag", "--build-arg APP_ENV=testing --build-arg SPEED=$SPEED ./")
    sh "docker push $imageAndTag"
} else {
    testImage = docker.image(imageAndTag)
}
testImage.inside("--net bridge1 -v \"${codePath}:/var/www/laravel\" -e 'APP_ENV=testing'") {
    stage('prepare') {
        echo 'preparing...'
        sh 'composer install'
        echo 'prepare done.'
    }
    stage('test') {
        echo 'testing...
        sh './lint.sh'
        sh './phpunit.sh'
        junit 'junit.xml'
        echo 'test done.'
    }
}

完整代码请看:GitHubCODING

当然需要先获得 Docker 镜像仓库的密码,有这些服务商:

docker hub 价格

经过试验,同一个项目在不同平台的持续集成速度如下:

  • Jenkins 第一次运行:7分钟
  • Jenkins 第二次运行:1分钟24秒
  • CircleCI:2分钟-4分47秒

CODING CI(Jenkins 云服务) CircleCI