Jenkins pipeline + Docker SpringBoot프로젝트 SSHAgent로 배포하기(+Slack Notification)

devdo·2022년 3월 26일
4

Jenkins

목록 보기
8/8
post-thumbnail

https://velog.io/@mooh2jj/Jenkins-pipeline-Docker-SpringBoot프로젝트-배포하기

이전 블로그에서는 Jenkins pipeline으로 jenkins가 설치되어 있는 인스턴스에 배포하는 작업을 하였습니다.

이번에는 pipeline으로 원격에 있는 AWS EC2 인스턴스에 SSH 원격 서버에 배포하는 작업을 구현하는 실습을 해봅시다.

구현도는 다음과 같습니다.

Jenkisn 실행

# jenkins 실행
docker run \
  --name jenkins-docker \
  -p 9000:8080 -p 50000:50000 \
  -v /home/jenkins:/var/jenkins_home \
  -v /var/run/docker.sock:/var/run/docker.sock \
  -v /usr/bin/docker:/usr/bin/docker \
  -u root \
  -d \
  jenkins/jenkins:lts
  • Jenkisn 실행로그 확인
docker logs [jenkins 컨테이너ID]

Jenkins pipeline 설정

jenkins 홈페이지에 들어가서 pipeline 설정으로 Item을 만들어봅니다.

그 전 블로그에서는 Pipeline > Pipleline script from SCM 으로 Jenkinsfile을 설정했다면

Pipleline script 으로 파이프라인 문법으로 작성해보고 하는 것으로 시작해도록 하겠습니다.

이는 Pipeline Syntax를 사용하기 위함입니다.

Pipeline Syntax는 SSH나 기타 Credentials 설정에서 pipeline 문법에 맞게 설정해주는 데 아주 유용합니다.

Jenkins Credentials 설정은 ssh 원격 서버에 접속하기 위한 publish-over-ssh 또는 private Git 프로젝트 등등 필요합니다. 이와 관련한 작업은 아래 블로그를 참주해주세요.

1) ssh 원격 서버 Credentials 설정: https://velog.io/@mooh2jj/젠킨스-자동배포하기
2) Git 프로젝트 Credentials & webhook 설정: https://velog.io/@mooh2jj/Jenkins-Git-Credentials-Github-webhook-설정


작성한 pipeline 작성 순서는

  • jenkins 인스턴스 : git clone -> gradle build -> docker build -> docker push
  • ssh 인스턴스 : docker pull -> docker run

순으로 작업을 진행합니다.

Jenkinsfile은 spring project 바로 아래에 놓여 있다. Dockerfile도 같은 위치에 놓여야 한다는 것을 주의한다.


Jenkins pipeline 순서

# 다음과 같은 순서로 동작하는 파이프라인이 완성된다.

1. jenkins인스턴스 git clone
2. jenkins인스턴스 gradle build
3. jenkins인스턴스 docker build
4. jenkins인스턴스 docker push
5. jenkins인스턴스 -> server인스턴스 ssh접속
6. server인스턴스 docker pull
7. server인스턴스 docker run

Jenkins pipeline 기본 구조

https://www.jenkins.io/doc/book/pipeline/

// Jenkinsfile (Declarative Pipeline)
pipeline {
    agent any 
    stages {
       stage('Checkout') {
            steps {
                git branch: 'master',
                    url: 'https://github.com/mooh2jj/docker-jenkins-pipeline-test2.git'
            }
        }
    
        stage('Build') { 
            steps {
                sh 	'echo "빌드" 단계와 관련된 몇 가지 단계를 수행합니다.' 
            }
        }
        stage('Test') { 
            steps {
                // 
            }
        }
        stage('Deploy') { 
            steps {
                sh  'echo "배포" 단계와 관련된 몇 가지 단계를 수행합니다.'
            }
        }
    }
}

Jenkinsfile 예시

pipeline{
    agent any

    stages {
        stage('Checkout') {
            agent any
            steps {
//                git credentialsId: 'git-creds', url: 'https://github.com/mooh2jj/docker-jenkins-pipleline-test.git'
                git branch: 'master',
                    url: 'https://github.com/mooh2jj/docker-jenkins-pipeline-test2.git'
            }

            post {

                success {
                    echo 'prepare success'
                }

                always {
                    echo 'done prepare'
                }

                cleanup {
                    echo 'after all other post conditions'
                }
            }
        }

        stage('Build Gradle') {
            steps{
                sh 'chmod +x gradlew'
                sh  './gradlew clean build'

                sh 'ls -al ./build'
            }
        }
        stage('Docker build image'){
            steps{
                sh 'docker build . -t mooh2jj/docker-jenkins-pipeline-test2'
            }
        }
        stage('Docker push image') {
            steps {
                withCredentials([string(credentialsId: 'dockerHubPwd', variable: 'dockerHubPwd')]) {
                    sh "docker login -u mooh2jj -p ${dockerHubPwd}"
                }
                sh 'docker push mooh2jj/docker-jenkins-pipeline-test2'
            }

            post {
                success {
                    echo 'success'
                }

                failure {
                    echo 'failed'
                }
            }
        }
        stage('Run Container on SSH Dev Server'){
            steps{
                echo 'SSH'
                sshagent (credentials: ['ssh231112']) {
					sh "ssh -o StrictHostKeyChecking=no ubuntu@172.31.38.217 'whoami'"
                    sh "ssh -o StrictHostKeyChecking=no ubuntu@172.31.38.217 'docker ps -q --filter name=docker-jenkins-pipeline-test2 | grep -q . && docker rm -f \$(docker ps -aq --filter name=docker-jenkins-pipeline-test2)'"
                    sh "ssh -o StrictHostKeyChecking=no ubuntu@172.31.38.217 'docker rmi -f mooh2jj/docker-jenkins-pipeline-test2'"
                    sh "ssh -o StrictHostKeyChecking=no ubuntu@172.31.38.217 'docker run -d --name docker-jenkins-pipeline-test2 -p 8083:8083 mooh2jj/docker-jenkins-pipeline-test2'"
                }

            }

        }

    }
}

**결과


dockerHubPwd 설정

여기서 dockerHubPwd는 jenkins 관리 > Credentials > System > Global credentials (unrestricted) > Add credential

  • kind : sceret text

  • Scope: Global
  • Secret: docker Hub 비밀번호 기입
  • ID: dockerHubPwd 로 기입

pipeline 내 문법

withCredentials([string(credentialsId: 'dockerHubPwd', variable: 'dockerHubPwd')]) {
                    sh "docker login -u mooh2jj -p ${dockerHubPwd}"
                }

Jenkins build

해당 화면에서 Build Now 를 클릭하면 jenkins build가 실행되고 잠시 후 다음과 같이 Stage View에 진행 상황이 나오는 것을 확인 할 수 있습니다.

실패하면 좌측 하단 Build History를 통해 자세한 로그를 확인할 수 있고 console out 에서도 확인할 수 있습니다.

파이프라인이 실패없이 진행되었다면 docker hub에서 해당 image가 update된 것을 확인할 수 있습니다.


EC2 인스턴스에 SSH 접속(SSH Agent 설치)

docker image pull 및 run 작업을 시켜줄려면jenkins 인스턴스에서 server인스턴스로 ssh server로 credentials 설정을 해줘야 합니다.

👀 왜? Publish Over SSH를 두고 SSH Agent를?

Jenkins에서 Publish Over SSH를 지원종료했기 때문입니다. 대충 요약하자면, 아래 취약점이 발견되어 제공을 중지했다고 하네요.

기존 Plugin Docs 페이지(https://plugins.jenkins.io/publish-over-ssh/)

* SSH 서버 이름을 이스케이프 하지 않기 때문에 XSS 취약점 발생
* 연결 테스트 구현 시 권한 검사가 누락되어 공격자가 SSH서버에 접속 가능함
* 파일 존재 여부를 위한 경호 순회기능을 이용한 경로탐색 취약점 발생
* 일반 텍스트로 저장된 비밀번호, 암호화 되지 않았기 때문에 보안에 취약함

참고 - https://hye0-log.tistory.com/44

그래서 대체용으로 ssh agent를 사용하고자 합니다.

서로 다른 Plugin 이기 떼문에 만약 Publish Over SSH 를 설치 이 플러그인으로 ssh 설정을 해도 ssh agent로 진행해야 합니다!

sshagent plugin을 jenkins에 설치해줍시다.

pipeline 프로젝트 내 구성에서 바로 설정하는 방법을 설명해드리겠습니다.

Dashboard -> Jenkins 관리 -> 플러그인 관리 > 설치가능 목록에서

ssh agent를 검색하고 체크 및 Download now and install after restart 버튼 클릭 후 재시작하시면 됩니다.

server인스턴스에 ssh접속할 수 있도록 Credentials을 등록해주어야 합니다.
이 화면은 앞서 Pipeline Syntax 안으로 들어가면 해당 설정으로 들어갈 수 있습니다.

Pipeline Syntax > Steps > Sample Step(sshagent: SSH Agent)

  • Add => Jenkins를 클릭하면 나옵니다.

Kind 드롭박스에서 SSH Username with private key를 선택해줍니다.
여기서 원격 접속할 ssh 서버를 jenkins인스턴스와 연동될 수 있도록 등록할 수 있습니다.

ID : Credential 식별 값으로 ssh231112로 만들었습니다.

Username : server인스턴스의 유저명인데, (ec2 ubuntu의 경우 리눅스 명령어로 whoami로 나온 값으로, ubuntu 로 합니다.)

Private Key에서 적어줘야 되는 것은
ssh server 인스턴스의 pem 파일내용입니다!(2022-12-27일자 재확인!)

-----BEGIN RSA PRIVATE KEY----- 

~~~~~ ssh 인스턴스의 pem 파일을 클릭하면 나옵니다

-----END RSA PRIVATE KEY-----

이 내용을 모두 입력해주고 Add 눌러주면 됩니다.

그러면 여기서 pipeline 문법으로 generate한 내용을 그대로 jenkinsfile에 옯겨주시면 됩니다.


이렇게 정리한 ssh 접속 pipeline stage는 아래와 같습니다.

위 설정할 내용대로 잘 적어주어야 합니다.

        stage('Run Container on SSH Dev Server'){
            steps{
                echo 'SSH'
                sshagent (credentials: ['{ssh-server credentials ID}']) {
					sh "ssh -o StrictHostKeyChecking=no ubuntu@{private aws IP} 'whoami'"
                    // docker 컨텐이너가 현재 돌아갈시에 실행해야함!, 처음 실행시 주석처리
                    // sh "ssh -o StrictHostKeyChecking=no ubuntu@{private aws IP} 'docker ps -q --filter name=docker-jenkins-pipeline-test2 | grep -q . && docker rm -f \$(docker ps -aq --filter name=docker-jenkins-pipeline-test2)'"
                    // sh "ssh -o StrictHostKeyChecking=no ubuntu@{private aws IP} 'docker rmi -f mooh2jj/docker-jenkins-pipeline-test2'"
                    sh "ssh -o StrictHostKeyChecking=no ubuntu@{private aws IP} 'docker run -d --name docker-jenkins-pipeline-test2 -p 8083:8083 mooh2jj/docker-jenkins-pipeline-test2'"
                }

            }

        }

jenkins pipeline 실행이 되면
ssh 설정한 인스턴스에 docker ps 명령어로 서비스가 실행된 것을 확인할 수 있습니다.


Jenkinsfile 경로 설정(option)

그 다음, 기존에 script로 적어서 설정한 pipeline script를 프로젝트 내 jenkinsfile로 등극해서 설정해줍니다. 이제 jenkins는 git 프로젝트 내 jenkinsfile로 pipeline을 읽게 하는 겁니다.

구성 > pipeline script from SCM 체크 ,springboot 프로젝트 Jenkinsfile 이 있는 위치까지 등록해서 설정해줍니다.


Jenkins Slack Notification 설정

jenkins pipeline script에서 slack Notification을 설정할 수 있습니다.

Jenkins에서 slack 플러그인Credential 설정은 아래 블로그
https://velog.io/@mooh2jj/Jenkins-Slack-Notification-등록
에서 참고하시기 바랍니다.

Jenkins pipeline

### jenkins pipeline stage 추가
stage("Slack Notification") {
            steps {
                echo 'slack test'
            }
            post {
                success {
                    slackSend channel: '#프로그래밍', color: 'good', message: "success deploy"
                }
                failure {
                    slackSend channel: '#프로그래밍', color: 'danger', message: "failure deploy"
                }
            }
        }

결과



참고

profile
배운 것을 기록합니다.

0개의 댓글