【问题标题】:Using a dockerfile with Jenkins Scripted Pipeline Syntax将 dockerfile 与 Jenkins 脚本化管道语法一起使用
【发布时间】:2020-04-28 10:02:54
【问题描述】:

使用Jenkins Declarative Pipeline,可以轻松指定Dockerfile、代理标签、构建参数和运行参数,如下所示:

Jenkinsfile(声明式管道)

agent {
    dockerfile {
        dir './path/to/dockerfile'
        label 'my-label'
        additionalBuildArgs  '--build-arg version=1.0'
        args '-v /tmp:/tmp'
    }
}

我正在尝试使用脚本化管道语法来实现相同的目的。我找到了传递代理标签并运行 args 的方法,但无法传递 目录build args。理想情况下,我会写这样的东西(标签和运行参数已经在工作):

Jenkinsfile(脚本化管道)

node ("my-label"){
    docker.dockerfile(
        dir: './path/to/dockerfile',
        additionalBuildArgs:'--build-arg version=1.0'
    ).inside('-v /tmp:/tmp') {
        \\ add stages here
    }
}

documentation 展示了如何使用现有的 docker 映像来完成此操作,即在管道中使用 image 指令。

Jenkinsfile(声明式管道)

pipeline {
    agent {
        docker { image 'node:7-alpine' }
    }
    stage('Test') {
        //...
    }
}

Jenkinsfile(脚本化管道)

node {
    docker.image('node:7-alpine').inside {
        stage('Test') {
            //...
        }
    }
}

但是,dockerfile 指令的脚本化管道语法缺失。 我目前使用的解决方法是自己构建图像。

node ("my-label"){
    def testImage = docker.build(
        "test-image",
        "./path/to/dockerfile",
        "--build-arg v1.0"
    )

    testImage.inside('-v /tmp:/tmp') {
        sh 'echo test'
    }
}

非常感谢任何帮助!

【问题讨论】:

  • 脚本化的 docker.build() 命令有 2 个参数:图像标签、docker build 命令行。该问题显示了 3 个论点。相反,它应该类似于 docker.build("name:1.0", "--build-arg version=v1.0 path/to/directory"

标签: docker jenkins jenkins-pipeline dockerfile jenkins-groovy


【解决方案1】:

我个人将 docker cli 参数放在图像文件夹路径之前,并使用 -f 参数指定 docker 文件名

除此之外,您这样做是正确的。代理 dockerfile 正在以与 docker.build 步骤相同的方式构建 docker 映像。除非您可以使用 docker.build 步骤将您的图像推送到注册表

这是我该怎么做

def dockerImage
//jenkins needs entrypoint of the image to be empty
def runArgs = '--entrypoint \'\''
pipeline {
    agent {
        label 'linux_x64'
    }
    options {
        buildDiscarder(logRotator(numToKeepStr: '100', artifactNumToKeepStr: '20'))
        timestamps()
    }
    stages {
        stage('Build') {
            options { timeout(time: 30, unit: 'MINUTES') }
            steps {
                script {
                    def commit = checkout scm
                    // we set BRANCH_NAME to make when { branch } syntax work without multibranch job
                    env.BRANCH_NAME = commit.GIT_BRANCH.replace('origin/', '')

                    dockerImage = docker.build("myImage:${env.BUILD_ID}",
                        "--label \"GIT_COMMIT=${env.GIT_COMMIT}\""
                        + " --build-arg MY_ARG=myArg"
                        + " ."
                    )
                }
            }
        }
        stage('Push to docker repository') {
            when { branch 'master' }
            options { timeout(time: 5, unit: 'MINUTES') }
            steps {
                lock("${JOB_NAME}-Push") {
                    script {
                        docker.withRegistry('https://myrepo:5000', 'docker_registry') {
                            dockerImage.push('latest')
                        }
                    }
                    milestone 30
                }
            }
        }
    }
}

【讨论】:

  • 感谢您的回复。在我的分布式用例中,添加 docker 注册表会增加额外的复杂性。使用 agent dockerfile 代替会自动重建更改(并在本地缓存更改)。这在我的情况下更可取,因为我有各种版本的 dockerfile,具体取决于当前的 git 分支。我一直在研究 Jenkins DSL,但无法理解 agent dockerfile 在内部使用什么。您对如何进一步调查有什么建议吗?
  • 我把注册步骤只是为了展示一个完整的工作流程。我目前无法在我自己的 jenkins 上进行测试,但如果您在同一个 linux slave 代理上使用docker.build,它应该会缓存您以前的构建。与代理 dockerfile 的唯一区别是它使用主服务器来构建您的 docker 映像,因此它始终使用同一台机器并且可以重用 docker 制作的缓存
  • 我不知道您可以混合使用声明式(新)和脚本式(旧)语法!这是访问某些功能所必需的,还是可以通过脚本(旧)语法完成?
  • 我想一切都可以用“旧”语法来完成。但是,声明性语法允许您对管道进行 lint,并为您提供良好的结构。理想情况下,您会将旧语法放在共享库中的方法后面。您还可以使用 github.com/SAP-archive/jenkins-pipelayer 之类的声明性管道生成作业
【解决方案2】:

这是一个纯粹的旧语法脚本管道,它解决了签出、构建 docker 映像并将映像推送到注册表的问题。它假设 Jenkins 项目的类型是“来自 SCM 的管道脚本”。

我为需要代理才能访问公共互联网的服务器开发了这个管道。 Dockerfile 接受构建参数来为代理配置其工具。

我认为 @fredericrous 的结构非常好 :) 但我是管道新手,请帮助我改进!

def scmvars
def image
node {    
    stage('clone') {
        // enabled by project type "Pipeline script from SCM"
        scmvars = checkout(scm)
        echo "git details: ${scmvars}"
    }
    stage('env') {
        // Jenkins provides no environment variable view
        sh 'printenv|sort'
    }
    stage('build') {
        // arg 1 is the image name and tag
        // arg 2 is docker build command line
        image = docker.build("com.mycompany.myproject/my-image:${env.BUILD_ID}",
              " --build-arg commit=${scmvars.GIT_COMMIT}"
            + " --build-arg http_proxy=${env.http_proxy}"
            + " --build-arg https_proxy=${env.https_proxy}"
            + " --build-arg no_proxy=${env.no_proxy}"
            + " path/to/dir/with/Dockerfile")
    }
    stage('push') {
        docker.withRegistry('https://registry.mycompany.com:8100',
                            'jenkins-registry-credential-id') {
            image.push()
        }
    }
}

【讨论】:

    猜你喜欢
    • 2018-01-29
    • 1970-01-01
    • 1970-01-01
    • 2021-12-14
    • 2020-05-10
    • 1970-01-01
    • 1970-01-01
    • 2020-12-25
    • 2020-10-21
    相关资源
    最近更新 更多