Jenkins
Jenkins 개요
- Jenkins is a free and open source automation server
- It helps automate the parts of software development related to building, testing and deploying, facilitating continuous integration and continuous delivery
Jenkins 특징
- 오픈소스인 자동화 서버
- 다양한 플러그인 제공
- Pipeline
- Authentication / Authorization
- Git
- Docker
- 다양하게 확장
Jenkins 설치 및 실행 with Docker-compose
https://github.com/Sanses/devops_06_03_jenkins/blob/master/src/jenkins_local/docker-compose.yml
version: '3.9' services: jenkins: image: jenkins/jenkins:latest #2.60.3 container_name: jenkins environment: - "TZ=Asia/Seoul" ports: - "8080:8080" volumes: - "./data:/var/jenkins_home"
Jenkins Pipeline of Sample
pipeline { agent any stages { stage("Build") { steps { echo "Jenkins Pipeline running" } } } }
Jenkins Pipeline
Jenkins Pipeline 개요
- Jenkins 2.x or later (older versions back to 1.642.3 may work but are not recommended)
- Required Plugin 'Pipeline plugin'
- Support CD
- Pipeline as code (DSL, Jenkinsfile)
Jenkins Pipeline Script
Scripted pipeline
- inject groovy script
- Java API reference
Declarative pipeline (recommended)
- Jenkins DSL
- Isolate complex logic into Jenkins plugin
Jenkins Pipeline Syntax
Section
- agent
- pipeline or stage가 실행될 노드 지정
- node
- any
- label
- node
- docker
- dockerfile
- kubernetes
- pipeline or stage가 실행될 노드 지정
- stages
- 순차적인 작업의 명세인 stage들의 묶음
- steps
- stage안에서의 실행되는 단계
- post
- 위치에 따라 stages들의 작업이 끝난 후 추가적인 steps 혹은 stage에 steps들의 작업이 끝난 후 추가적인 step
- Condition
- always
- changed
- fixed
- regression
- aborted
- failure
- success
- unstable
- unsuccessful
- cleanup
- agent
Directive
- parameters
- key = value
- pipeline 내부에서 사용할 환경변수
- credentials()를 통해 Jenkins credential에 접근 가능
- environments
- pipeline을 trigger할 때 입력 받아야 할 변수를 정의
- Type
- string
- text
- booleanParam
- choice
- password
- when
- stage를 실핼 할 조건 설정
- ...
- parameters
Jenkins Pipeline Overview
Jenkins 설치 with Docker
https://github.com/Sanses/devops_06_03_jenkins/blob/master/src/jenkins_remote_docker/Dockerfile
DockerfileFROM jenkins/jenkins:lts ARG DOCKER_GID=1000 USER root # docker install COPY scripts/install_docker.sh /install_docker.sh RUN chmod +x /install_docker.sh && \ /install_docker.sh # aws cli install COPY scripts/install_aws.sh /install_aws.sh RUN chmod +x /install_aws.sh && \ /install_aws.sh # set jenkins user to host docker group RUN /usr/sbin/groupadd -g ${DOCKER_GID:-1000} -f docker && \ /usr/sbin/usermod -aG docker jenkins USER jenkins
docker-compose.ymlversion: '3.8' services: jenkins: build: context: "" args: DOCKER_GID: ${DOCKER_GID} container_name: jenkins environment: TZ: "Asia/Seoul" JAVA_OPTS: "-Dhudson.model.DownloadService.noSignatureCheck=true" DOCKER_GID: ${DOCKER_GID} ports: - "8080:8080" volumes: - "./data:/var/jenkins_home" - "/var/run/docker.sock:/var/run/docker.sock"
Jenkins Pipeline
https://github.com/Sanses/devops_sample_app_python/blob/master/deploy/Jenkinsfile
pipeline { agent { label 'master' } parameters { booleanParam(name : 'BUILD_DOCKER_IMAGE', defaultValue : true, description : 'BUILD_DOCKER_IMAGE') booleanParam(name : 'RUN_TEST', defaultValue : true, description : 'RUN_TEST') booleanParam(name : 'PUSH_DOCKER_IMAGE', defaultValue : true, description : 'PUSH_DOCKER_IMAGE') booleanParam(name : 'PROMPT_FOR_DEPLOY', defaultValue : false, description : 'PROMPT_FOR_DEPLOY') booleanParam(name : 'DEPLOY_WORKLOAD', defaultValue : true, description : 'DEPLOY_WORKLOAD') // CI string(name : 'AWS_ACCOUNT_ID', defaultValue : '657976307134', description : 'AWS_ACCOUNT_ID') string(name : 'DOCKER_IMAGE_NAME', defaultValue : 'demo', description : 'DOCKER_IMAGE_NAME') string(name : 'DOCKER_TAG', defaultValue : '1.0.0', description : 'DOCKER_TAG') // CD string(name : 'TARGET_SVR_USER', defaultValue : 'ec2-user', description : 'TARGET_SVR_USER') string(name : 'TARGET_SVR_PATH', defaultValue : '/home/ec2-user/', description : 'TARGET_SVR_PATH') string(name : 'TARGET_SVR', defaultValue : '10.0.3.61', description : 'TARGET_SVR') } environment { REGION = "ap-northeast-2" ECR_REPOSITORY = "${params.AWS_ACCOUNT_ID}.dkr.ecr.ap-northeast-2.amazonaws.com" ECR_DOCKER_IMAGE = "${ECR_REPOSITORY}/${params.DOCKER_IMAGE_NAME}" ECR_DOCKER_TAG = "${params.DOCKER_TAG}" } stages { stage('============ Build Docker Image ============') { when { expression { return params.BUILD_DOCKER_IMAGE } } agent { label 'build' } steps { dir("${env.WORKSPACE}") { sh 'docker build -t ${ECR_DOCKER_IMAGE}:${ECR_DOCKER_TAG} .' } } post { always { echo "Docker build success!" } } } stage('============ Run test code ============') { when { expression { return params.RUN_TEST } } agent { label 'build' } steps { sh''' aws ecr get-login-password --region ${REGION} | docker login --username AWS --password-stdin ${ECR_REPOSITORY} docker run --rm ${ECR_DOCKER_IMAGE}:${ECR_DOCKER_TAG} /root/.local/bin/pytest -v ''' } } stage('============ Push Docker Image ============') { when { expression { return params.PUSH_DOCKER_IMAGE } } agent { label 'build' } steps { echo "Push Docker Image to ECR" sh''' aws ecr get-login-password --region ${REGION} | docker login --username AWS --password-stdin ${ECR_REPOSITORY} docker push ${ECR_DOCKER_IMAGE}:${ECR_DOCKER_TAG} ''' } } stage('Prompt for deploy') { when { expression { return params.PROMPT_FOR_DEPLOY } } agent { label 'deploy' } steps { script { env.APPROAL_NUM = input message: 'Please enter the approval number', parameters: [string(defaultValue: '', description: '', name: 'APPROVAL_NUM')] } echo "${env.APPROAL_NUM}" } } stage('============ Deploy workload ============') { when { expression { return params.DEPLOY_WORKLOAD } } agent { label 'deploy' } steps { sshagent (credentials: ['aws_ec2_user_ssh']) { sh """#!/bin/bash scp -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no \ deploy/docker-compose.yml \ ${params.TARGET_SVR_USER}@${params.TARGET_SVR}:${params.TARGET_SVR_PATH}; ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no \ ${params.TARGET_SVR_USER}@${params.TARGET_SVR} \ 'aws ecr get-login-password --region ${REGION} | docker login --username AWS --password-stdin ${ECR_REPOSITORY}; \ export IMAGE=${ECR_DOCKER_IMAGE}; \ export TAG=${ECR_DOCKER_TAG}; \ docker-compose -f docker-compose.yml down; docker-compose -f docker-compose.yml up -d'; """ } } } } post { failure { slackSend( channel: "#jenkins_test", color: "danger", message: "[Failed] Job:${env.JOB_NAME}, Build num:#${env.BUILD_NUMBER} @channel (<${env.RUN_DISPLAY_URL}|open job detail>)" ) } } }