Programming/Tips, Fix, Anything Else

[TFAE] 스프링부트 프로젝트 GitHub Action CI&CD연대기 - 1

Supreme_YS 2022. 2. 17. 15:24
현재의 상황

아일랜드에 거주하는 한국인 유학생들을 대상으로 한 거래 플랫폼을 제작중이다. 일명 - . 열심히 코드를 작성하고, 이것 저것 테스트를 마치고 이제 세상에 선보여야 할 때가 왔다.

 

첫 번째 문제

만든 프로젝트가 세상에 나오려고 알을 깨려는데, 껍질이 꽤 두껍다. 배포가 잘 안되었다. 배포가 안되는 이유는 여러가지 이유가 있었다.

첫 째로, CI 도구의 선택이다. Jenkins, Travis, Circle CI 등등. 굉장히 많은 CI 도구들이 있었고, 어느 것을 선택해야 할지 몰랐다. 단 한 번도 써본적이 없었기 때문이다. 배포라고 해봤자, EC2에 Github Repository에서 가져온 다음 EC2 환경에서 빌드하는 수준? 딱 그 정도 였다. 물론, 이 것도 당시에는 굉장한 큰 기쁨으로 다가왔다. 하지만, 실질적인 서비스를 운영하기 위한 무중단 배포를 위해 다양한 도구들을 테스트 해보았다.

 

Jenkins

첫 번째로 테스트한 CI 도구는 Jenkins 였다. 현업에서도 많이 쓰이는 도구이며, 그만큼 많은 Legacy들이 있다기에 도즈언하였다. 호기롭게 도전하였고, EC2의 프리티어에서는 Jenkins가 뻑이난다기에 메모리 스왑까지 해가면서 꾸역꾸역 환경을 구축했다.

하지만 언제나 조져지는 건 나였다. 

여러 문제 중 가장 큰 것은 Jenkins Publish over SSH Plugins이 서비스를 2022년 1월 XX일자로 서비스를 중단했다는 것이다 ^^..ㅎ 물론 보안상의 이슈로 종료한 것이기에 잘한 일이지만, 내 입장에선 원망스러웠다. 아니 그러면 대체제는 있는가? 있긴했다. Jenkins 시스템을 설정하는 과정에서 SSH로 Host를 Publish하는 필드가 있었다. 하지만 필드값을 열심히 Documents를 보면서 잘 채워도, 운영 EC2와 붙질 않았다. 결국 Connection Error

 

이것도 경험이지, 좋아. 다른 툴을 써보자 Travis 도전!

다른 팀원이 호기롭게 도전했다.

GitHub Action이란게 있더라구요, 한 번 찍.먹 가보실까요?

우리 프로젝트는 어떤 기능을 붙이기 전에 개인 레파지토리에 참고하는 사이트대로 진행하며 테스트를 먼저 진행했다. 이후에 우리 프로젝트에 적용하는 방향으로 진행했다. 따라서, GitHub Action을 개인 레파지토리에 테스트 해보고, 동작 원리를 파악했다. 생각보다 깃헙 액션 공식 문서도 잘 되어있고, 블로그 레퍼런스도 나름 많이 공개되어 있어서 적용하기 수월할 것 같았다. 그래서 CI 툴은 GitHub Action으로 정했다. 

 

아키텍쳐 설계

그래, GitHub Action으로 CI 할게. 아키텍쳐는 누가 할래?

CI 툴도 정했겠다. 깃헙 액션이 어떻게 돌아가는지도 알겠다. 이제 우리는 어떤 구조로 CI/CD를 구현할 것인지 정해야만 했다. 즉, 아키텍쳐를 구성해야 했다. 시나리오는 다음과 같다. 

순서 프로세스
1 깃헙 액션에 Push로 요청이 온다
2 깃헙 액션을 추가하면 생기는 .github/workflows/main.yml의 내용을 실행시킨다.
3 main.yml의 작업 순서는 다음과 같다.
4 main 브랜치에 있는 repository를 깃헙 액션 자체 서버(ubuntu)에서 빌드한다.
5 깃헙 액션 자체 서버에서 빌드된 파일을 이미지화 한다.
6 도커 허브로 이미지 파일을 Push 한다.
7 원격 서버(EC2)는 도커 허브에 업로드 된 이미지 파일을 Pull 한다.
8 실행중이던 이미지 파일을 중지 및 삭제한다.
9 새로 받은 이미지 파일을 도커로 실행시킨다.

세부적인 내용을 요약해서 적어보았다. 이제 4번부터 9번까지 main.yml에 일련적으로 적어주고, main 브랜치에 push를 진행했다. 깃헙액션이 push 요청을 받아, 열심히 main.yml에 적은 스크립트를 실행했다. 

하지만 조져지는 건 역시 나였다.

성공은 했는데, 문제가 있다.

아, 많은 문제들이 있었지만 세세한 걸 이 글에 모든 것을 다룰 수 없다. 깃헙 액션이 실행하면서 설정한 스텝에서 발생하는 문제들을 하나씩 해결해갔고, 결국 EC2에 도커 허브의 이미지 파일이 불러와지는 것을 성공했다. 원하는 시나리오대로 실행에 성공한 것이다. 근데 치명적인 문제가 있었다. 깃헙 브랜치에는 스프링 부트에서 설정한 application.yml (설정 파일)이 있다. 그 곳에는 개인 암호 정보나, Redis, Kafka, Port, Host 등등의 민감한 중요 정보들이 다 담겨있다. 깃헙 정책상 이런 정보는 담아서 올리면 안된다. 대놓고 "내 주소와 아이디와 비밀번호가 이것이니 가져다 채굴을 하시든 마음대로 쓰십시요!!" 하고 바치는 꼴인 것이다. 이러면 안된다. 그래서 파일을 아래의 코드와 같이 캡슐화하였다. 보이는 secrets. 구문은 깃헙 액션에서 제공하는 Secret을 일일이 다 설정해준 것이다. 

spring:
  redis:
    host: ${{secrets.SPRING_REDIS_HOST}}
   port: 6379
    timeout: '1'
  security:
    oauth2:
      client:
        registration:
          kakao:
            client-id: ${secrets.KAKAO_CLIENT_ID}}
            redirect-uri: ${secrets.KAKAO_REDIRECT_URI}}
            client-secret: ${secrets.KAKAO_CLIENT_SECRET}}
            client-authentication-method: post
            authorization-grant-type: authorization_code
        provider:
          kakao:
            authorization-uri: https://kauth.kakao.com/oauth/authorize
            token-uri: https://kauth.kakao.com/oauth/token
            user-info-uri: https://kapi.kakao.com/v2/user/me
            userNameAttribute: id
  jpa:
    hibernate:
      ddl-auto: create-drop
    properties:
      hibernate:
        format_sql: 'true'
    show-sql: 'true'
  cache:
    type: redis
  servlet:
    multipart:
      max-file-size: 10MB
      max-request-size: 10MB
  datasource:
    password: ${{secrets.POSTGRES_PASSWORD}}
    username: ${{secrets.POSTGRES_USERNAME}}
    url: ${{secrets.POSTGRES_URL}}
cloud:
  aws:
    s3:
      bucket:
        url: ${{secrets.AWS_S3_BUCKET_URL}}
        name: ${{secrets.AWS_S3_BUCKET_NAME}}
    credentials:
      instance-profile: 'true'
      accessKey: ${{secrets.AWS_ACCESSKEY}}
      secretKey: ${{secrets.AWS_SECRETKEY}}
    region:
      static: ap-northeast-2
    stack:
      auto: 'false'
logging:
  level:
    org:
      hibernate:
        type:
          descriptor:
            sql:
              BasicBinder: TRACE
        SQL:

 

어림도 없다.

어림도 없다

EC2에서 발생한 오류 구문은 값을 parsing 할 수 없다는 에러였다. 친숙한 언어로 요약하면 다음과 같다.

어, 이거 application.yml 파일은 읽었는데요. {secrets.뭐시기} 이것들이 뭐에여? 난 도통 알수가 없네요.

 

글이 길어질 거 같아서 1편 2편으로 나누어서 구성을 해야겠다. 본격적으로 SpringBoot 환경을 GitHubAction으로 빌드할 때, application.properties나 application.yml 파일을 처리하는 방법을 공개하도록 하겠다. 이렇게 구성한 레퍼런스가 전-혀 없어서 마치 선구자가 된 기분...행복하다.