[CI/CD] FastAPI 배포하기 - AWS EC2, Github Actions, Docker

THOVY·2023년 3월 10일
3

PROJECT

목록 보기
20/20

fastAPI 와 react 를 이용한 서비스를 다 완성했으니 배포를 해야지.

준비물

  • AWS EC2 - Linux (당연히 putty 도 필요)
  • Github Respository
  • 조금있다 하겠지만 python 설치 모듈을 관리하는 requirements.txt 파일 만들기
  • 오타 없는 코드를 완성할 수 있는 손가락

우린 AWS EC2 는 만들줄 알지.

모르면 저번에 썼던 CI/CD REACT 배포
에서 준비물 준비를 보면 된다.

  1. AWS 에서 EC2 Linux 로 만들고, 보안그룹을 관리해놓자.
    80 번 포트를 열려면 80을 열어놓고 8000번 포트를 열려면 8000번을 열어놓자.

  2. 만든 ec2 에 접속.

  3. 따라서 DOCKER 설치

Github Runners

EC2 를 만진 김에 Runners 바로 설치해주자.
그것도 다 있다. 이 글 아래쪽에 - CI/CD REACT 배포 - 다만 label-OOO 에 어떤거 적었는지는 꼭 기억하자.


이렇게
Runners 설치까지만 하고 nohup ./run.sh & 로 켜놓고 오자. putty 꺼도된다.

Python 인 FastAPI 에 맞게 dockerfile 만들기

매우매우 친절하게도 Docs 가 있다. Fastapi in Contianers - Docker
행복하다.

일단 저번시간에 했던 node 의 dockerfile 과 크게 다르지 않다.

하지만 중요한 건 속도.
cache 를 이용한다. 좀있다 얘기하고

# 나의 python 버전
FROM python:3.11.1

# /code 폴더 만들기
WORKDIR /code

# ./requirements.txt 를 /code/requirements.txt 로 복사
COPY ./requirements.txt /code/requirements.txt

# requirements.txt 를 보고 모듈 전체 설치(-r)
RUN pip install --no-cache-dir -r /code/requirements.txt

# 이제 app 에 있는 파일들을 /code/app 에 복사
COPY ./app /code/app

# 실행
CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "80"]

저는 requirements.txt 가 없는데요?

그럼 만들어주자.

우리의 프로젝트에 가서 터미널을 열고, pip freeze > requirements.txt 라고 하면 root 폴더에 파일이 만들어진다.
node 에서는 npm install 하면 알아서 package.json 을 보고 node_modules 를 만들지만 이건 node 가 아니야

이제 dockefile 의 세번째부터 하나씩 살펴보자.

# ./requirements.txt 를 /code/requirements.txt 로 복사
COPY ./requirements.txt /code/requirements.txt

react 프로젝트를 배포할 때는 ADD . /app 이라고 전체를 다 옮겼는데, 왜죠.
fastapi 에서는 이렇게 설명하고 있다.

이 파일은 자주 변경되지 않으므로 Docker 는 이를 감지하고 여기서 캐시를 사용합니다. 다음단계에서도 캐시를 활성화합니다.

캐시를 하는데 군데군데 캐시를 해놓고, 바뀌는 부분 안 바뀌는 부분을 구분하고자 함인 것 같다.

다음줄

# requirements.txt 를 보고 모듈 전체 설치(-r)
RUN pip install --no-cache-dir -r /code/requirements.txt

fastapi 에서는 설치 후 버전 업그레이드 까지하는 --upgrade 도 코드에 넣어놓았지만, 나는 버전이 달라졌을 때를 감당할 실력도 자신도 없으므로, 빼버렸다. ㅋㅋ아 내가 말 한 것만 하라구요 ;;

--no-cache-dir 은 무슨 말인지 모르겠다.

읽어보니 이해가 된다. Fastapi Docker Cache

-r 전체 설치

다음줄

# 이제 app 에 있는 파일들을 /code/app 에 복사
COPY ./app /code/app

fastapi 는 이때부터 혹은 이 뒤부터 docker 가 캐시를 사용하지 않는다고 한다.
왜냐면 자주 바뀌는 부분이니까!
그래서 fastapi 는 빌드 속도를 높이려면 이 부분을 dockerfile 끝부분에 위치시키는게 좋다고 한다.
역시 속도의 fastapi

다음줄

# 실행
CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "80"]

uvicorn 을 이용해서 실행하는 거다. 어느 주소든(0.0.0.0) 80번 포트로는 들어올 수 있어요.

그다음 github token 만들기

dockerfile 을 만들었으니 token 을 만들자.
여기 또 다 있다.

github 계정 - setting - 맨 아레 developer settings - personal access tokens - Tokens(classic) - new token(classic)

거기서 세 개 체크

다시 우리의 repo 로 와서, secrets and variables - actions - new reposiroty secret 에다가 저장.

저번에도 말했지만, name 꼭 기억하자. 나는 GHCR_TOKEN 이라고 햇다.

이제 actions

우리 레포에서 actions 에 들어가서 dockerfile 을 돌리도록 action 을 만들어주자.

  1. 새로운 workflow 를 만들고,
  1. 코드를 적는데 저번이랑 똑같이 적으면 된다.
name: Deploy with Docker
# 내가 만드는 이름이다 뭐든 상관없다

on:
  push:
    branches: [ main ]
    # 무슨 브랜치가 업데이트 될 때 Actions 를 작동시킬지 적는다.
    # develop 브랜치로 개발하며 완료되면 main 에 머지해 Actions 를 작동시키면 조금 더 안전하겠지.
    # 여러개 적어도 된다.

env:
  DOCKER_IMAGE: ghcr.io/${{ github.actor }}/myproject
  VERSION: ${{ github.sha }}
  NAME: newproject
  # Docker image 를 ghcr.io 에 올릴 때 우리의github이름/이미지이름 으로 저장한다. 이미지이름을 정해주면 된다.
  # Docker image 의 이름을 newproject 이라고 해놓은 것. 이름 뭐할지 정하면 된다.

jobs:
  build:
    name: Build
    runs-on: ubuntu-latest
    steps:
      - name: Checkout
        uses: actions/checkout@v2
      
      - name: Setup docker buildx
        id: buildx
        uses: docker/setup-buildx-action@v1
        
      - name: Cache docker layers
        uses: actions/cache@v2
        with:
          path: /tmp/.buildx-cache
          key: ${{ runner.os }}-buildx-${{ env.VERSION }}
          restore-keys: |
            ${{ runner.os }}-buildx-
      - name: Login to ghcr
        uses: docker/login-action@v1
        with:
          registry: ghcr.io
          username: ${{ github.actor }}
          password: ${{ secrets.GHCR_TOKEN }}
          # 우리가 방금 복사해서 setting secrets 에 붙여줬던 token 이다. 이름을 기억해 넣어주자.
          # 우리의 ghcr.io 에 접근하기 위함이다.
        
      - name: Build and push
        id: docker_build
        uses: docker/build-push-action@v2
        with:
          builder: ${{ steps.buildx.outputs.name }}
          push: true
          tags: ${{ env.DOCKER_IMAGE }}:latest
  
  deploy:
    needs: build
    name: Deploy
    runs-on: [ self-hosted, label-newproject ]
    # label-newproject 라는 이름으로 AWS EC2 가 Runner 를 작동시킬 때 사용했던 그 label
    steps:
      - name: Login to ghcr
        uses: docker/login-action@v1
        with:
          registry: ghcr.io
          username: ${{ github.actor }}
          password: ${{ secrets.GHCR_TOKEN }}
      
      - name: Docker run
        run: |
          docker stop ${{ env.NAME }} && docker rm ${{ env.NAME }} && docker rmi ${{ env.DOCKER_IMAGE }}:latest
          docker run -d -p 3000:3000 --name newproject --restart always ${{ env.DOCKER_IMAGE }}:latest
          
          # 첫 줄
          # 먼저 진행되고 있던 docker 를 stop(멈추고), rm 로 docker 컨테이너를 지우고, rmi 로 docker 이미지를 지운다.
          # 새롭게 build 된 docker 를 사용하기 위함이다.
          
          # 두번째 줄
          # -d : 백그라운드로
          # -p : 포트 번호 3000번에서 3000번으로 접근
          # --name : docker 이미지 이름을 newproject 로 할거다. 이게 나중에 위에 적은거랑 같아야하는데 왜냐면 첫 줄이랑 같아야 나중에 지워지니까. 확인하자.

job 이 돌아가는 일. build 하고 deploy 가 있지.
이름만 주의해주면 된다.

yml 이 완성되어 코드를 main 브랜치(main.yml 초입에 어떤 브랜치가 업데이트 될 때 actions 를 돌릴지 적은 그 브랜치) 에다가 commit 해주면 알아서 돌아간다.

docs 도 잘 표시되는 구먼!

에러가 나면 오타가 없는지 살펴보자.

그리고 우리는 local 에서 작업해왔기 때문에 endpoint 가 다를수도있어 cors 에러 가 발생할 수도 있다.

주의하자.

오늘 dockerdocekr 로 입력해서 세 번 에러 남. cache 안 했으면 하루 종일 돌리고 있었을 듯.

댕청해지지말고 정신차리자!

그리고 fastapi 에서 cors 에러 가 난다?
해결 방법은 좀있다 쓸 거다.

아무튼 끝

아무튼 어렵지 않게 fastapi 도 배포할 수 있었다.
Git Actions 가 매우 쉬운 덕도 있지만, fastapi 가 Docs 페이지에서 docker 에 관해 매우 상세하게 설명해주고 있는 덕이 크다.
감사합니다 tiangolo 사랑합니다.

profile
BEAT A SHOTGUN

0개의 댓글