본문 바로가기

SpringBoot

[스프링 부트 3 백엔드 개발자 되기] ch 12 CI/CD 도입하기

1. CI/CD

 

1) 지속적 통합, CI

 

- CI는 Continuous Integration을 줄인 표현, 개발자를 위해 빌드와 테스트를 자동화하는 과정

- CI는 변경 사항을 자동으로 테스트해 애플리케이션에 문제가 없다는 것을 보장한다. 그리고 코드를 정기적으로 빌드하고, 테스트하므로 여러 명이 동시에 작업을 하는 경우 충돌을 방지하고 모니터링할 수 있다. 

- 코드 변경 사항이 코드 저장소에 업로드되면 CI를 시작하고, CI 도중 문제가 생기면 실패하므로 오류도 쉽게 파악할 수 있다. 

 

 

2) 지속적 제공과 지속적 배포, CD

 

- CD는 CI 작업을 끝낸 다음 실행하는 작업이다. 배포 준비가 된 코드를 자동으로 서버에 배포하는 작업을 자동화하는 것이다. 

 

지속적 제공에서의 CD 의미

 

- 애플리케이션이 적용한 코드의 빌드와 테스트를 성공적으로 진행했을 때 깃허브와 같은 코드 저장소에 자동으로 업로드하는 과정

 

지속적 배포에서의 CD 의미

 

- 지속적 제공을 통해 성공적으로 병합한 코드 내역을 AWS와 같은 배포 환경으로 보내는 것을 의미한다. 이를 실무에서는 릴리스라고 한다. 

- 지속적인 배포는 지속적 제공의 다음단계까지 자동화한다. 

- 즉, 개발자가 애플리케이션에 변경 사항을 커밋한 후 몇 분 이내에 애플리케이션을 자동으로 배포되어 적용된다. 

 

 

2. 깃허브 액션 사용하기 

 

깃허브 액션(github action)

 

- 깃허브에서 제공하는 서비스로, 리포지터리에 특정 이벤트가 발생하면 특정 작업을 하거나, 주기적으로 특정 작업을 반복할 수 있게 한다. 

- 예를 들어, 누군가 코드를 작성해 깃허브에 업데이트하면 해당 코드에 문제가 없는지 자동으로 코드를 빌드, 테스트한 이후 배포까지 할 수 있다. 

 

1) 깃허브 리포지터리 생성하고 코드 푸시하기 

 

- 깃허브 액션을 사용하려면 깃허브 리포지터리에 지금까지 작업한 코드를 업로드해야 한다. 

- 깃허브에 코드를 업로드하는 행위를 푸시(push)라고 부른다. 

 

- 깃허브 홈페이지에서 [New repository] 버튼을 눌러 새 리포지터리 생성 화면으로 넘어가서 프로젝트 이름을 적은 뒤, 공개 범위를 설정한 후 리포지터리를 생성 

 

 

 

- 인텔리제이로 지금까지 작업한 프로젝트를 연다. 그런 다음 아래에 있는 [Terminal]을 눌러 터미널 창을 열고 git init 명령어를 입력한다. 

- git init 명령어는 특정 폴더를 깃 저장소로 만들 때 사용하는 명령어이다.

- 숨김 폴더로 .git 폴더가 생긴다. 바로 이 폴더에 코드의 변경 내역(버전) 관리를 위한 정보를 저장한다. 

 

- 깃허브의 리포지터리와 로컬의 깃 저장소를 연결하기 위해 remote 명령어를 사용한다. 

 

 

- 로컬 저장소의 이력, 파일을 리포지터리에 푸시하기 위한 add, commit 작업을 실행

- add . 명령어는 현재 프로젝트 폴더의 모든 파일을 대상으로 변경 사항 등을 추적하고 그 파일들을 스테이지에 올린다.

- 스테이지는 리포지터리에 올리기 전에 파일들의 변경사항을 미리 모아놓은 곳이다. 

- commit은 로컬 저장소에 올리기 위한 것이다. 즉, 커밋을 해야만 로컬 저장소에 변경 이력, 변경할 파일들이 업데이트된다. 

 

 

 

- 브랜치명을 main으로 바꾼 후 원격 저장소에 저장하기 위해 push 명령어를 입력해 푸시를 마무리한다. 

 

 

- 깃허브에 접속해서 리포지터리를 확인하면 커밋할 때 적었던 메시지와 함께 코드들이 업로드된 것을 확인할 수 있다. 

 

 

 

2) 깃허브 액션 스크립트 작성하기, CI

 

- 프로젝트 최상단에 .github 디렉터리를 만든다. 그 안에 workflows 디렉터리를 다시 만들고 ci.yml 파일을 생성해 다음 스크립트를 작성한다. 

 

ci.yml

name: CI # 워크플로의 이름 지정

# 워크플로가 시작될 조건 지정
# main 브랜치에 푸시를 할 때마다 워크플로를 시작하도록 작성
on:
  push:
    branches: [ main ]

jobs:
  build:
    runs-on: ubuntu-latest  # 실행 환경 지정

    #실행 스텝 지정
    #각 항목은 별도의 작업(uses) 또는 명령어(run)으로 이루어짐 
    steps:
      - uses: actions/checkout@v3

      - uses: actions/setup-java@v3
        with:
          distribution: 'zulu'
          java-version: '17'

      - name: Grant execute permission for gradlew
        run: chmod +x gradlew

      - name: Build with Gradle
        run: ./gradlew clean build

 

 

- 추가된 파일을 원격 저장소로 올리기 위해 커밋, 푸시를 진행하고 깃허브 리포지터리의 [Action] 메뉴에 들어가 CI가 실행되는 것을 확인한다. 워크플로가 성공적으로 동작하면 초록색 체크 모양으로 표시된다. 

 

 

3) 깃허브 액션 스크립트 작성하기, CD

 

- - plain 접미사가 붙은 jar 파일은 플레인 아카이브(plain archive)라고 하며 애플리케이션 실행에 필요한 의존성을 포함하지 않고 소스 코드의 클래스 파일과 리소스 파일만 포함한다. 따라서 플레인 아카이브만으로는 서비스를 실행할 수 없으므로 빌드 시에 일반 jar 파일만 생성하도록 그레이들 파일을 변경한다. 

 

build.gradle

...
jar {
    enabled = false
}
...

 

- 깃허브 액션 스크립트에서 만든 ci.yml 파일 이름을 cicd.yml로 변경하고 다음 코드를 추가 

 

cicd.yml

name: CI/CD

on:
  push:
    branches: [ main ]

jobs:
  build:
    runs-on: ubuntu-latest

    steps:
      - uses: actions/checkout@v3

      - uses: actions/setup-java@v3
        with:
          distribution: 'corretto'
          java-version: '17'

      - name: Grant execute permission for gradlew
        run: chmod +x gradlew

      - name: Build with Gradle
        run: ./gradlew clean build

      # 현재 시간 가져오기 
      - name: Get current time
        uses: josStorer/get-current-time@v2.0.2
        id: current-time
        with:
          format: YYYY-MM-DDTHH-mm-ss
          utcOffset: "+09:00"

      #배포용 패키지 경로 저장 
      # 빌드 이후 생성된 jar 파일을 찾아 "artifact"라는 환경 변수에 값을 넣어준다. 
      # $GITHUB-ENV를 사용해 깃허브 워크플로 전체적으로 사용할 수 있는 환경 변수를 설정할 수 있다. 
      - name: Set artifact
        run: echo "artifact=$(ls ./build/libs)" >> $GITHUB_ENV

      # 빈스토크 배포 
      # einaregilsson/beanstalk-deploy 플러그인을 사용해 빈스토크 배포를 진행 
      - name: Beanstalk Deploy
        uses: einaregilsson/beanstalk-deploy@v20
        with:
          aws_access_key: ${{ secrets.AWS_ACCESS_KEY_ID }}
          aws_secret_key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
          application_name: spring-boot-developer
          environment_name: SpringBootDeveloper-env
          version_label: github-action-${{steps.current-time.outputs.formattedTime}}
          region: ap-northeast-2
          deployment_package: ./build/libs/${{env.artifact}}

 

- IAM은 AWS 리소스를 사용하도록 권한을 부여하는 서비스

- AWS에 접속한 뒤 IAM 서비스를 접속한 다음 [사용자]를 클릭한다. 그런 다음 [사용자 생성] 버튼을 눌러 사용자를 추가한다. 

 

- [다음]을 눌러 나온 권한 설정에서는 [직접 정책 연결]을 선택한 뒤 AdministratorAccess-AWSElasticBeanstalk를 검색해 선택한다.  이 권한은 빈스토크를 사용하기 위해 필요한 모든 관리 권한을 사용자에게 제공하는 권한이다. 

 

- 사용자 생성을 마치고 github-action 사용자를 눌러 액세스 키를 만든다. 

- [서드 파티 서비스]를 선택하고 [다음]을 누르고 '설명 태그 값'을 github-action으로 해 액세스 키를 만든다. 

 

- 복사한 값을 등록하기 위해 깃허브 리포지터리에 접속한 뒤 [Settings->Secrets and variables -> Actions] 순서로 메뉴에 들어간다. 그 이후에 [New repository secrets] 버튼을 눌러 새로운 비밀 키를 각각 등록한다. 

 

 

- 깃허브에 커밋, 푸시를 하기 전에 민감한 값을 바꾼다. application.yml 파일을 열어 비밀값으로 정의한 client-id, client-secret, jwt 항목의 secret_key를 임의의 값으로 바꾼다. 이 값4들은 aws에 설정했던 값으로 자동으로 덮어씌워진다. 

 

application.yml

spring:
  jpa:
    show-sql: true
    properties:
      hibernate:
        format_sql: true
    defer-datasource-initialization: true
  h2:
    console:
      enabled: true
  security:
    oauth2:
      client:
        registration:
          google:
            client-id: test_id
            client-secret: test_secret
            scope:
              - email
              - profile
jwt:
  issuer: ajufresh@gmail.com
  secret_key: test_key

 

 

- cd가 정상적으로 작동하는 것을 확인하기 위해 커밋과 푸시를 차례대로 수행하고 확인