在持续集成中使用 Docker

背景介绍

Docker 目前已经是一个非常普遍的工具。在 COIDNG 的持续集成当中,除了使用 Docker 作为持续集成的构建环境外,您可能经常需要以 Docker 的形式运行额外的服务作为测试依赖,或在持续集成过程中构建 Docker 镜像,并推送到相关的制品库。

关于如何使用 Docker 作为持续集成的构建环境,我们已有文章进行说明:《持续集成的构建环境》

运行指定 Docker 镜像并在容器内执行命令

在构建过程中,您可能会需要使用到公有的 Docker 镜像仓库,去拉取指定的镜像执行命令。

pipeline {
    agent any
    stages {
        stage('Test') {
            steps {
                  script {
                    docker.image("ubuntu").inside('-e MY_ENV=123') {
                          sh 'echo ${MY_ENV}'
                    }     
                  }
            }
        }
    }
}

运行指定 Registry 的 Docker 镜像

在构建过程中,您可能会需要使用到私有的 Docker 镜像仓库,如:CODING 制品库所提供的 Docker 镜像仓库。

pipeline {
    agent any
    stages {
        stage('Test') {
            steps {
                  script {
                    docker.withRegistry('https://registry.example.com') {

                        // 将会从从主机名 registry.example.com 拉取 my-custom-image
                        docker.image('my-custom-image').inside {
                            sh 'make test'
                        }
                    }
                  }
            }
        }
    }
}

若所配置的 registry 对拉取操作带有鉴权,需要您提供有效的凭证 ID。

pipeline {
    agent any
    stages {
        stage('Test') {
            steps {
                  script {
                    docker.withRegistry('https://registry.example.com', 'my-credentials-id') {

                    }
                  }
            }
        }
    }
}

在持续集成过程中构建 Docker 镜像

pipeline {
    agent any
    stages {
        // 需要检出代码后,才可以使用代码仓库内的 Dockerfile
        stage('Checkout') {
            steps {
                checkout([
                    $class: 'GitSCM', 
                    branches: [[name: env.GIT_BUILD_REF]], 
                    userRemoteConfigs: [[url: env.GIT_REPO_URL, credentialsId: env.CREDENTIALS_ID]]])
            }
        }
        stage('Build') {
            steps {
                script {
                    // 默认将使用根路径的 Dockerfile 进行构建
                    docker.build('my-docker-image:1.0.0')
                }
            }
        }
    }
}

如需为构建指定额外的参数, 如:使用指定目录的 Dockerfile:

pipeline {
    agent any
    stages {
        // 需要检出代码后,才可以使用代码仓库内的 Dockerfile
        stage('Checkout') {
            steps {
                checkout([
                    $class: 'GitSCM', 
                    branches: [[name: env.GIT_BUILD_REF]], 
                    userRemoteConfigs: [[url: env.GIT_REPO_URL, credentialsId: env.CREDENTIALS_ID]]])
            }
        }
        stage('Build') {
            steps {
                script {
                    // 将使用 ./dockerfiles/Dockerfile.build 进行构建
                    docker.build('my-docker-image:1.0.0', '-f Dockerfile.build ./dockerfiles')
                }
            }
        }
    }
}

将 Docker 镜像推送到指定的 Registry

pipeline {
    agent any
    stages {
        // 需要检出代码后,才可以使用代码仓库内的 Dockerfile
        stage('Checkout') {
            steps {
                checkout([
                    $class: 'GitSCM', 
                    branches: [[name: env.GIT_BUILD_REF]], 
                    userRemoteConfigs: [[url: env.GIT_REPO_URL, credentialsId: env.CREDENTIALS_ID]]
                ])
            }
        } 

        stage('Build') {
            steps {
                  script {
                      docker.build('my-docker-image:1.0.0')

                    docker.withRegistry('https://registry.example.com', 'my-credentials-id') {
                        docker.image('my-docker-image:1.0.0').push()                    
                    }
                  }
            }
        }
    }
}

使用 Docker 运行额外的服务作为测试依赖

在测试过程当中,您可以使用 Docker 来运行 MySQL 等服务可能作为测试依赖服务。

下述示例使用了两个容器,一个作为 MySQL 的服务,另一个提供执行环境 (使用 docker link 连接两个容器)

pipeline {
    agent any
    stages {
        stage('Test') {
            steps {
                  script {
                    docker.image('mysql:5').withRun('-e "MYSQL_ROOT_PASSWORD=my-secret-pw"') { c ->
                        // 注意:这里 callback 的运行环境并不是上面运行的 mysql:5 环境内,而是运行 docker 的宿主机环境 

                        // 运行第二个 mysql 作为执行环境

                        docker.image('mysql:5').inside("--link ${c.id}:db") {
                          // 这里执行的命令都是在第二个运行的 mysql docker 容器内
                          // 等待 mysql 服务等待
                          sh 'while ! mysqladmin ping -hdb --silent; do sleep 1; done'
                        }

                        // callback 内容运行完毕后,mysql docker 容器将会自动 stop 和 rm 掉
                    }       
                  }
            }
        }
    }
}

同时运行多个容器作为测试的依赖服务

有时候您可能不止需要一个额外的服务作为测试依赖,可以使用嵌套的方式来运行多个服务。

pipeline {
    agent any
    stages {
        stage('Test') {
            steps {
                  script {
                    docker.image('mysql:5').withRun('-e "MYSQL_ROOT_PASSWORD=my-secret-pw"') { c1 ->
                        // 注意:这里 callback 的运行环境并不是上面运行的 mysql:5 环境内,而是运行 docker 的宿主机环境

                        docker.image('redis').withRun('') { c2 ->
                            // 注意:这里 callback 的运行环境并不是上面运行的 redis 环境内,而是运行 docker 的宿主机环境
                            sh 'docker ps'
                        } 
                    }       
                  }
            }
        }
    }
}

参考文档

如您还想进一步了解 Jenkins 当中使用 Docker 的配置方式,可以参考 Jenkins 官方文档:

上一篇使用凭据 ID 进行认证
文档是否对您有用?
感谢反馈有用
感谢反馈没用