【问题标题】:Jenkins pipeline and Docker multi-stage builds howtoJenkins 管道和 Docker 多阶段构建方法
【发布时间】:2021-10-05 12:39:15
【问题描述】:

问题

我必须在 Jenkins(以及 DockerHub 作为 CD 目标)的帮助下为多个 Git 存储库配置 CI/CD。我在 Docker 多阶段构建的帮助下做到了这一点(请参阅注意事项)。我害怕误解/过度复杂化一个简单的想法。

Jenkins + Docker 多阶段构建 = 最佳/良好实践吗?我是否以正确的方式应用了这个想法?

注意事项

来自this presentation 我认为在 Jenkins 中使用 Docker 是个好主意。看了一篇文章Using Multi-Stage Builds to Simplify and Standardize Build Processes,Docker 多阶段构建看起来是使用 Jenkins + Docker 的下一步。

similar question 的回答还说 Docker 多阶段是有意义的,但没有提供实现示例。

实施

Jenkins 从 SCM 存储库创建管道。

Git 存储库

Dockerfile
Jenkinsfile
project-folder
  |-src
  |-pom.xml

Dockerfile

FROM alpine as source
RUN apk --update --no-cache add git
COPY project-folder repo

FROM maven:3.6.3-jdk-8 as test
COPY --from=source repo repo
WORKDIR repo
RUN mvn clean test

FROM maven:3.6.3-jdk-8 as build
COPY --from=test repo repo
WORKDIR repo
RUN mvn clean package

FROM openjdk:8 as final
MAINTEINER xxx <xxx@gmail.com>
LABEL owner="xxx"
COPY --from=build repo/target/some-lib-1.8.jar /usr/local/some-lib.jar
ENTRYPOINT ["java", "-jar", "/usr/local/some-lib.jar"]

Jenkins 文件

我使用docker build --target 来获得更精细的 Jenkins UI。

#!/usr/bin/env groovy

def imageId = "use-name/image-name:1.$BUILD_NUMBER"

pipeline {

    agent {
        label 'docker'  # separate agent (launched as JAR on host machine) to avoid running docker inside docker
    }
    stages {
        stage('Test') {
            steps {
                script {
                    sh "docker build --no-cache --target test -t ${imageId} ."
                }
            }
        }
        stage('Build') {
            steps {
                script {
                    sh "docker build --target build -t ${imageId} ."
                }
            }
        }
        stage('Image') {
            steps {
                script {
                    sh "docker build --target final -t ${imageId} ."
                }
            }
        }
        stage('Deploy') {
            steps {
                script {
                    docker.withRegistry('' , 'dockerhub') {
                        dockerImage = docker.build("${imageId}")
                        dockerImage.push()
                    }
                }
            }
        }
        stage('Clean') {
          steps{
            sh "docker rmi ${imageId}"
          }
        }
    }
}

【问题讨论】:

  • 是的,多阶段构建是目前的最佳实践。您的实现很好,但我个人认为在 Jenkinsfile 中拆分步骤没有多大意义,尤其是在您处理多个项目时。只需做一个完整的 docker 构建,如果出现故障 - 你会从日志中知道它发生在哪里。
  • @taleodor 非常感谢您的 asnwer!
  • 我计划创建一个类似的设置。你是否从 docker 镜像构建中获取测试和覆盖数据,如果是,如何获取?

标签: docker jenkins


【解决方案1】:

按照 taleodor 的回答,我建议下一个 jenkinsfile:

pipeline {
  agent {
    label 'docker'  # separate agent (launched as JAR on host machine) to avoid running docker inside docker
  }
  environment {
    imageId = 'use-name/image-name:1.$BUILD_NUMBER'
    docker_registry = 'your_docker_registry'
    docker_creds = credentials('your_docker_registry_creds')
  }
  stages {
    stage('Docker build') {
      steps {
        sh "docker build --no-cache --force-rm -t ${imageId} ."
      }
    }
    stage('Docker push') {
      steps {
        sh'''
          docker login $docker_registry --username $docker_creds_USR --password $docker_creds_PSW
          docker push $imageId
          docker logout
        '''
      }
    }
    stage('Clean') {
      steps{
        sh "docker rmi ${imageId}"
      }
    }
  }
}

【讨论】:

  • 谢谢!在接受答案之前只有一个问题 - 为什么您更喜欢显式的 Docker 凭证管理?在我的管道中,我只是隐式使用通过 Jenkins UI 配置的凭据。
  • 抱歉,忍不住再问一个附带问题——这个管道在多个并行构建的情况下是否有效?意味着 SCM 插件将代码拉到同一个文件夹中,我想将代码拉到 Dockerfile 中(但最终认为这个想法很糟糕)
  • 假设它将在并行阶段工作。我也更喜欢使用声明式的管道。另外使用 --force-rm 选项不仅可以删除最终图像,还可以删除中间容器: sh "docker build --no-cache --force-rm -t ${imageId} ."
  • @DmitriTarasevich 谢谢!我会去做。您能否澄清一下显式和隐式 DockerHub 凭据?
  • 正如我所说 - 我更喜欢使用声明式的管道。在我的示例中,我提供了声明式的凭据。使用任何你喜欢的风格。以声明方式 - 安装掩码密码插件以在输出中隐藏凭据。
猜你喜欢
  • 2018-09-26
  • 2020-02-19
  • 1970-01-01
  • 2018-06-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-07-13
  • 2022-11-25
相关资源
最近更新 更多