2024. 8. 12. 20:32ㆍ개발자 과정/Kotlin
CI와 CD 파이프라인을 구축하는 역할을 하였다. 이번 최종프로젝트에서 나는 참 많은 것을 해보는 것 같다.
S3+CDN, apache tika, multimedia, db migration, web crawling, EC2+LoadBalancer, RDS+MySQL, Route53
등등... 하나 하나 한번에 되는 법이 없어서 스트레스도 좀 받았지만, 이런것도 마인드 컨트롤 하는게 개발자 아니겠나?
하지만 그 중 거지같은걸 뽑아보자면 CI/CD이다.
난 이 두개가 비슷하니까 하나 하면 다른 하나는 잘 될거라 생각했는데, 서로 다른 지옥도가 펼쳐지더라..
두 번씩이나 이 거지같은 섬에 버려지다니~
뭔가 디버깅을 하고 파이프라인을 정리해보니, 내용 자체는 별게 남지 않은 같다.
그래서 트러블 슈팅 위주로 올려보려한다.
트러블 슈팅
CI
Bean 주입 및 Datasource를 못읽는 문제
Test 빌드인데 RDS를 의존하려다 보니 발생한 문제.
=테스트 yml파일 분리로 Datasource를 H2 In-memory로 사용하도록 변경
WineEmbedding 관련 서비스부터 최종적으로 WineController 까지 Bean 주입 실패 문제
=프로젝트가 embedding-data.json을 불러오도록 되어 있는데, 이를 디렉토리에 넣어주지 않아
생기는 문제였기에 해당 파일을 넣어줌
가장 힘들었던건 Test 빌드인데 RDS를 의존하려다 보니 발생한 문제로 로컬에선 이미 구성요소등으로
이미 테스트 가능한 환경을 구축해둔 경우가 많았고, yml자체를 못불러오는지, yml의 어떤 부분에서 요건이
충족되지 않았는지 자체는 추적하기가 불투명한 부분이 많아 이 문제를 해소하기가 참 쉽지 않았다.
CD
JAR 파일 전송 후 실행 명령어 먹통 문제
해당 문제는 원인을 분석해 해결하기 보단, 우회로를 통해 해결을 하였다.
=
1. 우선 깃허브 액션으로 CD가 되는거 부터 성공해보자고 했으나, SSH 로 명령어를 보내는 것이 되지 않았음.
2. 계속된 시도에도 안되니까 차라리 도커를 통해 해결을 해보자 생각
3. 강의를 듣고 도커의 사용성에 대해 계속 생각해 보면서 기본적인 CD액션의 다이어그램이 그려짐
4. 이를 통해 도커를 설명할 순 없으나, 추상적 차원에서 이해하고 개발가능하였음
5. 깃허브 액션을 통해 빌드된 환경과 필요 한 파일을 도커로 업로드
6. SSH로 도커 명령어를 보내 인스턴스에서 pull 받아옴
7. 이 이미지를 실행하여 배포완료까지의 환경 구축
Docker의 image라는 개념이 생소해 이를 이해하기가 쉽지 않았다. image라고 하면, 사진찍으면 나온 그런걸 먼저 떠올리니까...자꾸 "빌드된 환경 " 이라 하는데 대체 이게 뭔소린가 했지만, 직접 적용해보니 진짜 말 그대로 "빌드된 환경" 그 자체를 제공해 준다는 것을 알 수 있었다.
이제 내가 만든 CI/CD를 보여줄 차례이다.
대부분 결국 구글링을 통한 레퍼런스를 활용하게 되는데, 출처들을 다시 알아볼 수 없어
참조를 못하는 점 양해...
WorkFlows
CI
name: CI
on:
push:
branches: [ dev, feat/* ]
pull_request:
branches:
- dev
- main
jobs:
build:
runs-on: [ ubuntu-latest ]
steps:
- name: checkout
uses: actions/checkout@v4
- name: java setup
uses: actions/setup-java@v2
with:
distribution: 'adopt' # See 'Supported distributions' for available options
java-version: '17'
# gradle caching - 빌드 시간 향상
- name: Gradle Caching
uses: actions/cache@v3
with:
path: |
~/.gradle/caches
~/.gradle/wrapper
key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }}
restore-keys: |
${{ runner.os }}-gradle-
#application.yml 복사
- name: set yml
run: |
mkdir -p ./src/test/resources/
echo "${{ secrets.APPLICATION_TEST_YML }}" | base64 --decode > ./src/test/resources/application.yml
- name: make executable gradlew
run: chmod +x ./gradlew
# test 진행
- name: run unittest
run: |
./gradlew clean test --scan
# 결과 Slack에 전송
- name: result send slack
uses: 8398a7/action-slack@v3
with:
status: ${{ job.status }}
fields: repo,message,commit,author,action,eventName,ref,workflow,job,took,pullRequest # selectable (default: repo,message)
env:
SLACK_WEBHOOK_URL: ${{ secrets.RESULT_SLACK_CI }} # required
if: always() # Pick up events even if the job fails or is canceled.
CD
name: CD
on:
workflow_dispatch:
pull_request:
branches:
- main
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Set up JDK 17
uses: actions/setup-java@v2
with:
java-version: '17'
distribution: 'adopt'
# gradle caching - 빌드 시간 향상
- name: Gradle Caching
uses: actions/cache@v3
with:
path: |
~/.gradle/caches
~/.gradle/wrapper
key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }}
restore-keys: |
${{ runner.os }}-gradle-
# application.yml 복사
- name: set yml
run: |
mkdir -p ./src/main/resources
echo "${{ secrets.APPLICATION_YML }}" | base64 --decode > ./src/main/resources/application.yml
find src
# application-dev.yml 복사
- name: set yml
run: |
mkdir -p ./src/main/resources
echo "${{ secrets.APPLICATION_DEV_YML }}" | base64 --decode > ./src/main/resources/application-dev.yml
find src
# application-prod.yml 복사
- name: set yml
run: |
mkdir -p ./src/main/resources
echo "${{ secrets.APPLICATION_PROD_YML }}" | base64 --decode > ./src/main/resources/application-prod.yml
find src
# gradle 빌드
- name: Grant execute permission for gradlew
run: chmod +x ./gradlew
- name: gradlew bootJar
run: |
./gradlew bootJar
# docker 빌드 & 푸쉬
- name: Docker build & push
run: |
docker login -u ${{ secrets.DOCKER_USERNAME }} -p ${{ secrets.DOCKER_PASSWORD }}
docker build -f Dockerfile -t ${{ secrets.DOCKER_USERNAME }}/docker-prod .
docker push ${{ secrets.DOCKER_USERNAME }}/docker-prod
# 인스턴스1에 배포
- name: Deploy to application
uses: appleboy/ssh-action@master
with:
host: ${{ secrets.SSH_HOST }}
username: ubuntu
key: ${{ secrets.SSH_KEY }}
port: 22
script: |
sudo docker stop $(sudo docker ps -q)
sudo docker rm $(sudo docker ps -a -q)
sudo docker pull ${{ secrets.DOCKER_USERNAME }}/docker-prod
sudo docker run -d -p 8080:8080 ${{ secrets.DOCKER_USERNAME }}/docker-prod
sudo docker image prune -f
# 결과 Slack에 전송
- name: result send slack
uses: 8398a7/action-slack@v3
with:
status: ${{ job.status }}
fields: repo,message,commit,author,action,eventName,ref,workflow,job,took,pullRequest # selectable (default: repo,message)
env:
SLACK_WEBHOOK_URL: ${{ secrets.RESULT_SLACK_CD }} # required
if: always() # Pick up events even if the job fails or is canceled.
DockerFile
# open jdk 17 버전의 환경
FROM eclipse-temurin:17-jdk-alpine
# EC2나 LoadBalancer에 물려 있다면 보안그룹에서
연결중인 포트번호와 일치시켜야 한다.
EXPOSE 8080
# JAR_FILE이라는 변수 명에 build/libs/*.jar 선언
ARG JAR_FILE=build/libs/*.jar
# JAR_FILE을 app.jar로 복사
COPY ${JAR_FILE} app.jar
# JSON 파일을 컨테이너의 적절한 위치에 복사
COPY ./data/embedding-data.json /data/embedding-data.json
# 운영 및 개발에서 사용되는 환경 설정을 분리
ENTRYPOINT ["nohup", "java", "-jar", "-Dspring.profiles.active=prod", "/app.jar", ">", "nohup-dev.out", "2>&1", "&"]
처음엔 깃허브액숀 자체도 생소해서 뭐가 뭔지 모를테지만, workflow 한줄 한줄을 다 이해하려 하기 보단,
-name과 그에 따른 액션을 눈대중으로 보고 대략적인 기능을 파악한 후 파고들면 그리 어렵지 않게 리딩이 가능하다.
여담
머리가 깨져라 구축하는데에 많은 노력을 할애 했는데, 막상 그 과정들을 헤쳐나간 후 남은 결과물은
그렇게 대단하지도, 어렵지도 않아 보이기에 조금은 허탈한 마음도 있긴 있다.
하지만, 이 과정을 통해 한가지 절실히 깨달은 것이 있다. 그것이 뭐냐면
이런 파이프 라인은 프로젝트 초기단계에 적용이 되어야 한다는 것이다.
거의 다 완성된 프로젝트에 적용하려고 하면, 이에 맞춰 workflow를 짜고,
원인을 알 수 없는 버그들을 잡아야 함에 따라 너무 고생을 하게 된다.
아무튼 이렇게 해서 CI/CD까지 무사히 마쳤다!
짝짝짝
'개발자 과정 > Kotlin' 카테고리의 다른 글
springboot기초(2)-가위바위보를 고도화 해보자 (1) | 2024.09.24 |
---|---|
springboot기초(1)-백엔드로 가위바위보를 만들어보자 (3) | 2024.09.23 |
s3와 tika 의존성 분리 (0) | 2024.07.26 |
괴도키드가 웹 크롤링을 한 이유 (0) | 2024.07.18 |
N+1 성능 개선(사용자가 가르강튀아로 가기VS쿼리최적화) (0) | 2024.07.09 |