Product Serving(8): 모델, 코드배포

SeongGyun Hong·2024년 12월 17일

NaverBoostCamp

목록 보기
47/64

1. 환경 분리와 배포

  • Local
  • Dev
  • Staging
  • Production

개발 환경을 나누는 이유는 실제 운영중인 서비스에 장애가 되면 안되기 때문임.

  • Git Flow

    • [main]
      프로덕션 서버

    • [staging]
      Staging Server

    • [dev]
      Dev Server

    • [feautre/기능 이름]

서버에 코드를 보내는 것과
반복적으로 진행할 Test를 어떻게 실행하는 방법은?
Dev Branch에 Merge되면 => Local에서 Git Pull & Test 실행 후 코드 배포(FTP, SCP로 파일 전송)
=> 매우 번거로운 일!
그래서 나온 것이 CI/CD

CI: Continuous Integration(지속적 통합)

  • 새롭게 작성한 코드 변경 사항이 Build, Test 진행한 후 Test Case에 통과했는지 확인
  • 지속적으로 코드 품질 관리
  • 10명의 개발자가 코드를 수정했다면 모두 CI 프로세스 진행
  • 빌드, 테스트 자동화

CD: Continuous Deploy/Delivery(지속적 배포)

  • 작성한 코드가 항상 신뢰 가능한 상태가 되면 자동으로 배포될 수 있도록 하는 과정
  • CI 이후 CD를 진행
  • dev / staging / main 브랜치에 Merge가 될 경우 코드가 자동으로 서버에 배포
  • 배포 자동화

모델 배포에서 주의할 점

  • Docker 이미지
    • 사이즈가 보통 큰 편이어서 관리가 필요하다
    • 호스트 머신의 디스크 용량 관리가 필요하다
      (로그를 주기적으로 삭제하거나 클라우드로 보내기)
  • 모델 버저닝
    • 모델 코드에 대한 확실한 버저닝
    • 어떤 버전의 모델이 현재 배포 중이고, 과거에는 어떤 버전으로 배포되었는지
    • 롤백이 필요하다면 어떤 버전으로 재배포해야 하는지
    • 모델의 버전 별 특징을 쉽게 볼 수 있어야 함
  • 모델 아티팩트
    • 모델 이미지에 저장하기 보다 S3, 오브젝트 저장소(S3, Cloud Storage)에 저장하는 것을 권장
      • 모델을 만들었는데 10기가 넘어가고 이렇다면,,, 그걸 도커 이미지 안에 우겨넣는 것 보다 따로 S3와 같은 오브젝트 저장소를 통해서 관리하는 것이 바람직!
    • 모델 버전과 아티팩트의 버전이 다른 경우도 있으므로 메타정보를 체크할 것
      • 이를 해결하기 위해 나온 것이 바로 MLflow
    • 적합한 파일 권한 관리 (VM 인스턴스, Object Storage 둘 다)
      • VM 인스턴스에서 pth 파일을 읽지 못한다면 정상 실행 불가능
      • Object Storage에서 다른 사용자가 버킷을 삭제하면 롤백 불가능(삭제 권한 제어 필요)

2. Github Action

소프트웨어 Workflow 자동화를 도와주는 도구

  • Test Code
    • 특정 함수의 return 값이 어떻게 나오는지 확인하는 Test code
    • 특정 함수의 타입 체크
    • Unit Test
    • End to End Test
  • 배포

    • Prod, Staging, Dev 서버에 코드 배포
    • FTP로 파일 전송할 수도 있고, Docker Image를 Push하는 방법 등
    • Node.js 등 다양한 언어 배포도 지원
  • 파이썬, 쉘 스크립트 실행

    • Github Repo에 저장된 스크립트를 일정 주기를 가지고 실행
    • crontab의 대용
    • 데이터 수집을 주기적으로 해야할 경우 활용할 수도 있음
  • Github Tag, Release 자동으로 설정

    • Main 브랜치에 Merge 될 경우에 특정 작업 실행
    • 기존 버전에서 버전업하기
    • 새로운 브랜치 생성시 특정 작업 실행도 가능

그 외에도 다양한 Workflow를 만들 수 있음
사용자가 만들어서 Workflow 템플릿을 공유하기도 한다.
원하는 기능이 있는 경우 <기능> github action 등으로 검색!
Action Marketplace : https://github.com/marketplace?type=actions
Awesome Github Action : https://github.com/sdras/awesome-actions

단 , Github Action에는 다음의 제약이 있음

  • 하나의 Github Repository 당 Workflow는 최대 20개까지만 가능
  • Workflow에 존재하는 Job(실행)은 최대 6시간 실행할 수 있으며, 초과시 자동으로 중지됨
  • 동시에 실행할 수 있는 Job 제한 존재

Github Action을 어떻게 잘 활용할 수 있을까?

  1. 코드 작업
  2. 코드 작업 후, Github Action으로 무엇을 할 것인가?
  3. 사용할 Workflow 정의
  4. Workflow 정의 후 정상 작동하는지 확인

Github Action 핵심 개념

  • Workflow

    • 여러 Job으로 구성되고 Event 별로 Trigger(실행)되는 자동화된 Process
    • 최상위 개념
    • Workflow파일은 YAML으로 작성되고, Github Repository의
      .github/workflows 폴더에 저장
  • Event

    • Workflow를 Trigger하는 특정 활동, 규칙
      • 특정 Branch로 Push, Pull Reaquest 하는 경우
      • 특정 시간대에 반복(Cron)
  • Job

    • Runner에서 실행되는 Steps의 조합
    • 여러 Job이 있는 경우 병렬로 실행하며, 순차적으로 실행도 가능하다.
      • 다른 Job에 의존 관계를 가질 수 있음
  • Step

    • Job에서 실행되는 개별 작업
    • Action을 실행하거나 쉘 커맨드 실행
    • 하나의 Job에선 데이터를 공유할 수 있음
  • Action

    • Workflow의 제일 작은 단위
    • Job을 생성하기 위해 여러 Step을 묶은 개념
    • 재사용 가능한 Component
    • 개인적으로 Action을 만들수도, Marketplace의 Action을 사용할 수도 있음
  • Runner

    • Github Action도 일종의 서버에서 실행되는 개념
    • Workflow가 실행될 서버
    • Github-hosted Runner: Github Action의 서버를 사용하는 방법
      • 성능: vCPU 2, Memory 7GB, Stroage 14GB
    • Self-hosted Runner: 직접 서버를 호스팅해서 사용하는 방법

.github/workflows/ ~.yml 분석

# Functions: GitHub Actions work-flow 파일로써, 코드 품질 검사를 자동화하는 설정을 포함하고 있음.

# 본 work-flow의 이름으로써 본 워크플로우 이름을 "check-lint"로 지정함.
name: check-lint

# 본 work-flow는 pull-request가 생성될 때마다 실행됨(본 파일의 목적인 코드 품질 검사를 실행) 
on: [pull_request]

# 이하는 작업의 구성 요소를 의미
jobs:
  check-lint:                                   # 작업 이름
    runs-on: ubuntu-latest                      # 이 작업은 최신 Ubuntu 환경에서 실행될 것임. 

    steps:                                      # 작업에서 수행할 단계를 정의함
      - name: Checkout code                     # 첫번째로 실행되는 step
        uses: actions/checkout@v4               # actions/setup-python@v4을 사용하여 저장소의 코드를 체크아웃함
                                                # 무슨말이냐면 현재 이 work-flow가 정의된 저장소를 `$GITHUB_WORKSPACE` 디렉토리로 클론한 후에
                                                # 발생되는 이벤트(본 work-flow의 경우 pull-request)에 따라 해당 커밋을 `$GITHUB_WORKSPACE` 디렉토리에서 checkout 함
                                                # Q. 왜 그렇게 해주나요? 
                                                # => 아니 코드를 VM으로 가져와야 아래 step들에 해당하는 내용들을 체크하지요..?
                                                # GitHub Actions의 runner는 기본적으로 비어 있어서, 워크플로우에서 코드를 사용할 수 있도록 `actions/checkout`이 필요한 것!
                                                # Q. 왜 하나요? 
                                                # => 단순히 로컬에서 push 해버리고 끝! 이게 아니라, CI/CD 파이프라인에서 테스트 및 기타 작업을 하기 위해서 위 단계가 필수적으로 필요한 것.
                                                # code-lint, test, build 등의 자동화 작업에서는 runner 환경에 코드가 존재해야하므로, actions/checkout은 핵심적인 역할을 함.
                                                                       
      - name: Set up Python 3.11                # 두번째로 실행되는 step
        uses: actions/setup-python@v5           # actions/setup-python@v5을 사용하여 python 버전 확인
        with:                                   # 이때 Python 버전은 3.11로 지정
          python-version: "3.11"

      - name: Install dependencies              # 세번째로 실행되는 step: 명령어 실행
        run: |                                  # '|'은 멀티라인 문자열로써, run 키워드 다음에 오는 명령어를 여러줄로 작성 가능하게 해줌
          python3 -m pip install --upgrade pip  

      - name: Check Lint                        # 네번째로 실행되는 step: 명령어 실행
        run: |
          make quality

3. 모델 이미지 준비

배포하기 전에 모델 이미지도 준비해서 모델도 같이 업데이트 하려면!

  • 사전준비
    • 서빙할 모델 코드
    • Online Serving을 위한 API Endpoint 정의 코드
    • 컨테이너화를 위한 의존성 정의 (requirements.txt)

      Docekr Image Registry란?

    • 수많은 도커 이미지들을 저장하는 저장소
    • 자체적으로 이미지의 이름과 버전 등을 저장하고 불러옴
    • Docker 공식 저장소(ex. Dockerhub) 또는 클라우드의 저장소를 사용
      • 우리가 사용할 서비스는
        Google Cloud Artifact Registry
      • Google Cloud의 이미지 저장소: Docker Image, npm 패키지 등을 저장, 관리할 수 있음
      • Repository: 저장소

3.1 Artifact Registry에 Docker Image를 Push하는 과정

  • Docker Image Build

  • 태그 설정

  • 이미지 Push

  1. 먼저 GCP에서 artifacts에 들어가서 CREATE REPOSITORY 클릭하고
    (Project ID 꼭 확인)

  2. 이름 지정한 후에 Format은 Docker로 정의

  3. 로컬에서 Docker Image Build
    (-t를 통하여 model_deploy:test로 설정)

  4. 이제 태그설정을 해야함
    docker tag "기존 이미지:태그""새이미지 이름:태그"
    새 이미지 이름은 Google Cloud의 Artifact Registry URL
    boostcamp-ai-tech-serving은 각자의 Project ID로 변경

    docker tag model_deploy:test asia-northeast3-docker.pkg.dev/boostcamp-ai-tech-serving/model-deploy/v1:latest
  5. 이제는 푸시를 해주면 된다.

docker push asia-northeast3-docker.pkg.dev/boostcamp-ai-tech-serving/model-deploy/v1:latest
  1. 웹 콘솔에서 확인하면 Repository에 올라간 것을 확인할 수 있음

  2. 올라간 Docker Image를 Pull하고 싶다면

docker pull asia-northeast3-docker.pkg.dev/boostcamp-ai-tech-serving/model-deploy/v1:latest

3.1.1 Github Action을 통해서 특정 조건의 Docker Image Build, Push 자동화를 하면 어떨까?

  • 예들들면, main에 Merge되면 Docker Image를 새로 만들고, Registry에 Push하는 것

  • 이 작업을 하기 위해 Google Cloud Service Account 설정

여기 Secrets에는 뭘 저장하나요..?

  1. 서비스 계정 클릭 후 만든 다음
  2. 생성된 json파일 전체 경로를 넣고 이름 지정하면 됨.

3.2 Google Cloud Service Account와 Github Actions를 이용한 Docker 자동화 설정 방법

3.2.1 서비스 계정 설정

1. Google Cloud Console에서 서비스 계정 생성

  • Google Cloud Console(console.cloud.google.com)에 접속
  • IAM & Admin > Service accounts로 이동
  • "Create Service Account" 클릭

2. 서비스 계정 세부 정보 입력

  • 서비스 계정 이름 입력 (알파벳과 숫자로 6-30자)
  • 설명 추가 (선택사항)
  • "Create and Continue" 클릭

3. 권한 설정

  • 필요한 IAM 역할 부여 (예: Storage Admin, Container Registry Service Agent)

3.2.2 Github Repository 설정

1. Github Secrets 설정

  • Repository의 Settings > Secrets and variables > Actions로 이동
  • 서비스 계정에서 다운로드한 JSON 키 파일의 내용을 새로운 Secret으로 등록
  • Secret 이름을 GCP_SA_KEY로 설정

3.2.3 Github Actions Workflow 설정

.github/workflows/docker-build.yml 생성:

name: Build and Push Docker Image

on:
  push:
    branches:
      - main

env:
  REGISTRY: gcr.io
  IMAGE_NAME: ${{ github.repository }}

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout
        uses: actions/checkout@v3
      
      - name: Auth to Google Cloud
        uses: google-github-actions/auth@v1
        with:
          credentials_json: ${{ secrets.GCP_SA_KEY }}
          
      - name: Set up Cloud SDK
        uses: google-github-actions/setup-gcloud@v1
      
      - name: Configure Docker
        run: gcloud auth configure-docker
        
      - name: Build and Push
        uses: docker/build-push-action@v4
        with:
          context: .
          push: true
          tags: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest

3.2.4 동작 방식

  1. main 브랜치에 코드가 머지되면 워크플로우가 자동으로 시작됨
  2. Google Cloud 인증을 수행하고 Docker 빌드 환경을 설정
  3. Dockerfile을 기반으로 이미지를 빌드
  4. 빌드된 이미지를 Google Container Registry(GCR)에 푸시

이 설정을 통해 main 브랜치에 코드가 머지될 때마다 자동으로 새로운 Docker 이미지가 빌드되고 GCR에 푸시됨.

4. 배포하기

  • GCP에서 VM 만들 때 내가 위에서 빌드한 컨테이너 이미지를 사용할 수 있음

  • 볼륨마운트도 가능

  • 인스턴스를 띄울 때 Docker Image 기반으로 생성하면, 이후 나온 Image를 기반으로 Container 업데이트가 가능하다.

  • 만약 그냥 서버를 띄웠다면, 새로운 코드를 서버에 전송하고, 그 코드를 기반으로 앱을 재실행(reload 옵션 등이 있으면 설정)

Compute Engine은 이미지로 만들어진 인스턴스를 빠르게 업데이트 할 수 있는 기능을 CLI로 제공한다.

gcloud compute instances update-container <서버이름>-container-image <컨테이너 이미지>
  • CI(Continuous Integration)을 진행한 후, GCE VM Instance에 변경 사항 전파
    • needs 필드를 통해 CI 작업이 정상 완료 되어야 실행
    • 업데이트할 인스턴스, 존(영역) 정보를 사용해 해당 인스턴스 업데이트
profile
헤매는 만큼 자기 땅이다.

0개의 댓글