Windows 환경 Jenkins 설치 및 GitHub 연동 실습 트러블슈팅 정리
Debian/Ubuntu 기준으로 작성된 Jenkins 실습을 Windows 11 환경에서 진행하면서 겪은 설치, 계정, Gradle, GitHub Webhook, ngrok 관련 트러블슈팅을 정리한 글입니다.
1. 실습 배경
책에 나온 Jenkins 설치 명령어는 Debian/Ubuntu 계열 Linux 기준이었다.
sudo apt update
sudo apt install -y openjdk-17-jre-headless
java -version
하지만 Windows 환경에서는 apt, sudo 명령어를 그대로 사용할 수 없다.
따라서 Windows에서는 Java를 Windows용 패키지 설치 방식으로 설치하고, Jenkins는 Windows Installer를 통해 설치하는 방식으로 진행했다.
이번 실습의 핵심은 책의 명령어를 그대로 따라 치는 것이 아니라, 각 명령어가 하려는 목적을 이해하고 Windows 방식으로 바꾸는 것이었다.
책의 실습 목적은 크게 다음과 같았다.
1. Java 설치
2. Jenkins 설치
3. Jenkins 초기 설정
4. GitHub 인증 정보 등록
5. Jenkins Job 생성
6. Gradle 설치 및 등록
7. GitHub Webhook으로 Jenkins 빌드 트리거
2. Linux 명령어와 Windows 대응 관계
| Linux 명령어 | 의미 | Windows에서 대응되는 방식 |
|---|---|---|
sudo apt update |
패키지 목록 갱신 | 일반적으로 불필요 |
sudo apt install -y openjdk-17-jre-headless |
Java 17 실행 환경 설치 | winget으로 JDK 설치 |
java -version |
Java 설치 확인 | 동일하게 사용 |
| Jenkins GPG Key 등록 | apt 저장소 신뢰 키 등록 | Windows Installer 사용 시 직접 처리하지 않음 |
apt install jenkins |
Jenkins 설치 | Jenkins .msi 설치 파일 실행 |
wget ... -P /tmp |
파일 다운로드 | Invoke-WebRequest |
/tmp |
임시 디렉터리 | $env:TEMP |
/opt/gradle |
Gradle 설치 경로 | C:\gradle |
unzip |
압축 해제 | Expand-Archive |
nano |
터미널 편집기 | notepad 또는 GUI 편집 |
chmod +x |
실행 권한 부여 | Windows에서는 보통 불필요 |
source |
환경 변수 즉시 반영 | PowerShell 재실행 또는 $env:Path 수정 |
grep |
문자열 검색 | findstr, Select-String, Where-Object |
3. Java 17 설치
Windows PowerShell을 관리자 권한으로 실행한 뒤, 아래 명령어로 Java 17을 설치했다.
winget install -e --id EclipseAdoptium.Temurin.17.JDK
설치 과정에서 Microsoft Store 원본 사용 약관 동의가 필요했다.
모든 원본 사용 약관에 동의하십니까?
[Y] 예 [N] 아니요: y
이후 Java 17 설치가 정상적으로 완료되었다.
설치 확인 명령어는 다음과 같다.
java -version
실행 결과:
openjdk version "17.0.8.1" 2023-08-24 LTS
OpenJDK Runtime Environment (build 17.0.8.1+1-LTS)
OpenJDK 64-Bit Server VM (build 17.0.8.1+1-LTS, mixed mode, sharing)
즉, Java 17은 정상적으로 설치되어 있었다.
4. Java 21 설치 시도와 PATH 우선순위 문제
Jenkins 최신 버전에서는 Java 21이 권장되거나 요구될 수 있어 Java 21도 추가로 설치했다.
winget install -e --id EclipseAdoptium.Temurin.21.JDK
설치 결과는 성공이었다.
하지만 다시 java -version을 실행했을 때 여전히 Java 17이 표시되었다.
java -version
결과:
openjdk version "17.0.8.1" 2023-08-24 LTS
OpenJDK Runtime Environment (build 17.0.8.1+1-LTS)
OpenJDK 64-Bit Server VM (build 17.0.8.1+1-LTS, mixed mode, sharing)
Java 21 설치 자체는 성공했다.
다만 Windows에서 java -version을 실행할 때는 환경 변수 PATH에 등록된 Java 실행 파일 중 먼저 잡히는 Java가 실행된다.
즉, 현재 상태는 다음과 같이 볼 수 있다.
Java 17 설치됨
Java 21 설치됨
하지만 PATH 우선순위에서는 Java 17이 먼저 잡힘
따라서 java -version 결과는 Java 17로 표시됨
이 상황 자체가 Jenkins 설치 실패를 의미하지는 않는다.
다만 Jenkins가 Java 21을 요구하는 버전이라면 Jenkins 서비스가 Java 21 경로를 바라보도록 설정해야 할 수 있다.
5. Jenkins 설치 중 서비스 계정 오류
Jenkins Windows Installer 설치 중 다음과 같은 오류가 발생했다.
Invalid Logon
0x8007052e - Error logging on ...
이 오류는 Jenkins 문제가 아니라 Windows 서비스 실행 계정 설정 문제다.
설치 화면에서 Run service as local or domain user를 선택하면 Jenkins 서비스를 특정 Windows 사용자 계정으로 실행하려고 한다.
이때 입력한 계정명 또는 비밀번호가 맞지 않거나, 해당 계정에 서비스 로그온 권한이 없으면 오류가 발생한다.
원인
1. Jenkins 서비스를 특정 사용자 계정으로 실행하려고 함
2. Windows가 해당 계정으로 로그인 테스트 수행
3. 계정 또는 비밀번호 검증 실패
4. 설치 진행 불가
해결 방법
로컬 실습 환경에서는 별도 사용자 계정을 사용하지 않고 다음 옵션을 선택하면 된다.
Run service as LocalSystem
LocalSystem은 Windows의 로컬 시스템 계정으로 서비스를 실행하는 방식이다.
개인 PC에서 Jenkins를 실습용으로 설치할 때는 이 방식이 가장 간단하다.
6. Jenkins 초기 잠금 해제
Jenkins 설치 후 브라우저에서 접속했다.
http://localhost:8080
그러면 Unlock Jenkins 화면이 나온다.
이 화면에서는 Jenkins가 자동으로 생성한 초기 관리자 비밀번호를 입력해야 한다.
화면에 표시된 경로는 다음과 같았다.
C:\ProgramData\Jenkins\.jenkins\secrets\initialAdminPassword
PowerShell 관리자 권한에서 아래 명령어를 실행했다.
Get-Content "C:\ProgramData\Jenkins\.jenkins\secrets\initialAdminPassword"
실행 결과로 나온 값이 Jenkins 초기 관리자 비밀번호다.
해당 값을 Jenkins Unlock 화면의 Administrator password 입력 칸에 그대로 입력하면 된다.
블로그나 문서에는 초기 관리자 비밀번호 원문을 남기지 않는 것이 좋다.
7. 비밀번호 입력 시 주의사항
초기 비밀번호가 틀렸다고 나오는 경우는 보통 다음과 같은 이유다.
1. 앞뒤 공백까지 같이 복사한 경우
2. 줄바꿈 문자가 같이 들어간 경우
3. 다른 Jenkins 경로의 initialAdminPassword를 확인한 경우
4. Jenkins를 재설치하면서 이전 비밀번호를 입력한 경우
반드시 현재 Jenkins 화면에 표시된 경로의 파일을 확인해야 한다.
이번 실습 기준 경로:
C:\ProgramData\Jenkins\.jenkins\secrets\initialAdminPassword
8. Jenkins 비밀번호를 잊어버린 경우
이후 다시 초기 비밀번호를 확인하려고 다음 명령어를 실행했지만 오류가 발생했다.
Get-Content "C:\ProgramData\Jenkins\.jenkins\secrets\initialAdminPassword"
오류 내용은 다음과 같았다.
Cannot find path ... initialAdminPassword because it does not exist
이는 보통 Jenkins 초기 Unlock 과정이 이미 끝났고, 초기 관리자 비밀번호 파일이 더 이상 존재하지 않는 상태를 의미한다.
Jenkins 사용자 폴더를 확인했다.
Get-ChildItem "C:\ProgramData\Jenkins\.jenkins\users"
결과는 다음과 같은 형태였다.
admin_해시값
Jenkins 사용자 폴더명은 보통 다음 구조를 가진다.
사용자ID_해시값
따라서 현재 Jenkins 사용자 ID는 admin으로 볼 수 있었다.
다만 비밀번호는 직접 확인할 수 없다.
Jenkins는 비밀번호를 평문으로 저장하지 않고 해시로 저장하기 때문이다.
즉 비밀번호를 잊어버렸다면 기존 비밀번호를 “조회”하는 것이 아니라 “재설정”해야 한다.
보안을 임시로 끄고 재설정하는 방법
설정 파일 경로는 다음과 같다.
C:\ProgramData\Jenkins\.jenkins\config.xml
먼저 Jenkins 서비스를 중지한다.
Stop-Service Jenkins
그다음 설정 파일을 연다.
notepad "C:\ProgramData\Jenkins\.jenkins\config.xml"
기존 설정은 다음과 같았다.
<useSecurity>true</useSecurity>
이를 임시로 다음과 같이 변경한다.
<useSecurity>false</useSecurity>
저장 후 Jenkins를 다시 시작한다.
Start-Service Jenkins
이후 브라우저에서 Jenkins에 접속하면 로그인 없이 들어갈 수 있다.
http://localhost:8080
그 다음 admin 계정 비밀번호를 재설정하고, 반드시 다시 보안을 켜야 한다.
<useSecurity>true</useSecurity>
마지막으로 Jenkins를 재시작한다.
Restart-Service Jenkins
9. Manage Jenkins 메뉴가 보이지 않았던 문제
Jenkins 화면에서 Manage Jenkins 메뉴가 보이지 않는 문제가 있었다.
한글 UI에서는 이 메뉴가 Jenkins 관리로 표시될 수 있다.
또는 보안을 임시로 끈 상태에서는 로그인 사용자 상태가 일반적인 관리자 로그인 상태와 다르게 보일 수 있다.
이 경우 메뉴를 찾기보다 URL로 직접 접근하면 된다.
http://localhost:8080/manage
즉, Manage Jenkins 메뉴가 화면에서 보이지 않더라도 Jenkins 관리 페이지는 직접 URL로 접근할 수 있다.
10. GitHub 연동 준비
Jenkins 기본 설치가 끝난 후 GitHub와 연동하는 단계로 넘어갔다.
이 단계의 목적은 다음과 같다.
GitHub 저장소에 코드가 push됨
GitHub Webhook이 Jenkins로 이벤트를 전송함
Jenkins가 해당 이벤트를 받아 Job을 실행함
Gradle을 사용하여 프로젝트를 빌드함
전체 흐름은 다음과 같다.
GitHub Repository
→ GitHub Webhook
→ Jenkins /github-webhook/
→ Jenkins Freestyle Project
→ Git Checkout
→ Gradle Build
11. GitHub 토큰 생성
Jenkins가 GitHub 저장소에 접근하려면 인증 정보가 필요하다.
이를 위해 GitHub에서 Personal Access Token을 생성했다.
토큰은 Jenkins에서 GitHub API 접근 및 저장소 접근에 사용된다.
실습에서는 생성한 토큰을 Jenkins Credentials에 등록했다.
중요한 점은 GitHub 토큰 값은 한 번 생성 후 다시 볼 수 없다는 점이다.
따라서 생성 직후 안전한 곳에 보관해야 한다.
문서나 블로그에는 GitHub 토큰 원문을 절대 남기지 않는다.
12. Jenkins에 GitHub Credentials 등록
Jenkins에서 GitHub 토큰을 사용하려면 Credentials에 등록해야 한다.
흐름은 다음과 같다.
Manage Jenkins
→ Credentials
→ Add Credentials
→ Secret text 또는 Username with password 방식으로 GitHub 토큰 등록
이후 Manage Jenkins에서 GitHub Server 설정으로 이동하여 GitHub 서버를 추가했다.
흐름은 다음과 같다.
Manage Jenkins
→ System
→ GitHub
→ GitHub Servers
→ Add GitHub Server
→ Credentials에 등록한 GitHub 토큰 선택
인증 확인 결과 다음 메시지가 나왔다.
Credentials verified for user goodsosbva, rate limit: 5000
여기서 핵심은 다음 문구다.
Credentials verified
즉 Jenkins가 GitHub 토큰을 사용해서 GitHub 계정 인증에 성공했다는 의미다.
책에서는 rate limit: 4999가 나왔지만, 실습에서는 5000이 나왔다.
이는 문제가 아니다.
GitHub API의 인증된 사용자 기본 요청 제한이 5000이고, API 요청이 한 번 차감되면 4999처럼 보일 수 있다.
5000 → 인증 성공, 아직 요청 횟수가 줄지 않았거나 초기 상태
4999 → 인증 성공, 확인 요청 1회가 차감된 상태
따라서 Credentials verified가 나오면 GitHub 인증은 정상으로 보면 된다.
13. GitHub 저장소 생성
Jenkins에서 빌드할 프로젝트를 연결하기 위해 GitHub에 Repository를 생성했다.
이 저장소는 Jenkins Freestyle Project에서 Source Code Management 영역에 연결된다.
즉, GitHub 저장소는 Jenkins Job이 빌드할 소스 코드 위치가 된다.
14. Jenkins Freestyle Project 생성
Jenkins 메인 화면에서 New Item을 클릭하여 새로운 Job을 만들었다.
선택한 Job 유형은 다음과 같다.
Freestyle project
Freestyle Project는 Jenkins에서 가장 기본적인 Job 유형이다.
간단한 Git checkout, 빌드 명령 실행, Gradle/Maven 빌드 등을 구성할 수 있다.
생성 후 Configure 화면으로 들어가 GitHub 저장소와 빌드 설정을 연결했다.
15. Freestyle Project에 GitHub 저장소 연결
Job 설정 화면에서 Source Code Management 영역을 설정했다.
흐름은 다음과 같다.
Configure
→ Source Code Management
→ Git 선택
→ Repository URL 입력
→ Credentials 선택
Repository URL에는 GitHub 저장소 주소를 입력한다.
https://github.com/사용자명/저장소명.git
Private Repository인 경우 Credentials 선택이 필요하다.
Public Repository라도 실습 흐름에서는 GitHub 토큰 Credentials를 연결해두면 인증 관련 문제를 줄일 수 있다.
16. GitHub Hook Trigger 설정
Jenkins Job이 GitHub push 이벤트를 받으면 자동으로 실행되도록 Build Triggers를 설정했다.
Job 설정에서 다음 옵션을 선택했다.
GitHub hook trigger for GITScm polling
이 옵션의 의미는 다음과 같다.
GitHub Webhook 이벤트가 Jenkins로 들어오면
해당 Git 저장소와 연결된 Jenkins Job을 찾아
빌드를 자동으로 실행한다
즉, 이 옵션을 체크해야 GitHub에서 push가 발생했을 때 Jenkins Job이 자동으로 트리거된다.
17. Gradle 설치 과정
책에서는 Gradle을 Linux 방식으로 설치하도록 안내되어 있었다.
wget https://services.gradle.org/distributions/gradle-7.4.2-bin.zip -P /tmp
sudo unzip -d /opt/gradle /tmp/gradle-*.zip
ls /opt/gradle/gradle-7.4.2
sudo nano /etc/profile.d/gradle.sh
sudo chmod +x /etc/profile.d/gradle.sh
source /etc/profile.d/gradle.sh
gradle -v
하지만 Windows PowerShell에서는 이 명령어들을 그대로 사용할 수 없었다.
18. Gradle 다운로드
Linux 명령어는 다음과 같았다.
wget https://services.gradle.org/distributions/gradle-7.4.2-bin.zip -P /tmp
Windows PowerShell에서는 다음과 같이 바꿨다.
Invoke-WebRequest -Uri "https://services.gradle.org/distributions/gradle-7.4.2-bin.zip" -OutFile "$env:TEMP\gradle-7.4.2-bin.zip"
여기서 $env:TEMP는 Windows의 임시 폴더다.
Linux의 /tmp에 대응되는 위치라고 보면 된다.
19. Gradle 압축 해제
Linux 명령어는 다음과 같았다.
sudo unzip -d /opt/gradle /tmp/gradle-*.zip
Windows PowerShell에서는 다음과 같이 바꿨다.
New-Item -ItemType Directory -Force -Path "C:\gradle"
Expand-Archive -Path "$env:TEMP\gradle-7.4.2-bin.zip" -DestinationPath "C:\gradle" -Force
Linux의 /opt/gradle에 대응되는 Windows 경로로 C:\gradle을 사용했다.
20. /opt/gradle 경로 오류
압축 해제 후 책에 나온 명령어를 그대로 실행했다.
ls /opt/gradle/gradle-7.4.2
그러자 다음 오류가 발생했다.
Cannot find path 'C:\opt\gradle\gradle-7.4.2' because it does not exist.
이유는 Windows PowerShell에서 /opt/gradle/gradle-7.4.2를 Windows 경로처럼 해석했기 때문이다.
PowerShell은 해당 경로를 사실상 다음과 비슷하게 해석했다.
C:\opt\gradle\gradle-7.4.2
하지만 실제 Gradle은 다음 위치에 설치했다.
C:\gradle\gradle-7.4.2
따라서 올바른 확인 명령어는 다음과 같다.
ls "C:\gradle"
또는 Gradle의 bin 폴더를 확인하려면 다음과 같이 입력한다.
Get-ChildItem "C:\gradle\gradle-7.4.2\bin"
21. gradle.bat을 찾지 못한 문제
처음에는 다음 명령어로 gradle.bat을 찾으려 했지만 결과가 나오지 않았다.
Get-ChildItem "C:\gradle" -Recurse -Filter "gradle.bat"
이는 압축이 정상적으로 풀리지 않았거나 zip 파일이 제대로 다운로드되지 않았을 가능성을 의미했다.
그래서 기존 Gradle 폴더를 삭제하고 다시 다운로드 및 압축 해제를 진행했다.
Remove-Item "C:\gradle" -Recurse -Force
Invoke-WebRequest -Uri "https://services.gradle.org/distributions/gradle-7.4.2-bin.zip" -OutFile "$env:TEMP\gradle-7.4.2-bin.zip"
Expand-Archive -Path "$env:TEMP\gradle-7.4.2-bin.zip" -DestinationPath "C:\gradle" -Force
이후 다시 gradle.bat을 찾았다.
Get-ChildItem "C:\gradle" -Recurse -Filter "gradle.bat"
정상이라면 다음 경로가 확인된다.
C:\gradle\gradle-7.4.2\bin\gradle.bat
22. grep 명령어 오류
중간에 다음 명령어를 실행했다.
Get-ChildItem "C:\gradle" -Recurse -Depth 2 | grep gradle
그러자 다음 오류가 발생했다.
grep : The term 'grep' is not recognized
이는 grep이 Linux 명령어이기 때문이다.
Windows PowerShell에서는 기본적으로 grep을 사용할 수 없다.
PowerShell에서는 다음 명령어를 사용할 수 있다.
findstr
Select-String
Where-Object
하지만 이번 상황에서는 grep이 필요하지 않았고, gradle.bat을 직접 찾는 다음 명령어가 가장 정확했다.
Get-ChildItem "C:\gradle" -Recurse -Filter "gradle.bat"
23. Gradle 실행 확인
Gradle 설치가 완료된 후 버전을 확인했다.
gradle -v
처음에는 gradle 명령어가 인식되지 않았다.
gradle : The term 'gradle' is not recognized
이는 Gradle 설치가 안 된 것이 아니라, Windows PATH 환경 변수에 Gradle의 bin 경로가 등록되지 않았기 때문이다.
현재 PowerShell 창에서만 임시로 PATH를 추가했다.
$env:Path += ";C:\gradle\gradle-7.4.2\bin"
그 후 다시 확인했다.
gradle -v
정상적으로 다음 결과가 출력되었다.
Gradle 7.4.2
Build time: 2022-03-31 15:25:29 UTC
Revision: 540473b8118064efcc264694cbcaa4b677f61041
Kotlin: 1.5.31
Groovy: 3.0.9
Ant: Apache Ant(TM) version 1.10.11 compiled on July 10 2021
JVM: 21.0.11 (Eclipse Adoptium 21.0.11+10-LTS)
OS: Windows 11 10.0 amd64
이 결과로 Gradle 7.4.2가 정상 설치되었음을 확인했다.
24. Jenkins에 Gradle 등록
이후 Jenkins에서 Gradle을 사용하기 위해 Manage Jenkins의 Tool 설정에 들어갔다.
흐름은 다음과 같다.
Manage Jenkins
→ Tools 또는 Global Tool Configuration
→ Gradle
→ Add Gradle
여기서 입력해야 하는 값은 다음과 같다.
Name: gradle-7.4.2
GRADLE_HOME: C:\gradle\gradle-7.4.2
Install automatically: 체크하지 않음
주의할 점은 GRADLE_HOME에 bin 폴더까지 넣으면 안 된다는 것이다.
잘못된 예시는 다음과 같다.
C:\gradle\gradle-7.4.2\bin
올바른 값은 다음과 같다.
C:\gradle\gradle-7.4.2
Jenkins는 내부적으로 GRADLE_HOME\bin\gradle.bat을 찾아 실행한다.
따라서 GRADLE_HOME에는 Gradle 설치 루트 경로만 입력해야 한다.
25. Jenkins Build Step 추가
Gradle 등록 후 Freestyle Project 설정에서 Build Step을 추가했다.
흐름은 다음과 같다.
Configure
→ Build Steps
→ Add build step
→ Invoke Gradle script
Gradle Version에는 Jenkins Tools에서 등록한 값을 선택한다.
gradle-7.4.2
Tasks에는 프로젝트에서 실행할 Gradle 명령을 입력한다.
예를 들어 일반적인 Java/Gradle 프로젝트라면 다음과 같이 입력할 수 있다.
clean build
이 설정의 의미는 다음과 같다.
Jenkins가 GitHub 저장소에서 소스를 가져옴
등록된 Gradle 7.4.2를 사용함
clean build 명령을 실행함
빌드 결과를 Jenkins Job 결과로 표시함
26. Jenkins 포트 확인
GitHub Webhook 설정 전 Jenkins가 정상적으로 실행 중인지 확인했다.
먼저 Jenkins 서비스 상태를 확인했다.
Get-Service Jenkins
결과는 다음과 같았다.
Status Name DisplayName
------ ---- -----------
Running Jenkins Jenkins
즉 Jenkins 서비스는 실행 중이었다.
그 다음 Jenkins 기본 포트인 8080이 열려 있는지 확인했다.
netstat -ano | findstr :8080
결과는 다음과 같았다.
TCP 0.0.0.0:8080 0.0.0.0:0 LISTENING 31972
TCP [::]:8080 [::]:0 LISTENING 31972
여기서 중요한 부분은 다음이다.
0.0.0.0:8080 LISTENING
이 의미는 Jenkins가 현재 PC의 모든 네트워크 인터페이스에서 8080 포트를 받고 있다는 뜻이다.
즉 다음 주소들은 로컬 또는 내부 네트워크에서 접근 가능할 수 있다.
http://localhost:8080
http://127.0.0.1:8080
http://내부IP:8080
27. 내부 IP 확인
다음으로 ipconfig를 사용해 PC의 IP 주소를 확인했다.
ipconfig
또는 IPv4 주소만 확인하기 위해 다음 명령어를 사용했다.
ipconfig | findstr IPv4
결과는 다음과 같았다.
IPv4 Address. . . . . . . . . . . : 172.23.128.1
IPv4 Address. . . . . . . . . . . : 172.16.0.46
여기서 172.23.128.1은 vEthernet (Default Switch) 쪽 주소였다.
즉 Hyper-V, WSL, Docker 등에서 사용될 수 있는 가상 네트워크 어댑터 주소다.
실제 Wi-Fi 어댑터 주소는 다음이었다.
172.16.0.46
같은 내부 네트워크에서 Jenkins에 접근하려면 다음 주소를 사용할 수 있다.
http://172.16.0.46:8080
Webhook 경로까지 붙이면 다음과 같다.
http://172.16.0.46:8080/github-webhook/
하지만 이 주소는 GitHub Webhook에는 사용할 수 없다.
28. GitHub Webhook에서 localhost가 안 되는 이유
GitHub Webhook의 Payload URL에 처음에는 다음과 같은 주소를 넣을 수 있다고 생각할 수 있다.
http://localhost:8080/github-webhook/
하지만 GitHub에서는 다음과 같은 오류가 발생한다.
is not supported because it isn't reachable over the public Internet (localhost)
이유는 localhost의 의미 때문이다.
localhost는 항상 “현재 자기 자신”을 의미한다.
내 PC에서 localhost는 내 PC다.
하지만 GitHub 서버에서 localhost는 GitHub 서버 자기 자신이다.
즉 GitHub가 다음 주소로 요청을 보내면,
http://localhost:8080/github-webhook/
GitHub는 내 PC로 요청을 보내는 것이 아니라, GitHub 서버 자기 자신 안의 8080 포트로 요청을 보내려고 하는 셈이다.
따라서 GitHub는 로컬 Jenkins에 접근할 수 없다.
29. 내부 IP도 GitHub Webhook에 사용할 수 없는 이유
그렇다면 Wi-Fi 내부 IP인 다음 주소를 사용할 수 있을 것처럼 보인다.
http://172.16.0.46:8080/github-webhook/
하지만 이 주소도 GitHub Webhook에는 사용할 수 없다.
이유는 172.16.0.46이 사설 IP 대역이기 때문이다.
사설 IP는 같은 회사, 집, 학교 내부 네트워크에서는 접근 가능할 수 있다.
하지만 GitHub 서버는 해당 내부 네트워크 안에 있지 않다.
즉 주소별 의미는 다음과 같다.
http://localhost:8080
→ 내 PC 안에서만 가능
http://172.16.0.46:8080
→ 같은 내부 네트워크에서는 가능할 수 있음
GitHub Webhook
→ 외부 인터넷에서 접근 가능한 공개 URL만 가능
따라서 GitHub Webhook Payload URL에는 다음 주소들을 넣으면 안 된다.
http://localhost:8080/github-webhook/
http://127.0.0.1:8080/github-webhook/
http://172.16.0.46:8080/github-webhook/
http://172.23.128.1:8080/github-webhook/
30. ngrok이 필요한 이유
로컬 Jenkins를 GitHub Webhook과 연결하려면 GitHub가 접근할 수 있는 공개 주소가 필요하다.
하지만 로컬 PC는 일반적으로 외부 인터넷에서 직접 접근할 수 없다.
직접 외부 공개 서버를 만들려면 보통 다음 작업이 필요하다.
공인 IP 확보
공유기 포트포워딩
방화벽 설정
도메인 구매
DNS 설정
SSL 인증서 설정
서버 배포
실습 환경에서는 이 과정이 너무 번거롭다.
그래서 ngrok을 사용한다.
ngrok은 로컬 PC에서 실행 중인 서버를 외부 인터넷에서 접근 가능한 임시 URL로 연결해주는 터널링 도구다.
이번 실습에서는 Jenkins가 다음 주소에서 실행 중이었다.
http://localhost:8080
ngrok을 실행하면 외부에서 접근 가능한 주소가 생긴다.
예를 들면 다음과 같다.
https://abc123.ngrok-free.app
그러면 GitHub는 이 주소로 Webhook을 보낼 수 있고, ngrok은 그 요청을 로컬 Jenkins로 전달한다.
GitHub
→ https://abc123.ngrok-free.app/github-webhook/
→ ngrok 터널
→ http://localhost:8080/github-webhook/
→ Jenkins
31. ngrok의 동작 원리
보통 외부 공개 주소를 만들려면 도메인 등록, DNS 설정, 서버 배포가 필요하다.
하지만 ngrok은 사용자가 직접 도메인을 만드는 방식이 아니다.
ngrok 회사는 이미 공개 인터넷에 연결된 서버와 도메인을 가지고 있다.
예를 들어 다음 도메인은 ngrok이 관리하는 도메인이다.
ngrok-free.app
ngrok http 8080을 실행하면 ngrok은 이 도메인의 임시 하위 주소를 하나 할당한다.
예시는 다음과 같다.
https://abc123.ngrok-free.app
즉, 사용자가 도메인을 새로 등록한 것이 아니라 ngrok이 이미 가지고 있는 도메인의 일부를 임시로 빌려 쓰는 것이다.
동작 구조는 다음과 같다.
1. 내 PC에서 ngrok 프로그램 실행
2. ngrok 프로그램이 ngrok의 공개 서버로 먼저 연결을 생성
3. ngrok 서버가 임시 공개 URL을 할당
4. GitHub가 해당 공개 URL로 Webhook 요청 전송
5. ngrok 서버가 요청을 받음
6. 이미 연결되어 있는 터널을 통해 내 PC로 요청 전달
7. 내 PC의 ngrok 프로그램이 localhost:8080으로 요청 전달
8. Jenkins가 Webhook 요청을 받음
중요한 점은 외부에서 내 PC로 직접 들어오는 구조가 아니라는 것이다.
내 PC에서 먼저 ngrok 서버로 나가는 연결을 만들어둔다.
내 PC → ngrok 서버
이 연결은 일반적인 웹 접속처럼 “나가는 연결”이기 때문에 공유기나 방화벽 환경에서도 비교적 잘 동작한다.
그 다음 GitHub가 ngrok 공개 URL로 요청을 보내면 ngrok 서버가 이미 열려 있는 터널 연결을 통해 그 요청을 내 PC로 전달한다.
GitHub → ngrok 서버 → 기존 터널 연결 → 내 PC → Jenkins
즉 ngrok은 다음 역할을 한다.
외부 인터넷에서 접근 가능한 공개 주소 제공
해당 주소로 들어온 요청을 로컬 PC로 중계
로컬 서버가 외부에 공개된 것처럼 동작하게 함
32. ngrok과 localhost의 관계
Jenkins는 여전히 로컬에서 실행 중이다.
http://localhost:8080
ngrok은 Jenkins를 다른 서버로 옮기는 것이 아니다.
Jenkins를 클라우드에 배포하는 것도 아니다.
ngrok은 단지 외부 요청을 로컬 Jenkins로 전달해주는 통로를 만든다.
즉 실제 실행 위치는 여전히 내 PC다.
Jenkins 실행 위치: 내 PC
Jenkins 실제 주소: http://localhost:8080
외부에서 접근하는 주소: https://ngrok주소
요청 전달 역할: ngrok
따라서 ngrok 창을 끄면 터널도 끊긴다.
터널이 끊기면 GitHub가 더 이상 로컬 Jenkins에 Webhook을 보낼 수 없다.
무료 ngrok 주소는 재실행 시 바뀔 수 있으므로, 주소가 바뀌면 GitHub Webhook의 Payload URL도 다시 수정해야 한다.
33. ngrok 실행
Jenkins가 8080 포트에서 실행 중이므로 다음 명령어로 ngrok을 실행한다.
ngrok http 8080
이 명령의 의미는 다음과 같다.
내 PC의 localhost:8080으로 들어가는 서비스를
외부에서 접근 가능한 ngrok URL로 열어줘
정상 실행되면 ngrok 화면에 다음과 같은 Forwarding 주소가 표시된다.
Forwarding https://abc123.ngrok-free.app -> http://localhost:8080
여기서 GitHub Webhook에 넣어야 하는 값은 왼쪽의 https://...ngrok-free.app 주소다.
단, Jenkins GitHub Webhook endpoint는 /github-webhook/이므로 최종 Payload URL은 다음과 같이 입력한다.
https://abc123.ngrok-free.app/github-webhook/
34. GitHub Webhook 설정
GitHub Repository에서 Webhook을 설정했다.
흐름은 다음과 같다.
GitHub Repository
→ Settings
→ Webhooks
→ Add webhook
Payload URL에는 ngrok 주소를 사용한다.
https://ngrok주소/github-webhook/
Content type은 다음으로 설정한다.
application/json
Secret은 책이나 실습에서 별도 지정이 없으면 비워둘 수 있다.
이벤트는 일반적인 push 트리거 실습이라면 다음을 선택한다.
Just the push event
최종 구조는 다음과 같다.
Payload URL: https://ngrok주소/github-webhook/
Content type: application/json
Secret: 비워둠
SSL verification: Enable
Event: Just the push event
35. Webhook 요청 흐름
Webhook 설정 후 GitHub 저장소에 push가 발생하면 다음 흐름으로 동작한다.
1. 개발자가 GitHub Repository에 push
2. GitHub가 Webhook Payload URL로 HTTP 요청 전송
3. Payload URL은 ngrok 공개 URL
4. ngrok 서버가 요청 수신
5. ngrok 서버가 로컬 PC의 ngrok 프로그램으로 요청 전달
6. 로컬 ngrok 프로그램이 localhost:8080/github-webhook/으로 요청 전달
7. Jenkins가 GitHub Webhook 이벤트 수신
8. Jenkins가 연결된 Freestyle Project를 찾음
9. GitHub hook trigger for GITScm polling 옵션에 의해 Job 실행
10. Jenkins가 GitHub Repository에서 코드 checkout
11. Jenkins가 Gradle Build Step 실행
12. 빌드 결과가 Jenkins에 표시됨
즉 이번 실습의 최종 자동화 흐름은 다음과 같다.
GitHub push
→ GitHub Webhook
→ ngrok
→ Jenkins
→ Gradle build
36. 각 설정이 필요한 이유
이번 실습에서 설정한 항목들은 각각 역할이 다르다.
Java
Jenkins 자체를 실행하기 위한 런타임이다.
Java 없으면 Jenkins 실행 불가
Jenkins
CI 서버 역할을 한다.
GitHub 이벤트를 받아 빌드 작업을 실행
GitHub Token
Jenkins가 GitHub에 인증하기 위한 값이다.
GitHub API 접근
Repository 접근
Webhook 또는 저장소 관련 작업 인증
Jenkins Credentials
GitHub Token을 Jenkins 내부에 안전하게 저장하는 영역이다.
Job이나 GitHub Server 설정에서 재사용 가능
Freestyle Project
Jenkins에서 실제 빌드 작업을 정의하는 Job이다.
어떤 저장소를 가져올지
어떤 트리거로 실행할지
어떤 명령으로 빌드할지 정의
GitHub Hook Trigger
GitHub Webhook 요청을 받았을 때 Job을 자동 실행하기 위한 설정이다.
push 발생 시 자동 빌드
Gradle
프로젝트를 빌드하기 위한 빌드 도구다.
clean build 등의 작업 수행
ngrok
로컬 Jenkins를 외부 GitHub에서 접근 가능하게 해주는 터널이다.
GitHub → 로컬 Jenkins 연결
37. 최종 명령어 정리
Java 17 설치
winget install -e --id EclipseAdoptium.Temurin.17.JDK
Java 21 설치
winget install -e --id EclipseAdoptium.Temurin.21.JDK
Java 버전 확인
java -version
Jenkins 초기 관리자 비밀번호 확인
Get-Content "C:\ProgramData\Jenkins\.jenkins\secrets\initialAdminPassword"
Jenkins 서비스 상태 확인
Get-Service Jenkins
Jenkins 재시작
Restart-Service Jenkins
Jenkins 포트 확인
netstat -ano | findstr :8080
내 PC IP 확인
ipconfig
또는:
ipconfig | findstr IPv4
Gradle 다운로드
Invoke-WebRequest -Uri "https://services.gradle.org/distributions/gradle-7.4.2-bin.zip" -OutFile "$env:TEMP\gradle-7.4.2-bin.zip"
Gradle 압축 해제
New-Item -ItemType Directory -Force -Path "C:\gradle"
Expand-Archive -Path "$env:TEMP\gradle-7.4.2-bin.zip" -DestinationPath "C:\gradle" -Force
Gradle 실행 파일 확인
Get-ChildItem "C:\gradle" -Recurse -Filter "gradle.bat"
현재 PowerShell 세션에 Gradle PATH 추가
$env:Path += ";C:\gradle\gradle-7.4.2\bin"
Gradle 버전 확인
gradle -v
ngrok 실행
ngrok http 8080
38. 최종 설정값 정리
Jenkins 접속 주소
http://localhost:8080
Jenkins 관리 페이지
http://localhost:8080/manage
Gradle Jenkins Tool 설정
Name: gradle-7.4.2
GRADLE_HOME: C:\gradle\gradle-7.4.2
Install automatically: 체크하지 않음
GitHub Webhook Payload URL
https://ngrok주소/github-webhook/
GitHub Webhook Content type
application/json
GitHub Webhook Event
Just the push event
39. 이번 실습의 핵심 정리
이번 실습에서 겪은 문제들은 대부분 Jenkins 자체 오류라기보다는 Windows 환경과 Linux 기준 책 설명의 차이에서 발생했다.
핵심 차이는 다음과 같다.
Linux의 apt → Windows의 winget 또는 Installer
Linux의 /tmp → Windows의 $env:TEMP
Linux의 /opt/gradle → Windows의 C:\gradle
Linux의 unzip → Windows의 Expand-Archive
Linux의 source → PowerShell PATH 수정 또는 새 터미널 실행
Linux의 grep → Windows의 findstr 또는 PowerShell 검색 명령
localhost Webhook → GitHub에서는 접근 불가
내부 IP Webhook → GitHub에서는 접근 불가
로컬 Jenkins Webhook → ngrok 같은 공개 터널 필요
최종적으로 구성된 구조는 다음과 같다.
GitHub Repository
→ Webhook
→ ngrok 공개 URL
→ 로컬 Jenkins
→ Freestyle Project
→ GitHub Repository Checkout
→ Gradle Build
즉, 이번 실습은 단순히 Jenkins를 설치하는 것이 아니라, Windows 로컬 환경에서 Jenkins를 실행하고 GitHub Webhook과 Gradle 빌드까지 연결하는 전체 CI 흐름을 구성한 실습이었다.
40. 마무리
책의 실습 환경이 Linux라고 해서 Windows에서 실습할 수 없는 것은 아니다.
다만 명령어, 경로, 서비스 실행 방식, 네트워크 접근 방식이 달라진다.
이번 실습에서 특히 중요했던 포인트는 다음 세 가지였다.
1. Linux 명령어를 Windows 명령어로 대응시키기
2. Jenkins, Gradle, GitHub 인증 정보를 각각 올바른 위치에 설정하기
3. GitHub Webhook이 로컬 Jenkins에 접근할 수 있도록 ngrok 터널을 이해하고 사용하기
결론적으로 Windows 환경에서도 Jenkins와 GitHub, Gradle, ngrok을 조합하면 로컬 PC에서 CI 흐름을 충분히 실습할 수 있다.
41. NEXT
다음에는 ArgoCD를 셋팅해서 CD 구현을 진행하도록 한다.