💡 CICD 과정LINK의 개요에 따라 작성되었습니다.
순서를 따르면 순조롭게 진행할 수 있습니다.

Spring 프로젝트 생성 및 설정하기

이제 본격적으로 Spring 프로젝트를 생성해보자. develop 브랜치에 푸시된 내용은 개발 서버에 배포하고, main 브랜치에 push된 내용은 실제 운영 서버에 배포가 되도록 Jenkinsfile을 작성할 예정이다.

가장 먼저 Spring 프로젝트는 생성하고, 운영/개발 환경에 따라 설정을 분리해보자.

Spring 프로젝트 생성

기존의 GitHub Repository를 이용하면서, 강제 푸시를 통해 git history를 초기화할 예정이다.

기존 프로젝트에 스프링 프로젝트를 얹고 간단한 컨트롤러를 작성해보자.

LINK에 들어가 위와 같이 설정한다.

디펜던시는 간단하게 LombokSpring Web만 추가해서 간단하게 환경별로 다른 String을 리턴하는 컨트롤러를 작성할 예정이다.

GENERATE버튼을 누르면 zip파일이 생기는데 이를 풀어준다.

cicd디렉토리를 원하는 곳에 옮긴후 터미널에서 다음과 같이 입력한다.

1
2
3
4
5
6
7
8
9
10
11
12
$ cd cicd
$ git init
$ echo "# cicd" >> README.md
$ git add README.md
$ git commit -m "docs: README.md 생성"
$ git remote add origin [원격 리포지토리 주소]
$ git push -uf origin main
$ git branch develop
$ git switch develop
$ git add .
$ git commit -m "chore: 프로젝트 초기화"
$ git push -u origin develop

위의 과정은 다음과 같다.

  1. 새로운 프로젝트 디렉토리에 git을 초기화 한다.
  2. ”# cicd”가 작성된 README.md파일을 생성한다.
  3. README.md파일을 스테이지에 추가하고 main브랜치에 커밋후 원격 브랜치에 강제 푸시한다.
    1. 강제 푸시를 했기 때문에 원격리포지토리에서 했던 Jenkinsfile관련 작업과 히스토리는 삭제되고 README.md파일 생성 히스토리로 대체된다.
  4. develop브랜치를 만들고 develop브랜치로 이동해 생성된 프로젝트를 커밋한다.

위의 과정을 통해 원격 리포지토리의 main브랜치의 이전 히스토리는 삭제되고 로컬리포지토리와 동기화 되었다.

환경별 설정 분리

이제 환경별로 설정을 분리해 보자.

실제 프로젝트에서는 작동 환경별로 db정보나 세부 설정이 다를 것이다. 작동 환경별로 다르게 설정을 해보자. 이번 프로젝트는 cicd 테스트용 프로젝트이기 때문에 실제 민감한 정보가 아니라 환경별로 구분만 해주겠다.

src/resources 밑에 환경 설정 파일을 나누어 작성해보자. 기존 application.properties는 삭제 후 진행한다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# application.yml
spring:  
  profiles:  
    active: local  
  
---  
  
spring:  
  config:  
    activate:  
      on-profile: local  
  
server:  
  port: 8080  
  
my-secret: local환경입니다.
1
2
3
4
5
# application-dev.yml
server:  
  port: 8081  
  
my-secret: dev환경입니다.
1
2
3
4
5
# application-prod.yml
server:  
  port: 8082  
  
my-secret: prod환경입니다.

위와 같이 설정하게 되면 spring.profiles.active의 값이 무엇인지에 따라서 server.port의 값과 my-secret값이 다르게 로드되게 된다.

이제 프로젝트에 간단한 컨트롤러를 만들어 보자.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
package com.dukcode.cicd.controller;  
  
import org.springframework.beans.factory.annotation.Value;  
import org.springframework.web.bind.annotation.GetMapping;  
import org.springframework.web.bind.annotation.RestController;  
  
@RestController  
public class HelloController {  
  
   @Value("${my-secret}")  
   private String mySecret;  
  
   @GetMapping("/hello")  
   public String hello() {  
      return mySecret;  
   }  
}

controller 패키지를 만들고 HelloController클래스를 만들어 위와 같이 입력한다.

그리고 프로젝트를 실행시켜 보자.

프로젝트를 실행 후 http://localhost:8080/hello로 접속하면 위와같은 결과를 확인할 수 있다. spring.profiles.activelocal이므로 해당 환경에 맞는 설정을 불러왔기 때문이다.

spring.profiles.activedev로 변경하고 다시 프로젝트를 로드하고 http://localhost:8081/hello로 접속해보자. 기존엔 local프로파일이기 때문에 8080포트로 접속이 가능했지만 현재는 dev환경이기 때문에 8081로 접속해야 한다.

위처럼 dev프로파일에 맞는 환경이 로드된다.

또한, application.yml에서 spring.profiles.activeprod로 변경 후 http://localhost:8082/hello로 접속해 보면 다른 결과가 뜰 것이다.

위 처럼 실행 환경에 따라 다른 결과가 나오는 것을 확인할 수 있다.

민감한 정보 숨기기

my-secret이 github에 올라가면 큰 문제가 생길 것이다. 현재는 의미 없는 정보이지만 실제 프로젝트라면 db의 접속 계정과 패스워드 등이 될 수 있다.

그대로 GitHub Repository에 push한다면 민감한 정보가 그대로 노출 될 것이다.

민감한 정보를 환경변수화 해서 GitHub Repository 상에 보이지 않게 하는 방법, 파일 자체를 암호화 하는 방법 등이 있지만 나는 git-secret을 통해 파일 자체를 암호화 하는 방법을 사용하겠다.

git-secret이라는 프로그램을 이용하면 application-prod.yml파일과 application-dev.yml파일의 암호화/복호화를 쉽게 진행할 수 있다.

git-secret을 사용하여 해당 파일을 암호화 시킨후 암호화된 파일만 commit해보자.

git-secret 참고 링크 : git-secret 사용해보기

1
$ git secret init

프로젝트 최상단에서 위와 같이 입력해 해당 프로젝트 디렉토리를 git-secret 초기화 시킨다.

그리고 위의 링크를 참고해 gpg키를 만들어 준다. 나는 링크의 예시와 같이 test@email.com으로 진행하겠다.

젠킨스에서 해당 프로젝트에서 암호화 파일을 복호화 한 후, build해야하므로 jenkins의 키쌍도 만들어 줄 것이다. 따라서 jenkins가 사용할 gpg-key도 만들어 줄 것이다. 나는 test-jenkins로 key이름을 만들었고, passphrase를 설정하지 않았다.

1
2
$ git secret tell test@email.com
$ git secret tell jenkins@email.com

위와 같이 사용자를 추가한다.

1
2
3
$ git secret add src/main/resources/application-dev.yml
$ git secret add src/main/resources/application-prod.yml
$ git secret hide

위와 같이 secret파일들을 추가하고 hide명령어를 입력하면 자동적으로 yml 원본 파일은 .gitignore에 추가되고 .secret으로 변환된 파일만 git에서 관리된다.

이제 push를 진행하면 원본 파일은 노출되지 않고 암호화된 파일만 GitHub Repository에 올라가 민감한 정보를 아무나 확인할 수 없게 된다. 또한 .gitsecret에 public-key가 등록되고 private-key를 가지고 있는 사용자만 해당 .secret파일을 복호화 할 수 있게 된다.

이제 이 프로젝트에 변경점이 생겼을 때, 원하는 서버로 배포될 수 있도록 Jenkinsfile을 작성해보자.

마지막으로 환경별 설정 분리와 HelloController추가를 분리해 커밋하자.

1
2
3
4
5
6
7
8
9
10
11
12
# 환경 별 설정 분리 commit
$ git add src/main/resources
$ git add .gitignore
$ git add .gitsecret
$ git commit -m "chore: 환경 별 포트 및 설정 분리"

# HelloController 추가 commit
$ git add .
$ git commit -m "feat: HelloController 추가"

# push
$ git push

bootjar만 build하도록 변경하기

프로젝트를 build하고 나오는 jar파일을 통해 프로젝트를 실행시키게 된다.

gradle의 build 태스크를 실행해 보면 위와같이 bootJar태크스와 jar태크스가 모두 실행되는 것을 볼 수 있다.

build디렉토리의 libs디렉토리를 살펴보면 위와 같이 plain jar와 bootjar모두 생성되는 것을 확인할 수 있다.

bootjar와 jar(plain)의 차이는 내부에 프로젝트의 실행에 필요한 디펜던시가 포함되어있는지 여부이다. bootJar는 내부에 디펜던시가 포함되어있어 bootjar파일 자체로 실행 가능하다.

SpringBoot는 내부에 Tomcat을 내장하고 있어 다른 설정 없이 bootJar만으로 프로젝트를 실행할 수 있다. 따라서 추가적인 설정이 필요한 plain jar를 굳이 생성할 이유는 현재 없다.

또한, 추후 jar를 포함하여 docker image를 생성할 때 jar파일의 이름과 관계없이 *.jar로 jar파일을 가져오게 하기 위해서는 libs 디렉토리에 jar파일 하나만 존재하는 것이 편할 것이다.

따라서 plain jar가 생성되지 않는 옵션을 build.gradle에 설정해보자.

1
2
3
jar {  
   enabled = false  
}

build.gradle 하단에 위와 같이 추가해주고 clean 태스크를 실행 후, build 태스크를 실행시켜보자.

기존과 다르게 plain jar가 생성되지 않음을 확인할 수 있다.

1
2
$ git add .
$ git commit -m "chore: plain jar 빌드하지 않도록 변경"

위의 명령어로 작업내용을 commit하자.

이제 실제 프로젝트와 비슷한 환경으로 Spring프로젝트 설정을 마쳤다. 이제 다음 포스트 부터 Jenkins가 자동적으로 서버에 프로젝트를 배포할 수 있도록 Jenkinsfile을 작성해 보자.

댓글남기기