diff --git a/README.md b/README.md index 0ba41f6..971a38b 100644 --- a/README.md +++ b/README.md @@ -19,8 +19,9 @@ sudo -i # 切換 root cd /root/k8s # K3s 工作目錄 ``` -- **主機**: 192.168.42.120 +- **主機**: 192.168.42.120 (vm120 master + vm121/vm122 workers) - **K3s 目錄**: `/root/k8s` +- **舊 manifests**: `/root/k8s-manifests` (備份保留) - **本地目錄**: `/Users/timmy/42_120/k8s` - **Git Repo**: http://192.168.42.124:31337/timmy/k3s.git @@ -32,6 +33,8 @@ cd /root/k8s # K3s 工作目錄 |------|------|----------| | [CodiMD](apps/codimd/) | Markdown 協作筆記 | `./apps/codimd/status.sh` | | [Opengist](apps/opengist/) | Git Snippets 管理 | `./apps/opengist/status.sh` | +| [Vaultwarden](apps/vaultwarden/) | 密碼管理器 | `./apps/vaultwarden/status.sh` | +| [Adminer](apps/adminer/) | 資料庫管理工具 | `./apps/adminer/status.sh` | | [PostgreSQL](apps/postgres/) | 通用資料庫 | `./apps/postgres/status.sh` | --- @@ -41,10 +44,13 @@ cd /root/k8s # K3s 工作目錄 ``` k8s/ ├── apps/ -│ ├── codimd/ # 筆記應用 -│ ├── opengist/ # Git Snippets -│ └── postgres/ # 資料庫 -└── cluster/ # 叢集工具 +│ ├── adminer/ # 資料庫管理工具 +│ ├── codimd/ # 筆記應用 +│ ├── opengist/ # Git Snippets +│ ├── postgres/ # 資料庫 +│ ├── template/ # 新 App 範本 +│ └── vaultwarden/ # 密碼管理器 +└── cluster/ # 叢集工具 ``` 每個 app 都包含: @@ -53,7 +59,7 @@ k8s/ - `deploy.sh` - 部署腳本 - `stop.sh` - 停止腳本(保留資料) - `status.sh` - 狀態檢查 -- `backup.sh` - 備份腳本 +- `backup.sh` - 備份腳本(如有) --- @@ -79,7 +85,7 @@ kubectl get ingress -A 1. **本地修改** → 在此目錄編輯 manifests 或腳本 2. **Git 提交** → `git add -A && git commit -m "描述" && git push` -3. **同步遠端** → `rsync -avz --rsync-path="sudo rsync" . ubuntu@192.168.42.120:/root/k8s/` +3. **遠端更新** → `git -C /root/k8s pull` 4. **套用變更** → `kubectl apply -f manifests/` --- @@ -89,16 +95,15 @@ kubectl get ingress -A ``` ┌─────────────────────────────────────┐ │ Traefik Ingress │ -│ (note.xxx.com / git.xxx.com) │ +│ (codimd / opengist / vw / adminer) │ └─────────────────┬───────────────────┘ │ - ┌─────────────┼─────────────┐ - │ │ │ -┌───▼───┐ ┌───▼───┐ ┌───▼───┐ -│ CodiMD│ │Opengist│ │PostgreSQL -│ + │ │ │ │ (獨立) -│ PG │ │ │ │ -└───────┘ └────────┘ └───────┘ + ┌─────────────┼─────────────┬─────────┐ + │ │ │ │ +┌───▼───┐ ┌───▼───┐ ┌───▼───┐ ┌──▼────┐ +│CodiMD │ │Opengist│ │Vault │ │Adminer│ +│ +PG │ │ │ │warden │ │ │ +└───────┘ └────────┘ └───────┘ └───────┘ │ │ │ └───▼─────────────▼─────────────▼───┘ Longhorn Storage diff --git a/SUMMARY.md b/SUMMARY.md index b787577..b544177 100644 --- a/SUMMARY.md +++ b/SUMMARY.md @@ -9,9 +9,12 @@ | 主機 | 192.168.42.120 | | 連線 | `ssh ubuntu@192.168.42.120` → `sudo -i` | | K8s 目錄 | `/root/k8s` | +| 舊 manifests | `/root/k8s-manifests` (備份) | | 本地目錄 | `/Users/timmy/42_120/k8s` | | Git Repo | http://192.168.42.124:31337/timmy/k3s.git | +**節點**: vm120 (master) + vm121 + vm122 (3 節點 HA) + --- ## 🚀 已部署服務 @@ -21,15 +24,10 @@ | 項目 | 值 | |------|-----| | 用途 | Markdown 協作筆記、團隊知識庫 | -| Ingress | `note.yourdomain.com` | +| Ingress | `codimd.lotimmy.com` | | 命名空間 | `default` | | 資料庫 | PostgreSQL (內建) | -**組件:** -- `codimd-app` - 應用程式 -- `codimd-db` - PostgreSQL 資料庫 -- Longhorn PVC - 資料持久化 - **腳本:** `apps/codimd/{deploy,stop,status,backup,restore}.sh` --- @@ -39,18 +37,37 @@ | 項目 | 值 | |------|-----| | 用途 | 自架 Git snippets、程式碼片段分享 | -| SSH Port | `2222` (Traefik TCP) | -| Web Port | `80`/`443` (Ingress) | +| Ingress | `opengist.lotimmy.com` | | 命名空間 | `default` | -**組件:** -- `opengist` - 應用程式 -- Longhorn PVC - 資料持久化 - **腳本:** `apps/opengist/{deploy,stop,status,backup,restore}.sh` --- +### Vaultwarden - 密碼管理器 + +| 項目 | 值 | +|------|-----| +| 用途 | 自架 Bitwarden 密碼管理 | +| Ingress | `vaultwarden.lotimmy.com` | +| 儲存 | 5Gi Longhorn PVC | + +**腳本:** `apps/vaultwarden/{deploy,stop,status,backup,restore}.sh` + +--- + +### Adminer - 資料庫管理 + +| 項目 | 值 | +|------|-----| +| 用途 | Web 資料庫管理工具 | +| Ingress | `adminer.lotimmy.com` | +| 連接目標 | 叢集內 PostgreSQL | + +**腳本:** `apps/adminer/{deploy,stop,status}.sh` + +--- + ### PostgreSQL - 獨立資料庫 | 項目 | 值 | @@ -68,23 +85,19 @@ ``` k8s/ ├── apps/ -│ ├── codimd/ # CodiMD 筆記應用 -│ │ ├── manifests/ # K8s YAML 檔案 -│ │ ├── backup/ # 備份檔案 -│ │ ├── tmpdir/ # 暫存/舊檔案 -│ │ └── *.sh # 管理腳本 -│ ├── opengist/ # Opengist Git Snippets -│ │ ├── manifests/ -│ │ ├── backup/ -│ │ └── *.sh -│ └── postgres/ # 獨立 PostgreSQL -│ ├── manifests/ -│ ├── backups/ # SQL 備份 -│ └── *.sh -└── cluster/ # 叢集檢查工具 - ├── check_access.sh # 檢查存取權限 - ├── check_nodes.sh # 檢查節點狀態 - └── check_storage.sh # 檢查儲存空間 +│ ├── adminer/ # 資料庫管理工具 +│ ├── codimd/ # CodiMD 筆記應用 +│ ├── opengist/ # Opengist Git Snippets +│ ├── postgres/ # 獨立 PostgreSQL +│ ├── template/ # 新 App 範本 +│ └── vaultwarden/ # 密碼管理器 +├── cluster/ # 叢集檢查工具 +│ ├── check_access.sh +│ ├── check_nodes.sh +│ └── check_storage.sh +├── README.md +├── QUICKSTART.md +└── SUMMARY.md ``` --- @@ -120,10 +133,11 @@ kubectl logs -f ## 🔄 維護工作流程 1. **本地修改** → 編輯 manifests 或腳本 -2. **同步遠端** → `rsync` 或 `git push` -3. **部署** → 執行 `deploy.sh` -4. **驗證** → 執行 `status.sh` -5. **備份** → 執行 `backup.sh` +2. **Git 提交** → `git add -A && git commit && git push` +3. **遠端更新** → `git -C /root/k8s pull` +4. **部署** → 執行 `deploy.sh` +5. **驗證** → 執行 `status.sh` +6. **備份** → 執行 `backup.sh` --- diff --git a/apps/adminer/deploy.sh b/apps/adminer/deploy.sh new file mode 100755 index 0000000..e8baa36 --- /dev/null +++ b/apps/adminer/deploy.sh @@ -0,0 +1,14 @@ +#!/usr/bin/env bash +set -euo pipefail + +BASE_DIR="$(cd "$(dirname "$0")" && pwd)" +MANIFESTS="$BASE_DIR/manifests" + +echo "🚀 部署 Adminer..." + +kubectl apply -f "$MANIFESTS/" + +echo "⏳ 等待 Pod 就緒..." +kubectl rollout status deployment/adminer --timeout=120s + +echo "✅ Adminer 部署完成" diff --git a/apps/adminer/manifests/adminer-deployment.yaml b/apps/adminer/manifests/adminer-deployment.yaml new file mode 100644 index 0000000..35608f5 --- /dev/null +++ b/apps/adminer/manifests/adminer-deployment.yaml @@ -0,0 +1,28 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: adminer + labels: + app: adminer +spec: + replicas: 1 + selector: + matchLabels: + app: adminer + template: + metadata: + labels: + app: adminer + spec: + containers: + - name: adminer + image: adminer:latest + ports: + - containerPort: 8080 + resources: + requests: + cpu: "10m" + memory: "32Mi" + limits: + cpu: "200m" + memory: "256Mi" diff --git a/apps/adminer/manifests/adminer-ingress.yaml b/apps/adminer/manifests/adminer-ingress.yaml new file mode 100644 index 0000000..1e1f9a6 --- /dev/null +++ b/apps/adminer/manifests/adminer-ingress.yaml @@ -0,0 +1,35 @@ +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: adminer-ingress + labels: + app: adminer + annotations: + traefik.ingress.kubernetes.io/router.entrypoints: web,websecure +spec: + ingressClassName: traefik + tls: + - hosts: + - adminer.192.168.42.120.nip.io + secretName: nip-io-cert + rules: + - host: adminer.lotimmy.com + http: + paths: + - path: / + pathType: Prefix + backend: + service: + name: adminer-service + port: + number: 80 + - host: adminer.192.168.42.120.nip.io + http: + paths: + - path: / + pathType: Prefix + backend: + service: + name: adminer-service + port: + number: 80 diff --git a/apps/adminer/manifests/adminer-service.yaml b/apps/adminer/manifests/adminer-service.yaml new file mode 100644 index 0000000..949d38f --- /dev/null +++ b/apps/adminer/manifests/adminer-service.yaml @@ -0,0 +1,15 @@ +apiVersion: v1 +kind: Service +metadata: + name: adminer-service + labels: + app: adminer +spec: + selector: + app: adminer + type: ClusterIP + ports: + - protocol: TCP + name: http + port: 80 + targetPort: 8080 diff --git a/apps/adminer/status.sh b/apps/adminer/status.sh new file mode 100755 index 0000000..1b026c4 --- /dev/null +++ b/apps/adminer/status.sh @@ -0,0 +1,20 @@ +#!/usr/bin/env bash +set -euo pipefail + +APP_NAME="adminer" + +echo "=== [ $APP_NAME 資源狀態 ] ===" +echo "" + +echo "--- Pods ---" +kubectl get pods -l "app=$APP_NAME" -o wide + +echo "" + +echo "--- Services ---" +kubectl get svc -l "app=$APP_NAME" + +echo "" + +echo "--- Access (Ingress) ---" +kubectl get ingress -l "app=$APP_NAME" -o custom-columns=NAME:.metadata.name,HOSTS:.spec.rules[*].host diff --git a/apps/adminer/stop.sh b/apps/adminer/stop.sh new file mode 100755 index 0000000..98acf54 --- /dev/null +++ b/apps/adminer/stop.sh @@ -0,0 +1,10 @@ +#!/usr/bin/env bash +set -euo pipefail + +echo "🛑 停止 Adminer..." + +kubectl delete deployment/adminer --ignore-not-found +kubectl delete service/adminer-service --ignore-not-found +kubectl delete ingress/adminer-ingress --ignore-not-found + +echo "✅ Adminer 已停止" diff --git a/apps/vaultwarden/backup.sh b/apps/vaultwarden/backup.sh new file mode 100755 index 0000000..2955599 --- /dev/null +++ b/apps/vaultwarden/backup.sh @@ -0,0 +1,25 @@ +#!/usr/bin/env bash +set -euo pipefail + +APP_NAME="vaultwarden" +BASE_DIR="$(cd "$(dirname "$0")" && pwd)" +BACKUP_DIR="$BASE_DIR/backup" +TIMESTAMP=$(date +%Y%m%d-%H%M) + +echo "📦 備份 $APP_NAME..." + +mkdir -p "$BACKUP_DIR" + +POD=$(kubectl get pod -l "app=$APP_NAME" -o jsonpath="{.items[0].metadata.name}") + +if [ -z "$POD" ]; then + echo "❌ 找不到 $APP_NAME 的 Pod" + exit 1 +fi + +echo "備份資料..." +kubectl exec $POD -- tar czf /tmp/backup.tar.gz /data +kubectl cp $POD:/tmp/backup.tar.gz "$BACKUP_DIR/$APP_NAME-$TIMESTAMP.tar.gz" +kubectl exec $POD -- rm /tmp/backup.tar.gz + +echo "✅ 備份完成: $BACKUP_DIR/$APP_NAME-$TIMESTAMP.tar.gz" diff --git a/apps/vaultwarden/deploy.sh b/apps/vaultwarden/deploy.sh new file mode 100755 index 0000000..b6ba9ad --- /dev/null +++ b/apps/vaultwarden/deploy.sh @@ -0,0 +1,14 @@ +#!/usr/bin/env bash +set -euo pipefail + +BASE_DIR="$(cd "$(dirname "$0")" && pwd)" +MANIFESTS="$BASE_DIR/manifests" + +echo "🚀 部署 Vaultwarden..." + +kubectl apply -f "$MANIFESTS/" + +echo "⏳ 等待 Pod 就緒..." +kubectl rollout status deployment/vaultwarden --timeout=120s + +echo "✅ Vaultwarden 部署完成" diff --git a/apps/vaultwarden/manifests/vaultwarden-deployment.yaml b/apps/vaultwarden/manifests/vaultwarden-deployment.yaml new file mode 100644 index 0000000..c41a999 --- /dev/null +++ b/apps/vaultwarden/manifests/vaultwarden-deployment.yaml @@ -0,0 +1,39 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: vaultwarden + labels: + app: vaultwarden +spec: + replicas: 1 + selector: + matchLabels: + app: vaultwarden + template: + metadata: + labels: + app: vaultwarden + spec: + containers: + - name: vaultwarden + image: vaultwarden/server:latest + resources: + limits: + memory: "512Mi" + cpu: "500m" + ports: + - containerPort: 80 + env: + - name: WEBSOCKET_ENABLED + value: "true" + - name: DOMAIN + value: "https://vaultwarden.lotimmy.com" + - name: ADMIN_TOKEN + value: "$$argon2id$$v=19$$m=65540,t=3,p=4$$EVIbGzNlkQUK5b0r7aMgKoUWV98aqrpPevU+8Bbv0EE$$JB51q0ih0LGmw6rp7ZVBgT+PNnCepy+bNYyaChD+VMc" + volumeMounts: + - mountPath: "/data" + name: data-vol + volumes: + - name: data-vol + persistentVolumeClaim: + claimName: vaultwarden-pvc diff --git a/apps/vaultwarden/manifests/vaultwarden-ingress.yaml b/apps/vaultwarden/manifests/vaultwarden-ingress.yaml new file mode 100644 index 0000000..548c25c --- /dev/null +++ b/apps/vaultwarden/manifests/vaultwarden-ingress.yaml @@ -0,0 +1,35 @@ +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: vaultwarden-ingress + labels: + app: vaultwarden + annotations: + traefik.ingress.kubernetes.io/router.entrypoints: web,websecure +spec: + ingressClassName: traefik + tls: + - hosts: + - vaultwarden.192.168.42.120.nip.io + secretName: nip-io-cert + rules: + - host: vaultwarden.lotimmy.com + http: + paths: + - path: / + pathType: Prefix + backend: + service: + name: vaultwarden-service + port: + number: 80 + - host: vaultwarden.192.168.42.120.nip.io + http: + paths: + - path: / + pathType: Prefix + backend: + service: + name: vaultwarden-service + port: + number: 80 diff --git a/apps/vaultwarden/manifests/vaultwarden-pvc.yaml b/apps/vaultwarden/manifests/vaultwarden-pvc.yaml new file mode 100644 index 0000000..4cfe6c3 --- /dev/null +++ b/apps/vaultwarden/manifests/vaultwarden-pvc.yaml @@ -0,0 +1,13 @@ +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: vaultwarden-pvc + labels: + app: vaultwarden +spec: + storageClassName: longhorn + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 5Gi diff --git a/apps/vaultwarden/manifests/vaultwarden-service.yaml b/apps/vaultwarden/manifests/vaultwarden-service.yaml new file mode 100644 index 0000000..f8f8cb5 --- /dev/null +++ b/apps/vaultwarden/manifests/vaultwarden-service.yaml @@ -0,0 +1,15 @@ +apiVersion: v1 +kind: Service +metadata: + name: vaultwarden-service + labels: + app: vaultwarden +spec: + selector: + app: vaultwarden + ports: + - protocol: TCP + name: http + port: 80 + targetPort: 80 + type: ClusterIP diff --git a/apps/vaultwarden/restore.sh b/apps/vaultwarden/restore.sh new file mode 100755 index 0000000..4f78eaa --- /dev/null +++ b/apps/vaultwarden/restore.sh @@ -0,0 +1,32 @@ +#!/usr/bin/env bash +set -euo pipefail + +APP_NAME="vaultwarden" +BASE_DIR="$(cd "$(dirname "$0")" && pwd)" +BACKUP_DIR="$BASE_DIR/backup" + +if [ $# -eq 0 ]; then + echo "用法: $0 " + echo "" + echo "可用備份:" + ls -lh "$BACKUP_DIR/"*.tar.gz 2>/dev/null || echo "無備份檔案" + exit 1 +fi + +BACKUP_FILE="$1" + +if [ ! -f "$BACKUP_FILE" ]; then + echo "❌ 備份檔案不存在: $BACKUP_FILE" + exit 1 +fi + +POD=$(kubectl get pod -l "app=$APP_NAME" -o jsonpath="{.items[0].metadata.name}") + +echo "📥 還原 $APP_NAME 從 $BACKUP_FILE..." + +kubectl cp "$BACKUP_FILE" $POD:/tmp/restore.tar.gz +kubectl exec $POD -- tar xzf /tmp/restore.tar.gz -C / +kubectl exec $POD -- rm /tmp/restore.tar.gz + +echo "✅ 還原完成,請重啟 Pod" +kubectl rollout restart deployment/$APP_NAME diff --git a/apps/vaultwarden/status.sh b/apps/vaultwarden/status.sh new file mode 100755 index 0000000..9b57493 --- /dev/null +++ b/apps/vaultwarden/status.sh @@ -0,0 +1,25 @@ +#!/usr/bin/env bash +set -euo pipefail + +APP_NAME="vaultwarden" + +echo "=== [ $APP_NAME 資源狀態 ] ===" +echo "" + +echo "--- Pods ---" +kubectl get pods -l "app=$APP_NAME" -o wide + +echo "" + +echo "--- Services ---" +kubectl get svc -l "app=$APP_NAME" + +echo "" + +echo "--- Storage (PVC) ---" +kubectl get pvc -l "app=$APP_NAME" + +echo "" + +echo "--- Access (Ingress) ---" +kubectl get ingress -l "app=$APP_NAME" -o custom_columns=NAME:.metadata.name,HOSTS:.spec.rules[*].host diff --git a/apps/vaultwarden/stop.sh b/apps/vaultwarden/stop.sh new file mode 100755 index 0000000..95987b0 --- /dev/null +++ b/apps/vaultwarden/stop.sh @@ -0,0 +1,10 @@ +#!/usr/bin/env bash +set -euo pipefail + +echo "🛑 停止 Vaultwarden(保留資料)..." + +kubectl delete deployment/vaultwarden --ignore-not-found +kubectl delete service/vaultwarden-service --ignore-not-found +kubectl delete ingress/vaultwarden-ingress --ignore-not-found + +echo "✅ Vaultwarden 已停止,PVC 資料保留"