###🔥 주의 🔥
해당 글은 에러와 실패 과정을 모두 포함한 (노력의 시간순서) 글이므로 만일 따라하실 때는 다 읽으시고 맞는 방법만 골라서 진행하시면됩니다. 正道만 걸으시라는 뜻.....
중간에 권한이 없어서 권한을 부여받을 때까지 며칠동안 작성한 글이기 때문에
두서가 없고, 시간 순으로 실시간 작성한 글이라서 정리가 안된 느낌이지만 그래서 오히려 누군가에겐 도움이 되지 않을까 싶어서 글을 포스팅 해본다.
(처음에 따라할 때 )
https://stalker5217.netlify.app/devops/github-action-aws-ci-cd-1/
(이 후 따라한 블로그)
https://bcp0109.tistory.com/363
repository의 github action 탭에 들어가면 다음과 같이 repository에 있는 language를 감지하여 화면이 나타남 개꿀
아래 코드 추가했고, 맨마지막에 gradle build 하는 줄을 블로그처럼 run : ./gradlew clean build 로 변경
- name: Grant execute permission for gradlew
run: chmod +x gradlew
chaebbiSpring/.github/workflows/gradle.yml
# 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 Java project with Gradle and cache/restore any dependencies to improve the workflow execution time
# For more information see: https://help.github.com/actions/language-and-framework-guides/building-and-testing-java-with-gradle
name: Spring Boot & Gradle CI/CD
on:
push:
branches: [ "main" ]
pull_request:
branches: [ "main" ]
permissions:
contents: read
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Set up JDK 11
uses: actions/setup-java@v3
with:
java-version: '11'
distribution: 'temurin'
- name: Grant execute permission for gradlew
run: chmod +x gradlew
- name: Build with Gradle
# uses: gradle/gradle-build-action@67421db6bd0bf253fb4bd25b31ebb98943c375e1
# with:
# arguments: build
run : ./gradlew clean build
github action 탭에서 다음과 같이 build 결과를 확인
테스트 관련 빌드 에러로 예상하고 테스트 스킵하고 빌드하는 걸로 코드 변경
run : ./gradlew clean build --exclude-task test
# 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 Java project with Gradle and cache/restore any dependencies to improve the workflow execution time
# For more information see: https://help.github.com/actions/language-and-framework-guides/building-and-testing-java-with-gradle
name: Spring Boot & Gradle CI/CD
on:
push:
branches: [ "main" ]
pull_request:
branches: [ "main" ]
permissions:
contents: read
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Set up JDK 11
uses: actions/setup-java@v3
with:
java-version: '11'
distribution: 'temurin'
- name: Grant execute permission for gradlew
run: chmod +x gradlew
- name: Build with Gradle
# uses: gradle/gradle-build-action@67421db6bd0bf253fb4bd25b31ebb98943c375e1
# with:
# arguments: build
run : ./gradlew clean build --exclude-task test
s3 bucket을 생성하고
사용자 추가 완료 ACCESSKEY와 SECRETKEY 를 꼭 잊지말고 적어둘 것
퍼블릭 엑세스 열고, 버킷 권한 정책 편집
{
"Version": "2012-10-17",
"Id": "Policy1657713262596",
"Statement": [
{
"Sid": "Stmt1657713261442",
"Effect": "Allow",
"Principal": "*",
"Action": [
"s3:GetObject",
"s3:PutObject"
],
"Resource": "arn:aws:s3:::chaebbi-deploy-bucket/*"
}
]
}
이제 github repository에서 해당 키 값들을 세팅한다. action에 키 값을 그대로 노출하는 것은 보안상 문제가 되므로 repository의 ‘Settings -> Secret’에서 해당 키 값을 등록
$GITHUB_SHA
: Github 자체에서 커밋마다 생성하는 랜덤한 변수 값
# 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 Java project with Gradle and cache/restore any dependencies to improve the workflow execution time
# For more information see: https://help.github.com/actions/language-and-framework-guides/building-and-testing-java-with-gradle
name: Spring Boot & Gradle CI/CD
on:
push:
branches: [ "main" ]
pull_request:
branches: [ "main" ]
permissions:
contents: read
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Set up JDK 11
uses: actions/setup-java@v3
with:
java-version: '11'
distribution: 'temurin'
- name: Grant execute permission for gradlew
run: chmod +x gradlew
- name: Build with Gradle
# uses: gradle/gradle-build-action@67421db6bd0bf253fb4bd25b31ebb98943c375e1
# with:
# arguments: build
run : ./gradlew clean build --exclude-task test
# 전송할 파일을 담을 디렉토리 생성
- name: Make Directory for deliver
run: mkdir deploy
# Jar 파일 Copy
- name: Copy Jar
run: cp ./build/libs/*.jar ./deploy/
# 압축파일 형태로 전달
- name: Make zip file
run: zip -r -qq -j ./springboot-intro-build.zip ./deploy
# S3 Bucket으로 copy
- name: Deliver to AWS S3
env:
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
run: |
aws s3 cp \
--region ap-northeast-2 \
--acl private \
./springboot-intro-build.zip s3://springboot-intro-build/
version: 0.0
os: linux
files:
- source: /
destination: /home/ubuntu/app
overwrite: yes
permissions:
- object: /
pattern: "**"
owner: ubuntu
group: ubuntu
hooks:
AfterInstall:
- location: scripts/stop.sh
timeout: 60
runas: ubuntu
ApplicationStart:
- location: scripts/start.sh
timeout: 60
runas: ubuntu
codedeply 가 없으므로 에러 발생
이제 두번째 블로그 https://bcp0109.tistory.com/363 블로그 위부터 다시 따라함
chaebbi-deploy-iam 에다가 s3 fullAccess 주고 ec2에 보안>iam 역할수정 으로 추가했음
배포 자동화용으로 만든 ec2 (이름 : jenkins)(ubuntu)에 apt install codedeploy-agent
https://docs.aws.amazon.com/ko_kr/codedeploy/latest/userguide/codedeploy-agent-operations-install-ubuntu.html
정상 설치 완료, 응답 완료
CodeDeploy 를 사용하기 위해 IAM 에서 역할 생성
내가 가진 iam aws 계정에서 codeploy:ListApplications 권한이 없어서 이를 요청하고 다시 시도함
권한 부여 받고 다시 애플리케이션 생성
이번에는 SNS:ListTopics 권한이 없다는 에러 → 다시 요청해 권한 부여받음
배포 그룹 이름 : chaebbi-codedeploy-deployment-group
어떤 인스턴스에서 동작할지 선택 :EC2 인스턴스에는 태그 추가해서 선택하는데 이 프로젝트 배포자동화를 위해서 사용할 ec2인 jenkins-ec2로 이름 붙여놓은 ec2 사용 (일전에 만들어둠 )
그 다음 설정을 해준다. 현재는 로드 밸런싱 사용하지 않으므로 활성화를 풀어주고 그룹생성을 진행한다.
배포 그룹 생성 성공!
aws를 github actions 워크 플로우에 접근 위해서 권한을 추가해준다.
이전처럼 iam ‘역할’추가가 아닌 ‘사용자’를 추가한다.
IAM 메뉴에서 사용자 추가를 클릭한다.
사용자 이름 : chaebbi-github-actions-iam-user
권한 설정에서 → 기존 정책 직접 연결 클릭 후
두개를 추가해준다.
검토 화면 은 다음과 같다.
사용자 만들기 버튼 클릭해서 사용자 생성 완료 하였다.
만들고 나면 생성되는 엑세스키 id 와 비밀 엑세스 키 는 다운로드할 수 있는 마지막 기회이므로 csv파일 꼭 저장하기!!!
github action 으로 가서 Github > Repository > Settings > Secrets
로 이동
이번에 만든 chaebbi-github-actions-iam-user 의 access key 와 secret key로 변경 해줌
이제 서버 띄울 EC2 : jenkins-ec2
배포 결과물 저장할 S3 : chaebbi-deploy-bucket
배포할 CodeDeploy : chaebbi-codedeploy-app
AWS 서비스들을 만들었다.
AppSpec 파일을 사용해서 프로젝트의 어떤 파일들을 EC2 의 어떤 경로에 복사할지 설정 가능하고, 배포 프로세스 이후에 수행할 스크립트를 지정하여 자동으로 서버를 띄울 수도 있음.
version: 0.0
os: linux
files:
- source: /
destination: /home/ubuntu/app
overwrite: yes
permissions:
- object: /
pattern: "**"
owner: ubuntu
group: ubuntu
hooks:
AfterInstall:
- location: scripts/stop.sh
timeout: 60
runas: ubuntu
ApplicationStart:
- location: scripts/start.sh
timeout: 60
runas: ubuntu
위의 3.2 appspec.yml 파일 생성 부분과 비교하면 차이가 없다.
그래서 이 부분은 이전에 생성해둔 대로 그대로 둠
바로 위 AppSpec Hooks 에서 실행할 스크립트 stop.sh
와 start.sh
를 설정
실행중인 애플리케이션이 있다면 종료하는 스크립트
블로그 스크립트에서 jar_file 이름과 kill 15에서 9로 변경 하였음
#!/usr/bin/env bash
PROJECT_ROOT="/home/ubuntu/app"
JAR_FILE="$PROJECT_ROOT/chaebbiSpring.jar"
DEPLOY_LOG="$PROJECT_ROOT/deploy.log"
TIME_NOW=$(date +%c)
# 현재 구동 중인 애플리케이션 pid 확인
CURRENT_PID=$(pgrep -f $JAR_FILE)
# 프로세스가 켜져 있으면 종료
if [ -z $CURRENT_PID ]; then
echo "$TIME_NOW > 현재 실행중인 애플리케이션이 없습니다" >> $DEPLOY_LOG
else
echo "$TIME_NOW > 실행중인 $CURRENT_PID 애플리케이션 종료 " >> $DEPLOY_LOG
kill -9 $CURRENT_PID
fi
애플리케이션 실행하는 스크립트
Github Actions 워크플로우에서 이미 빌드는 마쳤기 때문에 JAR 파일만 복사 후 실행
#!/usr/bin/env bash
PROJECT_ROOT="/home/ubuntu/app"
JAR_FILE="$PROJECT_ROOT/chaebbiSpring.jar"
APP_LOG="$PROJECT_ROOT/application.log"
ERROR_LOG="$PROJECT_ROOT/error.log"
DEPLOY_LOG="$PROJECT_ROOT/deploy.log"
TIME_NOW=$(date +%c)
# build 파일 복사
echo "$TIME_NOW > $JAR_FILE 파일 복사" >> $DEPLOY_LOG
cp $PROJECT_ROOT/build/libs/*.jar $JAR_FILE
# jar 파일 실행
echo "$TIME_NOW > $JAR_FILE 파일 실행" >> $DEPLOY_LOG
nohup java -jar $JAR_FILE > $APP_LOG 2> $ERROR_LOG &
CURRENT_PID=$(pgrep -f $JAR_FILE)
echo "$TIME_NOW > 실행된 프로세스 아이디 $CURRENT_PID 입니다." >> $DEPLOY_LOG
원래 수동으로 배포하던 배포 스크립트 deploy.sh
와 비교해서 차이를 확인해봤다.
#!/bin/bash
REPOSITORY=/var/www/html/spring
PROJECT_NAME=chaebbiSpring
cd $REPOSITORY/$PROJECT_NAME/
echo "> GIT PULL"
git pull
echo "> 프로젝트 빌드 시즈악"
./gradlew build -x check --parallel
echo ">step1 디렉 이도옹"
cd $REPOSITORY
echo "> Build 파일 복사"
cp $REPOSITORY/$PROJECT_NAME/build/libs/*.jar $REPOSITORY/
echo "> 현재 구동중인 애플리케이션 pid 확인"
CURRENT_PID=$(pgrep -f ${PROJECT_NAME}-0.0.1-SNAPSHOT.jar)
echo "현재 구동중인 어플리케이션 pid: $CURRENT_PID"
if [ -z "$CURRENT_PID" ]; then
echo "> 현재 구동중인 애플리케이션이 없으므로 종료하지 않습니다."
else
echo "> kill -9 $CURRENT_PID"
kill -9 $CURRENT_PID
sleep 5
fi
echo "> 새 어플리케이션 배포"
#JAR_NAME=$(ls -tr $REPOSITORY/ | grep *.jar | tail -n 1)
JAR_NAME=$(ls -tr $REPOSITORY/*.jar | tail -n 1)
echo "> JAR Name: $JAR_NAME"
echo "> $JAR_NAME 에 실행권한 추가"
chmod +x $JAR_NAME
echo "> $JAR_NAME 실행"
nohup java -jar \
-Dspring.config.location=/var/www/html/spring/application-real-db.properties,/var/www/html/spring/application.yml \
-Dspring.profiles.active=real \
$JAR_NAME 2>&1 &
블로그에서는
Spring Boot 2.5 버전부터는 빌드 시 일반 jar 파일 하나와 -plain.jar
파일 하나가 함께 만들어 진다는데, plain jar 파일이 만들어지지 않도록 내용 추가를 하고있지만 왜 해야하는지 몰라서 일단은 수정안함
블로그에서는 github repository에서 action > new workflow 선택 해서 simple workflow 생성하고있지만
우리는 기존의 workflow가 있기 때문에 1.1 의 Spring Boot & Gradle CI/CD WorkFlow 사용
그동안 codedeploy권한이 없어 진행을 못해 빨갛게 에러가 났던 빌드의 현장들 ..
3.1.1 생성된 gradle.yml 파일 과 블로그의 파일을 비교
아래는 블로그의 deploy.yml
name: Deploy to Amazon EC2
on:
push:
branches:
- main
# 본인이 설정한 값을 여기서 채워넣습니다.
# 리전, 버킷 이름, CodeDeploy 앱 이름, CodeDeploy 배포 그룹 이름
env:
AWS_REGION: ap-northeast-2
S3_BUCKET_NAME: my-github-actions-s3-bucket
CODE_DEPLOY_APPLICATION_NAME: my-codedeploy-app
CODE_DEPLOY_DEPLOYMENT_GROUP_NAME: my-codedeploy-deployment-group
permissions:
contents: read
jobs:
deploy:
name: Deploy
runs-on: ubuntu-latest
environment: production
steps:
# (1) 기본 체크아웃
- name: Checkout
uses: actions/checkout@v3
# (2) JDK 11 세팅
- name: Set up JDK 11
uses: actions/setup-java@v3
with:
distribution: 'temurin'
java-version: '11'
# (3) Gradle build (Test 제외)
- name: Build with Gradle
uses: gradle/gradle-build-action@0d13054264b0bb894ded474f08ebb30921341cee
with:
arguments: clean build -x test
# (4) AWS 인증 (IAM 사용자 Access Key, Secret Key 활용)
- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@v1
with:
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
aws-region: ${{ env.AWS_REGION }}
# (5) 빌드 결과물을 S3 버킷에 업로드
- name: Upload to AWS S3
run: |
aws deploy push \
--application-name ${{ env.CODE_DEPLOY_APPLICATION_NAME }} \
--ignore-hidden-files \
--s3-location s3://$S3_BUCKET_NAME/$GITHUB_SHA.zip \
--source .
# (6) S3 버킷에 있는 파일을 대상으로 CodeDeploy 실행
- name: Deploy to AWS EC2 from S3
run: |
aws deploy create-deployment \
--application-name ${{ env.CODE_DEPLOY_APPLICATION_NAME }} \
--deployment-config-name CodeDeployDefault.AllAtOnce \
--deployment-group-name ${{ env.CODE_DEPLOY_DEPLOYMENT_GROUP_NAME }} \
--s3-location bucket=$S3_BUCKET_NAME,key=$GITHUB_SHA.zip,bundleType=zip
차이점
블로그는 jobs를 deploy로 시작. 우리 yml은 build 로시작
일단은 차이 그대로 두고 진행해보겠음
진행결과
gradle.yml을 수정해서 action 탭에 들어가보니 실패가 뜬다. 이유는
every step must define a uses or run key
라고 뜬다.
구글링해보니 name 다음에는 해당 하나의 uses만 있어야 한다고 한다.
이부분에 있던 - 를 제거해주었다.
두근 두근 빌드를 기다리고있다
어머나 성공적으로 빌드 배포 되어버렸다
이름은 헷갈리지 않게 Deploy 로 바꿔주는게 좋겠다.
블로그처럼 Deploy로 바꿔도 과연 잘될까?
(jobs 밑에 build: 를 deploy: 로 변경. name에 Deploy 준다)
감격스럽다.
잘 된다
선생님 감사합니다 해결해써요 !