코드스테이츠_S4U10_4W_수,목

윤뿔소·2022년 12월 7일
0

CodeStates

목록 보기
45/47

서비스의 규모가 복잡해지고 커질수록, 서비스를 배포하는 과정이 복잡해지고 소요되는 시간이 늘어난다. 그래서 자주 배포도 하게 되는데 그를 위한 배포 자동화를 알아보자!

개발 프로세스

소프트웨어 개발 프로세스 모델은 소프트웨어 개발 생명주기(SDLC, Software Develpment Life Cycle)을 기반으로 만들어짐

  • 요구분석 및 시스템 명세 작성 : 문제분석 단계라고도 하며, 개발할 소프트웨어의 기능과 제약조건, 목표 등을 사용자와 함께 정확히 정의하는 단계입니다. 개발하고자 하는 소프트웨어의 성격을 정확히 이해하여 이를 토대로 개발 방법과 필요한 자원 및 예산 예측 후 요구명세를 작성합니다.

  • 설계 : 설계단계에서는 앞서 정의한 기능을 실제로 수행하기 위한 방법을 논리적으로 결정합니다. 크게 시스템, 프로그램, UI(User Interface) 설계로 나뉘며, 시스템 구조설계는 시스템을 구성하는 내부 프로그램이나 모듈 간의 관계와 구조를 설계하고, 프로그램설계는 프로그램 내의 각 모듈에서의 처리 절차나 알고리즘을 설계합니다.

    • UI(User Interface) 설계는 사용자 인터페이스 설계로, 사용자가 시스템을 사용하기 위해 보이는 부분을 설계합니다.
  • 구현 : 설계 단계에서 논리적으로 결정한 문제 해결 방법을 프로그래밍언어를 사용하여 실제 프로그램을 작성합니다. 이때 프로그래밍 기법은 구조화 프로그래밍과 모듈러 프로그래밍 두 개로 나뉩니다.

  • 구조화 프로그래밍 : 조건문, 반복문을 사용하여 프로그램을 작성하고, 순차구조, 선택구조, 반복구조의 세 가지 제어구조로 표현하며, 구조가 명확하여 정확성 검증과 테스트 및 유지보수가 쉬운 장점이 있습니다.
    모듈러 프로그래밍 : 프로그램을 여러 개의 작은 모듈로 나누어 계층 관계로 구성하는 프로그래밍 기법으로, 모듈별로 개발과 테스트 및 유지보수 가능하며, 모듈의 재사용 가능하다는 장점이 있습니다.

  • 테스트 : 테스트 단계에서는 개발한 시스템이 요구사항을 만족하는지, 실행 결과가 예상한 결과와 정확하게 맞는지를 검사하고 평가하는 일련의 과정입니다. 미처 발견하지 못한 오류를 발견할 수 있기 때문에 매우 중요한 과정입니다.

  • 배포 및 유지보수 : 배포와 유지보수 단계는 시스템이 인수되고 설치된 후(배포) 일어나는 모든 활동을 지칭합니다. 이후 일어나는 커스터마이징, 구현, 테스트 등 모두 이 단계에 포함되므로 소프트웨어 생명주기에서 가장 긴 기간을 차지합니다. 유지보수의 유형에는 수정형, 적응형, 완전형, 예방형 총 네 가지가 있습니다.

    • 수정형 유지보수 : 사용 중에 발견한 프로그램의 오류 수정 작업을 진행합니다.
    • 적응형 유지보수 : 시스템과 관련한 환경적 변화에 적응하기 위한 재조정 작업을 합니다.
    • 완전형 유지보수 : 시스템의 성능을 향상하기 위한 개선 작업을 합니다.
    • 예방형 유지보수 : 앞으로 발생할지 모를 변경 사항을 수용하기 위한 대비 작업을 수행합니다.

위 내용은 어찌됐든 무엇을 개발할지 결정하고 요구사항들을 구현 작업에 적합하게 명확하고 조직화된 구조로 바꾸는 과정을 거쳐, 실제 개발에 착수해가는 단계다. 대략적으로 말한거지 더 나뉠 수도 있고 그 나뉜 단계가 여러번 반복할 수도 있다. 다양한 모델이 있으니 앱 구조에 맞게 개발하자!

참고: 전통 프로세스- 워터폴프로세스

제조 및 건설 업계에서 유래, 그래서 단계 별로 명확하고 완료되기 전까지 진행하지 못함

애자일 프로세스

기본적인 단방향 전통 프로세스(워터폴)의 전달 방식의 한계로 짧은 주기인 스프린트를 반복하여 개발 사이클을 유지해나가는 프로세스 중 하나인 '애자일 프로세스'를 개발했다.
요구사항이 변해가는 걸 전제로 뒀기에 전통 개발 프로세스의 회귀 불가 한계를 깨고 르게 문제를 해결해 하루에도 여러 번의 배포가 가능해져 훨씬 효율적으로 개발에 착수할 수 있다. 이러한 방식은 요즘 트렌드인 'SaaS'(Software as a Service, 서비스형 소프트웨어)를 개발하는 데에 적합하다!

SaaS

클라우드 서비스의 한 방식, 브라우저에 접속하기만 해도 새 버전을 즉시 사용할 수 있는 서비스 방식

애플리케이션부터 서버, 가상화, 스토리지, 네트워킹까지 전부 공급자 쪽에서 관리하기 때문에 고객이 제어하거나 관리할 부분이 거의 없게 됐다. 또 사용자 업데이트에 대한 걱정에서 벗어나며, 하루에 여러 번의 배포도 가능하고, 빠른 배포 속도도 보장 받을 수 있는 서비스다.
예를 들어 Gmail을 들 수 있는데 SaaS 방식으로 서비스를 제공하기 때문에 웹에서 Gmail을 업데이트 하지 않고 바로 사용할 수 있다.

DevOps

전통적으로 IT 조직 구조로는 개발팀(Dev)과 운영팀(Ops)이 소프트웨어의 개발과 관리 및 유지보수를 담당해왔다.

Dev(개발팀)Ops(운영팀)
특징잦은 배포 및 업데이트, 애플리케이션을 통해 새로운 기능(리소스)제공프로덕션 앱의 안정성 확보, 인프라 관리, 모니터링 및 제어

개발팀은 변화를 일으키고 운영팀은 안정을 도모한다. 이러한 특성으로 충돌이 일어나 비효율적인 갈등이 일어나고 릴리즈 시기가 늦어졌다.
그래서 소프트웨어 개발(Development)과 IT 운영(Operations)를 합친 DevOps가 탄생했고, 소프트웨어를 자주 빨리 그리고 안전하게 배포하는 것을 목표로 하며 그렇기 때문에 애자일 개발 프로세스를 기반으로 한 것이다.

DevOps는 특정한 업무라던지 부서가 아닌 일종의 개발 문화였다. 만약 서비스가 중단된다면, 누구든지 문제점을 진단하고 시스템을 복구하여 운영할 수 있는 절차를 알고 있어야 한다. 이를 위한 기술과 지식이 제공되기 위해서 훈련과 효과적인 협업체계를 마련하는 것이 매우 중요했지만 실제 실무에서는 업무의 분리를 위해 DevOps팀, 혹은 부서를 두고 있는 곳들도 있다.

특징

DevOps는 개발에서 운영까지 하나의 통합된 프로세스로 묶어내고 사용하는 툴과 시스템을 표준화하여 의사소통의 효율성을 확보하고 일련의 작업들을 자동화한다. 즉 코드 통합, 테스트, 배포 과정을 자동화 시키는 것. 이 부분은 지속적으로 유지되어야 할 필요가 있는데, 지속적 통합 및 배포(CI/CD)라고 하며 DevOps의 핵심 원칙이다! 잘 구축된 CI/CD는 애플리케이션의 배포 시간을 워터폴 프로세스보다 더 크게 단축시킨다.

사례로는 Netflex의 트래픽을 AWS의 만개 이상 인스턴스에 10명의 DevOps팀에게 맡기고 있고, Spotify도 강력한 Devops 개발문화를 갖추고 오픈소스 도구를 활용하여 배포와 운영을 자동화해 관리하고 있다.

즉! Devops를 통하여 새로운 기능을 시장에 보다 자주 그리고 빨리 출시할 수 있고, 장애발생시 보다 대응과 시스템의 안정성을 향상시킬 수 있음을 알 수 있다!

CI/CD

CI: Continuous Integration, 개발자를 위한 자동화 프로세스인 '지속적 통합'
CD: '지속적 서비스 제공'(Continuous Delivery) 및/또는 '지속적 배포'(Continuous Deployment), 상호 교환적으로 사용

CI를 제대로 구현하면 애플리케이션에 대한 새로운 코드 변경 사항이 정기적으로 빌드 및 테스트되어 공유 리포지토리에 통합되므로 여러 명의 개발자가 동시에 애플리케이션 개발과 관련된 코드 작업을 할 경우 서로 충돌할 수 있는 문제를 해결 가능
CD는 파이프라인의 추가 단계에 대한 자동화를 뜻하지만 때로는 얼마나 많은 자동화가 이루어지고 있는지를 설명하기 위해 별도로 사용

단계

최근에는 클라우드 기술 발전과 맞물려 지속적 통합과 지속적 배포가 빠른 속도로 진행되면서 CI/CD를 하나로 묶어서 다루는 경우가 점차 증가하고 있다.
예를 들어, 이전에는 배포 자체가 상당히 오래 걸리고 힘든 일이어서 배포 이전 단계에서 많은 고민을 하곤 했다. 서버를 전부 재시작해야 한다거나, 일부 기능을 제공하지 못하는 경우도 많았기 때문. 요즘은 고객의 피드백을 빨리 받기 위해서라도, 서비스를 중단하지 않기 위해서라도 릴리즈만 잘 기록해두고 바로바로 배포하는 사례가 증가하고 있다.

지속적 통합(CI)

개발자를 위한 자동화 프로세스라고 볼 수 있으며, Code - Build - Test 단계

  • Code : 개발자가 코드를 원격 코드 저장소 (Ex. github repository)에 push하는 단계
  • Build : 원격 코드 저장소로부터 코드를 가져와 유닛 테스트 후 빌드하는 단계
  • Test : 코드 빌드의 결과물이 다른 컴포넌트와 잘 통합되는 지 확인하는 과정

이 과정에서 개발자는 코드를 잦게 원격 코드 저장소에 push하고, 테스트 및 빌드를 하며 빌드 결과를 통해 빌드가 성공했는지 실패했는지 확인을 하고, 통합 테스트 결과를 통해 개선 방안을 찾는다. 이 지속적인 통합 과정을 통해 개발자는 버그를 일찍 발견할 수 있고, 테스트가 완료된 코드에 대해 빠른 전달이 가능해지며 지속적인 배포가 가능해진다!

지속적 통합은 모든 코드 변화를 하나의 리포지토리에서 관리하는 것 부터 시작. 모든 개발팀이 코드의 변화를 확인할 수 있기 때문에, 투명하게 문제점을 파악할 수 있다. 그리고 잦은 풀 리퀘스트(pull request)와 머지(merge)로 코드를 자주 통합한다. 이 때, 기본적인 테스트도 작동시킬 수 있다. 이렇게 지속적 통합을 통해 개발팀은 각자 개발한 코드를 이른 시점에 자주 합치고 자주 테스트 해볼 수 있다!!

지속적 통합으로 보안 이슈, 에러 등을 쉽게 파악할 수 있어 해당 이슈를 빠르게 개선할 수 있다. 이전에는 각자 개발자가 작성한 코드를 합치고 난 후, 모두 모여서 빌드를 시작하고 나서야 문제점을 파악할 수 있었다. 지속적 통합이 적용된 개발팀은 코드를 머지하기 전, 이미 빌드 오류나 테스트 오류를 확인하여 훨씬 더 효율적인 개발을 할 수 있게 된다.

지속적 배포(CD)

지속적 서비스 제공 및 지속적 배포를 의미, 이 부분은 Release - Deploy - Operate 단계에서 꾀할 수 있다.

  • Release : 배포 가능한 소프트웨어 패키지를 작성
  • Deploy : 프로비저닝을 실행하고 서비스를 사용자에게 노출합니다. 실질적인 배포 부분
  • Operate : 서비스 현황을 파악하고 생길 수 있는 문제를 감지

지속적 배포의 경우, 코드 변경 사항의 병합부터 프로덕션에 적합한 빌드 제공에 이르는 모든 단계로, 테스트 자동화와 코드 배포 자동화가 포함된다.

이 프로세스를 완료하면 프로덕션 준비가 완료된 빌드를 코드 리포지토리에 자동으로 배포할 수 있기 때문에 운영팀이 보다 빠르고 손쉽게 애플리케이션을 프로덕션으로 배포 가능해진다.

가장 흔하게 쓸 수 있는 CI/CD 개발은 Github Page다. 지정해둔 디렉터리에 정해진 방식에 따라 잘 커밋하기만 하면, Github Page가 알아서 해당 index.html 파일과 해당 디렉터리에 있는 파일을 잘 번들링해서 Github Page 서버에 업로드한다. 이렇게 자동으로 인터넷에 배포가 되었고, 주변 가족이나 친구들에게 쉽게 만든 결과물을 공유할 수 있었다.

결론적으론 CI/CD는 파이프라인으로 표현되는 실제 프로세스를 의미하고, 애플리케이션 개발에 지속적인 자동화 및 지속적인 모니터링을 추가하는 것이다. 대부분의 기업에서는 CI를 먼저 추가한 다음 클라우드 네이티브 애플리케이션의 일부로서 배포 및 개발 자동화를 구현해 나간다

파이프라인

SaaS와 애자일 프로세스를 배우며 수없는 업데이트로 인한 배포가 발생한다. 그래서 CI/CD를 요한다.
다시 말해서 수없이 진행되는 배포 과정을 자동화시키는 방법을 구축하는 것이 CI/CD고, 그 과정을 'CI/CD 파이프라인'이라고 한다. 위의 사진은 배포 과정을 도식화한 것이다.

장점

  • 빌드 (소프트웨어 컴파일)
  • 테스트 (호환성 및 오류 검사)
  • 릴리스 (버전 제어 저장소의 애플리케이션 업데이트)
  • 배포 (개발에서 프로덕션 환경으로의 변환)
  • 규정 준수 및 유효성 검사

단계

각 단계는 파이프라인 안에서 순차적으로 실행되며, 각 단계마다 주어진 작업(Actions)들을 수행

  1. Source 단계: Source 단계에서는 원격 저장소에 관리되고 있는 소스 코드에 변경 사항이 일어날 경우, 이를 감지하고 다음 단계로 전달하는 작업을 수행
  2. Build 단계: Build 단계에서는 Source 단계에서 전달받은 코드를 컴파일, 빌드, 테스트하여 가공합니다. 또한 Build 단계를 거쳐 생성된 결과물을 다음 단계로 전달하는 작업을 수행
  3. Deploy 단계: Deploy 단계에서는 Build 단계로부터 전달받은 결과물을 실제 서비스에 반영하는 작업을 수행

Github Actions

Github가 공식적으로 제공하는 빌드, 테스트 및 배포 파이프라인을 자동화할 수 있는 CI/CD 플랫폼

레포지토리에서 Pull Request 나 push 같은 이벤트를 트리거로 GitHub 작업 워크플로(Workflow)를 구성할 수 있따.
워크플로는 하나 이상의 작업이 실행되는 자동화 프로세스로, 각 작업은 자체 가상 머신 또는 컨테이너 내부에서 실행 가능하다. 워크플로는 .yml (혹은 .yaml ) 파일에 의해 구성되며, 테스트, 배포 등 기능에 따라 여러개의 워크플로도 만들 수 있다. 생성된 워크플로는 .github/workflows 디렉토리 이하에 위치한다.

비공개 레포지토리의 경우 Github Actions가 작동할 때의 용량과 시간이 제한되어있으며 공개 레포지토리는 무료로 사용 가능!!

workflows

EC2와 같은 하나의 가상 인스턴스를 실행시켜서 원하는 작업을 시킬 수 있다. 그런데, 리포지토리를 push하기만 했는데, 왜 작동했을까? ./.github/workflows/pullRequest.yml파일을 작성했기 때문!

# ./.github/workflows/pullRequest.yml
name: Bare Minimum Requirements
# 언제 job을 작동시킬지
on: [push, pull_request]
# 어떤 job을 할지
jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v2
      - name: Bare Minimum Requirements
        uses: actions/setup-node@v1
        with:
          node-version: '16'
      - run: npm install
      - run: npm test
  • npm install은 빌드를 위한 준비과정으로 볼 수 있다. Node.js로 만든 서버 애플리케이션은 npm으로 관련 오픈소스를 모두 깔끔하게 설치해야 작동하기 때문.
  • npm test는 유닛 테스트 과정. 작성한 코드가 요구사항 충족을 위한 최소한의 조건을 만족했는지 확인하고 있다.

YAML

Yet Another Markup Language, 사람이 읽을 수 있는 데이터 직렬화 언어를 의미
데이터용임을 강조하는 말

YAML은 사람이 읽을 수 있고 이해하기 쉽고, 다른 프로그래밍 언어와 함께 사용할 수 있어 접근성, 유연성이 매우 뛰어나 자동화 프로세스를 생성하는 데에도 사용한다!

같이 key-value 형식인 Json과 많이 비교되는데 설정을 위한 스펙이나 프로퍼티 값 등이 JSON 파일에 비해 한 눈에 들어온다는 점과 {}처럼 객체 형태로 감싸주지 않기 때문에 스코프의 압박에 벗어 날 수 있다. 또, 주석도 사용 가능해 소통이 수월하다.
AML은 JSON의 상위 호환 격이므로, 기존 json문서를 그대로 yaml파일로 사용하거나 원하는 부분만 손볼 수 있다. 반대로 yaml을 json으로 변환해 사용할 수도 있다는 점이 장점으로 작용한다!

일반적으로 설정 파일(configure file 등)에 사용하기에 좋다. 그래서 spring boot, github action 등 다양한 CI/CD 툴이나 프레임워크에서 사용한다.
예를 들어 도커와 비슷한 쿠버네티스yml 파일로 문서 스트림을 사용해 클러스터 설정하거나 기본적인 팟, 레플리카, 디플로이먼트 등 내부 오브젝트가 작성돼있다.

문법

# 이런 식으로 주석을 작성할 수 있습니다.
--- # 문서 시작(선택사항)

# 이 사이에 내용이 들어갑니다.

... # 문서 끝(선택사항)

# 기본 형식
key: value

자료형

int, string, boolean, 리스트, 매핑을 지원
여기서 intstring 타입은 스칼라(Scalar)라 부르고, 배열 혹은 리스트는 시퀀스(Sequence)라 부른다. 매핑에는 기본 표현인 key-value 쌍 및 hash, dictionary가 포함된다.

#int(숫자)
int_type: 1

#string(문자열)
string_type: "1"

#blooean(참/거짓)
boolean_true_type: true
boolean_false_type: false

#이외에 yes, no로 작성하기도 합니다.
yaml_easy: yes
yaml_difficult: no

#리스트(배열 형태)
person:
  name: Chungsub Kim
  job: Developer
  skills: 
    - docker
    - kubernetes
  # JSON 형식의 "skill" : [docker, kubernetes]와 같습니다.

Text

줄바꿈 표현(|)과 줄바꿈 무시 표현(>)

# |는 줄바꿈 표현입니다.
# JSON 형식의 "comment_line_break": "Hello codestates.\nIm kimcoding.\n"과 같습니다.
comment_line_break: |
  Hello codestates.
  Im kimcoding.

# >는 줄바꿈 무시 표현입니다.
# JSON 형식의 "comment_single_line": "Hello world my first coding."과 같습니다.
comment_single_line: >
  Hello world
  my first coding.

문자열 따옴표

# error가 납니다.
windows_drive: c:

# 이렇게 써야 합니다.
windows_drive: "c:"
windows_drive: 'c:'

실습

이런 식으로 나만의 아고라 스테이츠 서버를 불러와 AWS S3에 배포해보겠다.

  1. Source: Github reference 브랜치에 코드가 커밋되면
  2. Build: github acitons의 YAML 파일에 적힌 명령어를 토대로 Webpack을 이용해 빌드를 하고
  3. Deploy: github acitons의 YAML 파일에 적힌 명령어를 토대로 s3로 빌드 결과를 업로드.

2번은 npm build로, 3번은 어제 했던, 설정된 AWS S3로 하면 된다.

Proxy

CORS Error를 deal with하는, 우회할 수 있는 방법, Proxy에 대해 알아보자

배경

우리는 CORS 정책을 배웠다. 그리고 CORS 정책이 필요한 이유도 배웠었다. 다시 복습해보자

출처(Origin)

접근할 때 사용하는 URL의 스킴(프로토콜), 호스트(도메인), 포트
위 세 요소가 모두 같다면 같은 출처를 가짐. 일부는 CORS를 통해 제한을 해제

CORS 정책

교차 출처 리소스 공유(Cross-Origin Resource Sharing)
추가 HTTP 헤더를 사용해 한 출처에서 실행 중인 웹 애플리케이션이 다른 출처의 선택한 자원에 접근할 수 있는 권한을 부여하도록 브라우저에 알려주는 체제

기본적으로, 브라우저에서 기본적으로 API를 요청 할 때에 브라우저의 현재 주소와 API 의 주소의 도메인이 일치해야만 데이터를 접근 할 수 있지만
허락한 일부 도메인에서도 API를 쓰게 하는 것이 CORS 설정이라고 할 수 있다.

만약 실제 서비스가 되는 상용 앱을 운영 중이라면 유저 및 상품, 결제 등 다양한 정보의 데이터가 담겨진 라이브 데이터(live data)가 DB에 계속 쌓일 것이다. 이 상태에서 같은 도메인만 데이터를 가져올 수 있는데 개발하는데 귀찮다고 모든 출처를 허락했다. 근데 다른 출처가 허락도 없이 막 갖다 쓴다면? 수정한다면? 모두 죽는 거다!!

그래서 모든 도메인을 허락하는 것이 아닌 특정 도메인을 허용하도록 구현해야한다. 프론트엔드는 백엔드에게 개발 서버의 도메인을 허용해달라 요청하고 백엔드는 프엔에게 응답 헤더에 필요한 값들을 담아서 전달해줘야한다.

여기서 Proxy를 쓰면 위의 정석적인 과정 없이 바로 쓸 수 있다.

정의

클라이언트가 자신을 통해서 다른 네트워크 서비스에 간접적으로 접속할 수 있게 해 주는 컴퓨터 시스템이나 응용 프로그램
클라이언트와 서버 사이에 위치하여 HTTP 메시지를 정리하는 중개인처럼 동작

  • 정석적인 방법

    1. React 앱에서 브라우저 쪽으로 요청
    2. 브라우저는 백엔드, 즉 서버 쪽으로 리소스를 요청
    3. 접근 권한이 있는지, 즉 출처가 같은지 확인 => 서버는 정상이면 200 OK 응답을 브라우저에게 응답
    4. 브라우저는 받은 리소스 및 응답과 함께 출처가 같은지 아닌지 확인
    5. 출처가 다르다면 응답을 파기(CORS Error), 출처가 같다면 응답을 파기하지 않고 다시 프론트엔드 쪽으로 응답
  • Proxy 방법

    1. React 앱에서 브라우저를 통해 API를 백엔드 서버로 proxy를 통해 우회하여 요청
    2. 서버는 응답을 React 앱으로 보내고, React 앱은 받은 응답을 백엔드 서버 대신 브라우저에게 전달
    3. 출처가 같아지기 때문에 브라우저는 이 사실을 눈치 채지 못하고 허용

정석적인 과정 없이 React 라이브러리, 혹은 Webpack Dev Server에서 제공하는 proxy 기능을 사용하면 CORS 정책을 우회할 수 있다. 왜?
브라우저에게 정보를 주지 않아 보안을 개선하고, 응답 및 요청을 줄여줘 성능을 높여주며, 비용을 절약한다. 또한 중개인처럼 동작하기 때문에 모든 HTTP 트래픽을 제어할 수 있어서!

사용법

웹팩의 내장 기능 webpack dev server proxy를 이용해 json과 도메인을 건들여보자!

webpack dev server proxy 전제

webpack dev server에서 제공하는 proxy 기능을 사용
webpack dev server의 proxy를 사용하게 되면, 브라우저 API를 요청할 때 백엔드 서버에 직접적으로 요청을 하지 않고, 현재 개발서버의 주소로 우회 요청

웹팩 개발서버의 proxy 설정은 원래 웹팩 설정을 통해서 적용을 하지만, CRA 로 만든 리액트에서는 package.json 에서 "proxy" 값을 설정하여 쉽게 적용할 수 있도록 구성이 되어 있다.

1. package.json 수정

...
"browserslist": {
    "production": [
      ">0.2%",
      "not dead",
      "not op_mini all"
    ],
    "development": [
      "last 1 chrome version",
      "last 1 firefox version",
      "last 1 safari version"
    ]
  },
  	# 보통 잘 찾기 위해 맨 아래에 작성
	"proxy" : "우회할 API 주소"
}

2. 기존 fetch, axios 수정

// 이거를
export async function getAllfetch() {
  const response = await fetch('우회할 api주소/params');
  .then(() => {
		...
    })
}
// 이거로 변경하며 도메인 제거
export async function getAllfetch() {
  const response = await fetch('/params');
  .then(() => {
		...
	})
}

리액트 Proxy 사용법

webpack dev server 에서 제공하는 proxy는 전역적인 설정이기 때문에, 종종 해당 방법이 충분히 적용되지 않는 경우가 생기기도 한다. 그래서 수동으로 proxy를 적용해줘야 하는 경우가 있는데, 이때는 http-proxy-middleware 라이브러리를 사용해야 한다.

npm 설치 및 파일 구성

npm install http-proxy-middleware --save

그리고 React App의 src 파일 안에서 setupProxy.js 파일을 생성하고, 안에서 설치한 라이브러리 파일을 불러온 다음, 아래와 같이 작성.

const { createProxyMiddleware } = require('http-proxy-middleware');

module.exports = function(app) {
  app.use(
    '/proxy가 필요한 path prameter를 입력', 
    createProxyMiddleware({
      target: '타겟이 되는 api url를 입력', 
      changeOrigin: true, // 대상 서버 구성에 따라 호스트 헤더가 변경되도록 설정하는 부분.
    })
  );
};
// 또는 받아야할 도메인이 2개 이상이면
 app.use(
    ['/path prameter1', '/path prameter2'], // 배열로 생성
    createProxyMiddleware({
      target: '기본적으로 target되는 api url', // 기본적으로 target되는
      changeOrigin: true,
      router: {
        '/path prameter2' : '추가 api url'
        // '/api3' : 도메인으로 추가할 수 있음
      }
    })
  );

기존 fetch, axios 수정

webpack dev server 에서 제공하는 proxy 기능을 사용할 때와 동일

실습

클론해온 뒤 my app, api 각각 npm i 해주고 npm start, npm run dev 실행 시켜주자

실행 시키고 나서 Get all Books를 누르면 오류가 뜬다.CORS 에러가 뜨며 응답을 제대로 받아오지 못하는 것을 확인할 수 있다. 이걸 해결해보자!

  • 과제1
    페어와 함께 webpack dev server의 proxy 기능을 사용해 우회하여 응답을 받아옵니다.
  • 과제2
    레포지토리로 받아온 과제를 살펴보면 api2 라는 폴더가 존재하고 있습니다. 실제로 프로젝트 및 실무를 할 때, 하나의 도메인이 아닌 여러 개의 도메인에서 응답을 받아와야 하는 경우가 종종 있습니다. 이럴 때는 유연하게 proxy를 설정할 필요가 있습니다.
    • 페어와 함께 webpack dev server의 proxy 기능 대신 http-proxy-middleware의 proxy 기능을 사용하여 proxy를 유연히 설정해 2개의 도메인에서 모두 응답을 받아옵니다.
    • 페어와 함께 api2에 관련된 fetch 함수를 만들고, 컴포넌트를 하나 이상 만들어 2개의 도메인에서 모두 응답을 받아오는지 테스트 해봅니다.

webpack dev server proxy 전제

위의 사용법 그대로 순서를 지키며 해보겠다.

  1. json 파일 고치기
	...
    "development": [
      "last 1 chrome version",
      "last 1 firefox version",
      "last 1 safari version"
    ]
  },
  "proxy": "http://localhost:3080"
}
  1. 기존 fetch, axios 수정
export const getAllBooks = async () => {
  // const response = await fetch('http://localhost:3080/api/books');
  const response = await fetch("/api/books");
  return await response.json();
};

export const createBook = async (data) => {
  // const response = await fetch('http://localhost:3080/api/book', {
  const response = await fetch("/api/book", {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({ book: data }),
  });
  return await response.json();
};

리액트 Proxy 설정

  1. npm 설치 및 파일 구성
npm install http-proxy-middleware --save
// src/setupProxy.js
const { createProxyMiddleware } = require("http-proxy-middleware");

module.exports = function (app) {
  app.use(
    "/api",
    createProxyMiddleware({
      target: "http://localhost:3080",
      changeOrigin: true,
    })
  );
};

결과

5. 2개 이상의 api?

Todo 서버를 받아온다! book 컴포넌트와 비슷하게 변수만 바꿔주고 설정을 아래와 같이 바꾸자!

const { createProxyMiddleware } = require("http-proxy-middleware");

module.exports = function (app) {
  app.use(
    ["/api1", "/api2"],
    createProxyMiddleware({
      target: "http://localhost:3080", // 타겟이 되는 api url를 입력.
      changeOrigin: true, // 대상 서버 구성에 따라 호스트 헤더가 변경되도록 설정하는 부분.
      router: { "/api2": "http://localhost:3070" },
    })
  );
};
// 아니면 module.exports = function (app)을 2개 만들든가!!

결과

알게된 것

  1. 내가 창업을 한다면 프로세스를 어떻게 짜야할지 좀 와닿았다. 중요한 포인트로 사이클을 지정하는 것이 더 편하다는 것도!
  2. 생각보다 Github Actions는 편하다. AWS으로만 배포를 하지 않구나를 깨달았고 마이크로소프는 신이다!
  3. 프록시: "프록시 = 백엔드서버의 도메인"이란 느낌을 받았다!! 되게 편해!
profile
코뿔소처럼 저돌적으로

0개의 댓글