Github actions 기초
Github actions 의 기본 구성
- Events
- Workflows
- Jobs
- Actions
- Runners
Events
특정 event 가 발생하면 일련의 동작을 수행한다.
특정 이벤트 예시
- main 브랜치로 merge
- commit 을 push
- issue 를 누군가 열먼..
Workflow 이벤트를 정했으면 해당 이벤트가 발생했을 때, 수행할 동작을 정한다.
이를 Workflow 라고 한다.
수행할 동작을 Step 이라고 하며 해당 동작을 모아 Job 이라고 한다.
예를 들어 Job 을 두 개 만들었다.
- Job : run unit tests
- step1 : action check out
- step2 : npm test
- Job : run E2E tests
- step1 : action check out
- step2 : action setup node
- step3 : npm install
- step4 : npm run e2e-test
Job : run unit tests 는 step1, step2 를 차례대로 수행한다.
Job : run unit tests 와 Job : run E2E tests 은 병렬로 수행할 수도 있고 순차적으로 수행할 수도 있다. 이건 직접 설정하는 것이다.
이러한 Job 을 모아 하나의 Workflow 에 등록을 하면된다.
Actions
특정 일련의 작업을 모아 미리 정의해둔 것을 action 이라고 한다.
예를 들어 github 에서 미리 만들어둔 checkout 이라는 action이 있다. 내가 checkout 을 새로 구현할 필요 없이 가져다 사용하면 된다.
Runners
Job 이 수행되는 머신(VM 또는 Docker 의 컨테이너와 비슷함)을 Runner 라고 한다.
Job 은 각각의 Runner 에서 수행된다. Job 이 2개면 2개의 Runner 에서 각각의 Job이 수행된다.
설정방법
github actions 를 설정할 프로젝트로 간다.
다음 경로에 yml 파일을 만들어준다.
.github/workflow/원하는파일명.yml
그리고 파일 내용을 작성한다.
1
2
3
4
5
6
7
8
9
10
name: learn-gihub-actions ## 워크플로우 이름을 지정해준다.
on: [push] ## push 이벤트가 발생하면 수행한다.
jobs: ## Job 들을 작성해주는 영역
check-bats-version: ## 내가 원하는 Job 이름을 지정해준다.
runs-on: ubuntu-latest ## Job을 수행할 VM 지정
steps: ## step 들을 작성해주는 영역
- uses: actions/checkout@v3 ## step: 깃허브에서 제공하는 checkout 이라는 액션을 사용
job2: ## Job 이름
runs-on: ubuntu-latest ## Job을 수행할 VM 지정
## 이하 생략
실제로 적용하기
- Github actions 를 작업할 프로젝트를 들어가 action 탭으로 간다.
그 다음 set a workflow your self 를 클릭한다.
아래 추천해주는 것 중 선택해도 되지만, 처음하는거라 그런거 잘 모르고 내가 필요한 것만 직접 설정할 것이므로 set a workflow your self 버튼을 클릭한다.yml 을 직접 작성한다.
AWS 세팅을 먼저 하고 와도 되고, yml 코드를 먼저 작성해도 된다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
## 워크플로우 이름 작성
name: deploy-to-ec2
## on 은 어떤 이벤트가 발생했을 때 워크플로우를 수행할지 결정한다.
# main 브런치에 push 하면 실행
on:
push:
branches:
- main
## 환경변수 설정
# 환경변수 모르면 그냥 변수라고 생각하자..
# key : value 구조이다.
env:
# AWS S3 버킷을 생성하고 해당 버킷이름을 변수에 저장한다.
S3_BUCKET_NAME: unichat-deploy-bucket
# 애플리케이션 이름과 배포그룹 이름을 변수에 저장한다.
CODE_DEPLOY_APPLICATION_NAME: Unichat-CodeDeploy
CODE_DEPLOY_DEPLOYMENT_GROUP_NAME: Unichat-Deploy-Group
## 실행 할 job 목록
jobs:
# 딱히 생각나는 job 이름이 없다...
deployment-job:
# ubuntu 최신 버전에서 실행
runs-on: ubuntu-latest
# 이 Job 에서 수행할 동작들 작성
steps:
## 체크아웃이 뭔지 모르면 깃허브 repository 에서 코드를 내려받는 것...이라고만 알아두자.
# 각각의 step 에도 이름을 지정할 수 있다. 생략해도 무방함.
- name: Checkout
uses: actions/checkout@v3
## Java 를 set up 한다. 프로젝트의 java 버전이랑 맞춰준다.
- name: Set up Java 17
uses: actions/setup-java@v1
with:
java-version: 17
## gradlew 에 권한부여.
# gradlew 는 gradle 을 빌드하는 tool 이라고 한다.
# 권한부여를 안해주면 빌드하다가 오류가 날 수도 있다고 한다.
# shell 에서 수행하는건 run 으로 하는것 같다..
- name: Grant execute permission to gradlew
run: chmod +x ./gradlew
shell: bash
## Gradle 빌드 (test 코드 제외)
# 테스트 코드가 제대로 안만들어져있다.
# 테스트 코드에서 오류나면 안되니까 제외시켰다.
- name: build with gradle
run: ./gradlew build -x test
shell: bash
## 프로젝트를 zip 으로 압축
# GITHUB_SHA 는 Github actions 에서 자동으로 제공되는 환경변수 중 하나이다.
# SHA는 설명 안해도 알것이고.. 몰라도 상관없다. SHA 값은 현재 commit 의 SHA 해시 값이다.
- name: Make zip file
run: zip -r ./$GITHUB_SHA.zip
shell: bash
## AWS 자격 증명
# Github action secret 에서 값을 가져온다.
- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@v1
with:
aws-access-key-id: $ # IAM User 엑세스 키
aws-secret-access-key: $ # IAM User 시크릿 엑세스 키
aws-region: ap-northeast-2
## 압축한 zip 파일 S3 로 업로드
# aws s3 cp 는 약간 scp 명령어랑 비슷한 역할을 하는 듯?? 근데 이제 aws s3 에 맞게 커스텀이 된 명령어 같다..
# --region 은 S3 가 위치한 지역을 명시한다. ap-northeast-2 는 서울을 의미한다.
- name: Upload to S3
run: aws s3 cp --region ap-northeast-2 ./$GITHUB_SHA.zip s3://$S3_BUCKET_NAME/$GITHUB_SHA.zip
## S3 에 있는 zip 파일을 EC2 로 배포
# aws deploy create-deployment 는 awscli 명령어다. deployment를 생성하는 명령어인듯
# deployment config name 옵션 : 여러 EC2 인스턴스에 한번에 배포할지 순차적으로 배포할지 작성한다. 나는 인스턴스가 하나이므로 뭘 적든 의미가 없다.
# file exists behavior 옵션 : 배포할 파일의 이름이 중복될 경우 오류가 발생한다. 이 때 덮어씌워서 오류없이 지나갈 것인지 정할 수 있다.
# 나는 파일명이 SHA(해시함수) 이므로 매번 달라서 필요 없는 옵션이기는 하다.
- name: Code Deploy
run: |
aws deploy create-deployment \
--deployment-config-name CodeDeployDefault.AllAtOnce \
--file-exists-behavior OVERWRITE \
--application-name $ \
--deployment-group-name $ \
--s3-location bucket=$, bundleType=zip, key=$GITHUB_SHA.zip \
--region ap-northeast-2
위에서 공부한 문법을 그대로 쓰면 된다. 나는 spring boot 를 ec2 에 배포하는 방법을 검색하여 참고하여 작성했고 모르는 동작은 검색해서 주석으로 넣었다.
채워 넣을 수 없는 부분들은 AWS 를 직접 세팅하면서 채워넣으면 된다.
AWS 세팅
IAM 설정
우선 회권가입을 해준다.
콘솔에 로그인 클릭한다.
IAM 으로 이동한다. 검색해서 이동하면 간편하다.

검색창에 AmazonEC2FullAccess, AmazonS3FullAccess, AWSCodeDeployFullAccess 를 각각 검색하여 체크하고 다음으로 넘어간다.
Github actions 의 secret 에 액세스 키 저장
액세스 키는 타인에게 노출되면 안된다.
하지만 aws 에 액세스 하려면 Runner 가 액세스 키를 알아야한다.
workflow.yml 에 액세스 키를 작성하지 않고 Runner 에 넘겨주기 위해서는 Action secret 이라는 방법을 사용한다.
S3
1
2
3
4
5
## 환경변수 설정
# key : value 구조이다.
env:
# AWS S3 버킷을 생성하고 해당 버킷이름을 변수에 저장한다.
S3_BUCKET_NAME: 방금-생성한-버킷이름
내가 정의한 버킷 이름을 워크플로의 환경변수에 저장한다.
IAM 역할(Role) 생성
S3 에서 zip 을 다운받을 수 있도록 하는 역할 생성

EC2 를 선택합니다. 나중에 EC2 에 이 역할을 부여할 수 있다.
권한 추가 하는 부분에 다음 두 개를 체크하고 넘어간다.
- AWSCodeDeployFullAccess
- AmazonS3FullAccess
S3 와 CodeDeploy 에 접근을 할 수 있게 한다.
S3 에서 zip 파일을 다운로드하고, CodeDeploy 가 배포를 수행할 수 있어야 하기 때문이다.

이름을 붙여주고 역할 생성 버튼을 눌러 마무리한다.
EC2 에 부여할 역할이 생성되었다. 뒤에서 EC2에 이 역할을 부여한다.
CodeDeploy 가 배포를 할 수 있도록 하는 역할 생성
CodeDeploy 가 배포를 할 수 있게 하는 권한은 기본적으로 선택되어 있다. 이름 작성하고 바로 역할을 생성해준다.
EC2 생성 및 세팅
화살표를 따라가 지역을 서울로 변경한다.
키 페어 생성 완료 후 인스턴스 생성까지 완료한다.
역할 드롭박스를 클릭해 위에서 만든 ‘S3 에서 zip 을 다운받을 수 있도록 하는 역할’ 을 선택하고 역할 업데이트 버튼을 클릭한다.

이제 EC2 에 접속하여 다음 명령어를 입력해 세팅을 한다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
sudo apt update
sudo apt install ruby-full
sudo apt install wget
sudo apt install openjdk-17-jdk
java -version
cd /home/ubuntu
ls -l
wget https://aws-codedeploy-ap-northeast-2.s3.ap-northeast-2.amazonaws.com/latest/install
ls -l
chmod +x ./install
sudo ./install auto
CodeDeploy agent 설치 확인
1
systemctl status codedeploy-agent
install 실행이 끝나면 위 명령어를 입력해 EC2에 CodeDeploy agent 가 정상적으로 설치되었는지 확인한다.
CodeDeploy 생성
이제 CodeDeploy 를 생성하고 세팅할 차례이다.
역할에는 아까 위에서 만든 ‘CodeDeploy 가 배포를 할 수 있도록 하는 역할’ 로 설정한다.
사진대로 셋팅을 마치면 아래로 내려가 배포 그룹 생성 버튼을 눌러 완료한다.
1
2
3
4
5
6
7
8
## 환경변수 설정
# key : value 구조이다.
env:
# AWS S3 버킷을 생성하고 해당 버킷이름을 변수에 저장한다.
S3_BUCKET_NAME: 버킷이름
# 애플리케이션 이름과 배포그룹 이름을 변수에 저장한다.
CODE_DEPLOY_APPLICATION_NAME: 애플리케이션 이름
CODE_DEPLOY_DEPLOYMENT_GROUP_NAME: 배포 그룹 이름
EC2 인바운드 규칙 설정
내 프로젝트는 웹 사이트이므로 외부에서 HTTP(80) 포트와 8080 포트로 접속이 가능해야한다.
외부 모든 IP 주소에서 80 및 8080 포트를 통해 접속을 허용했다.
appspec.yml
AWS CodeDeploy 는 appspec.yml 에 적힌대로 수행한다.
세부적으로 수행할 동작은 스크립트를 만들어 hook 에 따로 명시한다.
프로젝트의 루트 경로에 appspec.yml 파일을 만들어준다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
version: 0.0
os: linux
# source 에 있는 파일들을 destination 으로 복사한다.
# source 는 appspec.yml 파일을 기준으로 상대경로가 된다.
# source: / 이렇게 작성하면 os 기준으로 root 경로가 아니라 appspec.yml 파일이 있는 위치이다.
# 즉 다음 내용은 appspec.yml 파일이 위치한 경로에 있는 모든 파일을 /opt/unichat 으로 복사한다.
files:
- source: /
destination: /opt/unichat
overwrite: yes
# 권한 부여
# object : 권한을 부여할 대상 지정
permission:
- object: /opt/unichat
owner: ubuntu
group: ubuntu
mode: 755
# install 단계가 끝나면 deploy.sh 스크립트를 수행하도록 설정.
# deploy.sh 는 jar 파일을 실행하는 스크립트이다.
# runas: root 는 deploy.sh 를 root 권한으로 실행한다는 의미이다.
hooks:
AfterInstall:
- location: deploy.sh
timeout: 60
runas: root
hooks 에 있는 AfterInstall 은 다음 사진을 봐야 이해가 된다.
jar 실행은 AfterInstall 이나 ApplicationStart 에 하는 것이 적절하다.
ValidateService 는 배포 완료 후 성공적으로 수행되었는지 확인하는 스크립트가 있는게 적절하다.
deploy.sh
이제 마지막으로 jar 파일을 실행하는 스크립트를 작성한다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
#!/usr/bin/env bash
# 내 프로젝트의 위치
REPOSITORY=/opt/unichat
APP_NAME=unichat
JAR_NAME=$(ls $REPOSITORY/build/libs/ | grep '.jar' | tail -n 1)
JAR_PATH=$REPOSITORY/build/libs/$JAR_NAME
echo "> 현재 구동 중인 애플리케이션 pid 확인"
CURRENT_PID=$(pgrep -f $APP_NAME)
echo "현재 구동 중인 애플리케이션 pid: $CURRENT_PID"
if [ -z "$CURRENT_PID" ]; then
echo "현재 구동 중인 애플리케이션이 없으므로 종료하지 않습니다."
else
echo "> kill -9 $CURRENT_PID"
kill -9 $CURRENT_PID
sleep 5
fi
echo "> 새 애플리케이션 배포를 시작합니다."
echo "> JAR PATH: $JAR_PATH"
echo "> $JAR_PATH 에 실행권한 추가"
chmod +x $JAR_PATH
echo "> $JAR_PATH 실행"
nohup java -Duser.timezone=Asia/Seoul -jar $JAR_PATH >> $REPOSITORY/nohup.out 2>&1 &
마지막 줄의 -Duser.timezone=Asia/Seoul 은 서울시간으로 실행한다는 의미
-jar 프로젝트.jar » 프로젝트위치/nohup.out 2>&1 는 프로젝트의 stdout(표준 출력)과 stderr(표준 에러) 를 nohup.out 파일에 추가한다는 의미다. Spring 실행 시 콘솔창에 출력되는 로그를 전부 nohup.out 에서 확인할 수 있다.
AWS RDS(MySQL)
프로젝트에 MySQL 이 있어야 한다면 아래 사진을 따라하면 된다.
복사 후 내 프로젝트의 sql 연동 하는 파일로 가서 다음과 같이 수정한다.
spring.datasource.url=jdbc:mysql://방금-복사한-내-엔드포인트:3306/DB이름?createDatabaseIfNotExist=true
테스트
워크플로.yml 파일을 push 하기 전에 EC2 를 두 개 켜자.
첫 테스트에 바로 성공하면 좋겠지만 그러지 않을 경우 어디서 문제가 발생했는지 알기 위해 EC2 를 두 개 켜놓는다.
첫번째 EC2 에서는 deploy.sh 파일에서 echo 로 출력한 문장을 확인하려고 한다.
1
2
3
4
cd /opt/codedeploy-agent/deployment-root/deployment-logs/
ls -l
tail -1f codedeploy-agent-deployments.log
두번째 EC2 에서는 프로젝트의 출력을 확인하는 방법이다.
아까 프로젝트의 stdout 과 stderr 를 nohup.out 파일에서 확인하기로 했다.
1
2
3
4
cd 프로젝트경로
ls -l
tail -1f nohup.out
두 로그를 띄워놓은 채로 yml 파일을 push 하여 어디서 오류가 나는지 확인하고 틀린부분 수정하면 된다.
오류를 모두 수정했다면 http://EC2-엔드포인트:8080/ 으로 접속해보면 정상적으로 접속할 수 있다.












































