본문 바로가기

개발/Web

[Elastic Beanstalk] 열받는(?) 배포(feat. Github Action)

기술 스택

- aws rds

- aws elasticbeanstalk

- github action

- nestjs

- typeorm

만났던 문제들

1. Database error  

- synchronize: true였다가 false로 바꿨던 상황을 조금 뒤늦게 인지

- 로컬에서 pgAdmin으로 aws rds에 붙어서 확인해보니까 테이블 생성이 안 된 걸 확인

- 아 엔티티 스키마가 아예 반영이 안 됐구나

- 마이그레이션 해보자

 

2. .ebextensions/01_migration.config에 마이그레이션 명령어 추가

commands:
  01_run_migration:
    command: |
      #!/bin/bash
      cd /var/app/current
      export DB_TYPE=$DB_TYPE
      export DB_HOST=$DB_HOST
      export DB_PORT=$DB_PORT
      export DB_USERNAME=$DB_USERNAME
      export DB_PASSWORD=$DB_PASSWORD
      export DB_DATABASE=$DB_DATABASE
      npx typeorm migration:run -d dist/data-source.js
    leader_only: true

- 명령어 실행에 번번이 에러가 발생

- 확인해보니 빌드 결과물인 dist가 /var/app/current에 없음

- 이리저리 알아봤지만 이 방법은 안 됨

- 이상한 방법임

- 이 방법을 추천한 Grok을 처음으로 블랙홀에 던져버리고 싶었음

- Github Action 워크플로우에 npx typeorm migration..을 추가하기로 함

 

3. 환경변수 문제

- DataSource에 환경변수가 들어가는데, 리포지토리 설정에 추가해놨는데도 계속 못 읽음

- 알고 보니 GithubAction 스텝이 진행되면서 실행되는 코드는 다시 별도로 변수를 만들어줘야 함을 알게됨

jobs:
  build-and-deploy:
    runs-on: ubuntu-latest
    env:
      DB_TYPE: ${{ secrets.DB_TYPE }}
      DB_HOST: ${{ secrets.DB_HOST }}
      DB_PORT: ${{ secrets.DB_PORT }}
      DB_USERNAME: ${{ secrets.DB_USERNAME }}
      DB_PASSWORD: ${{ secrets.DB_PASSWORD }}
      DB_DATABASE: ${{ secrets.DB_DATABASE }}
      ENV: ${{ secrets.ENV }}

 

4. no encrypt 이슈

- 이건 또 뭐임

- 알고 보니 ssl 설정이 필요한 거였음

- data-source.ts에 ENV === 'prod' 일 때는 ssl 설정이 적용될 수 있게 함

- rejectUnauthorized: false를 설정하더라도 ssl 설정은 추가해야함

dotenv.config();

export default new DataSource({
  type: process.env.DB_TYPE as 'postgres',
  host: process.env.DB_HOST,
  port: parseInt(process.env.DB_PORT || '5432'),
  username: process.env.DB_USERNAME,
  password: process.env.DB_PASSWORD,
  database: process.env.DB_DATABASE,
  synchronize: false,
  logging: false,
  entities: ['dist/**/*.entity.js'],
  migrations: ['dist/database/migrations/*.js'],
  ...(process.env.ENV === envKeys.prod && {
    ssl: {
      rejectUnauthorized: false,
    },
  }),
});

 

5. 그리고 당연한 거지만 마이그레이션 파일이 dist 폴더에 이미 존재해야 함

 

6. 드디어 에러 메시지가 마이그레이션 관련 오류로 바뀜 users_roles_enum 테이블이 없다는 생전 처음 보는 에러 문구를 만남

- synchronize: true 일 때 알아서 해주던 것의 고마움을 잊고 살았음

- rbac을 하기 위해 users 테이블에서 Role enum 타입의 컬럼(배열)이 존재함

- enum 타입을 사용하기 위해 데이터베이스에 enum type을 만들어야 하는 거였음

- 그런데 알고 보니 enum은 숫자가 안 됨

- 난 그동안 숫자를 잘만 넣었는데? synchronize: true 고맙다..

- 알고 보니 데이터베이스에 enum type을 생성할 때 숫자는 안 되니까 user 엔티티의 Role 타입 컬럼의 type을 자동으로 int로 만들었던 것

- enum type은 자동으로 만들어주지도 않아서 마이그레이션 파일을 새로 만들어서 enum type이 만들어지고 나서 테이블이 생성되도록 조정해놨는데 필요 없는 설정이었음

- 다음처럼 해서 문제 해결

@Column({
    type: 'int', // 'enum' 이었음
    enum: Role,
    default: [Role.user],
    array: true,
  })
  roles: Role[];

 

7. 드디어 마이그레이션도 통과하고 ElasticBeanstalk(이하 EB)에서 환경설정이 업데이트 되는데 nest nof found 에러가 발생함

- 갑자기 웬 nest 명령어?

- 개발할 때 사용하는 nest cli이기 때문에 만나면 안 되는데

- 알고보니 가장 처음에 수동으로 zip 파일을 배포할 때 그냥 프로젝트 전체를 압축한 거라 섬세하게 생각하지 못했었는데

- 파일 압축할 때 Procfile을 빼먹었음

- nest.js는 express 혹은 fastify을 랩핑하는데 express 기준으로, 배포할 때 Profile에 명령어를 넣어줘야 함

- 그래서 nest.js 배포할 때도 넣어줘야 함

web: npm run start:prod

// package.json
"start:prod": "node dist/main",

 

8. 배포 파일을 압축할 때 Profile 파일을 포함

- zip -r deploy.zip dist package.json Procfile

 

9. 이제 진짜 된 거 같은데 EB 환경설정 업데이트를 계속 실패

- 자꾸 타임아웃 발생하고

- 메모리인지 CPU 사용량인지 엄청 올라감

- 아, 컴퓨터가 느린 거구나

 

10. 애플리케이션 재생성해서 t3.small로 해서 드디어 배포 성공!

 

이렇게 축약했을 때 10단계고 실제로는 더욱 지난한 과정이었다.

꼬박 하루(24시간)이 조금 더 걸림. 해결하고 나면 쉽지만 그 전까지는 어떤 문제인지 찾기가 너무 어렵다.

결론: 배포는 어렵다. 성취감은 좋다. 그런데 어렵다.