ENV
- 도커로 깃랩, 젠킨스 컨테이너 active
- web에 깃랩, 젠킨스 접속 가능
깃랩, 젠킨스 연동 순서
- 깃랩 프로젝트 생성
- 생성된 깃랩 프로젝트와 application 소스코드 연결(port 번호 추가된 url)
- 깃랩 personal access token 발급
- 젠킨스에 깃랩 플러그인 설치
- 젠킨스 Credential 발급(personal access token 사용)
- Username with password
Username: 깃랩 아이디
password: personal access token
ID는 별도로 지정하지 않는다.
- Username with password
- 젠킨스 파이프라인 생성(add item)
- Build Triggers: Build when a change is pushed to GitLab. GitLab webhook URL: http://123.123.123.123:8080/project/test
- Secret token 생성
- 파이프라인 스크립트는 임시로 Hello World 로 해놓고 넘어간다.
- 깃랩 Webhook 설정
- 젠킨스에서 파이프라인 생성시 설정된 URL, Secret token 사용
- webhook 이 잘 설정되었다면, 파이프라인 스크립트 작성
깃랩, 젠킨스 연동할 때, 생긴 이슈
- webhook 설정 시, invalid URL given 에러 발생
admin > settings > network > Outbound requests
Allow requests to the local network from webhooks and integrations 체크 설정 필요
젠킨스 컨테이너 내 Gradle, SSH 설치
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
docker exec -it jenkins /bin/bash
# 패키지 목록 업데이트 및 SSH 설치
apt-get update && apt-get install -y openssh-client
# Gradle 설치(Java version 에 호환되는 버전으로 설치한다.)
RUN apt-get install -y wget unzip
wget https://services.gradle.org/distributions/gradle-7.3.3-bin.zip
unzip gradle-7.3.3-bin.zip -d /opt
ln -s /opt/gradle-7.3.3/bin/gradle /usr/bin/gradle
# 설치 완료 확인
docker exec -it jenkins /bin/bash
ssh -V
gradle -v
# ssh 위치 확인
which ssh
/usr/bin/ssh
파이프라인 스크립트 작성 시, 생긴 이슈들
credential 관련 오류
✅ Solution
credential 발급 시, GitLab API Token 으로 발급을 받았었는데, 해당 credential 인식이 불가능하여, Username with password 형식의 credential을 발급받아 적용
ERROR: Couldn’t find any revision to build. Verify the repository and branch configuration for this job. ERROR: Maximum checkout retry attempts reached, aborting
✅ Solution
main 브랜치 생성
FAILURE: Build failed with an exception.Where: Settings file ‘/var/jenkins_home/workspace/test1/settings.gradle’ What went wrong: Could not compile settings file ‘/var/jenkins_home/workspace/test1/settings.gradle’. startup failed: General error during semantic analysis: Unsupported class file major version 61 java.lang.IllegalArgumentException: Unsupported class file major version 61
Gradle version, Java version 이 호환이 안될 때 생기는 에러
✅ Solution
1
2
3
4
5
docker exec -it jenkins /bin/bash
apt-get update
apt-get install -y openjdk-17-jdk
update-alternatives --config java
1
2
3
// pipeline
JAVA_HOME = '/usr/lib/jvm/java-17-openjdk-amd64' // Java 17 경로 설정
PATH = "${JAVA_HOME}/bin:${env.PATH}"
JDK 17 설치 후, 해당 버전에 호환되는 Gradle 젠킨스 컨테이너에 설치
호환이 잘 되는 버전으로 맞춰도 해당 이슈 해결을 못해서 로그 출력 스크립트 추가
1
2
3
4
5
6
stage('Build') {
steps {
sh 'chmod +x ./gradlew'
sh './gradlew clean build --stacktrace' // 상세 로그 출력
}
}
로그로 원인 파악한 후 권한 추가
1
2
chown -R jenkins:jenkins /var/jenkins_home/workspace/test1
chmod -R 755 /var/jenkins_home/workspace/test1
FAILURE: Build failed with an exception. What went wrong: Execution failed for task ‘:test’. There were failing tests. See the report at: file:///var/jenkins_home/workspace/test1/build/reports/tests/test/index.html. Try: Run with –scan to get full insights.
✅ Solution
1
2
3
4
5
6
7
stage('Build') {
steps {
// -x test 추가: 테스트를 실행하지 않는다.
sh 'chmod +x ./gradlew'
sh './gradlew clean build --stacktrace -x test'
}
}
Warning: Identity file /home/ojg/.ssh/id_rsa not accessible: No such file or directory. ssh: connect to host 123.123.123.123 port 22: Connection timed out. scp: Connection closed
✅ Solution
1
2
3
4
5
6
sudo ufw status
sudo ufw allow 22
sudo ufw reload
docker exec -it jenkins /bin/bash
ssh -i /home/ojg/.ssh/id_rsa ojg@123.123.123.123
+ scp -i /home/ojg/.ssh/id_rsa build/libs/test.war ojg@123.123.123.123:/home/ojg/myFirstProject Warning: Identity file /home/ojg/.ssh/id_rsa not accessible: No such file or directory. Permission denied, please try again. ojg@123.123.123.123: Permission denied (publickey,password). scp: Connection closed
✅ Solution
1
2
3
4
5
# 젠킨스 내 ssh 키 파일 생성 필요
cat /var/jenkins_home/.ssh/id_rsa.pub | ssh ojg@123.123.123.123 'mkdir -p ~/.ssh && cat >> ~/.ssh/authorized_keys'
# id_rsa 파일 확인
/var/jenkins_home/.ssh/id_rsa
+ scp -i /var/jenkins_home/.ssh/id_rsa build/libs/test.war ojg@123.123.123.123:/home/ojg/myFirstProject. scp: stat local “build/libs/test.war”: No such file or directory
✅ Solution
1
2
3
4
5
# application 프로젝트 내 build.gradle 파일에 코드 추가
# 임의로 정한 war명인 test를 파이프라인 스크립트에도 명시해주어야 한다.
bootWar {
archiveFileName = 'test.war'
}
EOF: command not found
✅ Solution
배포 스크립트 내 sh “”” -> sh ‘’’ 로 수정
« EOF 로 열고, «< EOF로 닫음
배포 성공했으나, 웹 접속 불가
✅ Solution
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# application 포트 추가
sudo ufw status
sudo ufw allow 8888
sudo ufw reload
# 프로젝트 로그 확인(nohup: failed to run command 'java': No such file or directory 에러 발생)
cat /home/ojg/myFirstProject/app.log
# 포트 추가 하였으나, 동일 에러 발생
# 우분투에 자바 설치 필요(젠킨스 컨테이너에만 자바 설치한 상태)
ssh -i /var/jenkins_home/.ssh/id_rsa ojg@123.123.123.123
java -version
sudo apt-get update
sudo apt-get install -y openjdk-17-jdk
echo 'export JAVA_HOME=/usr/lib/jvm/java-17-openjdk-amd64' >> ~/.bashrc
echo 'export PATH=$JAVA_HOME/bin:$PATH' >> ~/.bashrc
source ~/.bashrc
Permission denied issue(maven app deploy)
⚠️ Error Log
1
2
3
4
+ scp -i /var/lib/jenkins/.ssh/id_rsa /var/jenkins_home/workspace/greoupware-dev/target/gw-dev-1.0.0.war core@123.123.123.123:/var/lib/tomcat9/webapps/
Permission denied, please try again.
Permission denied, please try again.
core@123.123.123.123: Permission denied (publickey,password).
✅ Solution
서버에서 암호 인증이 허용
/etc/ssh/sshd_config 파일 내 PasswordAuthentication yes 추가ssh에서 스크립트 명령어 수동 실행
scp -i ${SSH_KEY_PATH} /var/jenkins_home/workspace/greoupware-dev/target/${WAR_FILE_NAME} ${DEPLOY_USER}@${DEPLOY_SERVER_IP}:${TOMCAT_HOME}/webapps/
최종 파이프라인 스크립트
스프링부트 Gradle 배포 스크립트
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
pipeline {
agent any
environment {
GIT_REPO_URL = 'http://123.123.123.123:9090/ojg/firstproject.git'
GIT_CREDENTIALS_ID = 'vdsfds-fdsfds-fdsfd-fdsf-fdsfsfss'
DEPLOY_SERVER_IP = '456.456.456.456'
DEPLOY_USER = 'ojg'
SSH_KEY_PATH = '/var/jenkins_home/.ssh/id_rsa'
PROJECT_PATH = '/home/ojg/myFirstProject'
JAVA_HOME = '/usr/lib/jvm/java-17-openjdk-amd64'
PATH = "${JAVA_HOME}/bin:${env.PATH}"
WAR_FILE_NAME = 'test.war'
}
/*
GIT_REPO_URL : GitLab 저장소의 URL
GIT_CREDENTIALS_ID : Jenkins에 저장된 GitLab 자격 증명의 ID
DEPLOY_SERVER_IP : 배포할 원격 서버의 IP 주소
DEPLOY_USER : 원격 서버에 접속할 사용자 이름
SSH_KEY_PATH : Jenkins 컨테이너에 설치된 SSH 키 파일의 경로
PROJECT_PATH : 원격 서버에서 프로젝트가 배포될 경로
JAVA_HOME : 원격 서버에 설치된 Java의 경로
PATH : 원격 서버의 Java 실행 파일 경로를 시스템 PATH에 추가
WAR_FILE_NAME : 빌드된 WAR 파일의 이름
*/
stages {
stage('Checkout') {
steps {
git branch: 'main',
url: "${GIT_REPO_URL}",
credentialsId: "${GIT_CREDENTIALS_ID}"
}
}
stage('Build') {
steps {
// Gradle Wrapper 스크립트에 실행 권한 부여
sh 'chmod +x ./gradlew'
// 테스트를 제외하며, gradle 사용하여 프로젝트 빌드
sh './gradlew clean build --stacktrace -x test'
// 빌드 결과물 확인
sh 'ls -l build/libs'
}
}
stage('Deploy') {
steps {
script {
// SSH를 통해 배포 서버에 접속하여 소스를 배포
sh '''
scp -i ${SSH_KEY_PATH} build/libs/${WAR_FILE_NAME} ${DEPLOY_USER}@${DEPLOY_SERVER_IP}:${PROJECT_PATH}
ssh -i ${SSH_KEY_PATH} ${DEPLOY_USER}@${DEPLOY_SERVER_IP} << EOF
cd ${PROJECT_PATH}
# 기존 애플리케이션 종료 (필요한 경우)
pkill -f ${WAR_FILE_NAME} || true
# 새로운 애플리케이션 실행
nohup java -jar ${WAR_FILE_NAME} > app.log 2>&1 &
<<< EOF
'''
/*
scp -i ${SSH_KEY_PATH} build/libs/${WAR_FILE_NAME} ${DEPLOY_USER}@${DEPLOY_SERVER_IP}:${PROJECT_PATH}
빌드된 war 파일을 원격 서버에 복사
ssh -i ${SSH_KEY_PATH} ${DEPLOY_USER}@${DEPLOY_SERVER_IP}
ssh를 통해 원격 서버에 접속하여 여러 명령어를 실행
cd ${PROJECT_PATH}
원격서버에서 프로젝트 디렉토리로 이동
pkill -f ${WAR_FILE_NAME} || true
기존에 실행 중인 애플리케이션을 종료. 실패해도 무시
nohup java -jar ${WAR_FILE_NAME} > app.log 2>&1 &
새로운 애플리케이션을 백그라운드에서 실행하고, 로그를 app.log 파일에 기록
*/
}
}
}
}
post {
success {
echo 'Deployment successful!'
}
failure {
echo 'Deployment failed!'
}
}
}
스프링 Maven 배포 스크립트
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
pipeline {
agent any
environment {
GIT_REPO_URL = 'http://123.123.123.123:8081/c/abc.git'
GIT_CREDENTIALS_ID = 'fdsfadsaf-dfsfa-fdsfd-fdsfs-fdsfdsfds'
DEPLOY_SERVER_IP = '456.456.456.456'
DEPLOY_USER = 'core'
SSH_KEY_PATH = '/var/lib/jenkins/.ssh/id_rsa'
PROJECT_PATH = '/home/c/groupware_dev'
WAR_FILE_NAME = 'gw-dev-1.0.0.war'
TOMCAT_HOME = '/var/lib/tomcat9'
}
stages {
stage('Checkout') {
steps {
git branch: 'main',
url: "${GIT_REPO_URL}",
credentialsId: "${GIT_CREDENTIALS_ID}"
}
}
stage('Build') {
steps {
sh 'mvn clean package -DskipTests'
sh 'ls -l target'
}
}
stage('Deploy') {
steps {
script {
sh '''
scp -i ${SSH_KEY_PATH} /var/jenkins_home/workspace/greoupware-dev/target/${WAR_FILE_NAME} ${DEPLOY_USER}@${DEPLOY_SERVER_IP}:${TOMCAT_HOME}/webapps/
ssh -i ${SSH_KEY_PATH} ${DEPLOY_USER}@${DEPLOY_SERVER_IP} << EOF
# WAR 파일을 ROOT.war로 변경
echo "Deploying new WAR file: ${WAR_FILE_NAME} as ROOT.war"
mv ${TOMCAT_HOME}/webapps/${WAR_FILE_NAME} ${TOMCAT_HOME}/webapps/ROOT.war
if [ $? -ne 0 ]; then
echo "Error: Failed to rename WAR file."
exit 1
fi
/* permission denied issue */
sh '/var/lib/tomcat9/webapps/deploy.sh'
<<< EOF
'''
}
}
}
}
post {
success {
echo 'Deployment successful!'
}
failure {
echo 'Deployment failed!'
}
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# deploy.sh
TOMCAT_HOME="/var/lib/tomcat9"
# 파일 소유권 변경
echo "[core 계정 비밀번호]" | sudo -S chown core:core "${TOMCAT_HOME}/webapps/ROOT.war"
if [ $? -ne 0 ]; then
echo "Error: Failed to change ownership of ROOT.war."
exit 1
fi
# Tomcat 서비스 재시작
echo "[core 계정 비밀번호]" | sudo -S systemctl restart tomcat9.service
if [ $? -ne 0 ]; then
echo "Error: Failed to restart Tomcat service."
exit 1
fi
echo "Deployment completed successfully!"