AWS Cloud School 8기/프로젝트
81~84일차) 2025-04-24 ~ 2025-04-29 [3. k8s 팀 프로젝트] - 이스티오 실습(book review)
eitherwho
2025. 4. 29. 17:56
📌book-service
app.py
from flask import Flask, jsonify
app = Flask(__name__)
@app.route('/books', methods=['GET'])
def get_books():
books = [
{"id": 1, "title": "Clean Code"},
{"id": 2, "title": "The Pragmatic Programmer"},
{"id": 3, "title": "Refactoring"},
{"id": 4, "title": "Design Patterns"}
]
return jsonify(books)
if __name__ == '__main__':
app.run(host='0.0.0.0', port=5001)
dockerfile
FROM python:3.10-slim
WORKDIR /app
COPY app.py .
RUN pip install flask
EXPOSE 5001
CMD ["python", "app.py"]
📌frontend-service
app.py - v1
from flask import Flask, request, render_template_string, redirect
import requests
app = Flask(__name__)
TEMPLATE = """
<h1>Book List</h1>
<ul>
{% for book in books %}
<li>
<strong>{{book['title']}}</strong><br/>
<form method="post" action="/review/{{book['id']}}">
<input name="review" placeholder="Write a review"/>
<button type="submit">Submit</button>
</form>
<ul>
{% for r in reviews.get(book['id'], []) %}
<li>{{r}}</li>
{% endfor %}
</ul>
</li>
{% endfor %}
</ul>
"""
@app.route('/')
def index():
try:
books = requests.get("<http://book-service:5001/books>").json()
except Exception as e:
print("Error fetching books:", e)
books = []
reviews = {}
for book in books:
try:
r = requests.get(f"<http://review-service:5002/reviews/{book['id']}>").json()
except Exception as e:
print("Error fetching reviews for book", book['id'], ":", e)
r = []
reviews[book["id"]] = r
return render_template_string(TEMPLATE, books=books, reviews=reviews)
@app.route('/review/<int:book_id>', methods=['POST'])
def add_review(book_id):
review = request.form['review']
try:
requests.post(f"<http://review-service:5002/reviews/{book_id}>", json={"review": review})
except Exception as e:
print("Error posting review:", e)
return redirect('/')
if __name__ == '__main__':
app.run(host="0.0.0.0", port=5000)
app.py - v2
from flask import Flask, request, render_template_string, redirect
import requests
app = Flask(__name__)
TEMPLATE = """
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Book Review</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
</head>
<body class="bg-light">
<div class="container py-5">
<h1 class="mb-4">Book Review</h1>
{% for book in books %}
<div class="card mb-4 shadow-sm">
<div class="card-body">
<h5 class="card-title">{{ book['title'] }}</h5>
<form method="post" action="/review/{{ book['id'] }}" class="d-flex gap-2 mb-3">
<input name="review" class="form-control" placeholder="Write your review here" required>
<button type="submit" class="btn btn-primary">Submit</button>
</form>
{% if reviews.get(book['id']) %}
<ul class="list-group list-group-flush">
{% for r in reviews[book['id']] %}
<li class="list-group-item">{{ r }}</li>
{% endfor %}
</ul>
{% else %}
<p class="text-muted">No reviews yet.</p>
{% endif %}
</div>
</div>
{% endfor %}
</div>
</body>
</html>
"""
@app.route('/')
def index():
try:
books = requests.get("http://book-service:5001/books").json()
except Exception as e:
print("Error fetching books:", e)
books = []
reviews = {}
for book in books:
try:
r = requests.get(f"http://review-service:5002/reviews/{book['id']}").json()
except Exception as e:
print("Error fetching reviews for book", book['id'], ":", e)
r = []
reviews[book["id"]] = r
return render_template_string(TEMPLATE, books=books, reviews=reviews)
@app.route('/review/<int:book_id>', methods=['POST'])
def add_review(book_id):
review = request.form['review']
try:
requests.post(f"http://review-service:5002/reviews/{book_id}", json={"review": review})
except Exception as e:
print("Error posting review:", e)
return redirect('/')
if __name__ == '__main__':
app.run(host="0.0.0.0", port=5000)
- 헤더 추가 수정 코드
v1
from flask import Flask, request, render_template_string, redirect
import requests
import os
app = Flask(__name__)
TEMPLATE = """
<h1>Book List</h1>
<ul>
{% for book in books %}
<li>
<strong>{{book['title']}}</strong><br/>
<form method="post" action="/review/{{book['id']}}">
<input name="review" placeholder="Write a review"/>
<button type="submit">Submit</button>
</form>
<ul>
{% for r in reviews.get(book['id'], []) %}
<li>{{r}}</li>
{% endfor %}
</ul>
</li>
{% endfor %}
</ul>
"""
def get_forwarded_headers():
headers = {}
# B3 Propagation 헤더 추출 (가장 일반적인 방식)
b3_traceid = request.headers.get('X-B3-TraceId')
if b3_traceid:
headers['X-B3-TraceId'] = b3_traceid
b3_spanid = request.headers.get('X-B3-SpanId')
if b3_spanid:
headers['X-B3-SpanId'] = b3_spanid
b3_parentspanid = request.headers.get('X-B3-ParentSpanId')
if b3_parentspanid:
headers['X-B3-ParentSpanId'] = b3_parentspanid
b3_sampled = request.headers.get('X-B3-Sampled')
if b3_sampled:
headers['X-B3-Sampled'] = b3_sampled
b3_flags = request.headers.get('X-B3-Flags')
if b3_flags:
headers['X-B3-Flags'] = b3_flags
# W3C Trace Context 헤더 추출 (선택 사항 - Istio 설정에 따라)
traceparent = request.headers.get('traceparent')
if traceparent:
headers['traceparent'] = traceparent
tracestate = request.headers.get('tracestate')
if tracestate:
headers['tracestate'] = tracestate
return headers
@app.route('/')
def index():
headers_to_forward = get_forwarded_headers()
try:
books_response = requests.get("<http://book-service:5001/books>", headers=headers_to_forward)
books = books_response.json()
except Exception as e:
print("Error fetching books:", e)
books = []
reviews = {}
for book in books:
try:
reviews_response = requests.get(f"<http://review-service:5002/reviews/{book['id']}>", headers=headers_to_forward).json()
except Exception as e:
print("Error fetching reviews for book", book['id'], ":", e)
reviews[book["id"]] = []
reviews[book["id"]] = reviews_response
return render_template_string(TEMPLATE, books=books, reviews=reviews)
@app.route('/review/<int:book_id>', methods=['POST'])
def add_review(book_id):
review = request.form['review']
headers_to_forward = get_forwarded_headers()
try:
requests.post(f"<http://review-service:5002/reviews/{book_id}>", json={"review": review}, headers=headers_to_forward)
except Exception as e:
print("Error posting review:", e)
return redirect('/')
if __name__ == '__main__':
app.run(host="0.0.0.0", port=5000)
v2
from flask import Flask, request, render_template_string, redirect
import requests
app = Flask(__name__)
TEMPLATE = """
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Book Review</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
</head>
<body class="bg-light">
<div class="container py-5">
<h1 class="mb-4">Book Review</h1>
{% for book in books %}
<div class="card mb-4 shadow-sm">
<div class="card-body">
<h5 class="card-title">{{ book['title'] }}</h5>
<form method="post" action="/review/{{ book['id'] }}" class="d-flex gap-2 mb-3">
<input name="review" class="form-control" placeholder="Write your review here" required>
<button type="submit" class="btn btn-primary">Submit</button>
</form>
{% if reviews.get(book['id']) %}
<ul class="list-group list-group-flush">
{% for r in reviews[book['id']] %}
<li class="list-group-item">{{ r }}</li>
{% endfor %}
</ul>
{% else %}
<p class="text-muted">No reviews yet.</p>
{% endif %}
</div>
</div>
{% endfor %}
</div>
</body>
</html>
"""
# ★ 여기 추가: 헤더 포워딩 함수
def get_forwarded_headers():
headers = {}
# B3 Propagation 헤더
for key in ['X-B3-TraceId', 'X-B3-SpanId', 'X-B3-ParentSpanId', 'X-B3-Sampled', 'X-B3-Flags']:
if request.headers.get(key):
headers[key] = request.headers[key]
# W3C Trace Context 헤더
for key in ['traceparent', 'tracestate']:
if request.headers.get(key):
headers[key] = request.headers[key]
return headers
@app.route('/')
def index():
headers_to_forward = get_forwarded_headers()
try:
books = requests.get("http://book-service:5001/books", headers=headers_to_forward).json()
except Exception as e:
print("Error fetching books:", e)
books = []
reviews = {}
for book in books:
try:
r = requests.get(f"http://review-service:5002/reviews/{book['id']}", headers=headers_to_forward).json()
except Exception as e:
print("Error fetching reviews for book", book['id'], ":", e)
r = []
reviews[book["id"]] = r
return render_template_string(TEMPLATE, books=books, reviews=reviews)
@app.route('/review/<int:book_id>', methods=['POST'])
def add_review(book_id):
review = request.form['review']
headers_to_forward = get_forwarded_headers()
try:
requests.post(f"http://review-service:5002/reviews/{book_id}", json={"review": review}, headers=headers_to_forward)
except Exception as e:
print("Error posting review:", e)
return redirect('/')
if __name__ == '__main__':
app.run(host="0.0.0.0", port=5000)
Dockerfile
FROM python:3.10-slim
WORKDIR /app
COPY app.py .
RUN pip install flask requests
EXPOSE 5000
CMD ["python", "app.py"]
📌review-service
app.py
from flask import Flask, request, jsonify
app = Flask(__name__)
reviews = {
1: ["Great book!"],
2: ["Very useful."]
}
@app.route('/reviews/<int:book_id>', methods=['GET'])
def get_reviews(book_id):
return jsonify(reviews.get(book_id, []))
@app.route('/reviews/<int:book_id>', methods=['POST'])
def add_review(book_id):
try:
content = request.json.get("review", "")
if content:
reviews.setdefault(book_id, []).append(content)
return jsonify({"status": "ok"}), 201
else:
return jsonify({"error": "Empty review"}), 400
except Exception as e:
return jsonify({"error": str(e)}), 500
if __name__ == '__main__':
app.run(host='0.0.0.0', port=5002)
Dockerfile
FROM python:3.10-slim
WORKDIR /app
COPY app.py .
RUN pip install flask
EXPOSE 5002
CMD ["python", "app.py"]