문제
이번 주 핵심 구현사항은 CICD 파이프라인 작성이었고, 그 중 CI 워크플로우를 프로젝트에 적용하는 과정에서 어려움이 있었습니다.
사용한 툴은 githubActions 입니다. CICD 에 가장 많이 사용하는 두 가지 툴은 Jenkins 와 githubActions 입니다. 이번 프로젝트에서는, 별도로 서버를 설치할 필요 없이 클라우드를 제공해 주고 다소 복잡한 설정이 없는 githubActions 를 사용하기로 정했습니다.
강의와 예제를 보며, 아무 설정도 없는 기본 프로젝트에 워크플로우 적용 시 어떤 흐름으로 워크플로우의 작업들이 실행되는지 이해할 수 있었고, 실제 단위테스트까지 통과되어야만 병합이 가능하도록 하는 것을 보고 정말 테스트, 빌드 작업을 자동화 할 수 있겠다고 느꼈습니다.
하여 예전에 만들어 두었던 토이 프로젝트에 workflow 를 작성하고, 예제와 비슷한 양식의 yml 파일을 사용해서 빌드 및 테스트 성공까지 연습해 보고 실제 저희 프로젝트에 적용하였습니다.
초반에는 워크플로우를 통해 전체 단위테스트 중 실패하는 단위테스트가 있음을 발견하고 이를 팀원들에게 알리는 등 버그를 발견할 수도 있었으나, 단위 테스트를 모두 통과하도록 수정한 뒤에도 계속 아래 에러메세지가 뜨면서 빌드에 실패했습니다.
문제 해결
가장 아래 단락의 문구로 보아 Property 정보가 누락된 것이 원인임을 알 수 있었습니다.
실제 어플리케이션의 yml 파일에 존재하는 환경변수들이 github 에는 존재하지 않았고 프로젝트에서는 이를 참조하여 다양한 객체에 주입하고 있었으니, 빌드에 실패하는게 당연합니다.
그래서 yml 파일의 환경변수를 워크플로우 yml 파일에서 읽어오도록 하기 위해서, github 에서 제공하는 secrets 기능을 이용했습니다. 해당 리포지토리에서 민감한 정보들을 key:value 형식으로 저장하여 사용할 수 있도록 하는 기능이며, 한번 작성한 secret 은 어떤 값을 가지는지 조회가 불가능합니다. 해당 기능으로 secret 에 어플리케이션 yml 파일에서 민감한 정보였던 jwt secret, oauth2 클라이언트들의 id, secret 정보를 저장했습니다.
그러나 하면서도 의문이 들었던 점은, 해당 정보를 저장한다고 해서 실제 실행환경에서 어떻게 변수를 읽을까? 하는 점이었습니다. 조금 모호한 상태에서 빌드를 시도했지만 실패했고, 변수 양식이나 값들을 바꿔서 여러 번 시도에도 실패하고 나니 'yml 파일의 값들을 환경변수로 넣는게 정말 해결 방법일까?' 하는 생각이 들었습니다. IllegalArgumentException at PropertyPlaceholderHelper 라는 메세지를 보아 환경 변수가 누락된 문제가 확실해 보이는데 그렇다면 환경변수로 어떤 값을 설정해야 하는 걸까? 가 궁금해졌습니다.
해당 내용으로 구글링도 해 봤지만 cicd 관련으로는 아무 의존성이 없는 환경에서의 실행 예제가 대부분이었고 제 프로젝트와 비슷한 환경에서의 레퍼런스는 찾기 어려웠습니다.
그때 '좀 더 자세한 로그를 찍어보고 정확한 정보를 얻자' 는 생각이 들었고(이 생각을 왜 이렇게 늦게 했는지 모르겠습니다), 빌드를 실행하는 action 의 argument 로 --info 를 붙여 로그를 확인함으로써 정확한 실패 지점과 이유를 알 수 있었습니다.
빌드에 실패한 원인입니다. jwt 관련 설정은 secret key 만 환경변수로 저장돼 있었습니다. 이 로그를 보고 어플리케이션 yml 에 있는 모든 값을 환경변수로 넣어야겠다고 생각했습니다.
해서 yml 의 모든 설정 값들을 환경변수로 저장하고 나서, 몇 번의 실패 끝에 빌드와 테스트에 성공했습니다.
runner 환경에서 빌드를 위해 yml 설정 값이 필요하다는 사실을 알게 되고 ci 작업에 성공했지만, 그러고도 궁금했던 점은 workflow 에서 지정한 secret 값을 runner 에서 어떻게 읽어갈까? 하는 점이었습니다.
빌드 성공한 workflow 에서 지정한 변수 이름 입니다. 그러나 어플리케이션 코드에서는 ${auth.jwt.issuer} 의 양식으로 변수를 사용하고 있었기 때문에, 이런 다른 양식의 값을 runner 에서 어떻게 필요한 값으로 인식하고 읽어가는지가 궁금했습니다. 해당 동작 방식을 알아보기 위해 @Value 어노테이션으로 외부 설정 값을 가져오는 방식, 설정 파일에서 값 읽어오는 방법 등 여러 키워드로 공식문서 등 레퍼런스를 찾아 봤지만 정확히 원하는 부분에 대한 궁금증을 해결하진 못했습니다.
그러던 중 workflow 파일도 yml 포맷의 파일임을 상기하고, 실행 과정에서 실제 application.yml 에서 사용하는 설정과 일치하게끔 '_' 로 경로를 구분해 주어야 환경 변수로 인식한다는 것을 알게 됐습니다. 예를 들어 띄어쓰기를 기준으로 AUTH_JWT_ACCESS_TOKEN 을 변수명으로 사용하면 이를 인식하지 못합니다. application.yml 에서는 auth.jwt.accessToken 을 사용하고 있으며 이를 읽어오는 쪽에서도 같은 양식의 값을 읽어오기 때문인 것으로 생각합니다.
회고
CICD 를 맡게 되면서 많은 공부와 시행착오가 있었습니다. 구현에 앞서 알고자 했던 부분은 CICD 를 구축하면서 어떤 이점이 있는가? 에 대한 것이었습니다. 특히 이번 주에 구현했던 CI 만 생각했을 때 빌드와 테스트를 자동화하는 것이 큰 의미가 있나 싶었지만 pr 을 올리기에 앞서 수많은 테스트를 실행하느라 늦어지거나 본인의 담당 도메인만 테스트하고 pr 을 올렸던 등의 문제들을 생각했을 때 프로젝트 전반적으로 안정성을 높여주며 시간 리소스도 절약할 수 있게끔 하는 작업이라고 생각이 들었습니다. 이번 주에 자동 배포까지 시도하지 못한 것이 아쉽지만 이후에 CD 를 구현하는 과정에서도 많이 배우며 프로젝트에도 기여할 수 있을 것 같아 기대하고 있습니다.
전후데이터
기능 구현을 한 것이 아니기에 드러나는 지표는 없지만, 매번 수동으로 모든 테스트를 실행해 볼 필요가 없다는 점이 가장 크게 다가올 것 같습니다. 기능이나 코드가 추가되면 모든 테스트가 성공하는 것을 확인하고 pr을 올려야 하지만, 귀찮음과 시간 이슈로 본인의 도메인만 테스트하는 경우가 많습니다. 이를 워크플로우 실행 시 테스트 및 빌드에 실패할 경우 병합되지 않도록 설정한다면, 모든 pr 에 있어서 빌드 및 테스트 자동화가 실현되는 것이기 때문에 프로젝트 전체의 안정성과 편의성이 크게 올라갈 것으로 생각합니다.
'Study' 카테고리의 다른 글
CI/CD 개념 + 프로젝트에 적용 (0) | 2024.08.08 |
---|---|
AWS EC2, Docker, GithubActions 를 사용한 자동배포 과정 (0) | 2024.07.31 |
TCP/UDP (0) | 2024.07.24 |
OSI 7 계층 (0) | 2024.07.24 |
레디스 락 vs DB 락 (0) | 2024.07.10 |