이번 프로젝트에서는 AWS의 ElasticBeanstalk 을 이용해 application을 배포하고
github actions를 이용해 aws에 무중단 배포할 수 있는 환경을 구축하였다.
AWS의 서비스에 관해서는 이미 다룬 적이 있으니 생략하고
https://youarethebestcoding.tistory.com/119
프로덕션 배포 - 서비스 아키텍처
EC2 (Elastic Computer Cloud) : 애플리케이션을 실행할 수 있는 서버 컴퓨터라고 생각하면 된다. 우리는 EC2로 서버를 실행시키고 클라이언트가 애플리케이션을 실행하려면 EC2의 IP나 EC2에서 제공하는
youarethebestcoding.tistory.com
이번 포스팅에서는
aws cli로 환경을 생성하는 두가지 방법을 모두 설명하고
github actions 까지 다뤄본다.
#배포를 위한 애플리케이션 환경 설정
- properties(yaml) 파일 분리
배포를 할 때의 환경과 개발의 환경이 다른 경우
profile을 분리해주어야한다.
스프링부트의 profile은 'application-' 접두어 뒤에 단어로 구분한다.
보통 application- [local, dev, prod...] 와 같이 naming 한다.
본인은 개발환경의 profile을 local로 해주었다.
보통 profile을 분리하는 이유가 개발환경과 배포환경의 설정, 연동할 db 때문에 분리하게 되는데
profile을 분리하고 바로 실행을 하려하면 스프링부트는 어떤 profile로 실행해야할지 알지 못하기 때문에 애플리케이션을 실행하지 못한다.
profile을 설정하는 방법은
application.properties 파일을 작성해서
<application.yaml>
spring:
profiles:
active: local
<application.properties>
spring.profiles.active=local
active할 profile을 명시해주거나
이클립스 기준
Run-Run configurations에서
Profile을 지정해주면 된다.
profile이 없다면 빈칸으로 되어있을것이고
application.properties를 사용하고 싶다면 Profile에 default를 선택하면 된다.
만약 application.properties와 -dev, -local이 있고 default에 active profile이 명시되어있다면
default를 사용하거나 사용할 profile을 직접 선택해주면 된다.
보통 application.properties에
모든 환경에서 공통으로 설정할 부분을 적고 profile에 각 프로필마다 사용할 설정을 하기 때문에
application.properties에 active할 profile을 지정해주고 default를 run하는게 좋을것 같다.
server.port=5000
spring.jpa.database=MYSQL
spring.jpa.show-sql=true
spring.jpa.hibernate.ddl-auto=update
spring.datasource.url=jdbc:mysql://${rds.hostname}:${rds.port}/${rds.db.name}
spring.datasource.username=${rds.username}
spring.datasource.password=${rds.password}
[ application-prod.properties ]
일단 aws의 nginx는 5000포트를 default로 사용하기 때문에
포트를 5000번으로 설정하고
dev 환경의 데이터베이스는 학원의 oracle db를 사용했지만
prod 환경에서는 aws rds의 mysql을 사용할 것이기 때문에
database를 MYSQL로 변경하고
url, username, password는 rds 콘솔에서 엔드포인트, 포트를 확인하여 하드코딩할 수 있지만
rds로부터 변수를 받아 입력할 수 있게
${rds.variable}를 이용한다.
env.properties는 민감한 properties들을 입력해놓은 파일이다.
@Configuration
@PropertySources({@PropertySource("classpath:envs.properties")})
public class PropertyConfig {
}
env.properties는 gitignore에 등록하고 jar 파일을 배포하고
이후 github actions을 통해 무중단 배포를 할 때는 git에 올라오지 않기 때문에
git의 repository variable을 이용해 동적으로 파일을 생성해서 배포할 것이다.
- build.gradle에 mysql을 사용하기 위해 mysql connector를 import 해준다.
#cors 을 위한 설정
// 스프링 서버 전역적으로 CORS 설정
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOrigins("http://localhost:5000") // 허용할 출처, 이후 배포된 사이트의 도메인을 추가
.allowedMethods("GET", "POST", "PUT", "DELETE") // 허용할 HTTP method
.allowCredentials(true) // 쿠키 인증 요청 허용
.maxAge(3000); // 원하는 시간만큼 pre-flight 리퀘스트를 캐싱
}
#AWS CLI 다운로드 및 배포
AWS 계정 생성 후 AWS console에 IAM 으로 1로그인
++IAM ( Identity and Access Management )
기업에서 많은 개발자가 접근할 수 있는 계정이 있어야 하는데 만약 기업 계정에 모든 개발자가 아이디와 비밀번호를 알고 접근할 수 있게 하는것은 위험하므로
사람마다 역할마다 다른 접근 권한을 부여할 수 있게 한다.
사람에게는 아이디와 비밀번호, 프로그램에게는 액세스 키와 비밀 액세스 키를 제공
AWS CLI, EB CLI 설치를 위해 python 설치
AWS CLI, EB CLI는 파이썬 기반으로 작동
파이썬 설치
https://www.python.org/downloads/
Download Python
The official home of the Python Programming Language
www.python.org
파이썬 설치 버전 확인
python --version 커맨드 입력
AWS CLI 설치
https://aws.amazon.com/ko/cli/
Command Line Interface - AWS CLI - AWS
aws-shell은 명령줄 셸 프로그램으로서, AWS 명령줄 인터페이스를 사용하는 새로운 사용자와 고급 사용자 모두에게 도움이 되는 편의 기능 및 생산성 기능을 제공합니다. 주요 기능은 다음과 같습
aws.amazon.com
설치 후 터미널 재실행 후 aws --version 확인
콘솔에 로그인한 후 서비스 검색창에 IAM 검색하여 IAM 대시보드로 들어간다.
우리가 사용할 CLI 는 AWS에 접근해 우리의 커맨드를 대신 실행해줄 프로그램이므로 IAM으로부터 액세스 키와 비밀 액세스 키를 발급 받아야 한다.
액세스 관리 - 사용자 - 사용자 생성
사용자 이름을 입력하고 IAM 사용자를 생성해 AWS Management Console에 접근 권한을 제공한다.
++ AWS Management Console 접근 권한 제공 체크할 필요 없다.
aws가 바뀌면서 프로그래밍 방식 액세스 키를 발급 받는 작업은 사용자를 생성한 후 한다.
AWS Management Console 접근 권한은 접근 비밀번호를 지정하는 사용자가 되는 것이다.
CLI는 프로그램이라 필요가 없다.
직접 정책에 연결을 선택하고
AdministratorAccess 정책을 선택하고 다음으로 넘어간다.
태그를 생성하고 싶다면 생성하고 다음으로 넘어간다.
태그는 사용자에 추가될 수 있는 키-값 페어로 이메일이나 직급 등의 내용을 포함하고 싶을 때 사용할 수 있다.
++ 정책 Policy
권한을 나열한 문서
AdministratorAccess는 모든 AWS rss에 접근할 수 있는 모든 권한을 준다는 뜻이다.
AdministratorAccess-Amplify는 Amplify에 접근할 수 있는 모든 권한을 준다는 뜻이다.
생성된 사용자를 클릭해 세부 페이지로 들어오면 액세스키가 나오고 액세스 키가 없다면 생성하는 버튼이 나온다.
CLI를 선택하고 설명 태그 값에는 CLIaccessKey라고 입력했다. (선택사항)
발급받은 액세스키와 비밀 액세스 키를 메모해둔다.
비밀 액세스 키는 다시 확인할 수 없다.
터미널에서 aws configure 명령어로 aws cli를 설정해준다.
C:\Users\USER>aws configure
AWS Access Key ID [None]:
AWS Secret Access Key [None]:
Default region name [None]: ap-northeast-1
Default output format [None]: json
Default region : AWS 데이터센터가 있는 장소로 서비스를 실제로 사용할 사용자와 서비스가 호스팅되고 있는 데이터 센터가 가까울수록 네트워크 대기 시간이 짧아진다. 사용자가 한국에 거주할 확률이 높다면 ap-northeast-2를 선택하면 된다.
AWS CLI는 AWS의 모든 서비스를 위한 CLI 이고
EB CLI는 일래스틱 빈스톡만을 위한 CLI이다.
EB CLI로 일래스틱 빈스톡 환경을 구축하고 설정할 수 있다.
pip 를 이용해 awsebcli 설치
pip install awsebcli --upgrade --user
설치한 후 Warning에 환경변수를 추가하라고 나온다.
환경변수의 하단에 위치한 시스템 변수 Path에서
%USERPROFILE%\AppData\Roaming\Python\Python11\Scripts를 추가한다.
C:\Users\USER\AppData\Roaming\Python\Python311\Scripts도 추가해준다.
파이썬 12는 지금 awsebcli 설치하면 오류가 생긴다.
버전 차이 때문에 그런거 같은데 진짜 너무 고생했다...
파이썬 11로 다운그레이드하고 다시 시도해서 겨우 설치했다.
프로젝트의 위치에서 eb init 명령어로 일래스틱 빈스톡 환경 초기화
select default region
일래스틱 빈스톡이 어느 리전에 이 애플리케이션의 환경을 생성해야 하는지 물어보는 것
이후 생성되는 모든 리소스는 지금 선택하는 리전에 생성된다.
do you want to set up SSH for your instance?
일래스틱 빈스톡을 이용해 생성된 ec2에 접근하기 위해 ssh를 설정할 것인지 물어보는 것
일단 이 프로젝트에선 설정하지 않는다.
init을 완료하면 project directory에 .elasticbeanstalk 디렉터리가 생성되고
그 안에 init에서 설정한 내용이 들어있는 config.yml 파일이 생성된다.
이제 배포할 애플리케이션을 jar 파일로 build해주어야 한다.
1. cmd cli
프로젝트의 위치에서
gradlew build
2. IDE tool 이용하기
eclipse 기준
gradle tasks - build - build (또는 bootJar)
build 이후에
디렉토리의 build/llibs에 jar 파일이 생성된다.
다시 .elasticbeanstalk 의 config.yml 파일에
deploy:
artifact: build/libs/danaga-0.0.1-SNAPSHOT.jar
deploy:artifact: jar파일 을 추가한다.
eb create --database --elb-type application --instance-type t2.micro 명령어로 환경 생성
--database : 생성하는 환경에 RDS 데이터베이스를 만들기 위한 매개변수, 자동으로 데이터베이스가 생성된다.
--elb-type : 일래스틱 로드 밸런서 타입 매개변수, application,, classic, network가 있다.
https://aws.amazon.com/ko/elasticloadbalancing/features/?nc=sn&loc=2
네트워크 트래픽 분산 - Elastic Load Balancing - Amazon Web Services
aws.amazon.com
--instance-type : 애플리케이션이 동작할 인스턴스 타입, 프리티어에서 제공하는 t2.micro 사용
eb create --database --elb-type application --instance-type t2.micro
DNS CNAME prefix는 url이므로 이미 사용중인 url과 중복될 수 없어 본인이 고유값을 입력해준다.
would you like to enable spot fleet requests for this environment : N
정상적인 경우라면 성공적으로 배포했을텐데
나는 배포에 실패하고 severe 상태가 되었다.
사이트에 접속하면 502 bad gateway가 뜬다.
이럴때는
로그를 확인하면 된다.
로그 요청을 눌러서 발행된 로그에 다운로드를 클릭해서 로그를 확인할 수 있다.
나같은 경우는 application profile을 설정하지 않아서 배포에 실패했다.
프로젝트 당시 처음 배포했을 때는 thymeleaf 템플릿에 문제가 있어 로그를 계속 확인하면서 몇번을 고쳤다.
개발환경에서는 타임리프에 아무 문제 없고 사이트의 서비스에 아무 문제가 없었는데
배포할때는 개발환경에서 문제가 되지 않는 사소한 표현식에서 문제가 되었다.
#Github actions
Github action은 repository에서 workflow를 자동으로 할 수 있게 지원하는 깃헙의 툴이다.
workflow는 event, runner, jobs와 steps으로 이루어져있다.
event가 발생하면 runner가 job을 실행하고 job은 step들로 이루어져있다.
하나의 runner는 하나의 job을 실행하고 step은 순차적으로 진행된다.
그렇기 때문에 step끼리는 데이터가 전달될 수도 있다.
job내의 step들은 순차적으로 진행되지만 job끼리는 기본적으로 독립적으로 진행된다.
물론 어떤 job이 실행된 이후에 실행되어야할 다른 job이 있다면 packaging 하여 종속시킬수 있다.
GitHub Actions 이해 - GitHub Docs
GitHub Actions is a continuous integration and continuous delivery (CI/CD) platform that allows you to automate your build, test, and deployment pipeline. You can create workflows that build and test every pull request to your repository, or deploy merged
docs.github.com
#secrets and variables
github엔 민감한 정보를 secret으로 설정하고 변수처럼 사용할 수 있는 기능이 있다.
repository의 setting - security - secrets and variables - actions - new repository secret
위에 배포환경 profile에 대해 설명할 때 나온 env.properties 와 application.properties를 애플리케이션이 아닌
secret에 설정하고 workflow에서 배포할 때 파일을 만든 후 애플리케이션을 build 한다.
배포 과정에서 aws access key id와 aws secret access key 가 필요하므로 설정해준다.
이렇게 한번 만들어주면 다시 들어가도 이전에 초기화해둔 값을 확인하지 못하기 때문에
repository를 공유하는 팀원간에도 민감한 정보의 유출을 막으면서 변수를 사용해 값을 사용할 수 있다.
#workflow 작성
레포지토리의 actions에 들어가면 new workflow를 작성할 수도 있고
깃헙에서 제공하는 템플릿을 이용해 작성할 수도 있다.
# This workflow uses actions that are not certified by GitHub.
# They are provided by a third-party and are governed by
# separate terms of service, privacy policy, and support
# documentation.
# This workflow will build a package using Gradle and then publish it to GitHub packages when a release is created
# For more information see: https://github.com/actions/setup-java/blob/main/docs/advanced-usage.md#Publishing-using-gradle
name: Java CI with Gradle
on:
push:
branches:
- master
permissions:
contents: read
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Set up JDK 17
uses: actions/setup-java@v3
with:
java-version: '17'
distribution: 'temurin'
- name: Run chmod to make gradlew executable
run: chmod +x ./gradlew
- name: make application.properties
run: |
cd ./src/main/resources
touch ./application.properties
echo "${{ secrets.APP_PROPERTIES }}" > ./application.properties
- name: make env.properties
run: |
cd ./src/main/resources
touch ./env.properties
echo "${{ secrets.ENV_PROPERTIES }}" > ./env.properties
- name: Build with Gradle
uses: gradle/gradle-build-action@bd5760595778326ba7f1441bcf7e88b49de61a25 # v2.6.0
with:
arguments: clean build bootJar
- name: Get current time
uses: 1466587594/get-current-time@v2
id: current-time
with:
format: YYYYMMDDTHHmm
utcOffset: "+09:00"
- name: Generate deployment package
run: |
mkdir -p deployment
cp build/libs/danaga-0.0.1-SNAPSHOT.jar deployment/danaga-0.0.1-SNAPSHOT.jar
# cp deployment/Procfile deployment/Procfile
cd deployment && zip -r danaga-${{steps.current-time.outputs.formattedTime}} .
ls
- name: Deploy Danaga to EB
uses: einaregilsson/beanstalk-deploy@v14
with:
aws_access_key: ${{secrets.AWS_ACCESS_KEY_ID}}
aws_secret_key: ${{secrets.AWS_SECRET_ACCESS_KEY}}
application_name: danaga-app
environment_name: Danaga-env
version_label: danaga-${{steps.current-time.outputs.formattedTime}}
region: ap-northeast-1
deployment_package: deployment/danaga-${{steps.current-time.outputs.formattedTime}}.zip
on:
push:
branches:
- master
master 브랜치에 push될 때 workflow가 trigger된다.
스프링부트3는 자바17이상을 지원하기 때문에 자바 17로 세팅한다.
- name: Run chmod to make gradlew executable
run: chmod +x ./gradlew
그냥 빌드를 하려 했더니 gradle 실행 권한이 없어서 권한을 주는 step을 추가한다.
- name: make application.properties
run: |
cd ./src/main/resources
touch ./application.properties
echo "${{ secrets.APP_PROPERTIES }}" > ./application.properties
- name: make env.properties
run: |
cd ./src/main/resources
touch ./env.properties
echo "${{ secrets.ENV_PROPERTIES }}" > ./env.properties
빌드를 하기 전에 applciation.properties와 env.properties 파일을 생성하고 빌드한다.
- name: Generate deployment package
run: |
mkdir -p deployment
cp build/libs/danaga-0.0.1-SNAPSHOT.jar deployment/danaga-0.0.1-SNAPSHOT.jar
# cp deployment/Procfile deployment/Procfile
cd deployment && zip -r danaga-${{steps.current-time.outputs.formattedTime}} .
ls
- name: Deploy Danaga to EB
uses: einaregilsson/beanstalk-deploy@v14
with:
aws_access_key: ${{secrets.AWS_ACCESS_KEY_ID}}
aws_secret_key: ${{secrets.AWS_SECRET_ACCESS_KEY}}
application_name: danaga-app
environment_name: Danaga-env
version_label: danaga-${{steps.current-time.outputs.formattedTime}}
region: ap-northeast-1
deployment_package: deployment/danaga-${{steps.current-time.outputs.formattedTime}}.zip
jar파일을 zip으로 압축하여 ebs에 배포한다.
master에 workflow를 작성하면 트리거가 작동하여 workflow가 실행된다.
배포 step이 실패가 떠서 확인해본다.....
배포는 성공적으로 했는데 healthcheck가 잘못되어 실패로 처리되었다...
로그를 확인하러 aws 콘솔에 갔는데
상태 ok
헬스체크의 일시적인 문제로 보고
도메인 접속 결과 이상 없이 실행된다.
이렇게 master branch에 push 될 때마다 자동으로 배포가 되는 환경이 구축되었다.
'Java > Project' 카테고리의 다른 글
스프링부트 프로젝트 서비스와 예외처리 (1) | 2023.11.22 |
---|---|
스프링부트 프로젝트 JPA 활용 (0) | 2023.11.21 |
스프링부트 프로젝트 계층에 따른 데이터 전송 형태 (0) | 2023.11.21 |
다나가 쇼핑몰 프로젝트 ER diagram과 Entity (0) | 2023.11.20 |
쇼핑몰 웹사이트 제작 프로젝트 (0) | 2023.11.09 |