본문 바로가기
IT

[😃 배포완료] AWS EC2 를 이용한 Server 배포하기 (Github Actions, SCP, MySQL)

by 호야투은하 2025. 1. 15.
반응형

https://github.com/haeunsong/welcome-game-back

 

GitHub - haeunsong/welcome-game-back

Contribute to haeunsong/welcome-game-back development by creating an account on GitHub.

github.com

 

기초적인 배포 강의들을 듣고 나니 mysql 을 사용한 프로젝트도 배포할 수 있을 것 같다는 생각이 들었다.
GitHub Actions 를 이용하여 CI/CD 를 구성하고, 배포 자동화를 설정한다. 시작!

단계별로 쭉 회고해보며 마주한 문제들을 적어보자.

0. 큰 흐름

  1. AWS EC2 를 이용한 인스턴스 생성 (이건 https://velog.io/@meyame/posts 참고)
  2. 로컬에 있는 코드를 Github 레포지토리에 PUSH (프로젝트 상단에 .github/workflows/deploy.yml 파일도 추가하여 Github Actions 사용)
  3. 환경변수 저장 (Github - Settings - Secrets and variables - Actions - New repository secret)
  4. 배포는 deploy.yml 의 단계대로 자동 실행
    1. github 레포지토리의 파일들 불러오기
    2. JDK 17 설치
    3. application.yml 파일 생성
    4. MySQL 설정
    5. gradle 을 사용하여 빌드
    6. 빌드된 파일을 SCP 를 이용하여 .jar 파일을 EC2 로 전송
    7. SSH 로 EC2 에 접속
    8. EC2 에 접속해서 java, mysql 등 기본 환경설정 구성
    9. 애플리케이션 실행(nohup 으로 백그라운드 실행)

 

1. 깃허브 레포지토리 설정 문제

 

원래는 welcome-game 이라는 큰 틀 안에 welcome-game-front  welcome-game-server 이런식으로 깃을 관리하려고 했다. 하지만, Github Actions 을 쓰다보니 프론트 따로, 백 따로 레포지토리를 관리하는게 편할 것 같다는 생각이 들었다.

처음에는 기존의 구조를 유지한 채, welcome-game 프로젝트의 최상단에 .github/workflows/deploy.yml 파일을 만들고 working directory 를 추가하여 github actions 경로를 설정해보려했지만, 생각보다 복잡해지는 것 같아서 결국 레포지토리를 분리했다.

 

2. application.yml 파일 관리

 

기본적으로 .gitignore 파일에 application.yml 을 등록해두었다. 그리고 기존에는 인텔리제이에서 환경변수로 따로 설정해둔 부분이 있었는데,


1. 어차피 내 컴퓨터에서만 이 프로젝트를 진행하게 될 것 같아서
2. github 에는 해당 파일을 올리지 않을 것이기 때문에


환경변수를 지우고 mysql 과 관련된 부분을 모두 하드코딩 해두었다.
(But, 이건 추후에 변경하는게 좋을 듯)

 

그리고 deploy.yml 파일에서 사용되는 ${{ secrets.MYSQL_PASSWORD }} 와 같은 부분들은 Github - Settings - Secrets and variables - Actions - New repository secret 에 저장해두었다.


설정한 변수들은 아래와 같다.

 

EC2_HOST: EC2 퍼블릭 IP
EC2_USERNAME: EC2 사용자 이름(예: ubuntu).
EC2_PRIVATE_KEY: .pem 파일 내용.
MYSQL_USERNAME, MYSQL_PASSWORD: MySQL 접속 정보.
APPLICATION_PROPERTIES: application.yml 내용.

 

3. 3306 포트 열어주는 인바운드 보안그룹 추가

 

지금까지 한 배포에서는 MySQL 을 추가하지 않았기 때문에 아래 사진의 보안그룹으로 충분했다.


하지만 MySQL 은 localhost:3306 을 사용하기 때문에 추가적으로 3306 포트도 열어주어야했다.


이렇게 총 5개의 인바운드 보안그룹을 사용한다.
(아웃바운드 보안그룹은 디폴트로 전체 포트/프로토콜/대상 열어주는 1개 존재)

 

4. pem 의 접근 권한 수정

로컬에서 $ ssh -i pem/welcome-game-server.pem ubuntu@13.124.172.186 명령어로 ec2 에 접근하려했는데 아래와 같은 오류가 발생했다.

WARNING: UNPROTECTED PRIVATE KEY FILE!          @
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
Permissions 0644 for 'pem/welcome-game-server.pem' are too open.
It is required that your private key files are NOT accessible by others.
This private key will be ignored.
Load key "pem/welcome-game-server.pem": bad permissions

 

이건 pem 파일의 권한 설정이 현재 0644로 너무 느슨해서 생기는 문제였다.
아래 명령어로 pem 파일의 권한을 0600으로 설정하였다.

$ chmod 600 pem/welcome-game-server.pem

5. 빌드 전에 mysql 설정 코드 추가

MySQL 설정

현재 배포 방식은 빌드 후 생성되는 jar 파일을 SCP 로 EC2 로 전송하는 방식을 사용하고 있다. 그렇기에 너무도 당연한 이야기지만, 빌드하기 전에 mysql 설정을 해주어야한다. Github Actions 의 mirromutth/mysql-action@v1.1 라이브러리를 사용했다.

      - name: MySQL 설정하기
        uses: mirromutth/mysql-action@v1.1
        with:
          host port: 3306
          container port: 3306
          mysql database: 'welcome_game_db'
          mysql root password: ${{ secrets.MYSQL_PASSWORD }}

나는 현재 사용자 이름이 root 이기 때문에 이렇게 적어주었다.

 

6. SSH(원격접속)로 EC2 에 접속하기

EC2_HOST, EC2_USERNAME, EC2_PRIVATE_KEY 로 EC2 에 접속하면 기본적으로 java, mysql 을 설정해주어야한다. 처음에는 이걸 하지 않아서 오류가 났다. deploy.yml 파일의 script 부분에 추가한 코드이다.

script: |
   sudo apt update
   sudo apt install -y openjdk-17-jdk
   sudo apt install -y mysql-server
   java -version
   sudo systemctl start mysql || true 

 

7. MySQL 에 접속하여 auth_socket -> mysql_native_password 플러그인으로 수정

오류

서버를 실행하다가 만난 오류 중에 다음과 같은 오류를 만났다.

[welcome-game-back] [main] o.h.engine.jdbc.spi.SqlExceptionHelper   : Access denied for user 'root'@'localhost'

사실 이 오류는 상당히 자주 만나는 오류인데, 때마다 이유는 달랐지만 이번에는 명쾌한 해답이 있었다.

원인

MySQL 이 auth_socket 플러그인을 사용하도록 설정되어있으면, 비밀번호 인증이 아닌 Unix 소켓 기반 인증만 허용된다.

스프링부트 애플리케이션은 일반적으로 비밀번호 기반 인증을 통해 데이터베이스에 연결한다. 하지만, auth_socket 설정은 비밀번호가 아닌 Unix 소켓 인증을 사용하기 때문에 문제가 발생한다.

스프링부트나 원격 클라이언트는 auth_socket 방식을 지원하지 않는다!

해결

auth_socket 플러그인을 mysql_native_password 플러그인으로 수정해주면 된다.

# mysql 접속
$ sudo mysql -u root
# 현재 root 사용자 설정 확인
> SELECT user, host, plugin FROM mysql.user WHERE user = 'root';
# 출력 예시
+------+-----------+-------------+
| user | host      | plugin      |
+------+-----------+-------------+
| root | localhost | auth_socket |
+------+-----------+-------------+
# 만약 auth_socket 로 되어있다면 mysql_native_password 로 바꾸어야한다.
> ALTER USER 'root'@'localhost' IDENTIFIED WITH mysql_native_password BY 'password';
> FLUSH PRIVILEGES;
# 변경 후 사용자 확인
> SELECT user, host, plugin FROM mysql.user WHERE user = 'root';
# 출력 예시
+------+-----------+-----------------------+
| user | host      | plugin                |
+------+-----------+-----------------------+
| root | localhost | mysql_native_password |
+------+-----------+-----------------------+

8. EC2의 MySQL 내에서 DB가 자동으로 생성되도록 설정

당연한 말이지만 현재 EC2 의 mysql 에는 내가 생성한 DB 가 없다. 직접 생성해줘도 되지만, application.yml 파일을 수정하여 자동으로 생성되도록 설정하는 방식이 더 편해보여서 택했다.

spring:
  datasource:
    url: jdbc:mysql://localhost:3306/welcome_game_db?createDatabaseIfNotExist=true
    username: root
    password: password
    driver-class-name: com.mysql.cj.jdbc.Driver

createDatabaseIfNotExist=true 이 옵션을 붙이면 DB 가 없을경우 자동으로 생성된다.

9. 오류 찾아내는 방법

deploy.yml 코드에 최종적으로 nohup 을 통해 서버를 실행시킬 때 아래와 같은 명령어를 사용한다.

nohup java -jar project.jar > ./output.log 2>&1 &

이는 project.jar 파일을 실행시키고, 그 표준출력 및 오류를 output.log 파일에 입력하는 명령어다.
output.log 파일을 확인하며 오류를 찾아내어갔다.

10. 결과

인스턴스를 생성하고 탄력적 IP 를 받았는데 IP주소:포트번호 이렇게 해서 접속하면 된다.
나는 swagger 를 사용했기 때문에, swagger 페이지를 띄웠다.

11. 추가 궁금증

Q. Github Actions 에서 JDK 설치(actions/setup-java) VS EC2 서버에서의 Java 설치(appleboy/ssh-action)의 차이는?

전자의 목적은 Github Actions의 빌드 환경에서 자바를 사용하기 위해 설치하는 것이다. 이 때는 EC2 서버가 아니라 GitHub 의 가상머신에 설치된다. Gradle 빌드를 실행하기 위해 필수적이다.

후자의 목적은 Spring Boot 애플리케이션을 실행하기 위해 JDK 를 설치한다. 빌드된 .jar 파일이 java 로 실행되기 때문에 당연히 있어야한다. EC2 서버에 JDK 가 설치된다.

GitHub Actions는 빌드 머신, EC2 서버는 애플리케이션이 실제로 배포되고 실행되는 환경이라고 생각하면 된다.

12. 코드

가장 핵심역할을 하는 application.yml 파일과 deploy.yml 은 아래와 같다.(민감한 정보 제외)

application.yml

spring:
  application:
    name: welcome-game-back
  datasource:
    url: jdbc:mysql://localhost:3306/welcome_game_db?createDatabaseIfNotExist=true
    username: root
    password: password
    driver-class-name: com.mysql.cj.jdbc.Driver
  jackson:
    date-format: yyyy-MM-dd
  jpa:
    hibernate:
      ddl-auto: update
    properties:
      hibernate:
        show_sql: true
        format_sql: true
        dialect: org.hibernate.dialect.MySQLDialect
    open-in-view: false

deploy.yml

name: EC2 로 배포하기

on:
  push:
    branches:
      - main

jobs:
  Deploy:
    runs-on: ubuntu-latest
    steps:
      - name: Github Repository 에 올린 파일들을 불러오기
        uses: actions/checkout@v4

      - name: 잘 되고 있는지 Test 하기
        run: |
          ls
          pwd

      - name: JDK 17버전 설치
        uses: actions/setup-java@v4
        with:
          distribution: temurin
          java-version: 17

      - name: application.yml 파일 만들기
        run: |
          pwd
          mkdir -p src/main/resources
          echo "${{ secrets.APPLICATION_PROPERTIES }}" > src/main/resources/application.yml

      - name: MySQL 설정하기
        uses: mirromutth/mysql-action@v1.1
        with:
          host port: 3306
          container port: 3306
          mysql database: 'welcome_game_db'
          mysql root password: ${{ secrets.MYSQL_PASSWORD }}

      - name: 테스트 및 빌드하기
        run: |
          ./gradlew clean build

      - name: 빌드된 파일 이름 변경하기
        run: |
          mv ./build/libs/*SNAPSHOT.jar ./project.jar

      - name: SCP로 EC2에 빌드된 파일 전송하기
        uses: appleboy/scp-action@v0.1.7
        with:
          host: ${{ secrets.EC2_HOST }}
          username: ${{ secrets.EC2_USERNAME }}
          key: ${{ secrets.EC2_PRIVATE_KEY }}
          source: project.jar
          target: /home/ubuntu/welcome-game-server/tobe

      - name: SSH(원격 접속)로 EC2에 접속하기
        uses: appleboy/ssh-action@v1.2.0
        with:
          host: ${{ secrets.EC2_HOST }}
          username: ${{ secrets.EC2_USERNAME }}
          key: ${{ secrets.EC2_PRIVATE_KEY }}
          script_stop: true
          script: |
            sudo apt update
            sudo apt install -y openjdk-17-jdk
            sudo apt install -y mysql-server
            java -version
            sudo systemctl start mysql || true          
            rm -rf /home/ubuntu/welcome-game-server/current
            mkdir /home/ubuntu/welcome-game-server/current
            mv /home/ubuntu/welcome-game-server/tobe/project.jar /home/ubuntu/welcome-game-server/current/project.jar
            cd /home/ubuntu/welcome-game-server/current
            sudo fuser -k -n tcp 8080 || true
            nohup java -jar project.jar > ./output.log 2>&1 &
            rm -rf /home/ubuntu/welcome-game-server/tobe
반응형

댓글