[학습] 젠킨스 프리스타일 vs 파이프라인

반응형
반응형

왜 이름을 프리스타일로 했는지는 알 수 없지만 젠킨스 프리스타일은 젠킨스에서 GUI로 CI/CD를 할 수 있게 제공하는 기능이라고 생각하면 된다.
그러면 프리스타일을 어떻게 하면 파이라인으로 바꿀 수 있을지 생각해보자.

일단 CI/CD를 하기 위해서는 코드가 필요하다. 코드를 가져올 수 있는 방법은 크게 2가지가 있는데
직접 가져오는 방법이 있겠고 깃에서 가져오는 방법이 존재한다.

근데 사실상 직접 넣으면 젠킨스로 CI/CD를 하는 이유가 전혀 없을 거 같다.
그렇다면 젠킨스는 어떻게 코드를 가져올 수 있을까?

 

이 그림은 젠킨스-프리스타일로 할때 깃에서 코드를 가져오는 구문이다.
이렇게 되면 깃에서 코드를 가져올 수 있게 된다.
다른 방안이 있는지는 잘모르겠지만 아무튼 이것을 프리스타일이 아닌 파이프라인으로 변경하면 어떻게 될까?

stage('Git Clone') {
     steps {
       git branch: 'develop', url: 'https://github.com/sparta-MOIM/MOIM-Server.git/'
     }
}

요렇게 작성하면 된다. 아래에 프리스타일 문법을 적어놓을 예정이기 때문에 지금은 1:1 대응으로 보면 좋을거 같다. (지금 이걸 그대로 쓴다고 정상적으로 실행은 안될거다... 아마도??? 그렇지 않을까..)
이것을 하게 되면 특정 브랜치에서 깃 코드를 가져올 수 있게 된다.

이렇게  코드를 가져오면 젠킨스내에 저장되어지게 된다. 

/var/lib/docker/volumes/jenkins_jenkins_home/_data/workspace/test/build/libs/**

요 밑으로 가져오는거 같다.
그럼 이제 어떻게 해야 할까?
코드를 가져왔으니 이걸 옮겨야 할까?
아님 실행을 시켜봐야 할까?
두가지 모두 할 수 있겠지만 수 많은 파일을 옮기는 건 쉽지 않을 수도 있다. 또, 자바는 어떤걸로 실행이 되는지 생각을 해봐야 한다.
자바는 java -jar을 통해 자바를 실행시킨다.

우리가 ide에 찌들여서 java -jar을 망각하는 경우가 있는데 ide로 실행하게 되어도 빌드 과정이 무조건 진행이 되어진다.
아무튼 우리가 필요한건 수많은 소스코드를 서버로 옮기냐 jar파일을 옮기냐의 차이인데 
jar파일을 옮기는 것이 더 간단한 작업일지도 모른다.

아니 그럴 확률이 높다.
그래서 나는 jar파일을 만드는 방법을 선택했다. 그러면 이걸 어떻게 해야 할까?
바로 빌드를 하면 된다.
자바를 위에서 말한것처럼 java -jar을 할 수 도 있겠지만
우리는 그레들,메이븐....같은 빌드 도구들이 존재한다. 엔트라는게 있다는 소문은 들었지만 잘 모르겠다.
얘네를 이용하게 되면 빌드를 쉽게 할 수 있다.
그러면 젠킨스에서 얘네를 어떤 기준으로 결정하는지 생각해보면 그냥 어떤걸로 만들었는지 생각을 해보면된다.
메이븐은 메이븐으로 그레들은 그레들로..
그러면 어떻게 할 수 있을까?

바로 요렇게 할 수 있는데 지금 task쪽을 보면 알 수 있듯이 gradle같은 건 생략이 되어있다. 그러니까 저걸로 빌드를 하면 된다. 
또한 저기는 그레들 문법을 작성하면 되기 때문에 생략한다!!

그러면 요걸 파이프라인으로 바꿔보면...

stage('Gradle Build') {
     steps {
          sh "./gradlew :${SERVICE_NAME}:clean :${SERVICE_NAME}:build -x test"
       }
}

요렇게 작성할 수 있다. 저 가려진게 머냐고 물어볼수 있는데 저거는 추후에 설명예정이다.
이렇게 작성하면 위에서 확인한 /var/lib/docker/volumes/jenkins_jenkins_home/_data/workspace/test/build/libs/**
요기에 jar파일이 옮겨졌다는것을 확인 할 수 있다. 물론 경로는 사람마다 다를 수 있으니
sudo find / -name "*.jar" 요걸 통해 알 수 도 있다.
참고로 *은 전체를 뜻하니 특정 파일의 이름을 넣어서 찾으면 된다.

여기까지가 CI다 이렇게 젠킨스 내부에서 코드를 통합하는 과정이 있다.
요걸 응용하면 git push가 들어올때 CI까지 하게 만들 수 도 있는데 젠킨스에 대한 이해도가 떨어져서 고건 힘들지도..

이제 CD다. CD는 쉽게 말해 배포다. 단지 내가 아니라 젠킨스가 대신 해주는 고런 느낌으로 생각하면 된다.

이걸 내가 다 작성하는게 맞는지는 모르겠지만 지금 너무 힘들다.
그냥 플러그인 알려줄테니 알아서 찾기를...

일단 서버에 접속을 하려면 SSH를 통해 접속할 수 있다.
근데 ec2에 접근을 하려면 ssh만으로는 부족하다 바로 pem키라는게 필요한데 ssh -i {key.pem} 요렇게 접근 해야 ec2에 접근할 수 있다. 문제는 요게 잘안먹힐 수 있다는.. 저 방법이 젠킨스에서 문제가 뭐냐면 저파일이 젠킨스 내에 어디에 정확히 알고 있어야 저 명령어가 의미가 있는데 pem키를 생성할때마다 젠킨스에 넣는 건 좀 거추장스럽다. 

그러면 어떻게 할까 제일 먼저 소개할 플러그인은 Publish Over SSH 요거다. 요거는 system에 pem키를 넣을 수 있다. 자세한건 생략ㅎ
등록을 하게 되면 프리스타일에서는 요런것을 추가할 수 있다.

요기서 시스템에서 지정한 ssh-server의 이름을 넣고 souce file은 내가 보낼 jar파일을 넣는데 문제는 저걸 어떤 기준으로 작성했는지 까먹었다. ㅎㅎㅎ
그리고 Remote directory 요건 보낼곳 (서버 -ec2젠킨스 서버아님) 을 정해놓으면 된다.
마지막으로 Exec command 이 cmd명령어를 작성하면 된다. 이곳은 젠킨스 환경이 아닌거롤 명심해야 한다.

이걸 파이프라인으로 가져다 사용하면 잘 되지는 않는다.
왜냐하면 파이프라인에서는 ssh over publish가 잘 안먹혔던걸로 기억하기 때문이다. 내가 방법을 모르는거 일 수도 있는데

두번째 소개할 플러그인이 바로 ssh agent다.
요것도 ec2에 접근할 수 있게 도와주는 녀석이다.
두가지의 큰 차이점은 pemkey에 있다. 전자의 경우 하나의 pemkey만 등록이 가능하지만, 후자는 여러개가 등록이 가능하다. 어케하는지는 여기에 작성이 되지 않는다. 귀찮다

     stage('SSH 접속 및 확인') {
            steps {
                sshagent (credentials: ['ec2-ssh-key']) {
                    sh "scp -o StrictHostKeyChecking=no ${JAR_FILE} ubuntu@${sever}:${REMOTE_PATH}/"
                }
            }
        }
        
        stage('Run Deploy Script') {
            steps {
                sshagent (credentials: ['ec2-ssh-key']) {
                    sh """
                    ssh -o StrictHostKeyChecking=no ubuntu@${sever} '
                    chmod +x /home/ubuntu/deploy/deloly.sh &&
                    /home/ubuntu/deploy/deloly.sh
                    '
                    """
                }
            }
        }

요 부분으로 ssh을 사용할 수 있게 되었다. 
sshagent (credentials: ['ec2-ssh-key'])  여기에 잘 등록만 해주면 된다.

코드를 보고 딜로이가 머냐고 생각할 수 있다 저건 deploy의 오타이며 sh내용은 ec2에 저장되어있다.
그니까 접근해서 저 cmd명령어를 전달한다. 머 요런뜻이다.

+ 파이프라인 문법 (요거는 gpt로 대체합니다.)

pipeline {
    agent any

    stages {
        stage('Stage 이름') {
            steps {
                sh '명령어'
            }
        }
    }
}

기본적으로 요런 코드를 작성해야 한다.

구성요소설명

pipeline 파이프라인 전체 정의 시작
agent 어떤 머신(노드)에서 실행할지 지정 (any면 아무데나)
stages 작업 단계들 묶음
stage 각 단계 (ex: 빌드, 테스트, 배포)
steps 각 단계 안에서 실제 실행할 명령어들

1. agent :

  • 아무 에이전트에서 실행
    agent any
  • 특정 노드 지정하려면:
    agent { label 'my-server' }

2. stages + stage + steps

stages {
    stage('Build') {
        steps {
            sh './gradlew build'
        }
    }
    stage('Deploy') {
        steps {
            sh 'scp app.jar 서버로 복사'
        }
    }
}

 

- 여러 stage가 순서대로 실행돼.

3. 환경변수 environment

environment {
    SERVICE_NAME = 'chat-service'
    DEPLOY_PATH = '/home/ubuntu/deploy'
}

- SERVICE_NAME 같은 값을 steps 안에서 쓸 수 있어.

4. 조건부 실행 when

stage('Deploy') {
    when {
        branch 'main'
    }
    steps {
        sh './deploy.sh'
    }
}

- 특정 브랜치(main) 에서만 실행되게 할 수 있어!

5. 트리거 triggers

triggers {
    githubPush()
}

- git push 되면 자동으로 빌드 시작!

6. 병렬 실행 parallel

stage('Test') {
    parallel {
        stage('Unit Test') {
            steps {
                sh './gradlew test'
            }
        }
        stage('Integration Test') {
            steps {
                sh './gradlew integrationTest'
            }
        }
    }
}

여러 테스트를 동시에 병렬로 돌릴 수 있어.

기본구조

pipeline {
    agent any
    environment { 변수 정의 }
    triggers { 이벤트 설정 }
    stages {
        stage('1') { steps { 명령어 실행 } }
        stage('2') { steps { 명령어 실행 } }
        stage('3') { when { 조건 } steps { 명령어 실행 } }
    }
}

7. post: stages가 다 끝나고 빌드 성공, 실패, 항상(always) 등에 따라 실행되는 블록

조건설명

always 성공, 실패 상관없이 무조건 실행
success 빌드 성공했을 때만 실행
failure 빌드 실패했을 때만 실행
unstable 빌드 결과가 unstable(성공은 했지만 경고 있음)일 때 실행
changed 이전 빌드랑 결과가 다를 때 실행

8. 파라미터: 배포시 선택값 사용

Jenkins Pipeline에서 파라미터 사용하는 방법

기본은 이렇게 작성해:

pipeline {
    agent any

    parameters {
        choice(name: 'DEPLOY_ENV', choices: ['dev', 'stage', 'prod'], description: '배포 환경을 선택하세요.')
        booleanParam(name: 'ROLLBACK', defaultValue: false, description: '롤백 실행 여부')
        string(name: 'VERSION_TAG', defaultValue: 'latest', description: '배포할 버전 태그 입력')
    }

    stages {
        stage('Print Parameters') {
            steps {
                echo "선택한 배포 환경: ${params.DEPLOY_ENV}"
                echo "롤백 여부: ${params.ROLLBACK}"
                echo "버전 태그: ${params.VERSION_TAG}"
            }
        }
    }
}

여기서

파라미터 종류설명예시
choice 여러 옵션 중 선택할 수 있게 한다 dev, stage, prod
booleanParam true/false 체크박스 롤백 실행 여부 같은 거
string 자유 입력 문자열 버전 이름, 태그 등

Jenkins 빌드 버튼을 누르면 → 파라미터 입력 화면이 먼저 떠!


 흐름 부드럽게 요약

  1. Jenkinsfile 안에 parameters 블록 추가
  2. Jenkins Job 생성할 때 "This project is parameterized" 자동 활성화
  3. 빌드 누르면 선택/입력하는 화면 나옴
  4. params.변수이름 으로 파이프라인 안에서 사용 가능

아주 쉬운 예시

  • DEPLOY_ENV가 "prod" 이면 진짜 배포하고,
  • 아니면 그냥 빌드만 하고 넘어가고 싶을 때!
stage('Deploy') {
    when {
        expression { params.DEPLOY_ENV == 'prod' }
    }
    steps {
        echo "프로덕션에 배포 시작!"
        // 배포 스크립트 실행
    }
}

이렇게 파라미터 값에 따라 분기할 수 있어.

추가적으로
sh는 리눅스 명령어 실행할 때 쓰인다

Jenkins Pipeline에서 알아두면 좋은 블록 모음

블록 이름설명실전에서 많이 쓰이는 이유
environment 환경변수 선언 (ex: SERVICE_NAME) 값 관리가 편해지고, 수정할 때 한 곳만 바꾸면 됨
options 파이프라인 옵션 설정 (ex: timeout, retry 등) 빌드 제한, 재시도 같은 제어가 쉬워짐
parameters 사용자 입력값 받을 때 사용 "이 서비스만 배포" 같은 선택지를 주고 싶을 때
tools 빌드 툴 설정 (ex: Gradle, Maven 설치 자동화) 개발환경 맞춰주기 좋음
triggers 외부 이벤트로 파이프라인 자동 실행 (ex: Git push) Webhook이나 주기적 빌드에 필요
when 조건부 실행 (ex: 특정 브랜치일 때만 배포) Stage 실행 제어할 때 필수

 각각 부드럽게 예시도 들어줄게


1. environment

 
environment { SERVICE_NAME = 'chat-service' DEPLOY_PATH = '/home/ubuntu/deploy' }
  • 변수를 선언해서 어디서든 ${SERVICE_NAME}처럼 쓸 수 있어.

 2. options

options { timeout(time: 10, unit: 'MINUTES') // 빌드가 10분 넘으면 강제 종료 retry(2) // 실패하면 2번 더 시도 }
  • 빌드가 너무 오래 걸리거나 잠깐 실패했을 때 다시 시도할 수 있게 해.

3. parameters

parameters { choice(name: 'ENV', choices: ['dev', 'stage', 'prod'], description: '배포 환경 선택') }
  • 빌드할 때 사용자가 dev/stage/prod 중에 선택할 수 있어.

 예를 들면:
"prod만 진짜 배포하고, dev는 그냥 테스트 빌드" 이런 분기 만들 수 있어!


 4. tools

 
tools { gradle 'Gradle-8.5' }
  • Jenkins 서버에 설치된 Gradle, Maven 등을 자동으로 잡아줄 수 있어.

5. triggers

triggers { githubPush() }
  • GitHub에 Push 발생하면 자동으로 파이프라인 실행!

또는 스케줄링도 가능해:

triggers { cron('H 2 * * *') // 매일 새벽 2시에 실행 }

6. when

stage('Deploy to Prod') { when { branch 'main' } steps { sh './deploy-prod.sh' } }
  • "main 브랜치에만 진짜 배포" 같은 조건 걸 수 있어.

실무에서는 이게 없으면 잘못해서 dev 브랜치에 배포해버리는 사고가 나기도 해.



반응형

댓글

Designed by JB FACTORY