728x90
반응형

1. 기존에 서버를 배포하던 방식

기존에는 수동으로 배포를 진행하였다. 보통 배포하는 서버는 EC2를 사용하고, Docker를 이용해서 배포하였다.

  1. Gradle을 사용해서 Spring 프로젝트를 빌드하여 jar 파일을 만든다.
  2. Dockerfile을 사용하여서 도커 이미지를 만든다.
    1. 사용한 Dockerfile은 다음과 같다.
    2. FROM openjdk:11 ARG JAR_FILE=build/libs/*.jar COPY ${JAR_FILE} app.jar ENTRYPOINT ["java","-jar","/app.jar"]
  3. 생성된 Docker 이미지를 Docker hub에 push한다.
  4. EC2를 ssh를 통해 접속한다
  5. EC2에서 docker hub의 이미지를 pull해서 가져온다.
  6. sudo docker pull (도커HOST)/(이미지 이름) // sudo docker pull jakeheon/MZTI
  7. docker run을 통해 실행한다.
  8. // 그냥 실행 sudo docker run jakeheon/MZTI // 백그라운드 실행 sudo docker run -it -d jakeheon/MZTI // 포트 80으로 실행 sudo docker run -it -d -p 80:8080 jakeheon/MZTI

문제점

해당 방식은 수동으로 진행하는 것이라서 시간도 걸리고 불편하다. 그리고 여러 사람이 같이 협업을 할 경우 충돌 문제가 생길 수 있다. 특정 branch에 올릴 때 해당 branch를 배포 자동화하려고 하였다.

2. GithubAction 사용해서 자동으로 CI/CD 진행하기

1. GithubAction이란?

자동으로 CI, CD를 도와주는 Github 내장 프로그램

2. GithubAction VS Jenkins

Github Actions or Jenkins? Making the Right Choice for You

3. GithubAction으로 간단한 Spring Project 배포하기

  1. 먼저 Spring Project를 하나 만들고 Github Repository와 연결해준다.
    1. 사용 기술 : java 11, springboot 2.7.15
  2. github에 직접 들어가서 Action탭에서 yml파일을 작성해준다.
    1. 해당 yml 파일에 적힌대로 실제 코드가 git에 push되면 알아서 실행을 해준다.
    2. 만약 실패할 경우… 메일로 실패했다고 전달해온다. (며칠간 100개는 받은것 같다..)
    3. 먼저 아래의 코드를 실행할 때 secret키들은 따로 저장해두어야 한다.
      1. Github Repository에 setting에 action setting에 들어가서 설정할 수 있다.
      2. 이 부분은 다른 블로그에도 많이 있으므로 따라하면 된다.
    4. 정말 간단한데.. 하나씩 test해보면서 로그를 보고 어디가 문제인지 찾으면 된다. (너무 고생한것들을 트러블 슈팅에 기록하였다.)
    5. 여기서 ‘- name: ‘ 이게 하나의 단위이다. 이 상태대로 stage가 나누어지기 때문에 log를 볼때 해당 사항을 잘 살펴보면 된다.
    6. name: Java CI with Gradle on: push: branches: [ "main" ] pull_request: branches: [ "main" ] permissions: contents: read jobs: build: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - name: Grant execute permission for gradlew and build run: | chmod +x gradlew ./gradlew build - name: Set up JDK 11 uses: actions/setup-java@v3 with: java-version: '11' distribution: 'temurin' - name: init with Gradle uses: gradle/gradle-build-action@v2 - name: Build with Gradle run: | chmod +x ./gradlew ./gradlew clean build - name: Set up Docker Buildx uses: docker/setup-buildx-action@v1 with: version: v0.7.0 - name: Docker build & push to docker repo run: | docker login -u ${{ secrets.DOCKER_HUB_USERNAME }} -p ${{ secrets.DOCKER_HUB_PASSWORD }} docker build -t jakeheon/githubaction -f Dockerfile . docker push jakeheon/githubaction - name: Build and deploy uses: appleboy/ssh-action@master id: deploy with: host: ${{ secrets.HOST }} username: ubuntu key: ${{ secrets.KEY }} envs: GITHUB_SHA script: | sudo docker stop $(sudo docker ps -aq) sudo docker rm -f $(docker ps -qa) sudo docker pull jakeheon/githubaction sudo docker run -it -d -p 80:8080 jakeheon/githubaction
  3. yml파일 내용 간단 설명gradle로 빌드할 수 있도록 권한을 주는 코드이다. 만약 이 부분에서 잘못된다면 아마 Spring project의 위치 문제일 것이다. run 제일 첫번째 줄에 directory 실행 위치를 찍어보면 알 수 있다. 아래 트러블 슈팅에서 더 자세히 설명하겠다.차례대로 JDK 11을 사용하겠다는 의미와 Gradle을 통해 build하는 과정이다. 아마 이 부분은 위와 같이 directory 문제가 아니라면 오류가 생기지 않을 것이다.Docker를 통해 로그인을 하고, build한 뒤 push 하는 코드이다. Dockerfile의 위치를 잘 확인해야 한다. 지금 여기에는 jakeheon/githubaction으로 내가 만들 이미지로 되어있는데 해당 내용도 secret에 두는 것이 좋은것 같다. 본인이 원하는 호스트와 이미지를 Dockerfile을 이용해서 만드는 코드이다.
    • EC2에 접속해서 배포하는 코드이다. EC2에 접속할 때 필요한 HOST와 KEY를 secret에 저장해둔다. pem.key의 경우 EC2에서 다운받은걸 모두 복사해서 secret에 넣어두면 된다. HOST는 접속하는 EC2의 주소를 의미하므로 ip주소나 DNS주소를 입력하면 된다.
    • 나머지는 원래 배포하던 코드랑 같다. 먼저 실행하고 있는 docker container를 stop 시켜준 뒤, 컨테이너를 삭제하고, 이미지를 Pull 받아서 실행한다.
  4. - name: Build and deploy uses: appleboy/ssh-action@master id: deploy with: host: ${{ secrets.HOST }} username: ubuntu key: ${{ secrets.KEY }} envs: GITHUB_SHA script: | sudo docker stop $(sudo docker ps -aq) sudo docker rm -f $(docker ps -qa) sudo docker pull jakeheon/githubaction sudo docker run -it -d -p 80:8080 jakeheon/githubaction
  5. - name: Set up Docker Buildx uses: docker/setup-buildx-action@v1 with: version: v0.7.0 - name: Docker build & push to docker repo run: | docker login -u ${{ secrets.DOCKER_HUB_USERNAME }} -p ${{ secrets.DOCKER_HUB_PASSWORD }} docker build -t jakeheon/githubaction -f Dockerfile . docker push jakeheon/githubaction
  6. - name: Set up JDK 11 uses: actions/setup-java@v3 with: java-version: '11' distribution: 'temurin' - name: init with Gradle uses: gradle/gradle-build-action@v2 - name: Build with Gradle run: | chmod +x ./gradlew ./gradlew clean build
  7. - name: Grant execute permission for gradlew and build run: | chmod +x gradlew ./gradlew build

3. 트러블 슈팅

1. Spring 프로젝트와 Dockerfile 위치 문제

문제 원인

매번 내가 github repository를 만들 때 잘못하고 있었던 것이다.. (이번으로 다른 프로젝트도 수정해야 할 것같다)

.git의 위치를 항상 Spring project 바깥에 두어서 github action이 해당 프로젝트에 들어올려면 폴더 하나를 더 거쳐야하는 문제가 생겼었다.

예를 들자면, TestRepositorySpring이라는 Spring boot 프로젝트를 생성했을 때 repository이름도 TestRepository라고 한다면 TestRepository 에 .git 파일과 TestRepositorySpring이라는 스프링 프로젝트 파일이 존재하는 것이다. 그럼 github action을 실행하기 위해서는 cd 명령어로 TestRepositorySpring으로 들어가야하는 문제가 생긴다…

동일하게 Dockerfile을 통해 빌드할 때도 Dockerfile을 TestRepositorySpring 안에 있으므로 안되는 문제가 생긴다.

보통 다른 블로그나 글들을 찾아봤을때 나와 같은 문제는 없었던 것 같다. (나만 계속 이상하게 하고 있는 것이므로..) 호오오옥시 나랑 동일한 문제가 있는 것 같다면 아래 방법으로 해결하면 된다.

해결 방법

  1. Spring Project 안에 들어가서 실행해야할 Dockerfile빌드라던가 jar 빌드 등을 할 때, yml에 cd를 통해 해당 폴더로 이동 뒤에 실행한다. (실수하거나 깜빡할 수 있으므로 2번을 그냥.. 하는게 맞는것 같다)
  2. .git을 Spring 프로젝트 안에 둔다.

2. jar 파일 빌드 문제(Error: Invalid or Corrupt jar file /app.jar)

문제 원인

이건 신기하게 Action은 다 성공해서 체크 모양이 떴는데 실제 반영이 안된 문제였다. 그래서 뭐가 문제인지 한참을 고민하다가 EC2에서 docker pull을 받아온 다음에 docker를 실행시켰더니 다음과 같은 메시지가 떴었다.

로그를 봤을 때 빌드는 성공적으로 된 것을 확인했는데 저런 오류 메시지가 발생하였다면 .jar파일이 겹쳐서 생긴문제이다. 즉, gradle로 빌드할 때 (프로젝트 이름)-plain.jar도 생기고, (프로젝트 이름).jar 2개가 생기므로 겹쳐서 오류가 발생한 것이다. 이걸 하나로 만들어줘야 해결된다.

해결 방법

build.gradle에 다음과 같이 작성하면 plain.jar는 생기지 않는다.

jar {
    enabled = false
}

3. 기존 실행하던 컨테이너 중단, 종료 문제

문제 원인

이제 진짜 다 되었다! 했을 때 생긴문제.. Action도 다 잘되고 성공한 것을 보고 처음 배포했을 때 서버ip주소로 잘 접속되는 것까지 확인했는데 생긴 문제다. 이제 코드를 바꿔서 push해서 테스트 해봐야지~ 했는데 실패했다. (바뀌지 않았다.)

실제 EC2에 접속해서 docker 로그를 확인해보니 기존에 실행하던 이미지와 겹쳐서 실행이 안되던 것이였다. 즉, 기존에 잘 돌아가고 있는 컨테이너를 중지하고 새로 배포한 이미지를 컨테이너에 올려야되는데 중지를 안해서 생긴 문제였다. (물론 위에 yml 파일은 해당 오류를 해결한 코드이다.)

해결 방법

yml에 Build and deploy script 맨 위에 다음과 같은 코드를 추가한다. docker container를 stop하고 remove하는 코드이다.

sudo docker stop $(sudo docker ps -aq)
sudo docker rm -f $(docker ps -qa)

4. EC2에 접속할 때 필요한 pem.key를 어떻게 두어야할지 몰랐을 때

문제 원인과 해결 방법

이것도 처음에 너무 고민이였다.. 사실 pem key를 제대로 이해를 안하고 있었던 것 같다. pem key도 단순히 해시 알고리즘을 통해서 바뀐 String일텐데.. 그 생각을 못했던 것 같다. pem.key를 그대로 열어서 secret에 모두 복사해서 붙여넣으면 된다!

4. 앞으로 해결할 기능들

1. Docker-Compose를 이용하여서 데이터베이스와 함께 배포해보기

2. jar로 빌드된 것을 cache를 이용하여서 속도를 빠르게 하기

3. Spring 프로젝트 이외에 React나 언어의 프로젝트도 배포해보기

4. 온프레미스 환경에 배포해보기

728x90
반응형

'백엔드' 카테고리의 다른 글

[JWT] JWT 인증을 사용하는 이유  (2) 2023.10.04
세션  (0) 2023.08.25
[AWS] Elastic BeanStalk 배포와 Trouble Shooting  (0) 2023.05.23
[Spring] Spring으로 웹 개발을 진행할 때 알아야할 정보  (0) 2023.05.23
Gradle  (0) 2022.12.27

+ Recent posts