Search
Duplicate

ASP.NET Core/ 웹 개발 및 배포 환경 구축/ 4. Jenkins

설치

Jenkins는 Docker 버전이 아니라 인스톨 버전을 통해 설치한다. 이유는 다음과 같은데
1.
프로젝트를 Docker Build를 할건데, Docker로 된 Jenkins에서 다시 Docker 빌드를 하려면 Host의 Docker를 이용해서 해야 하는데 이게 까다롭고,
2.
Jenkins Docker는 기본적으로 ASP.NET SDK를 지원하지 않기 때문에 —이는 설치후 플러그인으로 해도 안 된다— 별도로 ASP.NET을 지원하는 버전을 따로 이용해야 하는데, 이 경우 해당 버전의 버전이 낮아서 플러그인과 호환성이 좋지 않기 때문이다.
따라서 그냥 속 편하게 아래의 링크에서 인스톨 버전을 다운 받아 설치한다.
설치를 하다 보면 포트 번호를 묻는데, Jenkins의 기본 포트가 8080이므로 이것은 다른 포트로 변경할 것을 권장 —8080은 여러 면에서 사용되는 포트이므로 이걸 Jenkins가 먹고 있으면 애매하다.
그 다음 JDK를 찾는 부분에서 현재 설치된 JDK를 찾아주면 되는데, 만일 JDK가 없다면 아래의 링크에서 OpenJDK를 받아 설치하고 해당 경로를 입력해 주면 된다.
설치 종료 후에 앞서 설정한 포트번호를 이용해서 최초 접속하면 password를 입력하라는 화면이 보인다. 이때 password가 있는 경로를 알려주므로 해당 경로에 들어가서 initialAdminPassword라는 파일을 열면 나오는 비밀번호를 입력하면 설치가 진행된다.
그 다음 나오는 플러그인 설치는 suggested를 설치할 것은 권장.
그 다음 관리자 계정 등록과 포트 번호를 확인하여 설치를 마무리 한다.

Gitea 연동

기본 플러그인에 Git 관련 플러그인들이 있지만 여기서는 Gitea를 쓰기 때문에 추가로 Gitea 플러그인을 설치해 주어야 한다.
Jenkins 관리 → PlugIn 관리 → 설치 가능 메뉴를 타고 들어간 뒤 Gitea 플러그인 검색해서 추가한다.
추가로 MS Teams에 빌드 메시지를 보내기 위해 Office 365 Connector 플러그인을 설치한다. —Slack을 쓴다면 Slack을 설치하면 된다.
플러그인 설치 화면에서 설치가 완료되면 Jenkins 재시작 체크박스를 선택해서 Jenkins를 재시작한다.
재시작이 끝났으면 Gitea를 연결하기 위해 우선 Gitea에 접속한다.
우측 상단의 프로필을 클릭해서 설정메뉴에 들어간 후에
어플리케이션 탭을 클릭하고, 토큰 이름을 입력한 후 토큰 생성을 한다.
토큰이 생성되면 1번만 보이는 Key가 발급되고 —잃어버리면 토큰을 다시 만들어야 함— 이 키를 Jenkins에 입력하기 위해 복사해 둔다.
Jenkins의 메인화면에서 Jenkins 관리 → 시스템 설정 메뉴에 들어가서 스크롤을 내리면 Gitea Servers 항목이 보인다. Add를 눌러서 Gitea 서버를 추가한다.
서버 이름을 입력하고 Gitea가 설치된 URL을 입력하면 Gitea 버전이 출력된다.
여기서 Manage Hooks 체크박스를 클릭하면, Credentials을 입력할 수 있는 화면이 뜬다.
다른 항목은 그대로 두고 Kind를 Gitea Personal Access Token을 선택하고
Token에는 아까 Gitea에서 발급 받은 Token을 입력한다. ID는 적절히 알아 볼 수 있는 이름을 입력
제대로 입력 되었다면 Hook management will be performed as ‘계정이름’이 뜬다. 여기까지 오면 Jenkins에서 Gitea 연동 완료. 저장하고 마무리 한다. —Teams 알람은 개별 빌드 아이템 단계에서 한다.

빌드 파이프라인 생성

Dashboard 화면에서 새로운 Item을 선택하고, 이름을 입력한 뒤 Pipeline을 선택한다. Freestyle도 많이 쓰지만, JenkinsFile로 좀 더 디테일하게 빌드를 제어할 수 있는 Pipeline을 권장하므로 Pipeline에 익숙해지는 것이 좋다.

Teams 연동

우선 Office 365 Connector에 Teams 채널을 연동한다. 이것을 연동하기 위해서는 Teams에서 Jenkins의 웹훅을 받을 수 있는 URL을 입력해 줘야 한다.
Teams를 열고 Jenkins 빌드 알림을 받을 수 있는 채널을 추가한다.
추가한 채널을 선택하고 커넥터를 선택한다.
채널에 연동할 수 있는 커넥터 중에 Jenkins를 선택한다.
사용할 이름을 입력하여 만들기를 선택하면
Jenkins에 넣을 수 있는 웹훅 URL이 나온다.
Teams에서 복사한 URL을 Office 365 Connector의 Notification Webhooks의 URL에 입력한다. —Name은 비워도 무방하다.

Build Schedule

스크롤을 내려서 Build Triggers에서 Poll SCM을 체크하고 아래의 체크 박스에 다음의 조건을 입력한다. —* 사이에 띄어쓰기가 있으니 주의
// 10분에 한 번씩 Git 저장소에 변경 사항이 있는지를 체크하라는 뜻 H/10 * * * *
Shell
복사
조건을 입력한 텍스트박스 아래에 날짜 형식이 제대로 표시되면 OK
참고) 엄밀히 말해 정확히 10분에 한 번은 아니고 Jenkins가 스스로의 스케쥴을 고려해서 비어 있는 시간을 사용한다고 한다.

Pipeline Script

스크롤을 내려서 Pipeline 항목에 Pipeline script from SCM을 선택한다.
그 아래 SCM에는 Git을 선택한다.
Git을 선택하면 나오는 Repository URL에 빌드를 수행할 저장소의 URL을 입력하고, Branch에는 Build를 체크할 Branch를 입력한다.
Script Path에 Jenkins File이 있는지 확인하고 저장한다.

JenkinsFile

JenkinsFile 작성

Pipeline에 JenkinsFile을 넣었다는 것은 Jenkins가 Git 저장소에 변화가 감지되면 해당 저장소에 있는 JenkinsFile을 이용해서 빌드를 수행한다는 의미다.
이말은 Git에 JenkinsFile이 존재해야 Jenkins가 빌드를 할 수 있다는 의미다. 처음 만들었던 프로젝트 폴더에 JenkinsFile을 추가하고 다음과 같이 내용을 입력한다.
여기서 docker run에 있는 설정은 앞서 Docker 빌드를 할 때 Visual Studio에서 만들어준 설정을 그대로 쓴 것이다.
pipeline { agent any // 이하 스크립트에서 사용할 변수 environment { IMAGE_NAME = 'testblazorapp' // 이미지는 소문자만 가능하므로 주의 CONTAINER_NAME = 'blazorapp' } // 각 빌드 단계는 stages 안에 묶는다. stages { // 개별 단계는 stage('이름') 의 모습을 띈다. // git에서 소스를 내려 받는다. 소스를 내려 받는데는 credentialsID가 없어도 된다. stage('checkout') { steps { // url과 branch를 입력한다. 이렇게 내려 받은 source는 jenkins가 설치된 경로의 workspace에 생김. git url: 'http://172.30.1.16:3000/BlueDragons/TestBlazor.git', branch: 'master' } } // nuget package restore stage('restore packages'){ steps{ // dotnet restore bat "dotnet restore BlazorApp.sln" } } // project clean stage('clean'){ steps{ bat "dotnet clean BlazorApp.sln --configuration Release" } } // test project test stage('test'){ steps{ bat "dotnet test BlazorApp.Client.Test/BlazorApp.Client.Test.csproj --configuration Release --no-restore" bat "dotnet test BlazorApp.Server.Test/BlazorApp.Server.Test.csproj --configuration Release --no-restore" } } // docker build. // DockerFile을 이용해서 Build를 수행한다. DockerFile은 Visual Studio가 만들어준 것을 그대로 사용한다. stage('docker build'){ steps{ // 기존 컨테이너 삭제 bat "docker rm -f ${CONTAINER_NAME}" // 기존 이미지 삭제 bat "docker rmi -f ${IMAGE_NAME}" // 이미지 빌드. Dockerfile은 Server 프로젝트 하위에 있다. bat "docker build -f ./Server/Dockerfile -t ${IMAGE_NAME} ." // 컨테이너 실행 - 테스트용이라 --restart always는 생략. 볼륨이나 환경변수는 Visual Studio에서 만들어준 것을 그대로 사용한다. bat "docker run -dt -v C:/Users/Suyeongpark/vsdbg/vs2017u5:/remote_debugger:rw \ -v C:/Users/Suyeongpark/AppData/Roaming/Microsoft/UserSecrets:/root/.microsoft/usersecrets:ro \ -v C:/Users/Suyeongpark/AppData/Roaming/ASP.NET/Https:/root/.aspnet/https:ro \ -e ASPNETCORE_LOGGING__CONSOLE__DISABLECOLORS=true \ -e ASPNETCORE_ENVIRONMENT=Development \ -e ASPNETCORE_URLS=https://+:443;http://+:80 \ -P \ --name ${CONTAINER_NAME} \ --entrypoint tail ${IMAGE_NAME} \ -f /dev/null" } } } }
Groovy
복사
JenkinsFile은 Stages의 단계를 순차적으로 진행하는데, 중간에 빌드 에러가 나면 뒤의 단계는 무시하고 진행한다.

Pull Request

앞서 작성한 Jenkinsfile을 프로젝트의 root 디렉터리에 놓고 개인 저장소에 push한다.
개인 저장소에 push한 commit을 팀 저장소에 반영하기 위해 ‘새 풀 리퀘스트’ 버튼을 클릭한다.
풀 리퀘스트를 하면 2개의 브랜치가 비교되는데, 이때 왼쪽에 있는 브랜치가 병합할 브랜치고, 오른쪽에 있는 브랜치가 풀 리퀘스트를 요청한 브랜치가 된다. (쉽게 말해 오른쪽에 있는 브랜치의 commit을 왼쪽의 브랜치에 병합한다고 보면 된다.)
비교에 문제가 없으면 ‘새 풀 리퀘스트’ 버튼을 클릭해서 두 브랜치를 병합한다.
병합 전에 병합할 메시지를 남기고 오른쪽 하단의 풀 리퀘스트 생성을 클릭하면 두 브랜치 병합이 진행된다.
병합이 완료되면, 최종적으로 병합된 내용을 commit 할 수 있다. Create merge commit을 클릭하면 병합된 내용이 원본 저장소의 브랜치에 반영된다.
push에 대한 commit 메시지를 남길 수 있다.
최종적으로 commit이 되면 풀 리퀘스트를 요청한 브랜치를 삭제할 것이냐고 묻는데, 이것은 Git-Flow상 임시로 만들어진 브랜치를 삭제할 때 사용한다. 현재는 그런 용도가 아니므로 무시하고 마무리한다.
저장소에 반영이 잘 되었는지 확인한다.

Jenkins Build

Jenkins 대시보드로 돌아가서 앞서 만들었던 아이템을 확인하고, 방금 소스 코드를 올렸으므로 빌드를 수행해 본다. (아이템의 가장 오른쪽의 녹색 삼각형 버튼)
빌드가 실행되면 Jenkinsfile에 작성했던 Stage 단계별로 빌드가 수행되는 모습이 보인다.
빌드가 모두 성공하면 녹색으로 표시되고 마무리된다.
만일 빌드가 도중에 실패했으면, 위의 #1, #2, #3처럼 빨간색으로 빌드 실패 표시가 뜬다. 해당 아이템을 선택하면 상세 내용을 확인할 수 있고
이 화면에서 다시 Console Output을 선택하면 정확히 어떤 원인으로 빌드가 실패했는지 알 수 있다. —이 경우에 콘솔 메시지를 확인하면 스크립트를 잘못 작성해서 빌드가 실패했다는 것을 알 수 있다.
빌드가 실패 또는 성공하면 Teams에도 알림이 온다. 알림이 문제 없이 도착했는지 확인한다.
빌드를 도커로 했으므로 Docker Desktop에 이미지와 컨테이너가 잘 빌드 되었는지 확인한다.
마지막으로 컨테이너의 Port를 입력해서 접속이 잘 되는지도 확인한다. 잘 되면 끝.
주의) 간혹 도커 빌드 후에 접속이 안되는 경우가 있는데, 도커 빌드가 꼬이면 도커 자체 문제로 안되는거 같다. 이럴 때는 도커 자체를 재시작 하면 문제 없이 접속이 된다.

시리즈

이 글은 아래와 같은 시리즈로 이루어짐

참조 자료