반응형

 

배포를 처음 해보면 보통 이런식으로 합니다.

코드를 다 짜고, 서버에 직접 접속해서, 손으로 빌드하고 다시 손으로 서버를 껐다가 켭니다.

몇 번은 괜찮은데 이게 반복되면 슬슬 실수가 나옵니다.

한 단계를 빠트리거나, 옛날 코드를 올려버리거나 하는 상황이 생깁니다. 

 

그래서 이번 글에서는 코드를 깃허브에 올리기만 하면 빌드부터 서버 배포까지 알아서 돌아가게 만드는 방법을 정리해보려고 합니다.

이걸 보통 CI/CD라고 부릅니다.

 


CI/CD

 

CI 지속적 통합 (Continuous Integration) 

- 코드를 올릴 때마다 이 코드가 제대로 빌드되고 테스트를 통과하는지 자동으로 검사합니다.

 

CD 지속적 배포 (Continuous Deployment)

- 검사를 통과한 코드를 자동으로 서버에 올려주는 것입니다.

 

즉 코드 검사이후 통과하면 서버에 자동 배포까지 한 줄로 이어진 흐름이라고 보시면 됩니다.

이 일을 대신 해주는 도구가 여러 개 있는데, 그중 깃허브를 이미 쓰고 있다면 가장 편한 게 깃허브 액션입니다.

따로 가입할 것도 없고, 저장소(레포지터리)안에 설정 파일 하나만 넣으면 동작합니다.

 


전체 흐름 미리보기 

 

 

정리하면 이런 순서입니다.

 

  1. 코드를 main 브랜치에 push 
  2. 깃허브 액션이 이걸 감지하고 자동으로 작업을 시작합니다.
  3. 백엔드와 프론트엔드를 각각 빌드하고 테스트합니다.
  4. 둘 다 통과하면, 배포 작업이 실행되어 서버에 올라갑니다. 

 

 


깃허브 저장소에서 미리 해둬야 하는 일

 

설정 파일을 만들기 전에, 깃허브 저장소 쪽에서 먼저 준비해둬야 하는 게 있습니다.

바로 비밀값 등록입니다. 

 

서버에 접속하려면 서버 주소, 접속 계정, 비밀번호(SSH)같은 민감한 정보가 필요합니다.

그런데 이런 값을 설정 파일에 그대로 적으면 코드를 본 사람 누구나 내 서버에 들어올 수 있습니다. 

그래서 이런 값은 코드에 적지 않고, 깃허브가 따로 숨겨서 보관해주는 공간에 등록합니다.

이것을 시크릿(Secrets, 비밀값)이라고 부릅니다.

 

등록하는 위치는 이렇습니다.

저장소 -> Setting(설정) -> 왼쪽 메뉴의 Secrets and variables ->
Actions -> New repository secret(새 비밀값 추가)

 

여기에 들어가서, 나중에 설정 파일에서 사용할 값들을 미리 등록해둡니다.

예를 들면 이런 것들입니다.

  • 서버 주소 (예: OOO_SERVER_HOST)
  • 서버 접속 계정 이름 (예: OOO_SERVER_USER)
  • 서버 접속용 SSH 키 (예: OOO_SERVER_SSH_KEY)
  • 서버 접속 포트 (예: OOO_SERVER_PORT)

이름은 본인이 원하는 대로 정하면 됩니다. 다만 한 가지만 지키면 됩니다.

여기서 등록한 이름과, 뒤에서 설정 파일에 적을 이름이 정확히 똑같아야 합니다.

대소문자 하나라도 다르면 인식하지 못합니다.

 


프로젝트 안에 만들어야 하는 파일

 

깃허브 액션은 약속된 위치에 파일을 두면 자동으로 인식합니다. 

프로젝트 최상위 폴더
ㄴ .github
	ㄴ workflows
    		ㄴ ci-cd.yml

 

.github/workflows/폴더 안에 .yml파일을 만들면 됩니다. 파일 이름은 자유롭게 정해도 됩니다.

이 .yml 이라는 형식은 들여쓰기(띄어쓰기로 단계를 구분하는 것)로 구조를 표현하는 파일이라, 띄어쓰기가 어긋나면 동작하지 않으니 그 점만 주의하시면 됩니다.

 

아래는 설정 파일의 전체 골격입니다. 본인 프로젝트에 맞게 바꿔야 하는 부분은 OOO으로 표시해뒀습니다. 

 

[1단계 - 언제 실행할지 정하기]

name: 내 프로젝트 CI/CD

on:
  push:
    branches:
      - main
  pull_request:
    branches:
      - main

 

on은 어떤 상황에서 이 작업을 실행할지 정하는 부분입니다. 

위 설정은 main 브랜치에 코드가 올라오거나(push), main 브랜치로 합치는 요청(pr)이 오면 실행하라는 뜻입니다. 

 

[2단계 - 코드 검사하기(CI)]

jobs:
  backend-ci:
    name: 백엔드 빌드 & 테스트
    runs-on: ubuntu-latest

    steps:
      - name: 소스 코드 가져오기
        uses: actions/checkout@v4

      - name: 언어 환경 설정
        uses: actions/setup-OOO@v4
        with:
          OOO-version: 'OOO'

      - name: 빌드 및 테스트
        working-directory: OOO(백엔드 폴더 경로)
        run: OOO(빌드 명령어)

 

여기서 하는 일을 풀어보면 이렇습니다.

  • runs-on : ubuntu-latest : 깃허브가 빌려 주는 임시 리눅스 컴퓨터에서 작업을 돌린다는 뜻입니다. 내 서버가 아니라, 깃허브가 잠깐 빌려주는 공짜 컴퓨터입니다.
  • actions/checkout : 그 임시 컴퓨터에 내 코드를 내려받는 단계입니다.
  • setup-OOO : 내 프로젝트가 쓰는 언어 환경을 설치하는 단계입니다. 자바면 setup-java처럼 본인 언어에 맞게 바꿉니다.
  • run : 실제로 실행할 명령어입니다. 평소 내 컴퓨터에서 빌드할 때 치는 명령어를 그대로 적으면 됩니다.

프론트엔드도 동일한 방식으로 하나 더 만들면 됩니다.

검사 대상이 두 개라면, jobs 아래에 백엔드용, 프론트엔드용 작업을 각각 적어주면 됩니다.

 

[3단계 - 검사를 통과하면 배포하기(CD)]

deploy:
    name: 서버 배포
    runs-on: ubuntu-latest
    needs: [backend-ci, frontend-ci]
    if: github.ref == 'refs/heads/main' && github.event_name == 'push'

    steps:
      - name: 소스 코드 가져오기
        uses: actions/checkout@v4

      - name: 서버로 파일 전송
        uses: appleboy/scp-action@v0.1.7
        with:
          host: ${{ secrets.OOO_SERVER_HOST }}
          username: ${{ secrets.OOO_SERVER_USER }}
          key: ${{ secrets.OOO_SERVER_SSH_KEY }}
          source: "OOO(서버로 보낼 파일)"
          target: "OOO(서버에서 받을 위치)"

      - name: 서버에서 배포 실행
        uses: appleboy/ssh-action@v1.0.3
        with:
          host: ${{ secrets.OOO_SERVER_HOST }}
          username: ${{ secrets.OOO_SERVER_USER }}
          key: ${{ secrets.OOO_SERVER_SSH_KEY }}
          script: |
            OOO(서버에서 실행할 배포 명령어)

 

배포 작업에서 중요한 두 줄이 있습니다.

  • needs : [backend-ci, frontend-ci] : 이 배포 작업은 앞의 두 검사가 모두 끝난 뒤에야 시작하라는 뜻입니다. 이 줄이 바로 검사를 통과해야만 배포한다는 안전장치입니다.
  • if: gihhub.ref == 'refs/heads/main' && github.event_name == 'push' : 이 배포는 main 브랜치에 직접 코드가 올라온 경우애만 실행하라는 뜻입니다. 합치기 요청(PR)단계에서는 검사만 하고 배포는 하지 않게 막아주는 역할입니다. 검토 중인 코드가 실수로 서버에 올라가는 걸 방지해줍니다.

그리고 값을 가져올 때 쓰는 ${{secrets.OOO_SERVER_HST}} 이 문법이 보이실텐데, 이게 바로 아까 위에서 등록해둔 비밀값을 꺼내 쓰는 방법입니다.

secrets. 뒤에 적는 이름이 등록한 이름과 똑같아야 한다는 점, 다시 한번 말씀드립니다. 

 

여기서 사용한 appleboy/scp-action과 appleboy/ssh-action은 다른 사람이 미리 만들어둔 도구입니다.

각각 서버로 파일을 보내는 일과, 서버에 접속해서 명령어를 실행하는 일을 대신 해줍니다.

직접 구현할 필요 업싱 가져다 쓰면 됩니다.

 


동작하는지 확인하기

 

파일을 다 만들었으면, 이 설정 파일 자체를 깃허브에 올려봅니다. (push). 그러면 저장소 상단의 Actions 탭에서 작업이 돌아가는 모습을 실시간으로 볼 수 있습니다.

각 단계가 초록색 체크 표시로 바뀌면 성공한 것이고, 빨간색 X가 뜨면 그 단계를 눌러서 어디서 멈췄는지 로그를 확인할 수 있습니다.

 

처음에는 거의 한 번에 안됩니다.

저도 그랬습니다. 띄어쓰기가 어긋났거나, 비밀값 이름이 다르거나, 빌드 명령어가 살짝 틀린 경우가 대부분이니, 빨간 X가 떠도 당황하지 말고 로그를 천천히 읽어보시면 됩니다. 

로그에 어느 줄에서 멈췄는지 친절하게 나옵니다.

 


정리

 

이번 글에서는 코드를 올리면 자동으로 검사하고, 통과하면 서버에 배포되는 흐름의 뼈대를 만들어봤습니다.

핵심만 다시 짚으면 이렇습니다.

  • 민감한 값(서버 주소,키 등)은 코드에 적지 말고 저장소의 비밀값에 등록합니다.
  • 설정 파일은 .github/workflows/안에 .yml로 만든다.
  • 검사 작업(CI)과 배포 작업(CD)을 나누고, 배포는 needs와 if로 검사 통과 +main 브랜치 일 때만 실행 되게 막는다.

다음 글에서는 이렇게 서버까지 코드가 전달된 다음, 서비스를 잠깐도 멈추지 않고 새 버전으로 갈아끼우는 방법,

무중단 배포(블루-그린 배포)를 다뤄보겠습니다.

728x90
반응형