Infra/CI, CD

[Jenkins] bitbucket - Jenkins 연동, merge 시 jenkins 이벤트 발생시키기 (with Generic Webhook Trigger)

민돌v 2022. 12. 13. 21:08

 

CI/CD 의 부푼 꿈을 안고 Bitbucket jenkins 연동을 개선해보고자 합니다.

 

📌 목표

  • Bitbucket Pull Requset Merge 시 Jenkins 에서 branch 별 별도의 event 발생시키기
  • (bitbucket jenkins branch merge reloading)

 

📌 시나리오

  1. bitbucket 에 webhook 을 등록하여 merge 를 triger 로 등록합니다.
  2. 이벤트 발생을 필요로하는 jenkins 서버 url 을 webhook 에 등록시키고
  3. Jenkins Generic Webhook Trigger 플러그인을 사용하여 Branch 별로 이벤트를 각각 발생시킬 수 있도록 설정해줍니다.

 

 

[목차]

  1. 웹 훅 이란
  2. bitbucket webhook 설정
  3. bitbucket webhook 가이드
  4. jenkins 플러그인 설치
  5. generic webhook triger 가이드
  6. postman 결과

 

1. Webhook 이란

Webhook의 정의

"A webhook in web development is a method of augmenting or altering the behavior of a web page or web application with custom callbacks." (Wikepedia)

 

📌 Webhook 이란 사용자 정의 HTTP 콜백입니다.

제 3자 웹페이지 혹은 어플리케이션에서 해당 어플리케이션에 대한 동작을 수행하기 위해 사용자 지정 콜백을 사용하여 요청을 보내는 것 것입니다.

형식은 일반적으로 Json 이고 요청은 HTTP POST 요청으로 수행됩니다.

해당 이벤트가 발생하면 소스 사이트는 Webhook에 대해 구성된 URL에 HTTP 요청을 합니다. 사용자는 한 사이트의 이벤트가 다른 사이트의 동작을 호출하도록 구성할 수 있습니다. (이벤트 ex - 블로그 댓글, 브랜치 push & merge)

 

이런 느낌으로 web hook 트리거 발생 등록 (출처 : https://more-learn.tistory.com/26)

 


 

2. BitBucket 에 webhook 설정하기

bitbucket 이나 github 같은 저장소에서 webhook 을 등록하여, 어떤 트리거가 실행되었을 때 이벤트를 발생시킬 수 있습니다.

저는 bitbucket을 사용하고, 특정 브랜치에 merge 가 일어나면 jenkins 를 build 하고 싶었습니다.

 

😄 Bitbucket

  • 먼저 Bitbucket 에 훅을 걸어보겠습니다.
  • 훅을 걸고자하는 저장소에 들어가 webhook을 설정해줍니다.

 

[Repository] - [Repository settings] - [WORKFLOW → webhooks] - "Add Webhooks"

 

1) title을 입력

  • 본인이 원하는 이름

2) url을 입력

  • 양식 : http://{jenkins가 설치되어있는 서버 ip}:8080/bitbucket-webhook/
  • http://{젠킨스 서버주소[:포트번호]}/bitbucket-hook/ (마지막 슬래시(/)를 꼭 붙여줍니다.
  • ex) http://ci.test.com/bitbucket-hook/

 

👏🏻 Generic Webhook Trigger 를 사용한다면 지정된 url 을 사용해야 합니다.

Generic Webhook Trigger URL 예시

Is triggered by HTTP requests to http://JENKINS_URL/generic-webhook-trigger/invoke
  • 토큰을 사용한다면, 쿼리 파라미터로 token 값을 넣어서 인증을 받아야하고
  • token 을 사용하지 않는다면 jenkins 아이디:비밀번호를 url에 담아야합니다.
{
    "jobs": null,
    "message": "Did not find any jobs with GenericTrigger configured! 
    If you are using a token, you need to pass it like ...trigger/invoke?token=TOKENHERE.
    If you are not using a token, you need to authenticate like http://user:passsword@example.org/generic-webhook... "
}

➡️ "Generic Trigger가 구성된 작업을 찾을 수 없습니다! 토큰을 사용하는 경우 트리거/실행과 같이 전달해야 합니다.token=여기를 클릭합니다.

➡️ 토큰을 사용하지 않는 경우http://user:passsword@example.org/http-webhook...과같이 인증해야 합니다.

 

3) 트리거

  • 해당 레포지토리에서 어떤 이벤트가 발생할 떄, webhook의 트리거를 당길거냐를 선택할 수 있습니다.
  • 저는 merge 할 때만 jenkins 에서 Re build 되길 원했기 때문에 [merge] 옵션만 선택하였습니다.

 

4) save 버튼을 클릭합니다.

 

 📌 설정에서 보다시피 Bitbucket 에서는 Branch 별로 이벤트를 발생시키는 세부적인 옵션이 존재하지 않습니다.

저장소 기준으로 Triger 가 발생하기 때문에, 이 문제를 Jenkins 에서 Generic Webhook Triger plugin을 사용해서 해결해보고자 했습니다. 


 

😄 Bitbucket Webhook post body

아래에서 볼테지만, jenkins 에서 Post content parameters 를 사용하여 어떤 값을 변수로써 사용할 것인지 설정할 수 있습니다.

webhook을 걸은 url 의 body 값을 가져오는 겁니다.

 

그럼 이제 bitbucket 에서는 webhook url 에 어떤 값을 바디에 담아서 보내는지 알아야겠져!!!

[Repository settings] - [webhooks] - [view requests] - [view details]

 

webhook을 건 후, 내가 걸어준 trigger 에 해당하는 요청이 들어왔을 떄, 해당 메뉴에서 결과를 볼 수 있습니다.

사진처럼 webhook request 에서 network error status -3 이 난 이유는, url을 Generic Webhook Trigger URL 양식에 맞춰주지 않았기 때문입니다..ㅎ

 

[view detail] 를 들어간 후 맨 아래에서 body 를 클릭하면 데이터 양식을 확인해 볼 수 있습니다.

 대충 아래와 같습니다. 

{
    "repository": {
        "type": "repository",
        "full_name": ~,
        "links": {
            ~
        },
        "name": ~,
        "scm": "git",
        "website": null,
        "owner": {
            "display_name": ~,
            "links": {
                ~
            },
            "type": "team",
            "uuid": ~,
            "username": ~
        },
        "workspace": {
            ~
        },
        "is_private": false,
        "project": {
            "type": ~,
            "key": "~,
            "uuid": ~,
            "name": ~,
            "links": ~
            }
        },
        "uuid":~
    },
    "actor": {
        "display_name": Merge 하는 사람,
        "links": {
            ~
        },
        "type": "user",
        "uuid":~,
        "account_id": ~,
        "nickname": ~
    },
    "pullrequest": {
        "comment_count": 0,
        "task_count": 0,
        "type": "pullrequest",
        "id": ~,
        "title": ~,
        "description": ~,
        "rendered": {
            "title": {
                "type": ~,
                "raw": ~,
                "markup": "markdown",
            },
            "description": {
                "type": "~",
                "raw": ~
                "markup": "markdown",
            }
        },
        "state": "MERGED",
        "merge_commit": {
            ~
        },
        "close_source_branch": true,
        "closed_by": {
            "display_name": ~,
            "links": {
                ~
            },
            ~
        },
        "author": {
            "display_name": ~,
            "links": {
                ~
            },
            "type": "user",
            "uuid": ~,
            "account_id": ~,
            "nickname": ~
        },
        "reason": "",
        "created_on": "2022-12-13T02:40:43.216398+00:00",
        "updated_on": "2022-12-13T10:05:33.354681+00:00",
        "destination": {
            "branch": {
                "name": "브랜치 이름~!!!! 매우 중요!!"
            },
            "commit": {
                "type": "commit",
                ~
            },
            "repository": {
                "type": "repository",
                "full_name": "프로젝트/레포지토리 네임",
                "links": {
                    ~
                },
                "name": "레포지토리 네임",
                "uuid": ~
            }
        },
        "source": {
            "branch": {
                "name": "merge 하는 브랜치 이름"
            },
            "commit": {
                ~
            },
            "repository": {
                "type": "~",
                "full_name": "~",
                "links": {
                    ~
                },
                "name": "~",
                "uuid": "{~}"
            }
        },
        "reviewers": [
            {
                ~
            }
        ],
        "participants": [
            ~ 승인한 사람
            }
        ],
        "links": {
            "self": {
             },
            "html": {
             },
            "commits": {
             },
            "approve": {
             },
            "request-changes": {
             },
            "diff": {
             },
            "diffstat": {
             },
            "comments": {
             },
            "activity": {
             },
            "merge": {
             },
            "decline": {
            },
            "statuses": {
            }
        },
        "summary": {
           }
    }
}

휴 너무 길어..


 

3. Jenkins 에서 generic Webhook Triger 사용하기

이제 jenkins 와 bitbucket을 연결해 봅시다.

 

😄 Jenkins

Jenkins Plugin 설치

Generic Webhook Trigger 를 사용하기 위해서는 젠킨스에서 플러그인을 설치해주어야합니다.

  • [Jenkins] - [Jenkins 관리] - [플러그인 관리] - [설치가능] - 검색 : Generic Webhook Trigger

 

 

 

 

😄 Jenkins 와 bitbucket 저장소 연동

구글링을 하면 Jenkins item을 새롭게 만들어서 설정하라고 하는데

저는 기존에 띄우고 있는 서버를 수정하면서 진행하였습니당

  • [Jenkins] - [해당 서버] - [구성] -[Build Triggers] - [Generic Webhook Trigger 체크박스]

 

😄 Jenkins Post Contents Parameters

위에서 말했던 변수를 설정하는 곳입니다. (다왔다 다왔어)

양식에 맞춰서 어떤 변수를 사용할 것인지 적어줍니다.

  • Variable : 내가 설정하는 변수명
  • Expression : webhook 은 post 형식에 json body 로 데이터가 오기 때문에 매핑할 데이터

 

 

😄 Jenkins Webhook 조건 필터링 (if, when)

(1) Optional filter 탭을 사용하여서, 들어오는 조건을 정규표현식으로 조건을 걸어, true 일 때만 pipeline 이 빌드되게 설정할 수 있습니다.

저는 bitbucket branch name 을 필터링 조건으로 잡았습니다.

  • Expression : 정규표현 조건 true 일때만 실행 (? 는 위에서 설정한 변수 값이 들어옴 - variable)
  • Text : 응답값을 확인할 수 있음

 

(2) 혹은 필터링 조건을 걸지않고, pipeline 을 무조건 실행시켜, groovy when 절로 실행하셔도 됩니다.

저는 그루비 문법을 잘몰라서 쳐다도 보고싶지 않았습니다.


 

🔥 결과

post 맨으로 generic webhook trigger url 로 날려보면 아래와같은 결과를 얻을 수 있습니다!!!

 

 

무야홍

 

 

 


* 참고