Jenkins 管道和 Docker 多阶段构建指南

Jenkins pipeline and Docker multi-stage builds howto

问题

我必须在 Jenkins(和 DockerHub 作为 CD 目标)的帮助下为 Git 个存储库配置 CI/CD。我是在 Docker 多阶段构建的帮助下完成的(请参阅注意事项)。恐怕misunderstand/overcomplicate一个简单的想法。

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

注意事项

this presentation I assume using Docker inside Jenkins is a good idea. After reading an article 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

Docker文件

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 UI.

上使用了 docker build --target 以获得更多粒度
#!/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}"
          }
        }
    }
}

根据 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}"
      }
    }
  }
}