Taeyoung Kim

Cloud & Platform

16강. 미니 프로젝트

16강. 미니 프로젝트 학습 내용을 정리한 백필 노트입니다.

이 글은 2025년 학습 기록을 블로그 형식으로 정리한 백필 노트입니다.

목차

  • 미니 프로젝트 소개
  • (실습) EC2 인스턴스 생성하기
  • (실습) SSH로 EC2 인스턴스 접속하기
  • (실습) EC2에 Node.js 설치하기
  • (실습) Express 설치하기
  • (실습) Vim 환경 설정하기
  • (실습) Node.js와 Express를 사용해서 웹서버 띄우기
  • (실습) Express generator로 애플리케이션 코드 생성
  • (실습) 이미지 파일 업로드를 위한 API 틀 만들기
  • (실습) 이미지 파일 업로드를 위한 웹페이지 작성
  • (실습) AWS SDK for JavaScript 설치하기
  • (실습) 서버에서 받은 이미지 파일을 S3에 저장하기
  • (실습) S3에 있는 이미지 파일들을 웹페이지에서 보여주기
  • (실습) S3에 CloudFront 연동하기
  • (실습) Node.js용 프로세스 매니저 pm2 설치
  • (실습) 서버 부팅 시 pm2 프로세스 자동으로 시작하도록 만들기
  • (실습) ELB Load Balancer 설정
  • (실습) AMI 생성
  • (실습) Auto Scaling 설정

미니 프로젝트 소개

사진 공유 웹사이트

이 미니 프로젝트는 사진을 공유하는 웹사이트를 구축하는 것을 목표로 합니다.

사진 공유 웹사이트 구조

  1. 웹사이트 접속: 사용자가 웹사이트에 접속합니다.
  2. ELB (Elastic Load Balancer): 트래픽을 여러 EC2 인스턴스로 분산합니다.
  3. ASG (Auto Scaling Group)EC2 인스턴스:
    • 사용자의 요청을 처리합니다.
    • 업로드된 사진을 S3 버킷으로 전송합니다.
  4. S3 (Simple Storage Service): 업로드된 사진 파일을 저장합니다.
  5. CloudFront: S3에 저장된 사진(이미지)을 사용자에게 빠르고 효율적으로 제공(CDN)합니다.
  6. 사진 이미지 요청: 사용자가 CloudFront를 통해 S3에 저장된 이미지를 요청하여 웹사이트에서 확인합니다.

구현을 위해 사용할 기술들

  • Front-end: jQuery, Bootstrap
  • Back-end: Node.js, Express

GitHub Repository


(실습) EC2 인스턴스 생성하기

  1. AWS 콘솔에 로그인 후 서비스 검색창에 'EC2'를 입력하여 EC2 대시보드로 이동합니다.
  2. EC2 대시보드에서 '인스턴스 시작' 버튼을 클릭합니다.
  3. 이름 설정: 인스턴스의 이름을 'MyServer'로 입력합니다.
  4. 애플리케이션 및 OS 이미지 (AMI): 'Ubuntu'를 선택하고, 'Ubuntu Server 22.04 LTS' 버전을 선택합니다. (프리 티어 사용 가능)
  5. 인스턴스 유형: 't2.micro'를 선택합니다. (프리 티어 사용 가능)
  6. 키 페어 (로그인):
    • '새 키 페어 생성'을 클릭합니다.
    • 키 페어 이름을 'my-key'로 입력합니다.
    • 키 페어 유형은 'RSA', 프라이빗 키 파일 형식은 '.pem'으로 설정합니다.
    • '키 페어 생성'을 클릭하고 생성된 .pem 파일을 로컬 컴퓨터에 다운로드합니다.
  7. 네트워크 설정:
    • '인터넷에서 SSH 트래픽 허용'이 체크되어 있는지 확인합니다. 소스는 '위치 무관 (0.0.0.0/0)'으로 설정합니다.
  8. 스토리지 구성: 기본값인 8GiB gp2 루트 볼륨으로 설정합니다.
  9. 설정이 완료되면 '인스턴스 시작' 버튼을 클릭하여 인스턴스 생성을 시작합니다.
  10. 잠시 후 인스턴스가 성공적으로 시작되었는지 확인하고, 생성된 인스턴스의 '퍼블릭 IPv4 주소'를 확인합니다.

(실습) SSH로 EC2 인스턴스 접속하기

  1. Windows에서 접속: PuTTY와 같은 SSH 클라이언트를 사용합니다. 자세한 내용은 공식 문서를 참고하세요.
  2. Linux 또는 macOS에서 접속:
    • 터미널을 엽니다.

    • 다운로드한 키 페어 파일(.pem)의 권한을 변경합니다. 다른 사용자가 접근할 수 없도록 설정해야 합니다.Bash

      chmod 400 ~/Downloads/my-key.pem
      
    • ssh 명령어를 사용하여 인스턴스에 접속합니다. i 옵션으로 키 파일의 경로를 지정하고, ubuntu 사용자와 인스턴스의 퍼블릭 IPv4 주소를 입력합니다.Bash

      ssh -i ~/Downloads/my-key.pem ubuntu@<Public IP 주소>
      
    • 처음 접속 시 나오는 연결 여부 질문에 yes를 입력합니다.

    • 접속에 성공하면 터미널 프롬프트가 ubuntu@ip-x-x-x-x:~$와 같이 변경됩니다.


(실습) EC2에 Node.js 설치하기

Node.js 설치는 Nodesource GitHub 저장소의 안내를 따릅니다.

  1. 패키지 목록을 업데이트합니다.Bash

    sudo apt-get update
    
  2. 필수 패키지(ca-certificates, curl, gnupg)를 설치합니다.Bash

    sudo apt-get install -y ca-certificates curl gnupg
    
  3. Nodesource GPG 키를 위한 디렉토리를 생성합니다.Bash

    sudo mkdir -p /etc/apt/keyrings
    
  4. Nodesource GPG 키를 다운로드하고 저장합니다.Bash

    curl -fsSL https://deb.nodesource.com/gpgkey/nodesource-repo.gpg.key | sudo gpg --dearmor -o /etc/apt/keyrings/nodesource.gpg
    
  5. Node.js 20.x 버전을 사용하도록 저장소를 설정합니다.Bash

    NODE_MAJOR=20
    echo "deb [signed-by=/etc/apt/keyrings/nodesource.gpg] https://deb.nodesource.com/node_$NODE_MAJOR.x nodistro main" | sudo tee /etc/apt/sources.list.d/nodesource.list
    
  6. 다시 패키지 목록을 업데이트합니다.Bash

    sudo apt-get update
    
  7. Node.js를 설치합니다.Bash

    sudo apt-get install nodejs -y
    
  8. 설치가 완료되면 nodenpm의 버전을 확인하여 정상적으로 설치되었는지 검증합니다.Bash

    node --version
    npm --version
    

(실습) Express 설치하기

Express는 Node.js를 위한 웹 애플리케이션 프레임워크입니다.

  1. 프로젝트를 위한 디렉토리를 생성하고 소유자를 변경합니다.Bash

    cd /home
    sudo mkdir project
    sudo chown ubuntu:ubuntu project/
    
  2. 생성한 project 디렉토리로 이동합니다.Bash

    cd project/
    
  3. npm init 명령어를 사용하여 package.json 파일을 생성합니다. y 옵션은 모든 질문에 기본값으로 답합니다.Bash

    npm init -y
    
  4. Express 설치 안내에 따라 Express를 설치합니다.Bash

    npm install express
    
  5. 설치가 완료되면 package.json 파일에 express가 dependencies 항목에 추가된 것을 확인할 수 있습니다.


(실습) Vim 환경 설정하기

EC2 인스턴스에서 코드를 편집하기 위해 Vim 편집기의 기본 설정을 합니다.

  1. ~/.vimrc 파일을 생성하고 엽니다.Bash

    vim ~/.vimrc
    
  2. i를 눌러 입력 모드로 전환한 후, 다음 내용을 작성합니다.Vim Script

    • set autoindent: 자동 들여쓰기 설정
    • set ts=4: 탭 크기를 4칸으로 설정
    • set shiftwidth=4: 자동 들여쓰기 너비를 4칸으로 설정
    • set nu: 줄 번호 표시
    set autoindent
    set ts=4
    set shiftwidth=4
    set nu
    
  3. Esc 키를 눌러 명령 모드로 전환한 후, :wq를 입력하고 Enter를 눌러 저장하고 종료합니다.

  4. 다시 vim ~/.vimrc를 실행하여 줄 번호가 자동으로 표시되는지 확인합니다.


(실습) Node.js와 Express를 사용해서 웹서버 띄우기

Express의 Hello world 예제를 사용하여 간단한 웹 서버를 실행합니다.

  1. project 디렉토리에서 index.js 파일을 생성하고 엽니다.Bash

    vim index.js
    
  2. 아래의 예제 코드를 복사하여 붙여넣습니다.JavaScript

    const express = require('express')
    const app = express()
    const port = 3000
    
    app.get('/', (req, res) => {
      res.send('Hello World!')
    })
    
    app.listen(port, () => {
      console.log(`Example app listening on port ${port}`)
    })
    
  3. 저장하고 종료합니다(:wq).

  4. node 명령어로 웹 서버를 실행합니다.Bash

    node index.js
    

    터미널에 Example app listening on port 3000 메시지가 출력됩니다.

  5. EC2 보안 그룹 인바운드 규칙 추가:

    • AWS EC2 콘솔에서 인스턴스를 선택하고 '보안' 탭으로 이동한 후, 보안 그룹 이름을 클릭합니다.
    • '인바운드 규칙 편집'을 클릭합니다.
    • '규칙 추가'를 클릭하고 다음을 설정합니다.
      • 유형: 사용자 지정 TCP
      • 포트 범위: 3000
      • 소스: Anywhere-IPv4 (0.0.0.0/0)
    • '규칙 저장'을 클릭합니다.
  6. 웹 브라우저에서 접속 확인:

    • 웹 브라우저 주소창에 http://&lt;EC2 퍼블릭 IP 주소>:3000을 입력하여 접속합니다.
    • 화면에 'Hello World!'가 표시되는지 확인합니다.

(실습) Express generator로 애플리케이션 코드 생성

express-generator는 Express 애플리케이션의 기본 구조(skeleton)를 자동으로 생성해주는 도구입니다.

  1. 기존에 만들었던 project 폴더를 삭제합니다.Bash

    cd /home
    sudo rm -rf project/
    
  2. Express generator 안내에 따라 npx를 사용하여 EJS 뷰 엔진을 사용하는 project라는 이름의 앱을 생성합니다.Bash

    sudo npx express-generator --view=ejs project
    
    • 설치 진행 여부를 물으면 y를 입력합니다.
  3. 생성된 project 폴더의 소유자를 ubuntu로 변경합니다.Bash

    sudo chown -R ubuntu:ubuntu project/
    
  4. project 디렉토리로 이동하여 npm install 명령어로 package.json에 명시된 의존성 패키지들을 설치합니다.Bash

    cd project/
    npm install
    
  5. npm start 명령어로 서버를 시작합니다.Bash

    npm start
    
  6. 웹 브라우저에서 http://&lt;EC2 퍼블릭 IP 주소>:3000으로 접속하여 'Express', 'Welcome to Express' 페이지가 나타나는지 확인합니다.


(실습) 이미지 파일 업로드를 위한 API 틀 만들기

이미지 파일을 서버로 업로드하기 위해 multer 라이브러리를 사용합니다.

  1. multer를 설치합니다.Bash

    npm install multer
    
  2. routes 폴더로 이동하여 users.js 파일을 images.js로 복사합니다.Bash

    cd routes/
    cp users.js images.js
    
  3. vim으로 images.js 파일을 엽니다.Bash

    vim images.js
    
  4. 기존 내용을 수정하여 파일 업로드를 처리하는 코드를 추가합니다.JavaScript

    var express = require('express');
    var router = express.Router();
    var fs = require('fs');
    var path = require('path');
    var multer = require('multer');
    var upload = multer({ dest: path.join(__dirname, '..', 'uploads') });
    
    /* GET users listing. */
    router.get('/', function(req, res, next) {
      res.send('respond with a resource');
    });
    
    router.post('/', upload.single('new-image'), function(req, res, next) {
      console.dir(req.file);
      res.send();
    });
    
    module.exports = router;
    
  5. 프로젝트의 메인 파일인 app.js를 수정하여 /images 경로에 대한 라우팅을 추가합니다.Bash

    cd ..
    vim app.js
    
  6. app.js 파일에 다음 두 줄을 추가합니다.JavaScript

    // var usersRouter = require('./routes/users'); 바로 아래에 추가
    var imagesRouter = require('./routes/images');
    
    // app.use('/users', usersRouter); 바로 아래에 추가
    app.use('/images', imagesRouter);
    

(실습) 이미지 파일 업로드를 위한 웹페이지 작성

BootstrapjQuery를 사용하여 파일 업로드 UI를 만듭니다.

  1. views 폴더의 index.ejs 파일을 엽니다.Bash

    cd views/
    vim index.ejs
    
  2. &lt;head> 태그 안에 Bootstrap CSS 링크를 추가합니다.HTML

    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-T3c6CoIi6uLrA9TneNEoa7RxnatzjcDSCmG1MXxSR1GAsXEV/Dwwykc2MPK8M2HN" crossorigin="anonymous">
    
  3. &lt;body> 태그가 끝나기 직전에 Bootstrap JS와 Popper.js, jQuery, jQuery UI, jQuery-File-Upload 스크립트를 CDN으로 추가합니다.HTML

    <script src="https://code.jquery.com/jquery-3.7.1.min.js" integrity="sha256-/JqT3SQfawRcv/BIHPThkBvs0OEvtFFmqPF/lYI/Cxo=" crossorigin="anonymous"></script>
    <script src="https://code.jquery.com/ui/1.13.2/jquery-ui.min.js" integrity="sha256-lSjKY0/srUM9BE3dPm+c4fagCwLcsrzVzjdOfILEGIqvN0E=" crossorigin="anonymous"></script>
    <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/js/bootstrap.bundle.min.js" integrity="sha384-C6RzsynM9kWDrMNeT87bh95OGNyZPhcTNXj1NW7RuBCsyN/o0jlpcV8Qyq46cDfL" crossorigin="anonymous"></script>
    <script src="https://cdn.jsdelivr.net/npm/@popperjs/core@2.11.8/dist/umd/popper.min.js" integrity="sha384-I7E8VVD/ismYTF4hNIPjVp/Zjvgyol6VFvRkX/vR+Vc4jQkC+hVqc2pM8ODewa9r" crossorigin="anonymous"></script>
    <script src="https://blueimp.github.io/jQuery-File-Upload/js/jquery.fileupload.js" crossorigin="anonymous"></script>
    
  4. &lt;body> 안에 파일 선택(input)과 진행률 표시 막대(progress bar)를 위한 HTML 코드를 추가합니다.HTML

    <div class="input-group mb-3">
        <label class="input-group-text" for="file-upload">Upload</label>
        <input type="file" class="form-control" id="file-upload" name="new-image">
    </div>
    
    <div id="progress" class="progress" role="progressbar" aria-label="Animated striped example" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100">
        <div class="progress-bar progress-bar-striped progress-bar-animated" style="width: 0%"></div>
    </div>
    
  5. 파일 업로드를 처리하는 jQuery 스크립트를 &lt;body> 끝에 추가합니다.HTML

    <script>
      $(function () {
        $('#file-upload').fileupload({
          url: '/images',
          dataType: 'json',
          progressall: function (e, data) {
            var progress = parseInt(data.loaded / data.total * 100, 10);
            $('#progress .progress-bar').css('width', progress + '%');
          }
        });
      });
    </script>
    
  6. npm start로 서버를 재시작하고 웹 페이지에 접속하여 파일 업로드 UI가 나타나는지, 파일 업로드가 정상적으로 동작하고 터미널에 로그가 찍히는지 확인합니다.


(실습) AWS SDK for JavaScript 설치하기

Node.js 환경에서 AWS 서비스를 사용하기 위해 AWS SDK를 설치합니다.

  1. S3 클라이언트 라이브러리를 설치합니다.Bash

    npm install @aws-sdk/client-s3
    
  2. 설치가 완료되면 package.json 파일의 dependencies@aws-sdk/client-s3가 추가된 것을 확인합니다.


(실습) 서버에서 받은 이미지 파일을 S3에 저장하기

  1. routes/images.js 파일을 열어 S3 클라이언트를 초기화하고, 파일 업로드 시 S3로 전송하는 로직을 추가합니다.JavaScript

    var express = require('express');
    var router = express.Router();
    var fs = require('fs');
    var path = require('path');
    var multer = require('multer');
    var { S3Client, PutObjectCommand } = require('@aws-sdk/client-s3');
    const s3Client = new S3Client({ region: 'ap-northeast-2' }); // 서울 리전
    
    var upload = multer({ dest: path.join(__dirname, '..', 'uploads') });
    
    /* GET images listing. */
    router.get('/', function(req, res, next) {
        res.send('respond with a resource');
    });
    
    router.post('/', upload.single('new-image'), async function(req, res, next) {
      try {
        const file = req.file;
        const stream = fs.createReadStream(file.path);
        const params = {
          Bucket: 'YOUR_S3_BUCKET_NAME', // 생성한 S3 버킷 이름
          Key: file.originalname,
          Body: stream,
          ContentType: file.mimetype,
        };
        const command = new PutObjectCommand(params);
        await s3Client.send(command);
        res.send({ success: true });
      } catch (err) {
        console.error(err);
        next(err);
      } finally {
        // uploads 폴더에 저장된 임시 파일 삭제
        fs.unlink(req.file.path, (err) => {
          if (err) {
            console.error(err);
          }
        });
      }
    });
    
    module.exports = router;
    

    주의: YOUR_S3_BUCKET_NAME 부분은 실제 생성한 S3 버킷 이름으로 변경해야 합니다. 또한, 이 코드가 정상 동작하려면 EC2 인스턴스에 S3 접근 권한(IAM 역할)이 부여되어야 합니다.


이후 실습 내용은 S3 이미지 웹페이지 표시, CloudFront 연동, PM2 설치, ELB 및 Auto Scaling 설정 등 고급 주제로 이어집니다. 각 단계는 AWS 콘솔에서의 설정과 코드 수정을 포함합니다.


마치며

  • 중요: 실습이 끝난 후에는 과금 방지를 위해 생성했던 모든 AWS 리소스(EC2 인스턴스, S3 버킷, ELB, Auto Scaling Group, CloudFront 배포 등)를 반드시 삭제해야 합니다.