Git

[kerdy] 서브모듈을 사용해서 yml 숨기기(feat. 하나의 yml에서 여러 profile 관리하기)

자바생 2023. 8. 2. 20:28
728x90

글을 쓰게 된 이유

우아한테크코스(우테코) 커디 팀에서 배포자동화를 구성하면서 고민이 하나 생겼습니다.

 

 

GitHub Actions를 사용하면서 runner 가 설치되어 있는 서버에 jar 파일을 전달하기 위해 artifact를 사용했습니다.

 

 

 

하지만 artifact를 사용하게 되면 해당 레포에 접근 권한이 있는 사람들, 더 나아가 organization에 포함되어 있으면 organization 사람들 모두 jar 파일을 다운로드할 수 있게 됩니다.

 

 

이게 위험한 이유는 jar 파일을 unzip 하여 내부 파일을 볼 수 있기 때문입니다.

 

결국 해결해야하는 점은 artifact를 사용하지 않고 jar 파일을 서버에 옮겨야 하고,

서버마다 필요한 설정 파일(yml 및 key)들을 감춰야 합니다.

 

 

 

현재는 yml 파일이 서버에 있어서 쉘 스크립트를 통해 jar 파일을 실행할 때 yml을 덮어씌우는 형식을 사용했었습니다.

 

 

하지만 이 방법은 서버가 추가될 때마다 쉘 스크립트를 옮겨줘야 하고, 배포자동화에는 어울리지 않는다고 생각했습니다.

 

 

그래서 생각한 방법은 아래와 같습니다.

  1. 서브 모듈 + docker
  2. secrets + docker

 

 

docker를 사용하는 이유는 artifact를 사용하지 않을 수 있는 점과 나중에 도커 이미지로 만들게 되면 jar 파일을 실행할 때 별다른 설정을 안 해줘도 되는 이유가 있었습니다. 물론 가장 큰 이유는 artifact를 사용하지 않는다는 점이죠.

 

 

그리고 설정 파일들을 감추기 위해서 secrets와 서브 모듈을 고민했는데 secrets는 변경 이력을 볼 수 없었기 때문에 너무 불편해서 1번 방법을 도입했습니다.

 

 

 

 

이제 서브모듈을 어떻게 도입했는지 작성해 보겠습니다.

 

 

 

 

 

 

 

서브 모듈 도입해 보기

 

 

서브 모듈을 도입하는 방법은 REFERENCES에 있는 블로그들을 참고해서 작성했습니다.

 

 

서브 모듈은 이제 부모 프로젝트(이하 루트 프로젝트)에서 보여주면 안 되는 값들을 넣어주는 것으로 사용했습니다.

키 값이나 DB 관련 정보 등등

 

 

 

저의 github에서 private repository를 하나 만들고 이를 서브 모듈로 사용하려고 합니다.

 

 

 

팀원들이 접근할 수 있도록 프로젝트 Settings에서 Collaborators로 추가해 주면 됩니다.

 

 

 

 

 

 

 

 

이제 루트 프로젝트에서 아래의 명령어를 통해 서브 모듈을 생성합니다.

 

 

현재 위치는 2023-emmsale/backend였으므로 emm-sale부터 경로를 시작하면 됩니다.

 

 

git submodule add <https://github.com/java-saeng/kerdy-submodule.git> emm-sale/src/main/resources/kerdy-submodule

 

 

어차피 모두 yml 및 key 파일이기 때문에 resource 하위에 만들어주었고,

또 다른 이유는 yml에서 classpath를 사용하여 더 쉽게 다른 yml들을 참조할 수 있기 때문입니다.

 

 

두 번째 이유 때문에 resources 하위에 만들어준 게 가장 컸습니다.

위 명령어를 실행하고 나면. gitmodules, 지정해 준 서브 모듈 디렉터리 이름(kerdy-submodule)이 생성됩니다.

[submodule "backend/emm-sale/src/main/resources/kerdy-submodule"]
	path = backend/emm-sale/src/main/resources/kerdy-submodule
	url = <https://github.com/java-saeng/kerdy-submodule.git>

 

 

 

 

이렇게 서브 모듈이 생겨서 우리 깃헙에 올라가는 yml(보여도 되는)은 아래만 같으면 됩니다.

 

 

spring:
  config:
    import: classpath:kerdy-submodule/application.yml

 

 

 

 

 

 

서브 모듈 수정 후 루트 프로젝트에 반영(PROD 설정 추가)

 

 

이제 DEV환경뿐만 아니라 PROD 관련 설정 yml 도 서브 모듈에 넣어줘야 합니다.

 

 

 

 

 

서브 모듈에 먼저 application-prod.yml을 추가해 준다.

그리고 제일 중요한 것은 루트 프로젝트에서도 서브 모듈에 반영된 것을 확인하고 루트 프로젝트의 원격 저장소에도 push를 해줘야 반영됩니다.

 

 

말이 어려우니까 다시 과정을 살펴보겠습니다.

 

 

git submodule update --remote

 

 

 

루트 프로젝트에서 해당 명령어를 통해 submodule을 update 시켜줍니다.

 

 

 

 

방금 서브모듈에서 추가했던 application-prod.yml 이 반영됐는지 확인합니다. 진짜 확인해야 함요

 

 

그리고 원격 저장소에 push 할 때, 서브 모듈들은 바뀐 것에 추가가 안되어있으므로 직접 git status로 확인한 후 add를 시켜줘야 합니다.

 

 

staging을 하고 나서 같이 push를 해줍니다.

 

 

 

 

 

그러면 이전 서브 모듈의 커밋 d22c3d 를 참조하였는데, push 이후에는 729ad9 를 참조하는 것을 알 수 있습니다.

 

 

 

다시 한번 강조하면 서브 모듈 반영본을 먼저 서브 모듈 원격 저장소에 push 하고,

루트 프로젝트에서 update를 한 뒤에, status를 통해 확인하고 루트 프로젝트 원격 저장소에 같이 push 해줘야 합니다.

 

 

 

 

 

하나의 yml 파일에서 여러 profile 설정하기

 

 

생각해 보면 로컬에서 필요한 yml 은 굳이 서브 모듈에 넣을 필요가 없다고 생각했습니다.

 

 

그리고 DEV, PROD 용 yml 은 서브모듈에 있으니 굳이 루트 프로젝트에서 application-dev.yml , application-prod.yml 또한 필요가 없을 겁니다.

 

 

그래서 하나의 application.yml 에서 default, dev, prod를 설정하려고 합니다.

 

 

spring:
  datasource:
    url: jdbc:mysql://localhost:3306/kerdy
    username: root
    password: 1234
    driver-class-name: com.mysql.cj.jdbc.Driver
  sql:
    init:
      mode: always
  jpa:
    hibernate:
      ddl-auto: validate
    properties:
      hibernate:
        dialect: org.hibernate.dialect.MySQL8Dialect
      format_sql: true
    show-sql: true
  config:
    activate:
      on-profile: default

logging:
  level:
    org:
      hibernate:
        type:
          descriptor:
            sql:
              BasicBinder: TRACE

github:
  client:
    id: client_id
    secret: client_secret
  url:
    access-token: access-token_url
    profile: profile_url

security:
  jwt:
    token:
      secret-key: secret_key
      expire-length: 3_600_000_000

firebase:
  project:
    id: kerdy

---

spring:
  config:
    import: classpath:kerdy-submodule/application-dev.yml
    activate:
      on-profile: dev

---

spring:
  config:
    import: classpath:kerdy-submodule/application-prod.yml
    activate:
      on-profile: prod

 

 

여기서 가장 중요한 점은 spring.config.active.on-profile입니다.

 

 

기존에는 하나의 yml에서 application.yml 만 참조하고 있어서 spring.config.import를 사용했지만 Spring Boot 2.4부터 지원해 주는 하나의 yml에서 여러 profile을 관리할 때는 spring.config.active.on-profile을 사용해야 합니다.

 

 

 

위 yml을 통해 우리는 하나의 yml 파일에서 여러 profile을 통해 jar를 실행할 수 있습니다.

 

 

 

그리고 해당 서버에 배포하고 나서 jar 파일을 -DSpring.profiles.active = [profile] 통해 실행해줘야 합니다.

 

 

 

 

GitHub Actions에서 서브모듈 추가하기

 

 

GitHub Actions에서 빌드를 할 때도 서브 모듈을 당연히 접근할 수 있어야겠죠?

 

 

서브 모듈 입장에서는 GitHub Actions도 누군지 알 수 없기 때문에 private repository에 쉽게 접근하지 못합니다.

 

 

그래서 private repository에 접근할 수 있도록 private repository 주인의 GitHub Access Token을 하나 발급해서 secrets에 넣어주고, GitHub Actions에 설정해줘야 합니다.

 

 

토큰을 발급받을 때는 아래와 같이 repo 권한만 줘도 충분합니다.

 

 

 

expiration 도 설정해 주세요!

저는 올해까지로 해놨습니다.

 

 

 

 

 

 

발급받은 토큰을 secrets에 넣어주고 with 명령어를 통해서 위와 같이 작성해 주시면 됩니다.

 

 

결론

 

설정 파일을 숨기기 위해서 Jasypt, 서버에 yml을 만들어서 jar 실행할 때 덮어씌우기, sub module 모두 사용해 보았습니다.

 

 

이 중에서 솔직하게 간편한 거는 Jasypt라고 생각이 들지만, 조금만 리소스를 투자하면 sub module이 훨씬 사용하기 좋고, private repository라 더 안정성이 있는 것 같고, 편하게 숨길(?) 수 있어서 더 좋았습니다.

 

 

 

이번 글은 앞서 작성한 파이어베이스와 같이 팀원들에게 서브 모듈을 설명하기 위해서 작성한 글인데, 팀원들이 잘 이해했길 바라며 글을 마쳐보겠습니다.

 

 

 

 

 

 

REFERENCES

 

https://hudi.blog/git-submodule/

https://tecoble.techcourse.co.kr/post/2021-07-31-git-submodule/

https://data-engineer-tech.tistory.com/20

https://leveloper.tistory.com/176

토큰 넣기

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

728x90