Jenkins , Travis ci 등 많은것들이 있지만
Travis Ci는 무료플랜이라고 해서 가입했더니 1달러를 뺏어가구
또 무슨 토큰을줘서 해당 토큰량을 사용할때까지만 무료라고해서 괘씸해서
Github Action으로 구현하였다.
ci(Continuous Integration, 지속적 통합) 란?
ci는 빌드/테스트 자동화과정을 의미한다. (테스트코드를 작성해놨으면 빌드시 테스트도 되니까?)
개발자가 일일이 빌드/테스트하는 그 일련의 과정을
jenkins라던지 travis ci라던지 github actions이라던지를 이용하여 구현한다.
그러면 개발자는 코드를 커밋할때마다 빌드와 테스트가 자동으로 이루어져 편리함을 제공함 +
커밋할때마다 빌드/테스트가 되서 공유 리포지토리에 통합되므로 여러명의 개발자가 동시에 어플리케이션 개발과 관련된 코드 작업을 할 경우 서로 충돌할 수 있는 문제를 해결할 수 있다고 한다.
CD(Continuous Delivery)란?
지속적인 배포를 의미하며 CD는 간단히 배포 자동화를 의미한다.
ci를 통해 빌드가 되고 테스트를 통과하면 서버에 해당 버전을 배포해줘야하는데 그럴때 CD가 자동적으로 배포를 해준다.
무중단 배포
배포 자동화를 진행할때 새로운 버전이 서버에 적용되기전에 켜져있던 서버를 끄고 ,
배포를 하고(새로운버전으로 업데이트하고) 다시 서버를 끼는 일련의 과정이 있기에
배포시 서버를 이용할 수 없다는 단점이 있다. 그런경우를 막기 위해 무중단 배포도 구현한다.
무중단 배포를 구현시 새로운버전을 배포하는 동안 서버가 꺼지는 경우가 없다.
참고,출처,더 자세한정보
ci/cd(+무중단) 의 전체흐름도
배포의 흐름순서는 다음과같습니다.
1. Github Actions에서 프로젝트 빌드/테스트 후 (오류가있다면 실패뜸) 빌드하면 jar파일이 생기므로 jar파일을 zip파일로 압축해서 s3에 업로드합니다.
2. 그다음 CodeDeploy에게 S3에 있는 jar파일을 가지고 배포를 해달라고 전달합니다.
3. CodeDeploy는 배포할 EC2 인스턴스(서버) 내부에 있는 Code Deploy Agent에게 배포명령을 내리고 Agent는 jar파일을 S3에서 받아서 주어진 스크립트(개발자가 작성)에 따라 배포를 진행합니다.
4. 업데이트된 버전의 Spring boot WAS를 띄우고(다른 포트를 이용하여) ,Nginx 스위칭을 통해 새로 띄운(업데이트된 버전의 서버의 포트를)가리키면서 무중단 배포를 한다.
WAS 개념참고
Github Actions
github Actions는 레포지토리에 있는 Actions를 이용하여 빌드/배포환경을 구축할 수 있다.
public 저장소에서는 무료로 지원함!
workflow 생성하기
레포지토리를 클릭하면 Actions버튼이 있을것이다.그걸 누르고
set up a workflow yourself 를 누르면 나만의 워크플로우를 만들 수 있다 ( 자동으로 빌드/테스트 + 배포 명령 전달 를 할때 어떤식으로 진행될지 진행순서를 작성하는곳이라고 생각하면될듯)
workflow는 yml 파일로 작성되며
왼쪽으로 적는칸 , 오른쪽은 어떻게 적을지 참조해보는곳으로 보면될듯하다.
workflow yml파일은 위에 보면 프로젝트이름/.github/workflows/ 에 저장이된다. (원격저장소에 폴더가 생기면서 저장됨)
빈곳에 다음과같이 작성한다.
# workflow이름.yml
name: action이름(어떤action 인지)
on:
workflow_dispatch:
#수동으로 workflow를 실행시키겠다는 의미 , 원하면 바꿔서 push할때나 pull할때로 동작하게끔 수정가능
jobs: #work flow에서 하는 작업을 의미
build:
runs-on: ubuntu-latest #어떤 os에서 실행하는지 지정.
steps: #jobs안에서 동작하는 세부 동작들
- name: Checkout
uses: actions/checkout@v2 #actions/액션이름 은 마켓에서 가져온 액션들이다.
- name: Set up JDK 1.8
uses: actions/setup-java@v1
with:
java-version: 1.8
- name: Grant execute permission for gradlew
run: chmod +x gradlew
shell: bash
- name: Build with Gradle
run: ./gradlew build
shell: bash
# 다음 단계에서 스크립트 추가 예정
job, steps :
workflow 는 하나 혹은 그 이상의 job 을 가질 수 있고 각 job 은 여러 step 에 따라 단계를 나눌 수 있습니다.
actions/행위 이름:
앞서 보았던 marketplace 에서 미리 정의되어 있는 행위를 가져와서 사용한 것입니다.
checkout :
깃헙이 제공하는 워크스페이스 (이 workflow 를 실행하는 공간) 에서 내 저장소가 위치한 곳으로 이동한다고 생각하시면 됩니다.이후에는 java 를 셋업하고 gradlew 에 실행권한을 준 뒤 프로젝트를 build 하는 과정입니다
checkout 관련
workflow 실행 - Actions 실행
이렇게 해놓고 스크립트를 저장하고 Actions 탭으로 가면 workflow를 실행 할 수 있는 페이지로 바뀌어있다.
방금 workflow_dispatch 로 workflow 를 수동 실행하겠다고 스크립트를 작성했기 때문에,
아래와 같이 Run workflow - 브랜치 선택하여 Job 을 실행합니다.
Run workflow를 눌러서 직접 실행해본다.
원격저장소 main브런치에 올라와있는 프로젝트를 대상으로 workflow에서 적은 step들이 실행된다.
실패한다면 어디서 실패했는지도 나오지 클릭해서 디테일하게 살펴볼것!
bash 명령어를 얼마든지 추가할 수 있기 때문에, 필요에 따라 echo 등으로 각 단계 별 상태를 확인하면서 진행할 수도 있다고 한다!
언제 했는지 얼마나 걸렸는지 어떤액션을 했는지 다 상세하게 나온다. -> 이미 진행중인 프로젝트로 실행시 오류가 뜬다 그이유는 gitignore관련된 파일이 원격저장소에 올라와있지않기때문임 해결하는방법은 아래에 나오니 실패해도 무시하고 진행하자.
해당 액션을 클릭하면 어떤 step순서대로 진행했는지 어디서 다나오니 잘 살펴보자
빌드한 결과인 jar파일 압축해서 S3에 올리기
위에 작성한 workflow는 빌드/테스트까지 하는 스크립트였다.
이제 빌드한 결과인 jar파일을 압축해서 s3에 올리기까지 진행해보자
일단
S3에 버킷을 생성해야함.
버킷생성
S3에 가서 버킷생성을 누른후 이름만 설정하고 기본값을 아무것도 바꾸지않고 버킷을 생성해준다.
(나는 이미 이미지파일을 업로드하던 버킷이있어서 해당 버킷으로 진행하였다 -> 원래 있는 버킷으로 해도됨)
IAM생성
AWS에서는 루트계정을 이용해서 리소스에 접근하였는데 루트계정은 모든 권한을 가진 계정이라 위험하다.
그래서 특정 권한을 가지는 계정을 만들어서 쓰는데 그게 IAM이다.
IAM -> 사용자 -> 사용자 추가
다음으로 이동!
기존정책에서
AmazonS3FullAccess 와 AWSCodeDeployFullAccess 를 선택
다음으로 이동!
태그는 넘어가고 쭉쭉 넘어가면 마지막에 엑세스 키 ID와 비밀 엑세스 키가 나오는데 따로 잘 저장하고
또 csv파일까지 다운로드해서 구글드라이브같은곳에 백업해둔다!
그러면 이제 s3와 deploy에 접근권한을 가진 IAM 사용자도 만들었고 버킷도 만들었다.
만든 버킷을 이용해서 build 결과파일인 jar파일을 압축해서 버킷에 올려보자
S3 에 jar 파일 업로드하기
아까 workflow를 위해 작성한 yml파일에 내용을 추가한다.
# workflow이름.yml
name: action이름(어떤action 인지)
on:
workflow_dispatch:
#수동으로 workflow를 실행시키겠다는 의미 , 원하면 바꿔서 push할때나 pull할때로 동작하게끔 수정가능
env: # 새로 추가한 부분
S3_BUCKET_NAME: 버킷이름적기
PROJECT_NAME: 프로젝트이름적기(s3에 빌드파일이 저장될 폴더만들거)
jobs: #work flow에서 하는 작업을 의미
build:
runs-on: ubuntu-latest #어떤 os에서 실행하는지 지정.
steps: #jobs안에서 동작하는 세부 동작들
- name: Checkout
uses: actions/checkout@v2 #actions/액션이름 은 마켓에서 가져온 액션들이다.
- name: Set up JDK 1.8
uses: actions/setup-java@v1
with:
java-version: 1.8
- name: Grant execute permission for gradlew
run: chmod +x gradlew
shell: bash
- name: Build with Gradle
run: ./gradlew build
shell: bash
# 새로 추가한 부분
- name: Make zip file #압축하고
run: zip -r ./$GITHUB_SHA.zip .
shell: bash
- name: Configure AWS credentials #방금 만든 IAM 계정의 키값들을 사용할곳
uses: aws-actions/configure-aws-credentials@v1
with:
aws-access-key-id: ${{ secrets.AWS_GITHUB_ACTION_ACCESS_KEY }}
aws-secret-access-key: ${{ secrets.AWS_GITHUB_ACTION_SECRET_ACCESS_KEY }}
aws-region: ${{ secrets.AWS_GITHUB_ACTION_REGION }}
- name: Upload to S3 # s3에 업로드
run: aws s3 cp --region ap-northeast-2 ./$GITHUB_SHA.zip s3://$S3_BUCKET_NAME/$PROJECT_NAME/$GITHUB_SHA.zip
env
현재 스크립트에서 사용할 환경변수를 정의하여 사용할 수 있습니다.
여러 곳에서 공통으로 사용되는 문자열이나, 명확하게 의미를 부여해야 하는 키워드에 사용하시면 됩니다.
$GITHUB_SHA
Github Actions 에서 제공하는 여러 기본 환경변수 중 하나입니다. 현재 workflow 를 실행시키는 커밋의 해쉬값입니다.
다른 기본 환경변수들도 필요에 따라 사용할 수 있습니다.
${{ secrets.KEY_이름 }}
위의 환경변수와는 비슷하면서도 조금 다른 Context 입니다. Github Actions 에서 ${{ }} 문법으로 여러 함수나 표현식, 값들을 등록하고 가져와서 사용할 수 있습니다.
secrets 는 저장소에 등록한 비밀 키값을 가져오는 키워드인데요, 아래에서 설명하겠습니다.
-> 레포지토리의 setting-> secret 부분에서 비밀값들을 저장할 수 있는데 해당 값들을 가져오는 부분이다!
aws s3 cp
aws cli 명령어 중 하나입니다. copy 명령어로 현재 위치의 파일을 S3로 업로드하거나, 반대로 S3의 파일을 현재 위치로 다운로드할 수 있습니다.
이제 jar파일을 압축하고 AWS credential 을 설정하고(credential == 자격 , s3에 접근하고 원하는 동작을 할수있게끔) , s3에 업로드까지 했다.
위에 ${{ secrets.KEY_이름 }}를 이용하기 위해 아까 IAM계정을 만들고 나서 받은 엑세스키와 비밀키를
저장소 안에 비밀값들을 저장하는곳에 저장해보자.
레포지토리 내에 비밀값들 저장!!
레포지토리에서 setting -> secrets -> actions에서 저장소의 비밀값들을 저장할 수 있다.
여기가 중요한 부분인데
프로젝트를 git 원격저장소에 올릴때 올리면 안되는 파일들이있다
( application.yml 처럼 aws계정이나 rds 엔드포인트등 중요한 정보가 저장되는 파일이나 , jwt키값같은 파일들)
이런 파일들은 원격저장소에 올라오지않기에 그 파일들을 빼고 빌드를 시도하면(workflow를 실행하면) 당연히 실패가 된다.
다음과 같은 파일들의 정보를 workflow가 실행될때 만들어줘서 빌드/테스트가 실패하지않게 해줘야한다!
New Repository Secret을 누르면
다음과 같이 작성가능하다.
name에 구분하기위한 이름
밑에는 그 내용을 적어야한다.
여기서 중요한거는
내용을 적을때 Base 64로 인코드 해야한다는것이다.
application.yml의 내용을 저장하고싶다면
name은 알아보기쉽게 appliction_yml 정도로 하면될것이고 내용은 전체 복사해서
다음과같은 Base64 사이트에 내용을 복붙한후 인코딩된 결과를 복사해서
Secret내용으로 적어주면된다!
한번 Secret을 만들면 안에 내용은 확인못하고 지우거나 전체를 수정하거나 밖에 되지않으니 주의한다!
아까
- name: Configure AWS credentials #방금 만든 IAM 계정의 키값들을 사용할곳
uses: aws-actions/configure-aws-credentials@v1
with:
aws-access-key-id: ${{ secrets.AWS_GITHUB_ACTION_ACCESS_KEY }}
aws-secret-access-key: ${{ secrets.AWS_GITHUB_ACTION_SECRET_ACCESS_KEY }}
aws-region: ${{ secrets.AWS_GITHUB_ACTION_REGION }}
이 부분에서 ${{ secrets.AWS_GITHUB_ACTION_ACCESS_KEY }} 와 같은 부분은 secret만들때 정해줬던 이름을 이용해서 secrets.내가설정한이름 이런식으로 구성한다. (액세스키값,시크릿키값,지역값 총 3개 등록해두면됨 기본적으로)
(지역값은 ap-northeast-2이다)
IAM의 키값이나 지역값은 위에처럼 하면되고
application.yml 이라던지 secret.java 라던지 중요한 파일들은 어떻게할까?
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v2
- name: Set up JDK 1.8
uses: actions/setup-java@v1
with:
java-version: 1.8
- name: Copy Secret
env:
PLANET_SECRET: ${{ secrets.PLANET_SECRET }}
PLANET_SECRET_DIR: src/main/java/com/example/demo/config/secret
PLANET_SECRET_TEST_DIR: src/test/java/com/example/demo/config/secret
PLANET_SECRET_DIR_FILE_NAME: Secret.java
run: echo $PLANET_SECRET | base64 --decode > $PLANET_SECRET_DIR/$PLANET_SECRET_DIR_FILE_NAME &&
echo $PLANET_SECRET | base64 --decode > $PLANET_SECRET_TEST_DIR/$PLANET_SECRET_DIR_FILE_NAME
- name: Copy dev_yml
env:
DEV_APPLICATION_YML: ${{ secrets.DEV_APPLICATION_YML }}
DEV_APPLICATION_YML_DIR: src/main/resources
# PLANET_SECRET_TEST_DIR: src/test/java/com/example/demo/config/secret
DEV_APPLICATION_YML_FILE_NAME: application.yml
run: echo $DEV_APPLICATION_YML | base64 --decode > $DEV_APPLICATION_YML_DIR/$DEV_APPLICATION_YML_FILE_NAME #&&
#echo $PLANET_SECRET | base64 --decode > $PLANET_SECRET_TEST_DIR/$PLANET_SECRET_DIR_FILE_NAME
내 workflow의 일부분인데
- name: Copy Secret
env:
PLANET_SECRET: ${{ secrets.PLANET_SECRET }}
PLANET_SECRET_DIR: src/main/java/com/example/demo/config/secret
PLANET_SECRET_TEST_DIR: src/test/java/com/example/demo/config/secret
PLANET_SECRET_DIR_FILE_NAME: Secret.java
run: echo $PLANET_SECRET | base64 --decode > $PLANET_SECRET_DIR/$PLANET_SECRET_DIR_FILE_NAME &&
echo $PLANET_SECRET | base64 --decode > $PLANET_SECRET_TEST_DIR/$PLANET_SECRET_DIR_FILE_NAME
이런식으로 gitignore때문에 제외된 파일을
만들어 줄 수 있다
(예를들어 Secret.java라는 파일을 만들어주고싶을때 )
name : 행동에 대한 이름
env에 환경변수값을 저장해주는데
PLANET_SECRET: ${{ secrets.PLANET_SECRET }} 는
Secret.java의 내용을 Base64로 인코드한 값을 내용으로 가진 Secret이다!
Dir은 이 파일이 어디에 있어야하는지를 적어주는부분 ( 어디다가 이 파일을 생성할지를 적어주면된다 , 하지만 해당 폴더가 존재하지않는다면 Action을 할때 실패한다. 빈값을 가진 java파일이라도 만들어서 폴더를 생성해주자 , 깃저장소는 빈폴더를 만들어주지않고 , 빈폴더를 push해도 안보임)
Test_dir은 spring 프로젝트에서 main도 있고 test도 있는데 test도 사용한다면 쓰고 아니면 주석처리하면된다.
dir_file_name에서 파일이름을 설정해준다.
run: echo $시크릿이름 .... 쭉 뒤에도 내가 설정한 변수이름으로 다 바꿔준다.
테스트 부분이 필요없으면 뒷부분은 주석처리한다.
이렇게 작성하고 실행하면
Actions이 실행되면서
DIR에서 설정한 위치에
dir_file_name에서 설정한 파일이름을 가지고
secret에서 만든 PLANET_SECRET이란 시크릿의 내용을 이용해서 파일을 내용을 가지는 파일이 생성된다!
그러면 해당 파일을 생성됬으니 그 후로 진행될 빌드에서 오류가 발생하지않고 성공할 것이다.
원하는 파일생성에 관한 자세한 내용은 다음 블로그에서 참고하였다!
---
이제 Actions를 실행하고 성공하고 난 후
s3버킷을 확인해보면
프로젝트이름의 폴더명안에 zip파일이 있는걸 확인할 수 있다! (빌드된 jar파일이 압축되서 업로드된 결과)!
이렇게되면 빌드/테스트 하고 s3에 업로드까지하게된거고
이제 s3에 올라간 빌드파일을 자동으로 배포하고 또 배포하는 도중 서버가 중단안되는 무중단 배포를 구현해보자.
다음 게시글에 계속
출처,참고,더 자세한 정보
'Spring > Spring ++' 카테고리의 다른 글
Github Actions + Code Deploy + Ngxin + ubuntu 20.04로 무중단 배포하기 (3) 마지막! (0) | 2022.10.23 |
---|---|
Github Actions + Code Deploy + Ngxin + ubuntu 20.04로 무중단 배포하기 (2) (1) | 2022.10.23 |
Spring - SMTP 네이버 이메일 인증 , redis로 인증번호 만료 구현 (0) | 2022.10.16 |
댓글