큐시즘에 들어오기 위해 지원서를 작성하고 면접을 봤던 순간이 어제같은데 벌써 큐시즘의 막바지에 다다르고 있다.
더웠던 날씨가 쌀쌀해지고 가을을 넘어 겨울이 다가오는 지금, 좋은 팀원들과 함께하는 밋업 프로젝트를 잊지않기 위해 중간회고를 하려한다.
개발 공부를 하다보면
"배포를 진행해야 한다."
"로컬에서만 돌아가는 프로젝트는 큰 의미가 없다."
같은 얘기를 많이 듣는다.
나도 공감하는 바인데, 배포란게 무료도 아니고 뚝딱~ 되는 것도 아니다.
큐시즘에선 Naver Cloud Platform(이하 NCP)과 협업한다.
NCP에서 제공해준 크레딧을 활용해 다양한 인프라 및 AI 기술을 사용할 수 있다.
돈 걱정 없이 클라우드 기술을 활용하고 배포도 할 수 있다는 뜻!!(큐시즘짱)
중간회고로 우리 프로젝트의 소개 , NCP에서 어떤 서비스를 사용했는지 , 배포하는 방법 등을 적어보려 한다!
1. 나의 시간 조각을 모아, 조각조각
내가 속해있는 Cnergy(C팀)은 조각조각이란 서비스를 만들고 있다.
간단히 소개를 하자면~
모든 사람이 이동시간 , 친구를 기다리는 시간 등 나도 모르게 버려지는 자투리 시간들이 있다.
자투리 시간에 할 수 있는 여러 활동을 AI를 통해 추천받고 자투리 시간을 알차게 쓰자!
컨셉의 프로젝트이다.
우리 프로젝트의 MVP 목표는 다음과 같다.
- 자투리 시간을 유의미하게 활용할 수 있는 다양한 활동을 사용자에게 추천한다.
- 사용자의 자투리 시간 길이와 유형에 따라 맞춤 활동을 추천한다.
- 현재 사용할 수 있는 자투리 시간을 입력받는다.
- 온/오프라인, 활동의 특성(생산성/재미 등등)에 대한 키워드로 선택한다.
- AI가 해당 특성에 따른 다양한 활동을 추천한다.
- 사용자가 제시된 활동 중 원하는 활동을 선택한다.
- 활동이 종료된 후, 활용한 자투리 시간이 시간 조각으로 쌓이는 과정을 시각화 해준다.
- 사용자의 자투리 시간 길이와 유형에 따라 맞춤 활동을 추천한다.
- 사용자가 자투리 시간 활용의 효능감/성취감을 느낄 수 있도록 한다.
- 얼마나 많은 자투리 시간을 다양하게 활용했는지 시각화 해준다.
- 얼만큼의 시간을 활용했는지 수치로 보여준다.
- 워드클라우드와 캘린더 형태로 사용자의 자투리 시간 활용 행태를 확인할 수 있게 한다.
- 얼마나 많은 자투리 시간을 다양하게 활용했는지 시각화 해준다.
- 자투리 시간에 대한 인식을 변화시킨다.
- 무언가를 제대로 하기에 애매한 시간 → 무엇이든 가볍게 시도해볼 수 있는 시간
- ‘자투리 시간을 이렇게나 다양한 방식으로 활용할 수 있다’를 서비스 활용을 통해 보여준다.
- 무언가를 제대로 하기에 애매한 시간 → 무엇이든 가볍게 시도해볼 수 있는 시간
해당 프로젝트에서 백엔드를 맡아 열심히 개발을 진행하고 있다!
(https://github.com/KUSITMS-30th-TEAM-C)
2. Ncloud에서 사용한 기술!
위 그림들을 보며 기술에 대한 간략한 소개를 해보려 한다.
1. 배포를 위해 NCP 서버를 사용했다.
2. Container Registry를 통해 도커 이미지를 관리하고 있다.
3. 추천은 AI를 통해 이뤄진다. Clova Studio를 사용했다.
4. Clova Studio에서 온 여러 추천 활동 장소의 세부 정보를 Naver 지역 검색 API를 통해 제공한다.
대표적으로 위 4가지 기술을 사용했다.
가장 중요한 기술은 Clova Studio 이다.
Clova Studio 를 우리 입맛에 맞게 쓰기 위해선 튜닝을 진행해야 한다.
튜닝방법에 대해선 아래 글을 읽어보면 된다!
https://securityinit.tistory.com/242
클로바 스튜디오 엔진 튜닝하기(온라인, API)
큐시즘 밋업 프로젝트를 진행하며 AI 튜닝을 진행하게 되었다.튜닝(모델 훈련)을 하는 방법을 찾아봤지만 다 비슷한 글에다 네이버에서 올라온 홍보와 비슷한 글 밖에 없었다. 잘하는 분들은 다
securityinit.tistory.com
3. 배포를 진행해보자!
처음 배포를 도전했을 때 글 하나에 배포 시작부터 끝까지 다 있는 글이 있었으면 생각했었다.
그래서 내가 적어보려한다!
(개념 설명은 최소화하고 그냥 따라하면 일단 배포가 되는! 글을 적어보려 한다 ㅎ.. 일단 배포부터 하고싶은게 사람 심리 아닐까? ㅎ )
우리가 많이 들어본 CI/CD 는 간단하게 설명하면 이렇다.
CI (지속적 통합, Countinous Integration)
- 개발자들의 코드 변경을 병합하는 프로세스
- 코드 변경이 발생할 때 자동으로 빌드 및 테스트 진행
- 이러다보면 버그도 빨리 알 수 있고 코드 품질도 향상시킬 수 있다!
CD(지속적 배포/제공 , Continuous Deployment)
- CI의 확장으로, 애플리케이션을 자동으로 배포하는 프로세스
- 테스트를 통과한 코드를 자동으로 프로덕션으로 배포
CI/CD를 수행할 수 있는 여러 툴이 있지만 난 Github Actions를 사용했다.
난 어플리케이션을 도커 컨테이너 이미지로 띄울 예정이다.
그러니까 현재 내가 작성하는 글은 도커를 통해 애플리케이션을 컨테이너로 패키징하고 NCP 환경에 docker로 서비스를 띄우는 과정이다.
NCP 환경을 안쓴다면 NCP 서버를 AWS EC2로, NCP Container Registry를 DockerHub나 AWS ECR로 변경하면 된다!
배포 과정은 똑같다~!
코드부터 따라쳐보자
Dockerfile
# OpenJDK 17 슬림 이미지를 기반으로 컨테이너를 생성
FROM openjdk:17.0.1-jdk-slim
# 컨테이너 내에서 애플리케이션이 실행될 작업 디렉터리를 /app으로 설정
WORKDIR /app
# 빌드된 JAR 파일을 컨테이너의 /app 디렉터리에 복사
COPY ./build/libs/backend-0.0.1-SNAPSHOT.jar /app/backend.jar
# 컨테이너의 8080 포트를 개방해 애플리케이션이 외부 요청을 받을 수 있도록 설정
EXPOSE 8080
# Java 명령어로 애플리케이션을 실행하기 위한 시작 명령어를 설정
ENTRYPOINT ["java"]
# JAR 파일을 실행하는 기본 명령어를 설정하여 애플리케이션을 시작
CMD ["-jar", "backend.jar"]
빌드하는 과정이 없다고?
CI때 빌드하고 빌드 결과물만 Dockerfile로 패키징 할 예정이다.
이러면 빌드 속도도 빨라지고, 불필요한 디펜던시도 도커 이미지에 포함되지 않는다.
쨋든 이렇게 하면 좋다 ㅎ
NCP 서버 생성은 아래 글을 참고해서 생성하자.
https://securityinit.tistory.com/240
네이버 클라우드에 서버를 생성해보자!(NCP)
큐시즘 밋업 프로젝트 중 네이버 클라우드의 지원을 받게 되었다.NCP(네이버 클라우드) 서버를 만들어보자.(신규회원의 경우 10만원의 크레딧을 준다. 나의 경우 지원을 받아 더 많은 크레딧이 있
securityinit.tistory.com
NCP에서 Dockerfile을 배포하려면 NCP Container Registry를 만들어야 한다.
아래 글을 참고해 Container Registry를 생성하자.
https://securityinit.tistory.com/246
[NCP] 제목은 Container Registry 생성하기로 하겠습니다. 근데 이제Object Storage를 곁들인...
깃허브에 우리가 코드를 저장하고 다른 사람의 코드를 내려받듯이, 도커이미지도 깃허브와 같은 저장소에 이미지를 저장하고 내려받을 수 있다.가장 유명한 퍼블릭 저장소는 DockerHub 이지만,
securityinit.tistory.com
그럼 현재 우리 상황은 다음과 같다.
- Dockerfile이 존재한다.
- 서버가 띄워져있다.
- Container Registry도 생성했다.
이젠 CI/CD 파이프라인을 작성하면 된다.
CI/CD도 사람마다 다르게 짜고, 여러 트리거를 넣어 특정 상황마다 배포를 하고 안하고 테스트를 하고 등등을 설정할 수 있지만...
우리에게 중요한 것은 일단 배포부터 하자! 니까 배포만 되도록 작성해보겠다.
(나중에 다른 사람들의 CI/CD 스크립트를 참고하며 여러 방법을 찾아보면 된다.)
그전에 사전 세팅을 해야한다.
우리가 곧 적게 될 CI/CD 스크립트엔 여러 작업을 적는다.
예를 들어 테스트를 진행해라 , 빌드를 해라, 빌드 결과물을 도커 이미지로 패키징해라 등등..
Github Actions는 'runner'라는 가상머신에서 위 작업들을 수행한다.
우리가 개발을 하면 외부로 노출되면 안되는 값들이 있다.
이런 값들을 환경변수로 설정한다.
즉, application.yml 파일에 넣고, 깃허브 레포지토리엔 올리지 않는다.
여기서 문제가 생긴다.
Github Actions는 어떻게 환경변수를 알 수 있을까 ?
'runner'에선 어떻게 이런 환경변수들을 사용할 수 있을까?
Github 레포지토리의 Secrets에 이런 값들을 저장하고, CI 스크립트에서 이런 값들을 불러와 사용한다!
먼저
본인의 레포지토리에 들어간다.
그 후 Settings -> Secrets and variables -> Actions 에 들어가 환경변수 값을 추가하면 된다.
우리가 곧 적게 될 CI/CD 스크립트에 여러 작업을 적는다.
Github Repository에 필요한 값들을 환경변수로 등록해야한다.
이렇게 환경변수 값을 설정하고 Add secret을 누르면 환경변수들이 등록된다!
그래서~ 우리가 등록해야 하는 환경변수 값들은 다음과 같다.
- APPLICATION_PROPERTIES : 서비스 환경변수
- TEST_APPLICATION_PROPERTIES : 테스트용 환경변수
- NCP_ACCESS_KEY : NCP 계정의 Access Key ID
- NCP_SECRET_KEY : NCP 계정의 Secret Key ID
- NCP_CONTAINER_REGISTRY : 컨테이너 레지스트리의 퍼블릭 엔드포인트
- NCP_HOST : NCP 서버의 IP 주소
- NCP_PASSWORD : NCP 서버 생성시 발급받은 비밀번호
- NCP_PORT : NCP 서버의 포트(주로 22)
- NCP_USERNAME : NCP 서버 유저네임(주로 root)
NCP_ACCESS_KEY , NCP_SECRET_KEY 확인하기 👇
NCP_ACCESS_KEY와 NCP_SECRET_KEY는
NCP -> 마이페이지 -> 계정관리 -> 인증키 관리
에서 볼 수 있다.

이렇게 다 등록을 했다면 이제 CI/CD 스크립트를 작성하자.
deploy.yml (참고로 .github/workflows 폴더 안에 작성을 해야한다.)
name: Cnergy Backend CI/CD
on:
push:
branches: [dev]
jobs:
ci:
runs-on: ubuntu-latest
steps:
- name: Checkout source code
uses: actions/checkout@v4
- name: Gradle 캐시 적용
uses: actions/cache@v3
with:
path: |
~/.gradle/caches
~/.gradle/wrapper
key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }}
restore-keys: |
${{ runner.os }}-gradle
- name: JDK 17 세팅
uses: actions/setup-java@v4
with:
java-version: '17'
distribution: 'temurin'
- name: YML 파일 세팅
env:
APPLICATION_PROPERTIES: ${{ secrets.APPLICATION_PROPERTIES }}
TEST_APPLICATION_PROPERTIES: ${{ secrets.TEST_APPLICATION_PROPERTIES }}
run: |
cd ./src
rm -rf main/resources/application.yml
mkdir -p test/resources
echo "$APPLICATION_PROPERTIES" > main/resources/application.yml
echo "$TEST_APPLICATION_PROPERTIES" > test/resources/application.yml
- name: gradlew 권한 부여
run: chmod +x gradlew
- name: 테스트 수행
run: ./gradlew test
- name: 스프링부트 빌드
run: ./gradlew build
- name: Docker Buildx 세팅
uses: docker/setup-buildx-action@v3
- name: NCP 레지스트리 로그인
uses: docker/login-action@v3
with:
registry: ${{ secrets.NCP_CONTAINER_REGISTRY }}
username: ${{ secrets.NCP_ACCESS_KEY }}
password: ${{ secrets.NCP_SECRET_KEY }}
- name: 도커 이미지 빌드 후 푸시
if: success()
uses: docker/build-push-action@v6
with:
context: .
file: ./Dockerfile
push: true
tags: ${{ secrets.NCP_CONTAINER_REGISTRY }}/cnergy-backend:${{ github.sha }}
platforms: linux/amd64,linux/arm64
- name: NCP 접속 후 이미지 다운로드 및 배포
if: success()
uses: appleboy/ssh-action@master
with:
host: ${{ secrets.NCP_HOST }}
username: ${{ secrets.NCP_USERNAME }}
password: ${{ secrets.NCP_PASSWORD }}
port: ${{ secrets.NCP_PORT }}
script: |
docker pull ${{ secrets.NCP_CONTAINER_REGISTRY }}/cnergy-backend:${{ github.sha }}
sudo chmod +x ./deploy.sh
export NCP_CONTAINER_REGISTRY=${{ secrets.NCP_CONTAINER_REGISTRY }}
export GITHUB_SHA=${{ github.sha }}
./deploy.sh
각 작업에 대해 알아보자.
0.
on:
push:
branches: [dev]
- dev 브랜치로 push가 발생할 때 아래 작업을 수행한단 의미!
- 직접 dev로 push를 하거나, dev로 pr을 남긴 뒤 merge를 하면 스크립트가 동작한다!
1. Checkout source code
- GitHub Actions에서 소스 코드를 가져오는 작업
- 현재 커밋된 코드를 runner로 가져온다.
2. Gradle 캐시 적용
- Gradle 캐시를 설정하여 의존성 다운로드 시간을 줄인다.
3. JDK 17 세팅
- JDK 17을 설정하는 작업
4. YML 파일 세팅
- 환경 변수를 통해 application.yml 파일을 설정한다.
- APPLICATION_PROPERTIES와 TEST_APPLICATION_PROPERTIES 환경 변수를 각각 main/resources/application.yml과 test/resources/application.yml 파일로 저장한다.
5. gradlew 권한 부여
- Gradle Wrapper(gradlew)에 실행 권한을 부여한다.
6. 테스트 수행
- ./gradlew test 명령어로 테스트를 실행한다.
- test가 실패하면 이후 작업이 실행되지 않는다.
7. 스프링부트 빌드
- 프로젝트를 빌드한다.
- 빌드된 파일을 이후 Docker 로 설정한다.
8. Docker Buildx 세팅
- 도커 빌드를 위한 Docker Buildx를 설정한다.
9. NCP 레지스트리 로그인
- NCP 레지스트리에 로그인해 Docker 이미지를 푸시할 수 있도록 권한을 설정한다.
10. 도커 이미지 빌드 후 푸시
- Docker 이미지를 빌드하고 NCP 레지스트리에 푸시한다.
- 현재 커밋의 해시값을 태그로 사용해 도커 이미지를 구분한다.
앞에서 환경변수를 잘 설정했다면 여기까지는 문제 없이 잘 따라왔을 것이다!
마지막 10번 단계에서 deploy.sh 파일이 있다.
sh파일은 shell 파일로 셸 스크립트를 작성한 파일이다.
간단히 말하면 운영체제(우린 리눅스)에서 실행할 명령어를 미리 적어놓은 파일이다.
우리가 수동으로 배포를 하게되면 직접 서버에 들어가 도커 파일을 다운받고 도커를 실행시켜야 한다.
매번 이런 작업을 수동으로 진행할 순 없으니, 셸 스크립트를 미리 작성해서 해당 sh 파일을 cicd 할때마다 실행시키면 된다!
sh파일은 서버에 생성하면 된다.
sh 파일 예시
#!/bin/bash
# 환경 변수 설정
IMAGE_TAG=${NCP_CONTAINER_REGISTRY}/cnergy-backend:${GITHUB_SHA}
LATEST_TAG=${NCP_CONTAINER_REGISTRY}/cnergy-backend:latest
CONTAINER_NAME="cnergy-backend"
echo "Deploy script started..."
# 현재 실행 중인 컨테이너가 있으면 중지 및 삭제
if [ "$(docker ps -q -f name=$CONTAINER_NAME)" ]; then
echo "Stopping and removing existing container..."
docker stop $CONTAINER_NAME
docker rm $CONTAINER_NAME
fi
# 커밋 해시값에 해당하는 이미지가 있는지 확인
echo "Checking if image with tag ${IMAGE_TAG} exists..."
if docker pull $IMAGE_TAG; then
echo "Image with tag ${GITHUB_SHA} found. Running the container..."
docker run -d --name $CONTAINER_NAME -p 80:8080 $IMAGE_TAG
else
echo "Image with tag ${GITHUB_SHA} not found. Pulling the latest image..."
docker pull $LATEST_TAG
echo "Running the latest image..."
docker run -d --name $CONTAINER_NAME -p 80:8080 $LATEST_TAG
fi
echo "Deployment completed."
현재 우리 서비스의 이름이 cnergy-backend 여서 cicd 스크립트, shell 파일에 모두 cnergy-backend로 이름이 설정되어 있다.
이름은 자유니까 편하게 설정하면 된다!
그래서 이제 배포 스크립트도 다 작성을 했다!!!
환경변수 값들과 배포를 위해 사용했던 환경들을 AWS로 바꾸면 AWS에 배포를 할 수 있는 것이다!
이 과정을 적을 때 목표는 이해는 일단 됐고, 배포부터 하자! 였기에 위 과정을 쭉 따라왔다면 일단 배포는 될 것이다.
내가 작성했던 ci 스크립트의 내용은 내가 작성한 내용일뿐 답이 아니다.
이후 각자 입맛에 맞게 스크립트를 수정하면 된다! ㅎㅎ
4. NCP를 사용하며 만족했던 부분과 아쉬운 부분
👍 만족한 부분
1. 한글
- Naver에서 만들어서 그런지 한글 문서가 잘 되어있어서 편했다.
2. 자세한 문서
- 대부분 서비스가 자세한 사용 예시가 있고 설명이 있어서 따라하기 편했다.
🥲 아쉬운 부분
1. 비싼 요금
- 크레딧 제공 없이 학생이 사용하기엔 비싼 감이 있다.. 무료나 낮은 요금으로 서비스 제공이 많아진다면 더 많은 사람들이 사용하게 될거같다!
2. 사용자가 적다보니 레퍼런스가 없다
- 아무래도 사용자가 적다보니 몇몇 서비스엔 레퍼런스가 적었다. 그러나 공식 문서가 잘 되어있어 대부분 공식 문서를 통해 문제를 해결할 수 있었다.
5. 남은 기간 목표
다시한번 큐시즘과 Naver에 고마운 마음을 전하고 싶다.
대부분 학생들은 AWS만을 사용해봤을텐데 좋은 기회를 얻어 NCP를 사용했다.
크레딧을 받고 내가 써보고 싶던 여러 서비스(레지스트리 , AI)를 사용할 수 있어서 기쁘다!
레퍼런스가 많이 없다고 단점을 적었는데, 동시에 내가 레퍼런스를 좀 많이 적어봐야지! 생각을 하고 있다.
지금은 못적었지만 밋업이 끝나고 시간이 날때마다 사용했던 NCP 기술들에 대한 내용을 정리해야겠다.
좋은 팀원들을 만나 즐겁게 개발하고 프로젝트를 진행하는 요즘이다.
아직 모든 기능 구현이 끝난 것은 아니기에 열심히 남은 기능을 구현해야겠다.
기능 구현이 끝났다고 끝인가?
아니다.
코드 리팩토링, 멘토님의 리뷰를 적용하기, 여러 성능 테스트 등을 해야한다.
할 일이 많다~!
우리 멋진 팀원들에게 하고싶은 말이 산더미지만 그런 얘기들은 밋업이 끝난 최종회고에서 해야겠다.
끝까지 최선을 다해서 기억에 남는 행복한 프로젝트가 되었으면 싶다!
우리 팀 Cnergy와 밋업 프로젝트로 바쁜 모든 큐시즘 30기 친구들 모두 힘내고 끝까지 달려보자!!!