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"]