반응형
11-07 19:20
Today
Total
«   2024/11   »
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
관리 메뉴

개발하는 고라니

[Jenkins] GCP + Docker + Jenkins를 이용한 CI / CD 본문

Open Source/Jenkins

[Jenkins] GCP + Docker + Jenkins를 이용한 CI / CD

조용한고라니 2021. 10. 3. 03:13
반응형

Index

  • Chapter 1
  • Chapter 2
    • 젠킨스 서버에 도커 및 젠킨스 설치, 배포 서버에 도커 설치
    • 젠킨스 설치 후 이것저것 설정
    • 젠킨스 Job 생성
  • Chapter 3
    • 배포 서버에 도커파일 생성
    • 배포 서버에 init.sh 작성
    • 깃헙에 push 해보기
    • 자동 배포 됬는지 확인

준비물

  • Github 리퍼지토리
  • Spring Boot 프로젝트 (gradle)
  • GCP 같은 클라우드 컴퓨팅 인스턴스 2개
    • A : 젠킨스가 있는 서버
    • B : 배포할 서버

시나리오

  1. 코드를 작성한다.
  2. 깃헙에 Push한다.
  3. Webhook이 걸려 젠킨스에게 Job을 실행하라고 한다.
  4. 젠킨스가 Build해준 결과를 배포 서버에 넘긴다.
  5. 배포 서버에서 컨테이너를 실행해 자동 배포한다.

▷ 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 설치

 

Install Docker Engine on Debian

 

docs.docker.com

여기를 보고 명령어 몇 개만 치면 되므로 위 링크로 대체한다.

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
Comments