[튜토리얼] AWS EC2 : 앱 배포하는 방법

JooSehyun·2023년 4월 18일
0

튜토리얼

목록 보기
4/18
post-thumbnail

튜토리얼

앱 배포하는 방법


앱 배포하는 방법

이번에 사용해 볼 배포 방법


EC2 Instance 생성

URL : https://aws.amazon.com/ko/

  1. AWS 회원가입

  1. 루트 사용자 로 회원가입을 하고 로그인을 한다.

  1. 검색창에 EC2 를 검색한다.

  1. 인스턴스 시작을 눌러준다.
  1. 애플리케이션 및 OS 이미지(Amazon Machine Image) 는 Quick Start 에서 가장 많이 사용하는 Ubuntu 를 서택한다
  1. 인스턴스 유형 (1년 미만 가입자이기에 프리티어 사용)

  1. 키 페어(로그인) 란은 새로운 키 페어 생성을 눌러준다.

  1. 키 페어 이름을 작성하고 유형은 기본값으로 두고 생성하면 파일이 하나 다운로드 되는데 이건 보관한다. (터미널로 접근할 때 필요함)

  1. 해당 IP 접근을 위해 방화벽 설정이다. 브라우저 -> 프론트엔드 80번 , 백엔드에서 4000번 , 데이터베이스 5432번 포트도 뚫어줘야하는데 조금 있다가 다시 한다. (일단 기본값으로 둔다)
  1. 인스턴스시작 버튼을 누른다.
  1. 인스턴스 메뉴에서 만든걸 확인한다. (인스턴스 상태는 실행 중)

  1. 체크박스 체크하고 오른쪽 상단 연결 버튼을 누른다.

보통은 SSH 클라이언트로 많이 하는데, EC2 인스턴스로 배포를 할 거기 때문에 EC2 인스턴스 연결을 눌러준다.

  1. 이런화면이 뜨는데 이제 여기서 필요한 모듈을 설치하고 설정한다.

URL : https://www.digitalocean.com/community/tutorials/how-to-install-and-use-docker-on-ubuntu-22-04

Ubuntu 22버전에 맞는 docker 인스톨 방법

이렇게 위 URL에 설치방법이 나오는데 하나하나 복사해서 EC2에 붙여넣기 하면된다.

  1. sudo systemctl status docker 까지 작성하여 설치를 마치면 설치가 완료된다.
  1. docker설치가 다 됐는데, docker-compose up이 되지 않는다.

경고문으로 나온 sudo apt install docker-compose 를 복사하여 붙여넣는다.

  1. 이제 EC2에 리액트 소스코드를 올려야하는데 2가지의 방법이 있다.

1번 : FTP를 이용해서 파일 올려주기 (Filezilla)
2번 : 깃허브로 리액트 파일을 올린 후에 EC2 인스턴스에서 Clone하기

  1. github 방법을 사용한다. 저장소를 만들고 올려준다.
  1. EC2 에서 git clone 주소 를 적고 저장소 코드를 클론한다.
  1. 완료가 되면 ls 를 입력하면 프로젝트명이 나오고 cd 프로젝트명 으로 들어가서 ls 를 입력하면 clientserver 가 잘 들어온걸 확인 할 수 있다.

  1. 이제 docker로 실행을 해본다. sudo docker-compose up


Docker Container는 성공


EX) Client 부분 소스코드 변경

환경에 따른 env 파일 생성

프론트엔드는 localhost:3000
백엔드는 localhost:4000 으로 들어갔지만 EC2에서는 퍼블릭 IPv4 DNS 로 들어간다.

그래서 로컬호스트에서 실행될 때와 AWS에서 실행될 때를 구분하여 환경에 따른 소스코드가 있어야한다.


개발환경 -> .env.development
운영환경 -> .env.production

기존 env.env.development 로 파일명을 변경하고, .env.production 에서는 EC2 인스턴스퍼블릭 IPv4 DNS 를 복사한다.

example ) NEXT_PUBLIC_SERVER_BASE_URL=http ://ec2-3-106-117-251.ap-southeast-2.compute.amazonaws.com:4000

env-cmd

이렇게 다르게 사용이 될 때 필요한 모듈이 있다.
env-cmd 패키지를 이용해서 환경에 따라 .env파일을 따라 정의해서 사용할 수 있다.

*sever쪽 말고 client에서

npm install env-cmd --save

설치를 해준다.

그런다음 client의 package.json"scripts" 에서 변경해준다.


기존

 "scripts": {
    "dev": "next dev",
    "build": "next build",
    "start": "next start",
    "lint": "next lint"
  },

변경

 "scripts": {
    "dev": "next dev",
    👉"build:dev": "env-cmd -f .env.development next build",👈
    👉"build:prod": "env-cmd -f .env.production next build",👈
    👉"start:dev":"env-cmd -f .env.development next start",👈
    👉"start:prod":"env-cmd -f .env.production next start",👈
    "start": "next start",
    "lint": "next lint"
  },

pm2를 위한 설정 파일 생성

npm install pm2 -g

PM2를 사용하려는 이유는 무엇인가?

  1. Node.js 애플리케이션을 계속 유지하기 위해서.
  2. Node.js가 다운되면 PM2는 다운타임 없이 자동으로 다시 복구한다.
  3. 로드 밸런서가 내장되어 있어 애플리케이션을 훨씬 쉽게 확장할 수 있다.
  4. Linux, WindowsMac OS에서 작동한다.
  5. 애플리케이션의 로그를 관리하는 방법에 도움이 될 수 있다.
  6. js파일을 수정했을 때, 자동으로 프로세스를 껐다/켠다.
  7. 백그라운드에서 계속 실행될 수 있게 해준다.
  8. Single Thread인 Node.jsCluster 모드를 이용해서 CPU 코어 수 만큼 프로세스를 지원할 수 있게 해준다.

쉽게 npm run start 를 통해서 하는거 보단 pm2의 도움을 받아서 실행을 해주는게 안정적이다.

pm2 를 위한 설정 파일 생성

  1. client에서 ecosystem.config.js 파일을 생성한다.
  2. 아래의 코드를 작성

module.exports = {
	apps: [{
		name:"community-client",
        script:"npm run start:prod"
    }]
}

3. index.tsx 에서 address 등 주소를 적어놓은 곳에는 localhost 주소를

example) 변경전

const address = "http://localhost:4000/api/subs/sub/topSubs";

example) 변경후

const address = "/subs/sub/topSubs";

example) 변경전

await axios.get("/auth/me", {headers: { cookie }});

example) 변경후

await axios.get(`${process.env.NEXT_PUBLIC_SERVER_BASE_URL}api/auth/me`, {headers: { cookie }});

운영환경 이미지 최적화를 위한 Sharp 모듈 설치

URL : https://nextjs.org/docs/messages/sharp-missing-in-production

*client에서
npm install sharp --save

설치를 하지 않는다면 Error 발생..

이미지를 (기본 프로필 이미지 gravatar.com) 위해서 도메인추가

client > next.config.js 에서


example) 변경전

/** @type {import('next').NextConfig} */
const nextConfig = {
  reactStrictMode: true,

  //gravatar 기존이미지 에러 허용
  images:{
    domains: ["www.gravatar.com", "localhost"]
  }
}

module.exports = nextConfig

example) 변경후

/** @type {import('next').NextConfig} */
const nextConfig = {
  reactStrictMode: true,

  //gravatar 기존이미지 에러 허용
  images:{
    domains: [
      "www.gravatar.com", 
      "localhost",
      👉"ec2-3-106-117-251.ap-southeast-2.compute.amazonaws.com"👈
    ]
  }
}

module.exports = nextConfig

EX) Sever 부분 소스코드 변경

Server 부분도 동일하다.

개발환경 -> .env.development
운영환경 -> .env.production

env-cmd

*server에서

npm install env-cmd --save


운영환경 -> .env.production

PORT=4000
NODE_ENV=development
APP_URL=http://ec2-3-106-117-251.ap-southeast-2.compute.amazonaws.com:4000
ORIGIN=http://ec2-3-106-117-251.ap-southeast-2.compute.amazonaws.com

JWT_SECRET=super_secret

개발환경 -> .env.development

PORT=4000
NODE_ENV=development
APP_URL=http://localhost:4000
ORIGIN=http://localhost:3000

JWT_SECRET=super_secret

Script 변경


기존

"scripts": {
      "start": "ts-node src/index.ts",
      "dev": "nodemon --exec ts-node ./src/server.ts",
      "test": "echo \"Error: no test specified\" && exit 1",
      "typeorm": "typeorm-ts-node-commonjs"
   },

변경

"scripts": {
      "start": "ts-node src/index.ts",
      "dev": "env-cmd -f .env.development nodemon --exec ts-node ./src/server.ts",
      "start:prod": "env-cmd -f .env.production ts-node ./src/server.ts",
      "test": "echo \"Error: no test s ecified\" && exit 1",
      "typeorm": "typeorm-ts-node-commonjs"
   },

그외에 http://localhost:XXXX 로 되어있는 부분을 바꿔준다.

ex )

기존
const origin = "http://localhost:3000";
변경
const origin = process.env.ORIGIN;


EC2 시간이 지나서 멈춰있는경우

EC2에서 docker를 실행하고 오래 놔두었더니 가만히 있었다. 다시 리프레쉬했고 sudo docker ps 를 입력해보았다.

ubuntu@ip-172-31-4-214:~$ sudo docker ps
CONTAINER ID   IMAGE             COMMAND                  CREATED        STATUS        PORTS                                       NAMES
af0f271fd7f3   postgres:latest   "docker-entrypoint.s…"   10 hours ago   👉Up 10 hours   0.0.0.0:5432->5432/tcp, :::5432->5432/tcp   postgres

Status가 Up이 되어있기 때문에 실행이 되고있었다. 이부분 확인 후 다시 진행한다.


Client 실행

순서 : npm 설치 -> 모듈 설치 -> next js build -> next js 시작

텍스트 에디터에서는 소스코드 변경이 끝났다.
이제 EC2에서도 변경된 코드가 들어가야하므로 다시 깃허브에 push하고 EC2에서 pull 해준다.

ubuntu@ip-172-31-4-214:~$ ls
project04_community
ubuntu@ip-172-31-4-214:~$ cd project04_community
ubuntu@ip-172-31-4-214:~/project04_community$ 

cd 경로가 초기화 되어서 다시 ls를 쳐서 project04_community 를 확인 하고 project04_community로 경로를 바꿔주고 git pull을 진행한다.

EC2 클라이언트 실행

**EC2에는 새로운 컴퓨터에서 실행이 되는거고 나의 github에서 클론이 되었기 때문에 .env로 인해 node_module이 없는 상황이다 그래서 클라이언트 실행조건을 만들기 위해 모듈설치를 한다.

npm 설치 sudo apt install npm

  1. npm 설치를 한다 sudo apt install npm

모듈 설치 npm install

  1. cd client 경로로 들어가서 npm install

2. npm install 문제점

2번을 진행하다가 오류가 생겼다. sh: 1: env-cmd: not found 어쩌고 저쩌고.. node 버전이 맞지 않다고 하는말 같은데


  1. bash 사용자
    curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.1/install.sh | bash
    Zsh 사용자
    curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.1/install.sh | zsh
    로 설치를 해주고..
    나는 curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.33.1/install.sh | bash 로 했음..

  1. source ~/.bashrc
    Zsh 사용자
    source ~/.zshrc

  1. nvm install node # 최신 버전 설치
    nvm install --lts # 최신 LTS 버전 설치
    nvm install 16.14.0 # 특정 버전 설치
    nvm install 16 # 특정 버전 16의 최신 릴리즈 설치
    nvm install 16.18 (lts 버전으로 설치)를 했다.

  1. npm -v 로 잘 설치되었는지 확인

  1. nvm use 16.18

  1. npm install 로 설치 ! 정상적으로 된다!

이어서...

Next.js build npm run build:prod

  1. cd client 경로에서 빌드 npm run build:prod 를 해준다.

  2. AWS > EC2 에서 보안그룹을 설정해야하는데 EC2안에서 왼쪽메뉴에 보안 그룹을 선택하고 보안 그룹 생성을 누른다.


  1. 기본 세부 정보에서 보안그룹이름을 지어주고 ex) project-community-deploy

  • 유형 : 사용자지정 TCP
  • 포트범위 : 80 , 3000(front) , 4000(back) , 5432(db)
  • 소스 : Anywhere-ip v4 를 선택하면 (0.0.0.0/0 아무나 접근가능 보안상 좋지는 않음)
  1. 생성 후 인스턴스 > 오른쪽 상단 작업 > 보안 > 보안그룹변경

  1. 아까 만들어준 보안그룹을 추가하고 저장

Next.js 시작 npm run start:prod

  1. 이어서 next.js 시작 npm run start:prod

URL : http://ec2-3-106-117-251.ap-southeast-2.compute.amazonaws.com:3000/ 로 들어가준다.

클라이언트는 배포가 완료


  1. 실제 배포가 된다면 3000번으로 들어오는 것이 아닌 80번으로 바꿔주어야한다. (실제로 뒤에 포트를 3000을 치고 들어오지 않기 때문 80번은 치지 않아도 됨)
http://ec2-3-106-117-251.ap-southeast-2.compute.amazonaws.com:3000/ 

Proxy : sudo iptables -A PREROUTING -t nat -i eth0 -p tcp --dport 80 -j REDIRECT --to-port 3000

포트 3000번에서 실행된 것을 포트 80번을 이용해서 접속할 수 있게 해주기위해 Proxy를 사용

sudo iptables -A PREROUTING -t nat -i eth0 -p tcp --dport 80 -j REDIRECT --to-port 3000

을 입력해주고 npm run start:prod 를 하고 3000번이 지워진 주소로 들어가면 나오게 된다.

http://ec2-3-106-117-251.ap-southeast-2.compute.amazonaws.com/ 

PM2를 이용한 무중단 배포

설정파일은 이미 ecosystem.config.js로 만들어 주었다.

module.exports = {
	apps: [{
		name:"community-client",
        script:"npm run start:prod"
    }]
}

지금 계속 켜져있는 EC2 인스턴스는 끄게된다면 같이 다운이 된다. PM2로 실행을 해준다.

npm install pm2 -g (client 경로에서)

설치가 안된다면 앞에 sudo를 붙여서 다시

pm2 start ecosystem.config.js

실행

잘 실행이 된 모습

URL : http://ec2-3-106-117-251.ap-southeast-2.compute.amazonaws.com/ 에서 잘 되는지 다시 확인

확인 후 PM2실행은 완료


Server 실행

EC2 : cd server

EC2에서 cd 경로를 server로 이동 한다.

server : npm install

server경로에서 npm install을 한다.

pm2로 실행 : pm2 start ecosystem.config.js

0개의 댓글