- Today
- Total
개발하는 고라니
[Jenkins] GCP + Docker + Jenkins를 이용한 CI / CD 본문
Index
- Chapter 1
- Chapter 2
- 젠킨스 서버에 도커 및 젠킨스 설치, 배포 서버에 도커 설치
- 젠킨스 설치 후 이것저것 설정
- 젠킨스 Job 생성
- Chapter 3
- 배포 서버에 도커파일 생성
- 배포 서버에 init.sh 작성
- 깃헙에 push 해보기
- 자동 배포 됬는지 확인
준비물
- Github 리퍼지토리
- Spring Boot 프로젝트 (gradle)
- GCP 같은 클라우드 컴퓨팅 인스턴스 2개
- A : 젠킨스가 있는 서버
- B : 배포할 서버
시나리오
- 코드를 작성한다.
- 깃헙에 Push한다.
- Webhook이 걸려 젠킨스에게 Job을 실행하라고 한다.
- 젠킨스가 Build해준 결과를 배포 서버에 넘긴다.
- 배포 서버에서 컨테이너를 실행해 자동 배포한다.
▷ Chapter 1
- 스프링 부트 프로젝트 생성과 깃헙 리퍼지토리 과정은 생략
GCP VM Instance
- 배포할 서버와 젠킨스를 돌릴 서버를 준비한다. (부팅 디스크는Debian GNU/Linux 10 (buster) 사용)
- 방화벽 8080, 7000, 50000을 열어준다. (중요)
- 8080은 tomcat, 7000은 젠킨스, 50000도 젠킨스
Publish Over SSH
지금 당장 쓸 것은 아니지만, 이따 해야하는 작업이므로 지금 미리 해두자. 젠킨스 서버에서 배포 서버로 접속해서 파일을 저장하고, 명령어를 입력해야하기 때문에 젠킨스가 배포 서버에 접속할 수 있도록 설정해주는 과정이다.
# web-jenkins
//공개키/비밀키 생성
$ ssh-keygen -t rsa -f ~/.ssh/id_rsa
$ cd ~/.ssh
#비밀키 확인
$ cat id_rsa
비밀키를 확인하면 이렇게 'OPENSSH ~~' 로 되어있는데, 이것을 RSA PRIVATE ~~로 바꿔줘야한다.
$ ssh-keygen -m pem -f ./id_rsa
이처럼 RSA PRIVATE ~ 로 바뀐다.
이제 젠킨스 서버에 만든 공개키를 GCP 인스턴스 메타데이터에 넣어줘야한다.
얘를 잘 기억했다가
저기에 붙여넣고 저장하자. (GCP는 메타데이터로 따로 관리해주기 때문에 이렇게 하지만, AWS 같은 경우 배포 서버의 ~/.ssh/authorized_keys 에 공개키를 복붙한다.)
이제 잘 되었는지 확인해보자. 젠킨스 서버에서 배포 서버로 접속하는 것을 시도할텐데 잘 완료되었다면 문제없이 접속이 될 것이다.
1) 젠킨스 서버 SSH 접속
2) $ ssh -i web-deploy [web-deploy의 내부 IP]
접속 완료!
▷ Chapter 2
- 젠킨스 서버에 도커 및 젠킨스 설치, 배포 서버에 도커 설치
- 젠킨스 설치 후 이것저것 설정
- 젠킨스 Job 생성
Docker 설치
여기를 보고 명령어 몇 개만 치면 되므로 위 링크로 대체한다.
Docker + Jenkins
젠킨스 서버에서 도커로 젠킨스를 구동해보자.
$ sudo docker run --name jks -p 7000:7000 -p 50000:50000 -d jenkins/jenkins:lts --httpPort=7000
# 호스트의 7000 <-> 컨테이너의 7000
# 호스트의 50000 <-> 컨테이너의 50000
# 컨테이너 이름 jks
# 젠킨스 사용할 포트 7000번
http://[IP 주소]:7000/ 로 접속
$ sudo docker logs -f jks
# 젠킨스 컨테이너 로그확인 -> 초기 비밀번호 입력
추천해주는대로 설치합시다.
계정 까지 만들어주고,,, 이제 젠킨스 시작.
Jenkins Config
- Plugin
- Global Config
- System Config
# Plugin
- Publish Over SSH
# Global Config
- JDK
- Git
# System Config
- Github Repository
- Github
- Publish Over SSH
Key : 아까 만든 비밀키 (젠킨스 서버에서 $ cat ~/.ssh/id_rsa)
Name : 아무거나 해도됨
Hostname : 배포 서버의 내부 IP 주소
Username : 유저 명
Remote Directory : 어디서 시작할건지
Create Jenkins's Job
CI / CD를 위한 잡을 만들어보자. 젠킨스 파일(선언적 파이프라인)로 만들어볼 것이다.
- 깃헙에 PUSH 되면 자동으로 젠킨스가 일을 해야하므로 Hook만 걸어놓자.
pipeline {
agent any
stages {
stage('Prepare') {
steps {
echo '=== Prepare ==='
}
}
stage('Build') {
steps {
echo '=== Build ==='
}
}
stage('Deploy') {
steps {
echo '=== Deploy ==='
}
}
}
}
일단 뼈대만 만들어놓자.
Git Clone
이렇게 Snipet을 만들어준다. Credential은 Public Repo면 none으로 해도 된다. 맨 아래 생긴 문자열을 'Prepare'에 복붙하자.
Build
빌드하기 위해 gradlew를 쓸 것이고 쉘 명령어 2줄만 추가해주자.
stage('Build') {
steps {
echo '=== Build ==='
sh '''
chmod +x gradlew
./gradlew clean build
'''
}
}
그럼 이제 전체적인 파이프라인은 다음과 같다.
pipeline {
agent any
stages {
stage('Prepare') {
steps {
echo '=== Prepare ==='
git 'https://github.com/rhacnddl/jenkinsTest.git'
}
}
stage('Build') {
steps {
echo '=== Build ==='
sh '''
chmod +x gradlew
./gradlew clean build
'''
}
}
stage('Deploy') {
steps {
echo '=== Deploy ==='
}
}
}
}
Deploy
여기는 일단 작성만 해두자. 다음과 같이 작성한다.
1. 소스파일의 위치, 빌드한 결과는 build/libs/---.jar에 위치한다.
2. 소스파일에서 원본 파일의 디렉토리를 어디까지 포함할 것인지에 대한 설정 (build/libs는 제거된다.)
3. remote directory 기준으로 배포될 경로를 적는다. (결과 : /home/swanjj11/deploy)
4. 전송을 마치고 실행할 Shell 명령어를 적는다. 이따 'init.sh'이라는 파일을 실행할 것이다.
이제 생성된 Snipet을 'Deploy'에 복붙하자.
pipeline {
agent any
stages {
stage('Prepare') {
steps {
echo '=== Prepare ==='
git 'https://github.com/rhacnddl/jenkinsTest.git'
}
}
stage('Build') {
steps {
echo '=== Build ==='
sh '''
chmod +x gradlew
./gradlew clean build
'''
}
}
stage('Deploy') {
steps {
echo '=== Deploy ==='
sshPublisher(publishers: [
sshPublisherDesc(configName: 'web-deploy', transfers: [
sshTransfer(cleanRemote: false, excludes: '', execCommand: 'sh init.sh', execTimeout: 120000, flatten: false, makeEmptyDirs: false, noDefaultExcludes: false, patternSeparator: '[, ]+', remoteDirectory: 'deploy/', remoteDirectorySDF: false, removePrefix: 'build/libs', sourceFiles: 'build/libs/*.jar')
], usePromotionTimestamp: false, useWorkspaceInPromotion: false, verbose: true)
])
} #마지막에 verbose를 true로 주면 트러블 슈팅하기 용이하다
}
}
}
이제 젠킨스에서 할 일은 끝났다.
▷ Chapter 3
- 배포 서버에 도커파일 생성
- 배포 서버에 init.sh 작성
- 깃헙에 push 해보기
- 자동 배포 됬는지 확인
배포 서버에 Dockerfile 생성
지금 도커파일이 무엇인지는 다루지 않겠다. 간단히 말하면 내가 만드는 이미지라고 생각하면 된다. 거기에 부가적으로 이런 저런 옵션, 명령어를 추가할 수 있어서 매우 유용하다.
# 배포 서버 (web-deploy)
$ vi Dockerfile
FROM openjdk:11
WORKDIR /var/deploy
EXPOSE 8080
CMD ["nohup", "java", "-jar", "jenkinsTest-0.0.1-SNAPSHOT.jar", ">", "app.log", "&"]
# openjdk11 이미지를 기반으로
# /var/deploy 디렉토리에서 작업할 것이고
# 8080포트를 노출한다.
# .jar 파일을 백그라운드에서 실행할 것이다.
Dockerfile을 작성했으면, 이제 이미지로 만들어주자.
$ sudo docker build -t java .
위 명령어를 입력하면 java라는 이름의 이미지가 생긴다.
배포 서버에 init.sh 작성
init.sh는 젠킨스가 배포 서버에 접속해서 실행할 쉘 명령어의 집합이라고 생각하면 된다. 도커 컨테이너를 제거하고, 다시 생성하는 것을 적어둘 것이다.
$ vi init.sh
sudo docker rm -f java-container
sudo docker run --name java-container \
-p 8080:8080 \
-d \
-v /home/swanjj11/deploy:/var/deploy \
java
# -v 호스트:컨테이너
# 호스트의 /home/swanjj11/deploy 디렉토리와
# 컨테이너의 /var/deploy 파일 시스템을 공유한다.
이제 모든 준비를 마쳤다. 코드를 작성해서 깃헙에 푸시 날려보자.
Github에 PUSH
@RestController
@RequestMapping("/api/tests")
public class TestApiController {
@GetMapping("/hello")
public HelloResponse getHello(){
return new HelloResponse(2L, "Hello World V21");
}
@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
static class HelloResponse{
private Long id;
private String content;
}
}
http://IP주소:8080/api/tests/hello 로 들어가면 {"id":2, "content":"Hello World V21"} 가 나와야한다.
자동 배포됬는지 확인
음.. push를 했는데 안온다.. 이는 왜그런건지 찾는 중이다. (이유는 없엇다... 활성/비활성 여러번 하니까 다시 된다...? 무슨 경우지)
빌드도 잘 마쳤고, 배포된 URL로 가서 확인해보자.
너무나도 잘나온다. 중간에 왠지모를 버그? 같은 것이 있었지만 큰 문제는 아니었고 저절로 해결되었다. 이로써 GCP + Docker + Jenkins를 이용해 간단한 CI / CD 파이프라인을 구축해보았다.
이 작업을 하면서 굉장히 뿌듯했다. 더 이상 깃허브에 올리고 SSH에서 pull-build-deploy 하고 빌드가 에러나진 않는지 별 귀찮은 작업을 자동으로 해주니 나는 개발에 집중할 수 있게 되었다.
원래는 빌드하고 도커파일로 만들어서 도커 허브에 올린 다음, 배포 서버에서 이미지로 받고 그걸 RUN할 생각이었는데, 생각보다 너무 어려워서... 그건 더 숙련되고 나면 도전해보려 한다. 도커와 젠킨스의 길은 너무 멀다..
(상처를 남긴 Commit)
비공식 commit 포함 약 40번의 커밋을 시도한 끝에 포스팅을 마무리 할 수 있었다 :)
# References
https://stackoverflow.com/questions/54994641/openssh-private-key-to-rsa-private-key
https://velog.io/@sihyung92
https://velog.io/@seunghyeon
https://velog.io/@kimsehwan96
https://psawesome.tistory.com/55
https://velog.io/@ckstn0777
https://jungeeyou.github.io/docker-3-post/
https://not-to-be-reset.tistory.com/428?category=916741
'Open Source > Jenkins' 카테고리의 다른 글
[Jenkins] Github 연동, push 후 빌드 자동화 (2) | 2021.09.29 |
---|---|
[Jenkins] Pipeline (2) | 2021.09.28 |
[Jenkins] 젠킨스로 E-mail 받기 (0) | 2021.09.27 |
[Jenkins] 젠킨스로 Spring Boot 빌드 (1) | 2021.09.27 |