iT邦幫忙

2024 iThome 鐵人賽

DAY 22
0
Kubernetes

K8s 資料庫管理系統系列 第 22 篇

day 22 k8s 選課資料庫管理系統

  • 分享至 

  • xImage
  •  

今天是第二十二天我們可以寫一個k8s選課資料庫管理系統,以下是我的程式碼

設計概述

  1. 資料庫: 使用 MySQL 資料庫儲存課程資訊、學生選課等資料。
  2. 後端 API: 使用 Python Flask 框架處理與資料庫的互動。
  3. 前端: 使用簡單的 HTML/JavaScript 作為用戶介面,讓學生可以選課與查看已選課程。
  4. Kubernetes 部署: 使用 Kubernetes YAML 文件來描述資料庫、後端 API 和前端的部署與服務。

系統架構

  • MySQL 資料庫
    • Kubernetes 部署一個 MySQL Pod 並建立 Persistent Volume。
  • Flask 後端 API
    • Kubernetes 部署 Flask 應用,處理 CRUD 操作。
  • 前端服務
    • 部署前端應用(HTML + JavaScript),與 Flask API 互動。

1. MySQL 資料庫部署

創建一個 mysql-deployment.yaml 檔案來部署 MySQL。

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: mysql-pv-claim
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 10Gi
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: mysql
spec:
  selector:
    matchLabels:
      app: mysql
  template:
    metadata:
      labels:
        app: mysql
    spec:
      containers:
      - name: mysql
        image: mysql:5.7
        env:
        - name: MYSQL_ROOT_PASSWORD
          value: "password"
        - name: MYSQL_DATABASE
          value: "course_db"
        - name: MYSQL_USER
          value: "admin"
        - name: MYSQL_PASSWORD
          value: "password"
        ports:
        - containerPort: 3306
        volumeMounts:
        - name: mysql-persistent-storage
          mountPath: /var/lib/mysql
      volumes:
      - name: mysql-persistent-storage
        persistentVolumeClaim:
          claimName: mysql-pv-claim
---
apiVersion: v1
kind: Service
metadata:
  name: mysql
spec:
  ports:
    - port: 3306
  selector:
    app: mysql

2. Flask 後端 API 部署

創建一個簡單的 Flask API,與 MySQL 互動。首先,撰寫 app.py:

from flask import Flask, request, jsonify
import mysql.connector

app = Flask(__name__)

def get_db_connection():
    conn = mysql.connector.connect(
        host='mysql',  # Kubernetes 服務名稱
        user='admin',
        password='password',
        database='course_db'
    )
    return conn

@app.route('/courses', methods=['GET'])
def get_courses():
    conn = get_db_connection()
    cursor = conn.cursor()
    cursor.execute('SELECT * FROM courses')
    courses = cursor.fetchall()
    cursor.close()
    conn.close()
    return jsonify(courses)

@app.route('/enroll', methods=['POST'])
def enroll_course():
    student_id = request.json['student_id']
    course_id = request.json['course_id']
    conn = get_db_connection()
    cursor = conn.cursor()
    cursor.execute('INSERT INTO enrollments (student_id, course_id) VALUES (%s, %s)', (student_id, course_id))
    conn.commit()
    cursor.close()
    conn.close()
    return 'Enrolled successfully!', 201

if __name__ == '__main__':
    app.run(host='0.0.0.0', port=5000)

創建 Dockerfile 來打包 Flask API:

FROM python:3.8-slim
WORKDIR /app
COPY requirements.txt requirements.txt
RUN pip install -r requirements.txt
COPY . .
CMD ["python", "app.py"]

requirements.txt:

Flask
mysql-connector-python

接著,創建 flask-deployment.yaml:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: flask-api
spec:
  selector:
    matchLabels:
      app: flask-api
  template:
    metadata:
      labels:
        app: flask-api
    spec:
      containers:
      - name: flask-api
        image: your-dockerhub-username/flask-api:latest
        ports:
        - containerPort: 5000
---
apiVersion: v1
kind: Service
metadata:
  name: flask-api
spec:
  ports:
    - port: 5000
  selector:
    app: flask-api

3. 前端服務

創建一個簡單的 index.html:

<!DOCTYPE html>
<html>
<head>
    <title>選課系統</title>
</head>
<body>
    <h1>選課系統</h1>
    <form id="enrollForm">
        學生 ID: <input type="text" id="student_id"><br><br>
        課程 ID: <input type="text" id="course_id"><br><br>
        <button type="submit">選課</button>
    </form>

    <h2>已選課程</h2>
    <ul id="coursesList"></ul>

    <script>
        document.getElementById('enrollForm').onsubmit = function(event) {
            event.preventDefault();
            const studentId = document.getElementById('student_id').value;
            const courseId = document.getElementById('course_id').value;

            fetch('/enroll', {
                method: 'POST',
                headers: { 'Content-Type': 'application/json' },
                body: JSON.stringify({ student_id: studentId, course_id: courseId })
            })
            .then(response => response.text())
            .then(data => alert(data));
        };

        fetch('/courses')
            .then(response => response.json())
            .then(courses => {
                const coursesList = document.getElementById('coursesList');
                courses.forEach(course => {
                    const li = document.createElement('li');
                    li.textContent = `課程 ID: ${course[0]}, 課程名稱: ${course[1]}`;
                    coursesList.appendChild(li);
                });
            });
    </script>
</body>
</html>

將此前端部署在 Nginx 上,並創建 nginx-deployment.yaml:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: frontend
spec:
  selector:
    matchLabels:
      app: frontend
  template:
    metadata:
      labels:
        app: frontend
    spec:
      containers:
      - name: nginx
        image: nginx:latest
        volumeMounts:
        - name: html
          mountPath: /usr/share/nginx/html
      volumes:
      - name: html
        configMap:
          name: frontend-html
---
apiVersion: v1
kind: ConfigMap
metadata:
  name: frontend-html
data:
  index.html: |
    # (Paste index.html content here)
---
apiVersion: v1
kind: Service
metadata:
  name: frontend
spec:
  ports:
    - port: 80
  selector:
    app: frontend

4. 部署與運行

運行以下指令將部署所有服務:

kubectl apply -f mysql-deployment.yaml
kubectl apply -f flask-deployment.yaml
kubectl apply -f nginx-deployment.yaml

這樣,Kubernetes 就會運行選課系統,前端透過 Nginx 提供服務,後端 Flask API 處理選課請求,並與 MySQL 進行互動。

1. MySQL 資料庫部署

在 mysql-deployment.yaml 中,定義了 MySQL 資料庫的 Kubernetes 資源。這裡主要包含以下幾個部分:

PersistentVolumeClaim (PVC)

這段程式碼是用來申請一塊持久性存儲空間,用於 MySQL 存儲資料。

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: mysql-pv-claim
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 10Gi
  • PersistentVolumeClaim (PVC):它用來請求一塊 10GB 的持久存儲。這塊存儲將會被用來保存 MySQL 資料庫的數據,即使 Pod 被重啟,數據也不會丟失。
  • accessModes:設置為 ReadWriteOnce,表示這塊存儲可以被一個節點讀寫。

Deployment

MySQL 被打包成一個容器,這裡通過 Deployment 創建和管理 MySQL Pod。

apiVersion: apps/v1
kind: Deployment
metadata:
  name: mysql
spec:
  selector:
    matchLabels:
      app: mysql
  template:
    metadata:
      labels:
        app: mysql
    spec:
      containers:
      - name: mysql
        image: mysql:5.7
        env:
        - name: MYSQL_ROOT_PASSWORD
          value: "password"
        - name: MYSQL_DATABASE
          value: "course_db"
        - name: MYSQL_USER
          value: "admin"
        - name: MYSQL_PASSWORD
          value: "password"
        ports:
        - containerPort: 3306
        volumeMounts:
        - name: mysql-persistent-storage
          mountPath: /var/lib/mysql
      volumes:
      - name: mysql-persistent-storage
        persistentVolumeClaim:
          claimName: mysql-pv-claim
  • Deployment:定義了 MySQL 容器的部署,管理 MySQL 的 Pod。
  • image: mysql:5.7:指定 MySQL 的 Docker 鏡像版本。
  • env:環境變量,用來設定 MySQL 的 root 密碼、資料庫名稱以及用戶憑證。
  • volumeMounts:將 PVC 持久化存儲掛載到容器內 /var/lib/mysql 目錄,這是 MySQL 存放數據的地方。

Service

apiVersion: v1
kind: Service
metadata:
  name: mysql
spec:
  ports:
    - port: 3306
  selector:
    app: mysql
  • Service:定義了如何對外暴露 MySQL 服務,讓其他 Pod(如 Flask API)可以通過 Kubernetes 的內部 DNS 名稱(mysql)來訪問資料庫。
  • port: 3306:指定 MySQL 使用的默認端口。

2. Flask API 後端

Flask API 是一個簡單的應用,它用來與 MySQL 資料庫互動,處理選課相關的操作。

Flask API (app.py)

引入庫與初始化 Flask 應用
from flask import Flask, request, jsonify
import mysql.connector

app = Flask(__name__)
  • Flask:引入 Flask 框架來處理 HTTP 請求。
  • mysql.connector:用來與 MySQL 資料庫連接。
  • app = Flask(__name__):初始化 Flask 應用,並且可以設定各種路由。
資料庫連接函數
def get_db_connection():
    conn = mysql.connector.connect(
        host='mysql',  # Kubernetes 服務名稱
        user='admin',
        password='password',
        database='course_db'
    )
    return conn
  • get_db_connection():用來建立與 MySQL 資料庫的連接。host='mysql' 表示 MySQL 是通過 Kubernetes 的內部 DNS 名稱來訪問。
  • user、password、database:與 MySQL 連接所需的憑證。
課程查詢 API
@app.route('/courses', methods=['GET'])
def get_courses():
    conn = get_db_connection()
    cursor = conn.cursor()
    cursor.execute('SELECT * FROM courses')
    courses = cursor.fetchall()
    cursor.close()
    conn.close()
    return jsonify(courses)
  • @app.route('/courses', methods=['GET']):定義了一個 GET 請求的 API,URL 是 /courses。這個 API 會查詢所有課程。
  • cursor.execute('SELECT * FROM courses'):從 courses 資料表中查詢所有課程。
  • jsonify(courses):將查詢結果轉換成 JSON 格式,回傳給客戶端。
選課 API
@app.route('/enroll', methods=['POST'])
def enroll_course():
    student_id = request.json['student_id']
    course_id = request.json['course_id']
    conn = get_db_connection()
    cursor = conn.cursor()
    cursor.execute('INSERT INTO enrollments (student_id, course_id) VALUES (%s, %s)', (student_id, course_id))
    conn.commit()
    cursor.close()
    conn.close()
    return 'Enrolled successfully!', 201
  • @app.route('/enroll', methods=['POST']):定義了一個 POST 請求的 API,URL 是 /enroll。這個 API 用來讓學生選課。
  • student_id 和 course_id:從請求中提取學生和課程的 ID。
  • INSERT INTO enrollments (student_id, course_id):將選課資訊插入到 enrollments 資料表中。

3. 前端 (index.html)

前端是一個簡單的 HTML 頁面,通過 JavaScript 與 Flask API 互動。

表單提交選課

<form id="enrollForm">
    學生 ID: <input type="text" id="student_id"><br><br>
    課程 ID: <input type="text" id="course_id"><br><br>
    <button type="submit">選課</button>
</form>
  • 表單允許用戶輸入學生 ID 和課程 ID,然後提交選課請求。

JavaScript 處理選課提交

document.getElementById('enrollForm').onsubmit = function(event) {
    event.preventDefault();
    const studentId = document.getElementById('student_id').value;
    const courseId = document.getElementById('course_id').value;

    fetch('/enroll', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ student_id: studentId, course_id: courseId })
    })
    .then(response => response.text())
    .then(data => alert(data));
};
  • onsubmit:攔截表單的提交動作。
  • fetch('/enroll', ...):向 /enroll API 發送 POST 請求,將選課資訊發送到伺服器。
  • JSON.stringify():將 JavaScript 對象轉換為 JSON 格式,發送至後端。

顯示已選課程

fetch('/courses')
    .then(response => response.json())
    .then(courses => {
        const coursesList = document.getElementById('coursesList');
        courses.forEach(course => {
            const li = document.createElement('li');
            li.textContent = `課程 ID: ${course[0]}, 課程名稱: ${course[1]}`;
            coursesList.appendChild(li);
        });
    });
  • fetch('/courses'):向 /courses API 發送 GET 請求,取得所有課程。
  • 將課程以列表形式顯示在網頁上。

4. Nginx 前端服務部署

前端的 HTML 和 JavaScript 被 Nginx 提供服務。

Nginx 部署 (nginx-deployment.yaml)

apiVersion: apps/v1
kind: Deployment
metadata:
  name: frontend
spec:
  selector:
    matchLabels:
      app: frontend
  template:
    metadata:
      labels:
        app: frontend
    spec:
      containers:
      - name: nginx
        image: nginx:latest
        volumeMounts:
        - name: html
          mountPath: /usr/share/nginx/html
      volumes:
      - name: html
        configMap:
          name: frontend-html
---
apiVersion: v1
kind: ConfigMap
metadata:
  name: frontend-html
data:


  index.html: |
    <!-- HTML 文件內容 -->
---
apiVersion: v1
kind: Service
metadata:
  name: frontend
spec:
  ports:
    - port: 80
  selector:
    app: frontend
  • nginx:用來提供靜態 HTML 文件服務。
  • ConfigMap:將 index.html 內容儲存在 ConfigMap 中,並掛載到 Nginx 容器的 /usr/share/nginx/html 目錄下。
  • Service:對外暴露 Nginx 服務,使用默認的 HTTP 端口 80。

總結

這個系統是一個簡單的選課系統,前端通過 Nginx 提供靜態頁面服務,後端 Flask API 用來處理資料庫操作,MySQL 資料庫存放課程和選課信息。每個部分都通過 Kubernetes 來管理和調度,使應用能夠在容器化環境中運行。


上一篇
day 21 K8s 微服務客戶喜好資料庫管理系統
下一篇
day 23 k8s 音樂庫資料庫管理系統
系列文
K8s 資料庫管理系統 共 30 篇
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言