들어가며

오늘은 회사에서 새로운 프로젝트를 시작하기 위해 리액트 프로젝트를 자동으로 AWS에 배포하는 과정을 진행했고 마주쳤던 이슈에 대해서 정리해보고자 합니다. 이 포스트는 아래와 같이 단계별로 구성되어 있습니다. 

1. S3로 배포하기

2. CloudFront로 배포 강화하기 - 예정

3. Github Action으로 배포 자동화하기 - 예정

 

기존 배포 과정과 문제점

기존에는 AWS 서비스에 대해서 잘 몰라 Nginx를 이용해서 정적 파일을 제공하도록 설계하고 이를 EC2에 올려 배포했습니다. 여기서 문제점은 단순히 정적 파일을 제공하는데 EC2라는 자원은 상당히 비싸다는 것입니다. 웹 페이지의 경우 특정 시간에는 접속이 낮은 경우가 많은데 EC2로 배포를 진행하게 될 경우 시간당 과금이 발생하기 때문에 불필요한 과금이 지속되기 때문입니다. 또한 단순히 정적 파일을 제공하는데 연산에 필요한 자원들은 거의 필요가 없기에 EC2의 자원낭비가 심했습니다.

 

문제 정의

해결방법을 모색하기 위해 지금 프로젝트에 필요한 요소들을 우선순위 기준으로 정의했습니다.

1. 정적 파일을 HTTP 기반으로 제공가능한 기능

2. 부하 분산 기능

3. TLS를 적용 기능

4. API 요청의 경우 리버스 프록시 기능

 

솔루션 탐색

AWS에서 제공하는 서비스 중에 위를 만족하는 서비스는 다음과 같았습니다.

1. 정적 파일을 HTTP 기반으로 제공 가능한 기능 : S3

2. 부하 분산 기능 : CloudFront

3. TLS를 적용 기능 : CloudFront

4. API 요청의 경우 리버스 프록시 기능 : CloudFront

탐색 결과, 운이 좋게 대부분의 요구사항이 CloudFront에서 제공하는 것을 알게 되었습니다. 

 

S3에 프로젝트 배포

1. S3 버킷 생성

S3 콘솔로 접속 후, 왼쪽 메뉴에서 버킷을 선택하고 버킷 만들기를 클릭합니다.

버킷 이름은 원하는 서비스 이름을 입력합시다. 여기서는 react-test-project라고 입력하겠습니다.

객체 소유권의 경우 ACL 활성화를 선택합니다. 

모든 퍼블릭 액세스 차단을 해제하고 확인을 클릭합니다. 우리는 정적 웹 사이트 호스팅에 이를 사용할 것이기 때문에 퍼블릭 액세스를 허용해야 합니다. 나머지 옵션 설정은 생략하고 버킷 만들기를 클릭합니다.

2. 파일 업로드

버킷을 생성했다면 해당 버킷에 들어가봅시다. 비어있는 객체 칸을 처음으로 확인할 수 있습니다. 여기에 배포할 파일을 업로드할 수 있습니다. AWS CLI를 이용하면 쉽게 업로드할 수 있습니다. 콘솔을 이용해도 되지만, 우리는 개발자니까 한번 시도해봅시다. 초기 설정은 어려울 수 있어도 이 시간이 지나면 편안함이 찾아옵니다. 우선 아래 링크를 통해 각자 환경에 맞게 AWS CLI를 설치합니다.

https://docs.aws.amazon.com/ko_kr/cli/latest/userguide/getting-started-install.html

 

최신 버전의 AWS CLI 설치 또는 업데이트 - AWS Command Line Interface

이전 버전에서 업데이트하는 경우 unzip 명령을 실행하면 기존 파일을 덮어쓸지 묻는 메시지가 표시됩니다. 스크립트 자동화와 같은 경우에 이러한 프롬프트를 건너뛰려면 unzip에 대한 -u 업데이

docs.aws.amazon.com

 

이제 IAM을 이용해서 배포 권한만 가지고 있는 사용자 계정을 만들어 보겠습니다. 루트 계정을 사용해도 배포를 할 수 는 있지만, 루트 계정의 인증 정보가 다른 곳에 유출되면 굉장히 위험합니다. 따라서 목적에 따라 최소한의 권한을 가진 계정을 생성해서 사용하는 것이 좋습니다. AWS IAM Console에 접속해봅시다. 콘솔 -> 사용자 -> 사용자 추가를 통해서 새로운 사용자를 만들 수 있습니다.

리액트 프로젝트를 배포할 TestReactDeployer라는 이름을 입력하고 CLI를 사용므로 자격 증명 유형은 액세스 키를 선택합니다. 

다음으로 사용자에게 줄 권한을 선택해봅시다. 권한은 AmazonS3FullAccess 에는 배포에 필요한 권한이 모두 들어있습니다. 하지만 필요 없는 권한도 있습니다. 세부적으로 정말 필요한 권한만 설정하면 좋겠지만 이 포스트의 목적과는 거리가 멀어 생략하고 AmazonS3 FullAccess를 사용하겠습니다. (힌트를 드리자면 세부적인 권한을 선택하기 위해선 IAM 정책을 활용할 수 있습니다. )

마지막으로 액세스 유형, 권한 을 확인하고 사용자를 생성합니다.

 생성한 사용자의 엑세스 키와 비밀 액세스 키를 확인할 수 있습니다. AWS CLI에서 인증할 때 필요한 정보이니 CSV를 소중히 다운로드해줍시다. 

 

이제 AWS CLI를 이용해 인증을 진행해봅시다.

프로파일을 설정하면 여러 자격증명 및 설정을 따로 관리할 수 있습니다. 위와 같이 커맨드를 입력하고 CSV에 포함된 키를 각각 입력합니다. 나머지 옵션도 위와 같이 입력해줍니다.

이제 업로드할 정적 파일로 이동합시다. 저는 Vite를 사용하고 있기 때문에 빌드를 하면 dist 디렉터리에 정적 파일이 생성됩니다. 일반적으로 build 디렉토리에 정적파일이 생성되니 상황에 따라 적절하게 이동하면 됩니다.

정적 파일 디렉터리로 이동하고 위와 같은 커맨드를 입력합니다. s3://[버킷 주소]를 입력하고 사용할 자격증명은 이전에 저장한 프로파일로 설정합니다. 이렇게 하면 한 줄의 커맨드로 아래와 같이 한 번에 필요한 파일들을 배포할 수 있습니다. 

3. 정적 웹 사이트 호스팅

자 이제 이 버킷을 정적 웹 사이트 호스팅용으로 변경해봅시다. 

선택한 버킷에서 속성을 선택합니다.

스크롤을 내리면 맨 아래 속성에서 정적 웹 사이트 호스팅을 확인해볼 수 있습니다. 편집을 누르고 정적 웹 사이트 호스팅을 활성화합니다. 

위와 같이 호스팅 유형을 설정하고 인덱스 문서를 버킷에 업로드한 파일 중 기본 페이지 파일 이름으로 설정합니다. 대부분 index.html 입니다:) 이제 변경사항을 저장합니다.

다시 속성을 확인하면 위와 같이 엔드포인트 주소를 확인할 수 있습니다. 저 링크로 접속해서 원하는 프로젝트에 접속이 가능하다면 성공입니다! 

다음

위 설정만으로 웹 사이트를 배포할 수 있습니다. 하지만 조금 아쉽습니다. HTTP가 아니라는 점, 접속자 수가 급증하면 부하 분산이 불가능하다는 점, 여러 지역에서 접속할 경우 거리마다 정적 파일이 제공되는 시간이 다르다는 점 그리고 API 서버와 연결하기 어렵다는 점 등 실제 서비스에 적용하기에는 부족한 점이 많습니다. 이 부족한 점을 CloudFront로 해결해보겠습니다. 

 

'Web' 카테고리의 다른 글

CSS - Element가 배치되는 방법들  (0) 2020.01.18
Servlet - Hellow World 출력하기(intellij)  (0) 2020.01.18
Web - Event & EventListener  (0) 2020.01.18
Ajax 통신 정의, 필요성, 예제  (0) 2020.01.18
JSP(Java Server Page) - 정의, 문법  (0) 2020.01.18

CSS - Element가 배치되는 방법


1. display : 기본적으로 Element의 배치 형식을 설정

  1) display :  block;

    :block 형식은 벽돌을 쌓은 것처럼 위에서 아래로 순서대로 채워짐
    (기본적으로 block인 태그: div, p , ...)
    예시:http://jsbin.com/xabafaxasi/1/edit?html,css,output

  2) display : inline;

    : 기본적으로 왼쪽에서 오른쪽으로 가지만 크기를 초과할 경우 다음 라인으로 넘어감
    (아주 기본적인 스타일)
    예시: http://jsbin.com/mefebos/2/edit?html,css,output
    (기본적으로 inline인 태그: span,a ,...)

2. position

  1) static

    :기본값, 그냥 순서대로 배치

  2)absolute

    : 기준점에 따라서 위치 top(필수), left(필수), right, bottom 사용
    * 기준: 상위 Element중 static이 아닌 position을 가진 Element

  3)relative

    :원래 자신이 위치해야할 곳을 기준으로 top, left, right, bottom을 사용해 이동

  4)fixed

    :스크롤을 내리든 말든 항상 정위치, viewport(전체화면)를 기준으로 위치 조절가능
  예시: http://jsbin.com/mesoqaf/edit?html,css,output

3. margin

  :근처의 엘리먼트와의 간격을 설정가능
  top, left, right, bottom을 사용함


4. float

  :엘리먼드가 둥둥뜨게 만드는것?
  ( 한 엘리먼트를 float처리하면 다른 엘리먼트는 이 엘리먼트가 없는것 처럼 행동)
  예시: http://jsbin.com/lecigox/1/edit?html,css,output

5. box-model

  :블록 엘리먼트의 경우 box의 크기와 간격으로 배치를 추가 결정할수 있습니다.
  1)margin: 위 처럼 Element간의 간격을 설정할떄 사용합니다.
  2)border: 블럭 엘리먼트를 감싸는 테두리를 뜻합니다.
  3)padding: 실제 블럭안의 내용(content)과 border간의 간격을 top, left, right, bottom을 사용해 결정합니다.
  자세한 예시: https://www.w3schools.com/css/css_boxmodel.asp
  *기본적인 박스의 크기: 부모의 크기를 만큼 가지게 됩니다.

6. box-sizing & padding

  : 기본적으롶 padding 속성을 늘리면 box 사이즈가 같이 늘어납니다.
  이를 컨트롤하기 위해서 box-sizing속성을 사용합니다.
  예시: http://jsbin.com/wosuwop/edit?html,css,output
  box-sizing:content-box; : 기본값
  box-sizing:border-box; : box 사이즈를 최대한 고정하려고 합니다. but padding이 너무 크다면 늘어날 수 있습니다.

*팁!: CSS는 1을 앞에 줘서 주석처리가 가능, w3w3schools에는 자세한 예시와 설명이 나와있습니다.(근데 영어입니다.ㅠㅜ)

출처:http://www.edwith.org/boostcourse-web/lecture/16677/

Servlet - Hellow World 출력하기(intellij)

1. Java Enterprice -> Web Application 열기

    : 이 때 다운받은 WAS서버(이 포스팅에는 Tomcat 사용) 종류와 폴더의 위치를 정해주고 난 후
    Next 버튼을 누르고 난 후에 프로젝트명을 설정해줍니다.

2. Servlet 파일 만들기

    : 사진을 따라서 서블릿 클래스 파일을 만듭니다.


3. 소스코드 입력하기

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
package examples;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
@WebServlet(name = "Servlet",urlPatterns = {"/firstServlet","/test"})
//urlPatterns는 이 서블릿의 주소를 명시해주고있습니다. 위는 http://http://localhost:8080/test 또는 http://localhost:8080/firstServlet이 됩니다.
public class HellowServlet extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    }
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        response.setContentType("text/html;charset=UTF-8");
//respone은 웹페이지에서 요청이 들어오면 기본적으로 응답해주는 인스턴스입니다.
//setContetType은 응답해주는 인스턴스의 특징을 명시해주는 함수입니다. html형식, 유니코드 8진수 표기를 사용한다고 명시합니다.
        PrintWriter out=response.getWriter();
// getWriter를 통해서 응답해주는 PrinterWirter 출력스트림을 가져옵니다.
        out.println("<h1>Hello World</h1>");
    }
}
cs

웹 페이지 화면에서 클릭이나 드래그 등의 동작에 반응을 주고 싶을 때 사용하는것이 이벤트 리스너이다. 여기에서는 간단하게 클릭한 정보를 콘솔에 출력하는 실습을 할 것이다.

이벤트:

   이벤트는 브라우저가 받는 활동들을 의미한다.
   Example : 보통 화면이나 요소를 클릭, 드래그, 휠 조정등 다양한 입력들을 이벤트라고한다.

 이벤트 리스너(핸들러):

   특정한 이벤트가 일어났을때 해당 이벤트에 대한 반응을 의미한다.
   Example : 검색버튼을 클릭, 로그인버튼을 클릭 등등 다양하다.

학습을 위해서는 아래의 코드를 통해 브라우저로 실행한뒤 직접클릭해보면서 코드를 이해하는게 좋다

JS 파일
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
var el = document.querySelector(".outside1");
//querySelector를 통해서 리스너를 추가할 뷰를 선택한다.
// addEventListener의 함수의 인자와 동작에 대해서는 정식링크를 참조하는 것이 좋다.
//https://developer.mozilla.org/ko/docs/Web/API/EventTarget/addEventListener#%EA%B5%AC%EB%AC%B8
el.addEventListener("click"function(e){
  //function에 들어오는 인자는 클릭했을때는 호출한 이벤트의 정보가 있다.
  //do something..
  var target=e.target;
  //target은 어떤것이 클릭되었는지를 전달, 가장많이쓰임
  console.log("hellow",target.className,target.nodeName,target.innerText);
}, false);
// See :https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Building_blocks/Events#Event_handler_properties
cs
HTML파일
1
2
3
4
5
6
7
8
9
10
11
12
<!DOCTYPE html>
<html lang="en" dir="ltr">
  <head>
    <meta charset="utf-8">
    <title></title>
  </head>
  <body>
    <div class="outside1">outside element</div><br>
  </body>
  <script src="event_listener.js"></script>
</html>
cs

+ Recent posts