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 설정
미니 프로젝트 소개
사진 공유 웹사이트
이 미니 프로젝트는 사진을 공유하는 웹사이트를 구축하는 것을 목표로 합니다.
사진 공유 웹사이트 구조
- 웹사이트 접속: 사용자가 웹사이트에 접속합니다.
- ELB (Elastic Load Balancer): 트래픽을 여러 EC2 인스턴스로 분산합니다.
- ASG (Auto Scaling Group) 내 EC2 인스턴스:
- 사용자의 요청을 처리합니다.
- 업로드된 사진을 S3 버킷으로 전송합니다.
- S3 (Simple Storage Service): 업로드된 사진 파일을 저장합니다.
- CloudFront: S3에 저장된 사진(이미지)을 사용자에게 빠르고 효율적으로 제공(CDN)합니다.
- 사진 이미지 요청: 사용자가 CloudFront를 통해 S3에 저장된 이미지를 요청하여 웹사이트에서 확인합니다.
구현을 위해 사용할 기술들
- Front-end: jQuery, Bootstrap
- Back-end: Node.js, Express
GitHub Repository
(실습) EC2 인스턴스 생성하기
- AWS 콘솔에 로그인 후 서비스 검색창에 'EC2'를 입력하여 EC2 대시보드로 이동합니다.
- EC2 대시보드에서 '인스턴스 시작' 버튼을 클릭합니다.
- 이름 설정: 인스턴스의 이름을 'MyServer'로 입력합니다.
- 애플리케이션 및 OS 이미지 (AMI): 'Ubuntu'를 선택하고, 'Ubuntu Server 22.04 LTS' 버전을 선택합니다. (프리 티어 사용 가능)
- 인스턴스 유형: 't2.micro'를 선택합니다. (프리 티어 사용 가능)
- 키 페어 (로그인):
- '새 키 페어 생성'을 클릭합니다.
- 키 페어 이름을 'my-key'로 입력합니다.
- 키 페어 유형은 'RSA', 프라이빗 키 파일 형식은 '.pem'으로 설정합니다.
- '키 페어 생성'을 클릭하고 생성된
.pem파일을 로컬 컴퓨터에 다운로드합니다.
- 네트워크 설정:
- '인터넷에서 SSH 트래픽 허용'이 체크되어 있는지 확인합니다. 소스는 '위치 무관 (0.0.0.0/0)'으로 설정합니다.
- 스토리지 구성: 기본값인 8GiB gp2 루트 볼륨으로 설정합니다.
- 설정이 완료되면 '인스턴스 시작' 버튼을 클릭하여 인스턴스 생성을 시작합니다.
- 잠시 후 인스턴스가 성공적으로 시작되었는지 확인하고, 생성된 인스턴스의 '퍼블릭 IPv4 주소'를 확인합니다.
(실습) SSH로 EC2 인스턴스 접속하기
- Windows에서 접속: PuTTY와 같은 SSH 클라이언트를 사용합니다. 자세한 내용은 공식 문서를 참고하세요.
- Linux 또는 macOS에서 접속:
-
터미널을 엽니다.
-
다운로드한 키 페어 파일(
.pem)의 권한을 변경합니다. 다른 사용자가 접근할 수 없도록 설정해야 합니다.Bashchmod 400 ~/Downloads/my-key.pem -
ssh 명령어를 사용하여 인스턴스에 접속합니다.
i옵션으로 키 파일의 경로를 지정하고,ubuntu사용자와 인스턴스의퍼블릭 IPv4 주소를 입력합니다.Bashssh -i ~/Downloads/my-key.pem ubuntu@<Public IP 주소> -
처음 접속 시 나오는 연결 여부 질문에
yes를 입력합니다. -
접속에 성공하면 터미널 프롬프트가
ubuntu@ip-x-x-x-x:~$와 같이 변경됩니다.
-
(실습) EC2에 Node.js 설치하기
Node.js 설치는 Nodesource GitHub 저장소의 안내를 따릅니다.
-
패키지 목록을 업데이트합니다.Bash
sudo apt-get update -
필수 패키지(
ca-certificates,curl,gnupg)를 설치합니다.Bashsudo apt-get install -y ca-certificates curl gnupg -
Nodesource GPG 키를 위한 디렉토리를 생성합니다.Bash
sudo mkdir -p /etc/apt/keyrings -
Nodesource GPG 키를 다운로드하고 저장합니다.Bash
curl -fsSL https://deb.nodesource.com/gpgkey/nodesource-repo.gpg.key | sudo gpg --dearmor -o /etc/apt/keyrings/nodesource.gpg -
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 -
다시 패키지 목록을 업데이트합니다.Bash
sudo apt-get update -
Node.js를 설치합니다.Bash
sudo apt-get install nodejs -y -
설치가 완료되면
node와npm의 버전을 확인하여 정상적으로 설치되었는지 검증합니다.Bashnode --version npm --version
(실습) Express 설치하기
Express는 Node.js를 위한 웹 애플리케이션 프레임워크입니다.
-
프로젝트를 위한 디렉토리를 생성하고 소유자를 변경합니다.Bash
cd /home sudo mkdir project sudo chown ubuntu:ubuntu project/ -
생성한
project디렉토리로 이동합니다.Bashcd project/ -
npm init명령어를 사용하여package.json파일을 생성합니다.y옵션은 모든 질문에 기본값으로 답합니다.Bashnpm init -y -
Express 설치 안내에 따라 Express를 설치합니다.Bash
npm install express -
설치가 완료되면
package.json파일에 express가dependencies항목에 추가된 것을 확인할 수 있습니다.
(실습) Vim 환경 설정하기
EC2 인스턴스에서 코드를 편집하기 위해 Vim 편집기의 기본 설정을 합니다.
-
~/.vimrc파일을 생성하고 엽니다.Bashvim ~/.vimrc -
i를 눌러 입력 모드로 전환한 후, 다음 내용을 작성합니다.Vim Scriptset autoindent: 자동 들여쓰기 설정set ts=4: 탭 크기를 4칸으로 설정set shiftwidth=4: 자동 들여쓰기 너비를 4칸으로 설정set nu: 줄 번호 표시
set autoindent set ts=4 set shiftwidth=4 set nu -
Esc키를 눌러 명령 모드로 전환한 후,:wq를 입력하고Enter를 눌러 저장하고 종료합니다. -
다시
vim ~/.vimrc를 실행하여 줄 번호가 자동으로 표시되는지 확인합니다.
(실습) Node.js와 Express를 사용해서 웹서버 띄우기
Express의 Hello world 예제를 사용하여 간단한 웹 서버를 실행합니다.
-
project디렉토리에서index.js파일을 생성하고 엽니다.Bashvim index.js -
아래의 예제 코드를 복사하여 붙여넣습니다.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}`) }) -
저장하고 종료합니다(
:wq). -
node명령어로 웹 서버를 실행합니다.Bashnode index.js터미널에
Example app listening on port 3000메시지가 출력됩니다. -
EC2 보안 그룹 인바운드 규칙 추가:
- AWS EC2 콘솔에서 인스턴스를 선택하고 '보안' 탭으로 이동한 후, 보안 그룹 이름을 클릭합니다.
- '인바운드 규칙 편집'을 클릭합니다.
- '규칙 추가'를 클릭하고 다음을 설정합니다.
- 유형: 사용자 지정 TCP
- 포트 범위: 3000
- 소스: Anywhere-IPv4 (0.0.0.0/0)
- '규칙 저장'을 클릭합니다.
-
웹 브라우저에서 접속 확인:
- 웹 브라우저 주소창에
http://<EC2 퍼블릭 IP 주소>:3000을 입력하여 접속합니다. - 화면에 'Hello World!'가 표시되는지 확인합니다.
- 웹 브라우저 주소창에
(실습) Express generator로 애플리케이션 코드 생성
express-generator는 Express 애플리케이션의 기본 구조(skeleton)를 자동으로 생성해주는 도구입니다.
-
기존에 만들었던
project폴더를 삭제합니다.Bashcd /home sudo rm -rf project/ -
Express generator 안내에 따라
npx를 사용하여 EJS 뷰 엔진을 사용하는project라는 이름의 앱을 생성합니다.Bashsudo npx express-generator --view=ejs project- 설치 진행 여부를 물으면
y를 입력합니다.
- 설치 진행 여부를 물으면
-
생성된
project폴더의 소유자를ubuntu로 변경합니다.Bashsudo chown -R ubuntu:ubuntu project/ -
project디렉토리로 이동하여npm install명령어로package.json에 명시된 의존성 패키지들을 설치합니다.Bashcd project/ npm install -
npm start명령어로 서버를 시작합니다.Bashnpm start -
웹 브라우저에서
http://<EC2 퍼블릭 IP 주소>:3000으로 접속하여 'Express', 'Welcome to Express' 페이지가 나타나는지 확인합니다.
(실습) 이미지 파일 업로드를 위한 API 틀 만들기
이미지 파일을 서버로 업로드하기 위해 multer 라이브러리를 사용합니다.
-
multer를 설치합니다.Bashnpm install multer -
routes폴더로 이동하여users.js파일을images.js로 복사합니다.Bashcd routes/ cp users.js images.js -
vim으로images.js파일을 엽니다.Bashvim images.js -
기존 내용을 수정하여 파일 업로드를 처리하는 코드를 추가합니다.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; -
프로젝트의 메인 파일인
app.js를 수정하여/images경로에 대한 라우팅을 추가합니다.Bashcd .. vim app.js -
app.js파일에 다음 두 줄을 추가합니다.JavaScript// var usersRouter = require('./routes/users'); 바로 아래에 추가 var imagesRouter = require('./routes/images'); // app.use('/users', usersRouter); 바로 아래에 추가 app.use('/images', imagesRouter);
(실습) 이미지 파일 업로드를 위한 웹페이지 작성
Bootstrap과 jQuery를 사용하여 파일 업로드 UI를 만듭니다.
-
views폴더의index.ejs파일을 엽니다.Bashcd views/ vim index.ejs -
<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"> -
<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> -
<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> -
파일 업로드를 처리하는 jQuery 스크립트를
<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> -
npm start로 서버를 재시작하고 웹 페이지에 접속하여 파일 업로드 UI가 나타나는지, 파일 업로드가 정상적으로 동작하고 터미널에 로그가 찍히는지 확인합니다.
(실습) AWS SDK for JavaScript 설치하기
Node.js 환경에서 AWS 서비스를 사용하기 위해 AWS SDK를 설치합니다.
- 참고 링크: AWS SDK for JavaScript
-
S3 클라이언트 라이브러리를 설치합니다.Bash
npm install @aws-sdk/client-s3 -
설치가 완료되면
package.json파일의dependencies에@aws-sdk/client-s3가 추가된 것을 확인합니다.
(실습) 서버에서 받은 이미지 파일을 S3에 저장하기
-
routes/images.js파일을 열어 S3 클라이언트를 초기화하고, 파일 업로드 시 S3로 전송하는 로직을 추가합니다.JavaScriptvar 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 배포 등)를 반드시 삭제해야 합니다.