Learning to deploy microservices. Part 4. Jenkins


Hello, Habr!


" ", Jenkins . Jenkins , Docker-, Docker- . Jenkins , Helm ( ).


:


  1. Spring Boot, Docker


    : Java 11, Spring Boot, Docker, image optimization


  2. Kubernetes Google Kubernetes Engine


    : Kubernetes, GKE, resource management, autoscaling, secrets


  3. Helm 3


    : Helm 3, chart deployment


  4. Jenkins


    : Jenkins configuration, plugins, separate configs repository



Jenkins β€” , Java. - . Groovy, (Jenkinsfile) . , , .


GitHub .


Jenkins



Jenkins:


  • war-
  • Docker-
  • Kubernetes

War- (β„– Apache Tomcat). , .


, Jenkins Docker. Jenkins , . β€” ( ), 'docker:dind', Jenkins'.


Jenkins Kubernetes. Jenkins, . , . . Jenkins Google Kubernetes Engine .


, Jenkins Docker . , stateful Kubernetes. Jenkins Kubernetes.


, Jenkins . , , Google Compute Engine. , Jenkins Raspberry Pi, - "" Docker-. Raspberry Pi .


docker network create jenkins

docker volume create jenkins-docker-certs
docker volume create jenkins-data

docker container run \
  --name jenkins-docker \
  --detach \
  --privileged \
  --network jenkins \
  --network-alias docker \
  --env DOCKER_TLS_CERTDIR=/certs \
  --volume jenkins-docker-certs:/certs/client \
  --volume jenkins-data:/var/jenkins_home \
  --publish 2376:2376 \
  docker:dind

docker container run \
  --name jenkins-blueocean \
  --detach \
  --network jenkins \
  --env DOCKER_HOST=tcp://docker:2376 \
  --env DOCKER_CERT_PATH=/certs/client \
  --env DOCKER_TLS_VERIFY=1 \
  --publish 8080:8080 \
  --publish 50000:50000 \
  --volume jenkins-data:/var/jenkins_home \
  --volume jenkins-docker-certs:/certs/client:ro \
  jenkinsci/blueocean

Jenkins http://localhost:8080/ . Jenkins UI, . " " (IaC). β€” Groovy. . .



(Manage Jenkins -> Manage Plugins). . 'Blue Ocean', .


: Remote File Plugin Kubernetes CLI. Remote File Plugin Jenkinsfile , Kubernetes CLI kubectl .


Helm


Helm-, Helm. Helm , . (docker exec -it jenkins-blueocean bash), /usr/bin. Helm-:


helm repo add msvc-repo https://anshelen.imtqy.com/microservices-deploy/
helm repo update


, . , . , , Jenkins. , β€” .


(Manage Jenkins -> Configure System -> Global properties -> Environment Variables):


  • CLUSTER_URL β€” - Kubernetes. kubectl cluster-info
  • CLUSTER_NAMESPACE β€”
  • HELM_PROJECT β€” Helm
  • HELM_CHART β€” Helm-. 'msvc-repo/msvc-chart'


Jenkins , , -, , . Credentials -> System -> Global credentials -> Add Credentials:


github-credsusername with password/ git-
dockerhub-credsusername with password/ Docker-
kubernetes-credssecret text

NOTES.txt . , Helm- (helm status msvc-project).



, Groovy, . .


Jenkins () (stage). (agent).


:


  1. Build.
  2. Test. . , Maven
  3. Package. jar-
  4. Push Images. Docker- . β€” latest
  5. Trigger Kubernetes. Kubernetes Docker-



:


pipeline {
  agent none
  options { ... }
  environment { ... }
  stages {
    stage("Prepare container") {
      agent {
        docker {
          image 'openjdk:11.0.5-slim'
          args '-v $HOME/.m2:/root/.m2'
        }
      }
      stages {
        stage('Build') { ... }
        stage('Test') { ... }
        stage('Package') { ... }
      }
    }

    stage('Push images') {
      agent any
      when { branch 'master' }
      steps { ... }
    }

    stage('Trigger kubernetes') {
      agent any
      when { branch 'master' }
      steps { ... }
    }
  }
}

Jenkins "" β€” , . pipeline . , . pipeline 'none'. , - .


Build, Test Package Docker- . Docker- Java 11 (Jenkins Java 8). , 'Prepare container' 'docker'. args .m2 Jenkins'. .m2 Maven, , .


Push Images Trigger Kubernetes 'any'. , . Jenkins'. - (when { branch 'master' }).


, options environment.



options {
  skipStagesAfterUnstable()
  skipDefaultCheckout()
}

. :


  • skipStagesAfterUnstable Jenkins , e . UNSTABLE . .


  • skipDefaultCheckout . Jenkins force ( Prepare Checkout, Push images Trigger Kubernetes). . . β€” Build. skipDefaultCheckout, . , Jenkins . , , Build Test.




environment {
  IMAGE_BASE = 'anshelen/microservices-backend'
  IMAGE_TAG = "v$BUILD_NUMBER"
  IMAGE_NAME = "${env.IMAGE_BASE}:${env.IMAGE_TAG}"
  IMAGE_NAME_LATEST = "${env.IMAGE_BASE}:latest"
  DOCKERFILE_NAME = "Dockerfile-packaged"
}

, . , - . Docker-.


latest , , - . , , . IMAGE_TAG , BUILD_NUMBER. , ( ). BUILD_NUMBER , "". β€” . , .


, ,


stage("Prepare container") {
  agent {
    docker {
      image 'openjdk:11.0.5-slim'
      args '-v $HOME/.m2:/root/.m2'
    }
  }
  stages {
    stage('Build') {
      steps {
        checkout scm
        sh './mvnw compile'
      }
    }
    stage('Test') {
      steps {
        sh './mvnw test'
        junit '**/target/surefire-reports/TEST-*.xml'
      }
    }
    stage('Package') {
      steps {
        sh './mvnw package -DskipTests'
      }
    }
  }
}

, , . Maven , .


checkout scm. , Jenkins. bash- .


junit '**/target/surefire-reports/TEST-*.xml' Jenkins' . -.


jar- .


Docker-


Docker- . Jenkins, Maven-.


- , . - . , Jenkins. Dockerfile-packaged.


Dockerfile
FROM adoptopenjdk/openjdk11:jdk-11.0.5_10-alpine as builder
ADD . /src
WORKDIR /src
RUN ./mvnw package -DskipTests

FROM alpine:3.10.3 as packager
RUN apk --no-cache add openjdk11-jdk openjdk11-jmods
ENV JAVA_MINIMAL="/opt/java-minimal"
# build minimal JRE
RUN /usr/lib/jvm/java-11-openjdk/bin/jlink \
    --verbose \
    --add-modules \
        java.base,java.sql,java.naming,java.desktop,java.management,java.security.jgss,java.instrument \
    --compress 2 --strip-debug --no-header-files --no-man-pages \
    --release-info="add:IMPLEMENTOR=radistao:IMPLEMENTOR_VERSION=radistao_JRE" \
    --output "$JAVA_MINIMAL"

FROM alpine:3.10.3
LABEL maintainer="Anton Shelenkov anshelen@yandex.ru"
ENV JAVA_HOME=/opt/java-minimal
ENV PATH="$PATH:$JAVA_HOME/bin"
COPY --from=packager "$JAVA_HOME" "$JAVA_HOME"
COPY --from=builder /src/target/microservices-backend-*.jar app.jar
EXPOSE 8080
ENTRYPOINT ["java","-jar","/app.jar"]

Dockerfile-packaged:


FROM alpine:3.10.3 as packager
RUN apk --no-cache add openjdk11-jdk openjdk11-jmods
ENV JAVA_MINIMAL="/opt/java-minimal"
# build minimal JRE
RUN /usr/lib/jvm/java-11-openjdk/bin/jlink \
    --verbose \
    --add-modules \
        java.base,java.sql,java.naming,java.desktop,java.management,java.security.jgss,java.instrument \
    --compress 2 --strip-debug --no-header-files --no-man-pages \
    --release-info="add:IMPLEMENTOR=radistao:IMPLEMENTOR_VERSION=radistao_JRE" \
    --output "$JAVA_MINIMAL"

FROM alpine:3.10.3
LABEL maintainer="Anton Shelenkov anshelen@yandex.ru"
ENV JAVA_HOME=/opt/java-minimal
ENV PATH="$PATH:$JAVA_HOME/bin"
COPY --from=packager "$JAVA_HOME" "$JAVA_HOME"
COPY /target/microservices-backend-*.jar app.jar
EXPOSE 8080
ENTRYPOINT ["java","-jar","/app.jar"]

- .


Push Images:


stage('Push images') {
  agent any
  when {
    branch 'master'
  }
  steps {
    script {
      def dockerImage = docker.build("${env.IMAGE_NAME}", "-f ${env.DOCKERFILE_NAME} .")
      docker.withRegistry('', 'dockerhub-creds') {
        dockerImage.push()
        dockerImage.push("latest")
      }
      echo "Pushed Docker Image: ${env.IMAGE_NAME}"
    }
    sh "docker rmi ${env.IMAGE_NAME} ${env.IMAGE_NAME_LATEST}"
  }
}

Jenkins , . Jenkins , script.


docker.build . ( ) ${env.IMAGE_NAME}. docker.build , -.


docker.withRegistry('', 'dockerhub-creds') , 'dockerhub-creds'. , 'latest'. echo.


.


Kubernetes


Kubernetes, , .


stage('Trigger kubernetes') {
  agent any
  when {
    branch 'master'
  }
  steps {
    withKubeConfig([credentialsId: 'kubernetes-creds', serverUrl: "${CLUSTER_URL}", namespace: "${CLUSTER_NAMESPACE}"]) {
      sh "helm upgrade ${HELM_PROJECT} ${HELM_CHART} --reuse-values --set backend.image.tag=${env.IMAGE_TAG}"
    }
  }
}

withKubeConfig Kubernetes CLI kubectl . Helm-. Jenkins, , , ${CLUSTER_URL}.


Jenkinsfile


Jenkins-backend
pipeline {
  agent none
  options {
    skipStagesAfterUnstable()
    skipDefaultCheckout()
  }
  environment {
    IMAGE_BASE = 'anshelen/microservices-backend'
    IMAGE_TAG = "v$BUILD_NUMBER"
    IMAGE_NAME = "${env.IMAGE_BASE}:${env.IMAGE_TAG}"
    IMAGE_NAME_LATEST = "${env.IMAGE_BASE}:latest"
    DOCKERFILE_NAME = "Dockerfile-packaged"
  }
  stages {
    stage("Prepare container") {
      agent {
        docker {
          image 'openjdk:11.0.5-slim'
          args '-v $HOME/.m2:/root/.m2'
        }
      }
      stages {
        stage('Build') {
          steps {
            checkout scm
            sh './mvnw compile'
          }
        }
        stage('Test') {
          steps {
            sh './mvnw test'
            junit '**/target/surefire-reports/TEST-*.xml'
          }
        }
        stage('Package') {
          steps {
            sh './mvnw package -DskipTests'
          }
        }
      }
    }

    stage('Push images') {
      agent any
      when {
        branch 'master'
      }
      steps {
        script {
          def dockerImage = docker.build("${env.IMAGE_NAME}", "-f ${env.DOCKERFILE_NAME} .")
          docker.withRegistry('', 'dockerhub-creds') {
            dockerImage.push()
            dockerImage.push("latest")
          }
          echo "Pushed Docker Image: ${env.IMAGE_NAME}"
        }
        sh "docker rmi ${env.IMAGE_NAME} ${env.IMAGE_NAME_LATEST}"
      }
    }

    stage('Trigger kubernetes') {
      agent any
      when {
        branch 'master'
      }
      steps {
        withKubeConfig([credentialsId: 'kubernetes-creds', serverUrl: "${CLUSTER_URL}", namespace: "${CLUSTER_NAMESPACE}"]) {
          sh "helm upgrade ${HELM_PROJECT} ${HELM_CHART} --reuse-values --set backend.image.tag=${env.IMAGE_TAG}"
        }
      }
    }
  }
}


Jenkinsfile .



Jenkins . Multibranch pipeline. , .


, Jenkins. New Item -> Multibranch Pipeline. :


  • Branch sources. GitHub, 'Credentials' / URL .


  • Build Configuration. Mode 'by Remote File Plugin', β€” Repository URL, Jenkinsfile, Script Path .



  • Scan Repository Triggers. , Jenkins , - . , Jenkins , . β€” -. . , , Jenkins ( , Jenkins IP-). - .




, . Blue Ocean (Open Blue Ocean). , Maven-. , (helm get values msvc-project).


Jenkins .



Jenkins is a very flexible system that allows implementing the process of continuous integration and deployment of any complexity. In this article, we just touched on this tool, creating a simple pipeline for microservices of our project. In the future, this pipeline can be significantly improved and improved, for example, by adding notifications, additional steps, web hooks and much, much more.


All Articles