일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 | 30 | 31 |
- clusterrolebinding
- NAT
- aws ses #aws lambda
- fruition
- 에이전트 구성
- route53
- 추가 보안 그룹
- aws-loadbalacner-controller
- 에이전트 유형
- Service Account
- Docker0
- docker
- httpasswd
- node group
- 테라폼
- instances failed to join cluster
- Terraform
- kubernetes
- assumerole
- 코드커버리지
- saa-c03 #saa #aws certified solutions architect - associate
- ingestion
- Pipeline
- helm_release
- IRSA
- Amazon CloudWatch
- Gateway
- 클러스터 보안 그룹
- s3
- jenkins
- Today
- Total
cloudwithbass
[AWS] S3와 RDS를 이용하여 정적, 동적 콘텐츠를 제공하는 웹사이트 호스팅하기 본문
- 저는 정적 콘텐츠는 CloudFront + S3로 정적 페이지를 통해 제공하고, 동적 정보는 WAS에서 제공하는 것이 효율적인 구성이라는 것을 알고 있습니다.
- 하지만 프로젝트 경험이 부족해서 WAS에서 동적 정보를 제공하는 구체적인 방법을 알 수 없었습니다.
- 따라서 이번 포스팅을 통해 S3와 RDS를 통해 정적 정보와 동적 정보를 포함한 html 파일을 호스팅하는 데모를 생성하여 이 방법을 익히고자 합니다.
- 초급자용이 아니므로 리소스를 생성하기 위해 어떤 버튼을 눌러야하는지 등의 정보는 생략할 것입니다.
목차
1. RDS, EC2 생성
데이터를 저장할 RDS와 서버를 호스팅할 EC2를 생성합니다.
MySQL을 사용했으므로 DB가 사용하는 보안 그룹의 3306 인바운드 포트를 허용합니다.
퍼블릭 ip 54.180.150.44
2. IGW, 라우팅 테이블 생성
RDS는 VPC 내에 존재하므로 인터넷 게이트웨이가 필요합니다.
0.0.0.0/0에서 IGW로 라우팅하는 라우팅 테이블도 생성하여 VPC에 연결합니다.
3. DB 설정
mysql 명령으로 DB와 연결해서 'demo_db' 데이터 데이터베이스와 'users' 테이블을 생성하고, 세 개의 데이터를 추가합니다.
#-p는 대화형으로 패스워드를 입력하기 위한 옵션
mysql -h <DB-ENDPOINT> -u admin -p
mysql> CREATE DATABASE demo_db;
# 정상 응답:Query OK, 1 row affected (0.01 sec)
mysql> USE demo_db;
# 정상 응답: Database changed
mysql> CREATE TABLE users (
-> id INT AUTO_INCREMENT PRIMARY KEY,
-> name VARCHAR(100) NOT NULL,
-> email VARCHAR(255) NOT NULL UNIQUE,
-> created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
-> );
#정상 응답: Query OK, 0 rows affected (0.05 sec)
mysql> INSERT INTO users (name, email) VALUES
-> ('맛장우', 'user1@example.com'),
-> ('묵은지', 'user2@example.com'),
-> ('김참치', 'user3@example.com');
#정상 응답: Query OK, 3 rows affected (0.01 sec)
# Records: 3 Duplicates: 0 Warnings: 0
show tables; 명령과 decribe users; 명령을 통해 테이블과 객체가 잘 저장됐는지 확인합니다.
4. EC2 Flask 서버 설정
챗 gpt가 생성한 코드입니다.
/api/users 엔드포인트에서 모든 유저의 정보를 반환하도록 하는 간단한 api 서버입니다.
처음에 python3를 사용했다가 버전이 잘 안 맞아서 여러번 수정했기 때문에 아래 setup 내용은 틀릴 수 있습니다. 혹시 에러가 발생한다면 호환되는 버전의 패키지들을 사용해 주세요.
# setup
sudo apt install python3.11-venv
python3.11 -m venv venv #가상환경 사용
source venv/bin/activate
pip install Werkzeug==2.0.3
pip install SQLAlchemy==1.4.23
pip install flask==2.0.3
pip install flask-sqlalchemy==2.5.1
pip install flask-cors==3.0.10
pip install pymysql==1.0.2
pip install python-dotenv==0.19.0
<USER>, <PAWSSWORD>, <DB-ENDPOINT>는 각자의 설정에 맞게 수정해야 합니다.
#app.py
from flask import Flask, jsonify
from flask_cors import CORS
from flask_sqlalchemy import SQLAlchemy
from datetime import datetime
import os
app = Flask(__name__)
CORS(app)
# 데이터베이스 설정
app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql+pymysql://<USER>:<PASSWORD>@<DB-ENDPOINT>:3306/demo_db'
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
db = SQLAlchemy(app)
# 사용자 모델 정의
class User(db.Model):
__tablename__ = 'users' # 실제 테이블 이름을 명시
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(100), nullable=False)
email = db.Column(db.String(255), unique=True, nullable=False)
created_at = db.Column(db.DateTime, default=datetime.utcnow)
# API 엔드포인트
@app.route('/api/users', methods=['GET'])
def get_users():
try:
users = User.query.order_by(User.created_at.desc()).all()
return jsonify([{
'id': user.id,
'name': user.name,
'email': user.email,
'created_at': user.created_at.isoformat()
} for user in users])
except Exception as e:
return jsonify({'error': str(e)}), 500
if __name__ == '__main__':
app.run(host='0.0.0.0', port=5000)
이제 python3.11 app.py 명령으로 서버를 실행합니다.
EC2 터미널을 하나 더 띄워서 해당 주소의 /api/users에 curl 명령을 실행하니 정상적인 응답이 반환됐습니다.
EC2 보안그룹에서 인터넷 인바운드를 허용 후, 이번엔 EC2의 public ip의 /api/users 엔드포인트에 curl 명령을 실행했습니다. 마찬가지로 정상적인 응답이 반환됩니다.
5. S3 설정
퍼블릭 액세스를 허용한 버킷을 하나 생성합니다.
아래 문서를 참조해 퍼블릭 액세스를 위한 정책을 구성합니다.
아래 html 코드를 버킷에 업로드합니다. 저는 이름을 test2.html이라고 저장했습니다.
챗gpt가 생성한 코드입니다.
API_URL은 'http:// <public IP of EC2>/api/users/'로 설정해야 합니다.
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>정적/동적 콘텐츠 데모</title>
<style>
body {
font-family: 'Arial', sans-serif;
margin: 0;
padding: 20px;
background-color: #f5f5f5;
}
.container {
max-width: 800px;
margin: 0 auto;
background-color: white;
padding: 20px;
border-radius: 8px;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
}
h1 {
color: #333;
text-align: center;
margin-bottom: 30px;
}
.static-content {
padding: 20px;
background-color: #e8f4f8;
border-radius: 4px;
margin-bottom: 20px;
}
.dynamic-content {
padding: 20px;
background-color: #f8f0e8;
border-radius: 4px;
margin-bottom: 20px;
}
#userList {
list-style: none;
padding: 0;
}
#userList li {
padding: 10px;
border-bottom: 1px solid #ddd;
}
.loading {
text-align: center;
color: #666;
}
.error {
color: #ff4444;
text-align: center;
padding: 10px;
}
.refresh-btn {
display: block;
margin: 20px auto;
padding: 10px 20px;
background-color: #007bff;
color: white;
border: none;
border-radius: 4px;
cursor: pointer;
}
.refresh-btn:hover {
background-color: #0056b3;
}
</style>
</head>
<body>
<div class="container">
<h1>AWS S3 + RDS 데모</h1>
<div class="static-content">
<h2>정적 콘텐츠</h2>
<p>이 내용은 S3에서 호스팅되는 정적 HTML입니다.</p>
<p>이 스타일은 CSS로 정의되어 있으며, 역시 S3에서 제공됩니다.</p>
</div>
<div class="dynamic-content">
<h2>동적 콘텐츠</h2>
<p>아래 내용은 RDS에서 가져온 데이터입니다:</p>
<ul id="userList">
<li class="loading">데이터 로딩 중...</li>
</ul>
<button class="refresh-btn" onclick="fetchUsers()">새로고침</button>
</div>
</div>
<script>
// API 엔드포인트 URL
const API_URL = 'http://54.180.150.44:5000/api/users';
async function fetchUsers() {
const userList = document.getElementById('userList');
userList.innerHTML = '<li class="loading">데이터 로딩 중...</li>';
try {
const response = await fetch(API_URL);
if (!response.ok) {
throw new Error('API 요청 실패');
}
const users = await response.json();
userList.innerHTML = users.map(user => `
<li>
<strong>${user.name}</strong> (${user.email})
<br>가입일: ${new Date(user.created_at).toLocaleDateString()}
</li>
`).join('');
} catch (error) {
userList.innerHTML = `
<li class="error">
데이터를 불러오는 중 오류가 발생했습니다: ${error.message}
</li>
`;
}
}
// 페이지 로드시 자동으로 데이터 가져오기
document.addEventListener('DOMContentLoaded', fetchUsers);
</script>
</body>
</html>
이제 버킷의 속성 -> 최하단 정적 웹 사이트 호스팅 편집에 들어가 test2.html 파일을 호스팅하도록 설정합니다.
이렇게 설정하면 url이 생성될 것입니다.
웹 브라우저를 이용해 해당 url에 접근하면 아래와 같은 화면을 볼 수 있습니다.
동적 콘텐츠 부분의 내용은 Flask Server에서 실행 중인 api를 이용하여 동적으로 가져온 정보입니다.
동적 콘텐츠를 잘 가져오는지 테스트하기 위해 RDS에 유저 정보를 하나 더 삽입합니다.
삽입 후 새로고침 버튼을 누르면 아래 사진처럼 새로 추가된 데이터를 확인할 수 있습니다.
6. 개선 사항: 서버리스
EC2 서버 대신 Lambda를 이용하여 서버리스 아키텍처로 구성할 수 있습니다.
이 내용은 내일 오전에 있는 관련 aws Tech Camp 강의를 수강 후 자세히 작성하겠습니다.
'AWS' 카테고리의 다른 글
[AWS] NAT Instance로 AWS 요금을 줄여보자 (0) | 2024.12.19 |
---|---|
[AWS] Amazon OpenSearch Ingestion 튜토리얼과 가이드 (1) | 2024.11.13 |
[AWS] Cloud Watch 워크숍 예제 테라폼 코드 공유 (0) | 2024.10.19 |
[AWS] Route53 + S3로 사용자 지정 도메인 호스팅 실습하기 (1) | 2024.07.14 |
[AWS]★AWS SES란?, SES + Lambda + DynamoDB 실습해보기 (0) | 2024.07.07 |