1. Algorithm Study

2. Backend Class

배포

사용자가 작성한 코드를 컴퓨터 언어로 번역하여 ( 컴파일 과정 )
컴파일된 코드를 실제 실행할 수 있는 상태로 만들어 ( 빌드 )
빌드가 완성된 실행 가능한 파일을 다른 사용자가 접근할 수 있는 환경에 배치하는 것
→실무에서는 컴퓨터 종료 시, 서버가 꺼지기 때문에 yarn start:dev 명령어가 24시간 실행되고 있는( 서버가 켜져있는 ) 컴퓨터에서 배포를 진행

클라우드 사용 이유
서버 사용자가 많아지면 트래픽 증감 문제 발생 →Cloud Provider에서 컴퓨터를 빌려서, 빌린 컴퓨터를 사용하여 배포를 진행
Cloud Provider i.e) 아마존, Google, Microsoft
클라우드 서비스 i.e) AWS(아마존), GCP(구글), Azure(마이크로소프트)


GCP 인스턴스 배포

  • 구글에서 하나의 컴퓨터를 빌려 서버를 배포
  • Storage에는 이미지 파일이 저장
    -GCP 안에 도커 컨테이너로 백엔드 서버와 DB 띄우기
    -SSH로 빌린 컴퓨터의 터미널 접속 가능

📍up과 up -d의 차이

  • up
    • 언제든지 control + c 로 서버 종료 가능 : 해당 터미널내에서만 서버가 열리게 되는 Foreground Process(포그라운드 프로세스)
    • 서버가 올라가는 로그를 눈으로 확인 가능
    • 서버 종료가 쉽게 이루어지기 때문에 실제 배포는 포그라운드에서 진행되지 않음
  • up -d
    • 화면 뒤에서 서버가 실행되는 Background Process(백그라운드 프로세스)
    • 서버가 올라가는 로그가 눈에 보이지 않음
    • 실제 배포는 백그라운드로 이뤄짐

GCP 방화벽 해제

모든 사람들이 3000번 port로 접속할 수 있게끔 방화벽을 여는 작업이 필요
소스 IP 범위를 입력 : 0.0.0.0/0 범위로 지정한다면 누구든지 접속 가능하다는 뜻

  • TCP는 연결이 성공해야지만 통신이 가능하고, 신뢰성 있는 데이터를 전송(정확성 추구).
    제대로 데이터를 주고 받았는지 확인 절차를 거쳐야 하므로 속도가 느릴 수 있지만 안전
  • UDP는 연결 없이 통신이 가능하고, 신뢰성을 보장해 주지 않아 안전성이 떨어짐, but 속도 빠름

Docker root 권한 해제

리눅스에서 특정 명령을 실행하거나 파일에 접근하기 위해서는 루트(root) 권한이 필요
사용자가 root 권한을 사용하기 위해서 sudo라는 명령어를 사용
sudo 명령에 대한 사용 권한은 해당 사용자 계정이 sudo 그룹에 소속되어 있느냐에 의해 결정됨
sudo 그룹에 소속된 사용자만이 sudo 명령을 사용할 수 있음
사용자에게 sudo 권한을 부여하거나 해제하고 싶을 시, sudo 그룹에 사용자를 추가/삭제하면 됨.

배포 환경 분리

배포 환경(4단계)

local : 우리가 각자의 컴퓨터로 계속 작업하고 있었던 환경 →localhost를 사용하는 개발 환경, 여기서 배포하면 내 컴퓨터에서만 접근 가능

dev : 나 혼자만의 작업환경을 넘어서, 프론트엔드와 백엔드를 합쳐서 테스트 해 볼 환경이 필요, 개발자들이 실제 서버 환경에서 테스트 하면서 개발 가능

네번째로 prod 단계

prod : 개발을 완성한 다음에 실제로 서비스를 배포하고 운영하는 환경, 여기에 있는 DB는 실제 유저의 DB이기 때문에 매우 중요하고 함부로 삭제하면 안됨

세번째로 stage 단계

stage : 예를 들어 버전 1을 prod에 배포하고 서비스를 운영, 새로운 기능을 추가한 버전2를 dev에서 개발자들이 만듦

버전 2가 실제 서비스에 배포해도 될 정도의 수준으로 완성을 했다면, prod 환경이랑 동일하게 stage 환경을 만들어 stage에 배포를 함 → 기획자, PM, 디자이너 등이 stage에 올라간 것으로 테스트를 함
📍stage는 실서비스 수준으로 배포하기 때문에, 여기서 버그가 발생되지 않는다면 테스트용으로 만들어진 DB만 제외하고, prod로 배포

// auth.service.ts

import { Injectable } from '@nestjs/common';
import { JwtService } from '@nestjs/jwt';

@Injectable()
export class AuthService {
  constructor(
    private readonly jwtService: JwtService, //
  ) {}

  setRefreshToken({ user, res }) {
    const refreshToken = this.jwtService.sign(
      { email: user.email, sub: user.id },
      { secret: process.env.REFRESH_TOKEN_KEY, expiresIn: '2w' }, // 수정
    );

    // 개발환경
    res.setHeader('Set-Cookie', `refreshToken=${refreshToken}; path=/;`); // path 설정 반드시 필요!! (소셜로그인에서!!)

    // 배포환경
    // res.setHeader('Access-Control-Allow-Origin', 'https://myfrontsite.com')
    // res.setHeader(
    //   'Set-Cookie',
    //   `refreshToken=${refreshToken}; path=/; domain=.mybacksite.com; SameSite=None; Secure; httpOnly;`
    // )
  }

  getAccessToken({ user }) {
    return this.jwtService.sign(
      { email: user.email, sub: user.id },
      { secret: process.env.ACCESS_TOKEN_KEY, expiresIn: '1h' }, // 수정
    );
  }
}
// jwt-access.strategy.ts

import { PassportStrategy } from '@nestjs/passport';
import { Strategy, ExtractJwt } from 'passport-jwt';

export class JwtAccessStrategy extends PassportStrategy(Strategy, 'access') {
  constructor() {
    super({
      jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(), // req.headers.Authorization...
      secretOrKey: process.env.ACCESS_TOKEN_KEY, // 수정
    });
  }

  validate(payload) {
    console.log(payload); // { email: c@c.com, sub: qkwefuasdij-012093sd }
    return {
      email: payload.email,
      id: payload.sub,
    };
  }
}
// jwt-refresh.strategy.ts

import { PassportStrategy } from '@nestjs/passport';
import { Strategy } from 'passport-jwt';

export class JwtRefreshStrategy extends PassportStrategy(Strategy, 'refresh') {
  constructor() {
    super({
      jwtFromRequest: (req) => {
        const cookie = req.headers.cookie; // console로 찍히는 것 확인
        const refreshToken = cookie.replace('refreshToken=', ''); //토큰만 뽑아오기
        return refreshToken;
      },
      secretOrKey: process.env.REFRESH_TOKEN_KEY, // 수정
    });
  }

  validate(payload) {
    console.log(payload); // { email: c@c.com, sub: qkwefuasdij-012093sd }
    return {
      email: payload.email,
      id: payload.sub,
    };
  }
}

환경별 파일 셋팅(Dockerfile, docker-compose.yaml, env)

// docker-compose.dev.yaml

version: '3.7'

services:
  my-backend:
    build:
      context: .
      dockerfile: Dockerfile
    # volumes: // 배포 후 refresh 발생을 방지하기 위해 주석 처리 
    #   - ./src:/myfolder/src
    env_file:
      - ./.env.dev
    ports:
      - 3000:3000

  my-database:
    platform: linux/x86_64
    image: mysql:latest
    environment:
      MYSQL_DATABASE: 'mydocker'
      MYSQL_ROOT_PASSWORD: 'root'
    ports:
      - 3306:3306

3. HW

1개의 댓글

comment-user-thumbnail
2022년 12월 20일

수학을 잘 못하시나보네요

답글 달기