(CI/CD)github Action

전성영·2022년 7월 11일
1

spring

목록 보기
20/31

먼저 CI와 CD를 알아보자!

CI/CD란?

애플리케이션 개발 단계부터 배포 때까지의 단계를 자동화해 효율적이고 빠르게 사용자에게 빈번히 배포할 수 있는 것이다.

CI - 지속적인 통합(Continuous Integration)

  • 새로운 코드 변경 사항이 정기적으로 빌드 및 테스트되어 공유 리포지토리에 병합되는 것이다.
  • Build , Test 를 실시하는 프로세스를 말하며 , 이러한 통합 프로세스를 상시로 실히하는 것이다.
  • 다수의 개발자가 동시에 애플리케이션 개발과 관련된 코드 작업을 할 경우 , 서로 충돌 할 수 있는 문제를 해결하기 위함이다.

CD - 지속적인 배포(Continuous Deployment)

  • 개발자들이 애플리케이션에 적용한 변경 사항이 버그 테스트를 거쳐 리포지토리에 자동으로 업로드 되는 것이다.
  • 개발자의 변경 사항을 리포지토리에서 고객이 사용 가능한 프로덕션 환경까지 자동으로 릴리스 하는것이다.
  • 이 리포지토리에서 애플리케이션을 실시간 프로덕션 환경으로 배포된다.

Github Action이란?

GitHub에서 제공하는 CI/CD 플랫폼이다.
즉 개발 Workflow를 자동화 할 수 있는 도구이다.

Workflow는 Github 저장소에서 발생하는 build, test, package, release, deploy 등 다양한 이벤트를 기반으로 직접 원하는 Workflow를 만들 수 있다.

왜 Github Action?

Travis, jenkins와 달리 복잡한 절차 없이 Github을 통해 사용할 수 있는 장점이 있고,
환경 호환성을 위해 Docker 이미지에서 동작해야되는 jenkins와 달리 GithubActions은 모든 환경에서 호환이 됩니다.
또한 작업이 동기적으로 일어나는 jenkins와 달리 비동기 CI/CD가 가능한 Github Action이 배포하는 데에 시간이 절약 된다.

전체 흐름도

  • Github Actions에서 프로젝트 빌드 후, jar 파일을 압축해서 S3에 업로드합니다.
  • 이어서 CodeDeploy에게 S3에 있는 jar 파일을 가지고 배포를 진행해달라고 전달합니다.
  • CodeDeploy는 배포할 EC2 인스턴스 내부에 있는 CodeDeploy Agent에게 배포 명령을 내리고, Agent는 jar 파일을 S3에서 받아서 주어진 스크립트에 따라 배포를 진행합니다.
  • 새로운 Spring Boot WAS를 띄우고, Nginx 스위칭을 통해 무중단 배포를 할 수 있도록 Agent에게 배포 스크립트를 제공합니다.

시작!!!!!!!!!!!!!!
먼저 자신의 깃허브에 repository를 생성한다.

의존성 추가는 spring web 만 추가해주면 된다! 테스트니깐~

build.gradle

1. workflow를 생성

  • workflow(작업 흐름)란?

    GithubAction에서 가장 상위의 개념이다. 자동화를 해놓은 작업 과정.

이 순서대로 누르면 아래의 창이 나올 것이다.

yml 수정을 해보자!!

# This is a basic workflow to help you get started with Actions

name: CI

# Controls when the workflow will run
on:
  # Triggers the workflow on push or pull request events but only for the "main" branch
  push:
    branches: [ "main" ]
  pull_request:
    branches: [ "main" ]

  workflow_dispatch:
  
  
jobs:
  build:
    runs-on: ubuntu-latest

    steps:
      - uses: actions/checkout@v3
      
      - name: Set up JDK 11
        uses: actions/setup-java@v1
        with:
          java-version: 11
          
      - name: Grant execute permission for gradlew
        run: chmod +x ./gradlew
        working-directory: ./G.ATest

      - name: Build with Gradle
        run: ./gradlew build
        working-directory: ./G.ATest
          
      - name: Run a one-line script
        run: echo Hello, world!

      - name: Run a multi-line script
        run: |
          echo Add other actions to build,
          echo test, and deploy your project.

지금 만드는 yml파일은 /.github/workflows에 생성이 된다.

working-directory: ./G.ATest

이 친구는 gradlew를 찾지 못해 생기는 에러가 발생하여 붙여줬다.

그 후 다시 Action 탭에 들어가게 되면

기분 좋은 초록이... 👍


1-1 사용자 추가

사용자를 추가해서 키 값을 받아야 한다.
AWS 검색창에 IAM 검색 후 -> 사용자 -> 사용자 추가를 클릭한다.

IAM은 계정에 대한 인증 및 권한 부여를 제어하는 데 필요한 인프라를 제공


체크를 한 후 넘어간다.

기존 정책 직접 연결에서 AmazonS3FullAccessAWSCodeDeployFullAccess 를 선택합니다.

그렇게 하면 사용자가 만들어지는데, 발급받은 키 값을 깃허브에 등록을 해야한다.

AWWS_RESION은 ap-northeast-2 값을 넣어주도록 하자!

2. ec2 태그 추가


태그를 추가하고 저장한다.

3. IAM 역할 추가

AWS 검색창에 IAN 검색 후 -> 역할 -> 역할만들기를 들어간다.


사용 사례를 EC2로 체크한다.

AmazonS3FillAccess를 추가해준다.

역할 이름을 작성 후 저장을 한다.

들어가서 IAM 역할에서 방금 만든 역할을 집어넣고 저장하면 끝난다!

4. s3 버킷 생성

  • s3란?

    Simple Storage Service의 약자로 파일 서버의 역할을 하는 서비스다.
    일반적인 파일서버는 트래픽이 증가함에 따라서 장비를 증설하는 작업을 해야 하는데 S3는 이와 같은 것을 대행한다


이대로 만들면 된다!

5. CodeDeploy Agent 설치

  • CodeDeploy란?

    Amazon EC2 인스턴스로 애플리케이션 배포를 자동화하는 배포 서비스입니다.
    또한 배포 방식도 다양하게 구성할 수 있는데,
    Blue/Green Deployment를 수행하는 등의 과정으로 가동 중지 시간을 최소화할 수 있다.

Blue/Green 배포는 구 버전에서 새 버전으로 일제히 전환하는 전략이다. 구 버전의 서버와 새 버전의 서버들을 동시에 나란히 구성하고 배포 시점이 되면 로드밸런서를 통해 트래픽을 일제히 전환시킨다. 하나의 버전만 프로덕션 되므로 버전 관리 문제를 방지할 수 있고, 또한 빠른 롤백이 가능하다. 또 다른 장점으로 운영 환경에 영향을 주지 않고 실제 서비스 환경으로 새 버전 테스트가 가능하다.
!!!!하지만 블루-그린 배포를 위해서는 시스템 자원이 두 배로 필요하며 새로운 환경에 대한 테스트가 전제되어야 합니다.

로드 밸런서(Load Balancer)
서버에 가해지는 트래픽을 여러대의 서버에게 균등하게 분산시켜주는 역할

  • CodeDeploy Agent란?

    ec2에 설치하는 프로그램으로, CodeDeploy에서 해당 ec2를 사용할 수 있도록 하는 프로그램이다.
$ sudo apt update
$ sudo apt install ruby-full
$ sudo apt install wget
$ cd /home/ubuntu
$ wget https://aws-codedeploy-ap-northeast-2.s3.ap-northeast-2.amazonaws.com/latest/install
$ chmod +x ./install
$ sudo ./install auto > /tmp/logfile
$ sudo service codedeploy-agent status

고대~로 치면 끝난다.

재시작도 해주세요
sudo service codedeploy-agent restart

6. CodeDeploy 전용 IAM 생성 및 애플리케이션 생성

아까 역할 만들었던 거랑 비슷하다.
똑같이 AWS 검색창에 IAN 검색 후 -> 역할 -> 역할만들기를 들어간다.

다른 AWS 서비스의 사용 사례에 CdoeDeploy를 찾은 후 체크해준다.
그 후 저장을 한다.

저장을 하였으면 검색창에 CodeDeploy 검색 후 -> 애플리케이션 -> 애플리케이션 생성을 한다.

컴퓨팅 플랫폼을 EC2로 맞춘 후 생성을 해준다.
애플리케이션 이름은 나중에 사용하니 메모장에 적어두자! 찾기 귀찮으니깐!

그 후 바로 배포 그룹 생성을 하자!


작성 해주시고~


키 값도 작성 해주시고~

마지막으로 로드 밸런서를 취소해주면 끝~

7. appspec.yml 작성

최상단에 appspec.yml 파일을 만들어 준다.

지금까지 서버를 띄울 EC2, 배포할 결과물을 저장할 S3, 배포를 도와줄 CodeDeploy 이렇게 총 세 가지 AWS 서비스를 만들었다.

이제 CodeDeploy 에서 배포를 위해 참조할 AppSpec 파일을 작성해보자.

AppSpec 파일을 사용해서 우리는 프로젝트의 어떤 파일들을 EC2 의 어떤 경로에 복사할지 설정 가능하고, 배포 프로세스 이후에 수행할 스크립트를 지정하여 자동으로 서버를 띄울 수도 있다.

appspec.yml

version: 0.0
os: linux

files:
  - source:  /
    destination: /home/ubuntu/app
    overwrite: yes

- source: 인스턴스에 복사할 디렉터리 경로
- destination: 인스턴스에서 파일이 복사되는 위치
- overwrite: 복사할 위치에 파일이 있는 경우 대체

permissions:
  - object: /
    pattern: "**"
    owner: ubuntu
    group: ubuntu
    
- object: 권한이 지정되는 파일 또는 디렉터리
- pattern (optional): 매칭되는 패턴에만 권한 부여
- owner (optional): object 의 소유자
- group (optional): object 의 그룹 이름

추가로 Spring Boot 2.5 버전부터는 빌드 시 일반 jar 파일 하나와 -plain.jar 파일 하나가 함께 만들어진다고 하는데 그것을 막기 위해 build.gradle에 아래 코드를 추가해준다.

jar {
    enabled = false
}

이 부분을 추가해주는데 상황에 맞게 작성해야 한다.

- name: Make zip file
        run: zip -r ./$GITHUB_SHA.zip .
        shell: bash

      - 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: ${{ secrets.AWS_REGION }}


      - 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 .
        working-directory: ./G.ATest
  

      - 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
        working-directory: ./G.ATest
  

그 후 이 친구들도 추가해준다.


이렇게 하면?????????????????

git에서 push할 시 자동으로 ubuntu까지 전달해준다!!
끝!

(추가)Nginx를 활용한 무중단 배포

  • Nginx란?

    Nginx란 일종의 경량 트래픽이 많은 웹사이트의 확정성을 위해 개발된 경량 웹 서버이다.
  • 클라이언트로부터 요청을 받았을 때 요청에 맞는 정적 파일을 응답해주는 HTTP Web Sever로 활용되기도 하고
  • Reverse Proxy Server로 활용하여 WAS 서버의 부하를 줄일 수 있는 로드 밸런서로 활용되기도 한다.
    역방향 프록시(reverse proxy) : 클라이언트의 요청을 받아 웹서버로 전달하여 응답을 받은 후 다시 클라이언트에 전달하는 역할을 수행하는 서버. 즉, 클라이언트와 웹서버 사이에 존재하는 서버이다.
  • Nginx 구조

Nginx는 하나의 Master Process와 다수의 Worker Process로 구성되어 실행된다.
Master Process에는 설정 파일을 일고, 유효성을 검사 및 Worker Process를 관리한다.

  • Nginx vs Apache

curl 설치

apt install curl

nginx 설치

sudo apt-get install nginx

nginx 실행

sudo service nginx start

nginx 확인

ps -ef | grep nginx
sudo nginx -v 버전확인
sudo apt purge nginx. - 제거

nginx 설정폴더로 이동

cd /etc/nginx/sites-available

nginx 설정 수정하기

sudo vi default

이렇게 추가를 해주면 된다!

얘는 location 바깥
include /home/ec2-user/service_url.inc;
얘는 location 안쪽
proxy_pass $service_url;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
얘는 location 밑쪽
include /etc/nginx/default.d/*.conf;

inc파일 만들기

vi /home/ubuntu/service_url.inc

셋팅
set $service_url http://54.180.96.247:8090;

그 후 재시작을 해준다.

재시작

sudo service nginx restart - 재시작

여기까지가 ubuntu에서 할 셋팅이다.
그럼 인텔리제이로 고고~

appsec.yml에 추가

hooks:
  ApplicationStart:
    - location: scripts/run_new_was.sh
      timeout: 180
      runas: ubuntu
    - location: scripts/health_check.sh
      timeout: 180
      runas: ubuntu
    - location: scripts/switch.sh
      timeout: 180
      runas: ubuntu

그리고 scripts 최상단에 만들고 .sh 3개 추가

scripts/run_new_was.sh

새로운 WAS를 띄우는 스크립트입니다.
service_url.inc 에서 현재 서비스를 하고 있는 WAS의 포트 번호를 읽어온다.
현재 포트 번호가 8090이면 새로 WAS를 띄울 타겟 포트는 8091, 혹은 그 반대 상황이라면 8090을 지정한다.
만약 타겟포트에도 WAS가 떠 있다면 kill하고 새롭게 WAS를 띄운다.

scripts/health_check.sh

새로 띄운 WAS가 완전히 실행되기까지 health check 하는 스크립트이다.

scripts/switch.sh

nginx 리로드를 통해 서비스하는 포트를 스위칭하는 스크립트이다.
sudo service nginx reload 는 nginx 서버의 재시작 없이 바로 새로운 설정값으로 서비스를 이어나갈 수 있도록 한다.
sudo service nginx restart 는 말그대로 서버의 shutdown 이후 재시작하는 명령이므로 의도하지 않았다면 주의해야 한다.

tee
출력 내용을 파일로 만들어주는 커맨드이다.
새로 띄운 WAS의 포트를 nginx가 읽을 수 있도록 service_url.inc에 내용을 덮어쓴다.

실행

nohup java -jar -Dserver.port=8090 /home/ubuntu/final/build/libs/todori~~.jar & 

여기까지가 하면 무중단 배포 완성이다!! 라고 하고 싶었지만 밑에도 봐야 한다.

트러블 슈팅

자잘한 에러가 매우 많았지만 가장 큰 친구만 정리하려고 한다.

1.

이런 에러가 뜨면서 RESPONSE_CODE=$(curl -o /dev/null -s -w "%{http_code}" http://54.180.96.247:${TARGET_PORT}/health) 에서 RESPONSE_CODE 값이 200이 들어가지 않는 것 같다고 말씀해주셨다.

2.

Error creating bean with name 'proofImgService' defined in URL [jar:file:/home/ubuntu/final/build/libs/todoli-0.0.1-SNAPSHOT.jar!

를 비롯한 각종 에러가 나왔고 찾아보니 gitignore을 해주었던 .properties 파일이 읽히지 않는 것을 알아내었다.

해결 방법

workflows 경로에 있는 yml 파일에 추가를 해준다.
.properties는 중요한 정보가 담겨있어서 외부에 노출하면 안되기 때문에 secretKey 값으로 감싸서 넣어준다.
코드를 보면 경로를 생성을하고 해당 경로로 이동해서 파일을 생성한 후 properties에 담겨있는 각종 정보들을 넣어주는 코드이다.

이로써 무중단 배포를 완료하였다!
혼자가 아닌 둘이서 하면서 협업의 느낌도 받고 좋은 경험이었다!

느낀 점

  1. 알고쓰자.

reference

https://bcp0109.tistory.com/363
https://blogshine.tistory.com/428


https://wbluke.tistory.com/41?category=418851
https://blogshine.tistory.com/432
https://www.sunny-son.space/AWS/AWS%20CodeDeploy%EC%99%80%20nginx%EB%A1%9C%20%EB%AC%B4%EC%A4%91%EB%8B%A8%20%EB%B0%B0%ED%8F%AC/

profile
Slow and Steady

0개의 댓글