forked from ab/homelab
Compare commits
303 Commits
xelnagamex
...
auto-updat
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ee3fe94de6 | ||
| 860f83445a | |||
| 8e1e20f478 | |||
| 93afe8b187 | |||
| 54e83b0af9 | |||
| cbed0939fa | |||
| e545346fec | |||
| aae0255843 | |||
| c7fc3504ba | |||
| b2701a8435 | |||
| df39182fea | |||
| c9bee8c049 | |||
| 439ad751e9 | |||
| 4681a3b263 | |||
| 45f208a4ff | |||
| a19648aacc | |||
| 7d7906edc7 | |||
|
|
30a3b1cd60 | ||
|
|
8dfc8e2549 | ||
|
|
8e18775e3e | ||
| 1ee1b9a1c6 | |||
| 407b11f40d | |||
| 82cf742edb | |||
| 360f260cb5 | |||
| 31fe1bf95d | |||
| 7c8a3b2aaa | |||
| 792421ffc5 | |||
| 014db9ad81 | |||
| 602b729d97 | |||
| fa7b81c1b3 | |||
| 7deb5971a5 | |||
| dbfdc0f122 | |||
| 984f7030a3 | |||
| 3e2fe905bd | |||
| 45b49944b3 | |||
| bd8caa57bf | |||
| c93b8f2797 | |||
| 48fee5ceed | |||
| 75a9c140af | |||
| c8930bbebc | |||
| f52b3aab5b | |||
| 6f1b6dee5d | |||
| 5e1aa4cd37 | |||
| fef5303429 | |||
| ba389b8b1e | |||
| 79d106468a | |||
| ca19a1f46a | |||
| 280fbe41bf | |||
| 32c2ba2781 | |||
| 1587abfba8 | |||
| 704f9dc85e | |||
|
|
5ff4b8ecb2 | ||
|
|
1d8c0c1421 | ||
| 661c2c31aa | |||
| 6d76d20d02 | |||
| ab3e687cea | |||
|
|
6ade2bb13a | ||
| d49c382055 | |||
| 1b9775c63d | |||
| f7838be372 | |||
| ce74590719 | |||
|
|
280bdd3091 | ||
|
|
c34f5ed0a0 | ||
|
|
107782318b | ||
|
|
ed2a59948f | ||
| 03f6596262 | |||
| bed8f5b7c3 | |||
| 676a81852a | |||
| 73c09f80f7 | |||
| 104d67bfb3 | |||
|
|
71e5101604 | ||
|
|
5783db189a | ||
| 5659e4455b | |||
|
|
36e8c5c36b | ||
|
|
a6e0165027 | ||
|
|
09526f4e91 | ||
|
|
d1922019ab | ||
|
|
118a1c431a | ||
|
|
b9667ea5e7 | ||
|
|
b1446c53cd | ||
|
|
56fa6a5e05 | ||
|
|
aa19cd8e61 | ||
|
|
00837fb238 | ||
| 479a2a02ea | |||
|
|
95e12df43d | ||
| 5a33337aa1 | |||
| ce9ba3661b | |||
| 8bcba25f7e | |||
| be9f42afa7 | |||
| 656ec121d2 | |||
| 240fc4127f | |||
| 9b19d8ddd8 | |||
| 0b8fe99ee1 | |||
|
|
cff6c28b72 | ||
| 99a63eb840 | |||
| 4f3be5b14a | |||
| 9f5ec499dc | |||
|
|
7b169b8e6d | ||
| a79003740a | |||
|
|
6276d543bc | ||
|
|
18a9bfa22a | ||
|
|
4b6090910c | ||
|
|
cfa796cc94 | ||
|
|
3e4f5500d2 | ||
|
|
9dd761bc8e | ||
|
|
eb3b5183b0 | ||
|
|
c9c75c791b | ||
|
|
8b959fec49 | ||
|
|
1184ff9060 | ||
|
|
18c64ef812 | ||
|
|
993cf1985d | ||
|
|
3daf7cf79a | ||
|
|
caa3354b33 | ||
|
|
68ca195735 | ||
|
|
93d7cb6bf1 | ||
| 600a1dfb6e | |||
|
|
a8c089d9ec | ||
| e516f95f77 | |||
| 84dcdc343a | |||
| 094d80896a | |||
|
|
4ffc42af97 | ||
| b1183896f9 | |||
| 6f17dc23f1 | |||
| e353751031 | |||
| f3baf90672 | |||
|
|
d71935d063 | ||
| 7dde0d3f2a | |||
| 00cbd8830b | |||
| 3760908270 | |||
| 412d32aa68 | |||
| a6dd3638bb | |||
| 8e445f01ae | |||
| 3a8b14d3b4 | |||
| 7dde46f40d | |||
| 60fcf95476 | |||
| 7e95c361a8 | |||
| 0e5cb7686f | |||
| 15e1718861 | |||
| 902d630d09 | |||
| 9b7f953bd3 | |||
| 228a5e3b1c | |||
| 3a0bc6e0d2 | |||
|
|
39ac71e4ef | ||
|
|
fb80dfad0b | ||
|
|
8c3d29c5b6 | ||
| 1b69064a9a | |||
| 21fde3cfb4 | |||
| 201179f57d | |||
| 181b577255 | |||
| 10773abd14 | |||
| 049542f434 | |||
| ef6c7998a4 | |||
| ee703e8399 | |||
| 399833de34 | |||
| 4c571f63e7 | |||
| 56125caedf | |||
| 4aae2a87d6 | |||
| bbc1ba4c2a | |||
| 5924dcfc5f | |||
| 2cb9b5636c | |||
| a2d631d06f | |||
| aa61b78c47 | |||
|
|
27fe1d2f50 | ||
|
|
557d03eb32 | ||
|
|
f06c80162f | ||
| e8588a2d3b | |||
| 621871be93 | |||
| 91dcd9d5bf | |||
| e40357ad78 | |||
| fa544b3b7b | |||
| 8c112a1b0a | |||
| e1ffaa8ba2 | |||
| 1a2b09bcaa | |||
| 21f27adc80 | |||
| 142c828f2b | |||
| 5a01da21af | |||
| 269b2b5221 | |||
| 1417fa830d | |||
| 6b85343c9e | |||
| 0bcd23009c | |||
| 02b20c9fcc | |||
| dbe0fa9acf | |||
| 7d447163cb | |||
| b58a930052 | |||
| bf9b37b55f | |||
|
|
e093dd4f57 | ||
|
|
18a27dadcb | ||
|
|
288a4685d7 | ||
|
|
24d570e522 | ||
|
|
7541cee2eb | ||
|
|
c3fa6eb874 | ||
|
|
414d60edb4 | ||
|
|
364f5b38a9 | ||
|
|
e59215d2e9 | ||
|
|
3c6da4969c | ||
|
|
c08a3e745e | ||
|
|
00177d347f | ||
|
|
ca7fed506b | ||
|
|
2f0ada97cc | ||
|
|
ae516a79eb | ||
|
|
196d53a5a9 | ||
|
|
24d4d34733 | ||
| 74b7611ea0 | |||
| 91739d622e | |||
| 7730458061 | |||
| b482c2e768 | |||
| 7256c98046 | |||
| 56d315eb4a | |||
| 58a2cd4a74 | |||
| 0052a81389 | |||
| 34bd0f1ec4 | |||
| c1cedeaa13 | |||
| a37ccbe5ef | |||
| cc0a6559da | |||
| 88021e4bc0 | |||
| 81fa68af48 | |||
| 2a9c18cae0 | |||
| be5d76c1e8 | |||
| 229190f0e8 | |||
| d7adb966c4 | |||
| f8ef2a48f5 | |||
| a7cfc086d5 | |||
| dfba5434f7 | |||
|
|
4c68ddfc3a | ||
|
|
98a11199d0 | ||
| c9173fbcc3 | |||
| 4f91fdd26a | |||
|
|
b27d5594c5 | ||
| ae02f0fe2a | |||
|
|
b682b7f8ef | ||
| d7a425d005 | |||
| 422269f5e9 | |||
| a99b549e2e | |||
| a3c26117b3 | |||
| 5f8216cc7b | |||
| ceb405b069 | |||
| f53ea1976c | |||
| b9e1b73681 | |||
| 1b04222c3e | |||
| 3ed26f872c | |||
| aa615fe587 | |||
| 1be64f2f63 | |||
| 1212dfcaec | |||
| 28e06770c6 | |||
| 005cb0db72 | |||
| fd80f3ad65 | |||
| 5281d58fae | |||
| 4542d03bc5 | |||
| eb6a2e3e47 | |||
| 311ab269b6 | |||
| 5fa5843fa1 | |||
| 006f607e0d | |||
| 77371cd640 | |||
| e3373dfb5f | |||
| c3eb8ffc5c | |||
| c5eb2a80c2 | |||
| 46527d924a | |||
| 0c5076c649 | |||
| acf1f88412 | |||
| 01a88e21a2 | |||
| fbfbaf0826 | |||
| bf70cae59e | |||
| 95ea0c21fb | |||
| 816fa3662d | |||
| caeb350ece | |||
| ab184e559d | |||
| a6002e7cc3 | |||
| 03f61962f7 | |||
| 2ebc8e718e | |||
| a6cc4b067f | |||
| 37e79a1175 | |||
| 431f0df03d | |||
| bd91762c9d | |||
| e4c86235ae | |||
| 72a1154610 | |||
| 0beb0cd78b | |||
| e342aab9df | |||
| 26f811c3b7 | |||
| d1e834d175 | |||
| 02ec8fd4e1 | |||
| 7565c6c34f | |||
| a45c11f883 | |||
| cfc15d05eb | |||
| 3d1658f41d | |||
| 51a8cc1834 | |||
| 5dcbc9b11f | |||
| aed859b8e9 | |||
| 05f277c8cd | |||
| e25e9a8608 | |||
| 2ef7b23c69 | |||
| 4184534c8c | |||
| 145bdcaca1 | |||
| e0ef44d8bd | |||
| 628c250a0b | |||
| 2e0df4ad1b | |||
| 120d68bd57 | |||
| 6f7fc0b796 | |||
| a4f043c5c6 | |||
| 640447a4e0 | |||
| b55e1b936b | |||
| e939b14796 | |||
| a9d63a7c0c | |||
| 73a14e1397 |
147
.gitea/scripts/README-update-readme.md
Normal file
147
.gitea/scripts/README-update-readme.md
Normal file
@@ -0,0 +1,147 @@
|
|||||||
|
# Auto-Update README Workflow
|
||||||
|
|
||||||
|
## Overview
|
||||||
|
|
||||||
|
This workflow automatically updates the `README.md` file with the current list of ArgoCD applications based on the directory structure in `k8s/`.
|
||||||
|
|
||||||
|
## How it works
|
||||||
|
|
||||||
|
1. **Trigger**: Workflow runs automatically when changes are pushed to `k8s/**` paths
|
||||||
|
2. **Scan**: Python script scans `k8s/` directory structure and finds all applications
|
||||||
|
3. **Generate**: Creates README.md with badges for all found applications
|
||||||
|
4. **Create PR**: If changes detected, creates a Merge Request for manual review
|
||||||
|
|
||||||
|
## Files
|
||||||
|
|
||||||
|
- `.gitea/workflows/update-readme.yaml` - GitHub Actions workflow
|
||||||
|
- `.gitea/scripts/generate-readme.py` - Python script for README generation
|
||||||
|
|
||||||
|
## Directory Structure
|
||||||
|
|
||||||
|
The script expects the following k8s directory structure:
|
||||||
|
|
||||||
|
```
|
||||||
|
k8s/
|
||||||
|
├── core/ # Core infrastructure applications
|
||||||
|
│ ├── argocd/
|
||||||
|
│ ├── authentik/
|
||||||
|
│ └── ...
|
||||||
|
├── apps/ # User applications
|
||||||
|
│ ├── gitea/
|
||||||
|
│ ├── immich/
|
||||||
|
│ └── ...
|
||||||
|
└── games/ # Game servers
|
||||||
|
├── minecraft/
|
||||||
|
└── ...
|
||||||
|
```
|
||||||
|
|
||||||
|
Each subdirectory name becomes an application name in the README.
|
||||||
|
|
||||||
|
## Required Secrets
|
||||||
|
|
||||||
|
The workflow requires the following secrets to be configured in Gitea:
|
||||||
|
|
||||||
|
| Secret | Description | Example |
|
||||||
|
|--------|-------------|---------|
|
||||||
|
| `GT_URL` | Gitea instance URL | `https://gt.hexor.cy` |
|
||||||
|
| `GT_TOKEN` | Gitea API token with repo write access | `glpat-xxxxx...` |
|
||||||
|
| `GT_OWNER` | Repository owner (username or org) | `ab` |
|
||||||
|
| `GT_REPO` | Repository name | `homelab` |
|
||||||
|
|
||||||
|
### How to create a Gitea Token
|
||||||
|
|
||||||
|
1. Go to Settings → Applications → Generate New Token
|
||||||
|
2. Give it a name like "README Update Bot"
|
||||||
|
3. Select scopes: `repo` (Full control of repositories)
|
||||||
|
4. Generate and copy the token
|
||||||
|
5. Add it as a secret in repository settings
|
||||||
|
|
||||||
|
## Badge Format
|
||||||
|
|
||||||
|
Badges are generated using a predictable pattern:
|
||||||
|
|
||||||
|
```markdown
|
||||||
|
[](https://ag.hexor.cy/applications/argocd/app-name)
|
||||||
|
```
|
||||||
|
|
||||||
|
This allows you to immediately see which applications are:
|
||||||
|
- ✅ Healthy and synced (green badge)
|
||||||
|
- ⚠️ Degraded or out of sync (yellow badge)
|
||||||
|
- ❌ Unhealthy or failed (red badge)
|
||||||
|
|
||||||
|
## Manual Trigger
|
||||||
|
|
||||||
|
You can manually trigger the workflow from Gitea:
|
||||||
|
|
||||||
|
1. Go to Actions tab
|
||||||
|
2. Select "Auto-update README" workflow
|
||||||
|
3. Click "Run workflow"
|
||||||
|
4. Select branch and run
|
||||||
|
|
||||||
|
## Example Output
|
||||||
|
|
||||||
|
The generated README will look like:
|
||||||
|
|
||||||
|
```markdown
|
||||||
|
# homelab
|
||||||
|
|
||||||
|
ArgoCD homelab project
|
||||||
|
|
||||||
|
## ArgoCD Applications Status
|
||||||
|
|
||||||
|
| Application | Status |
|
||||||
|
| :--- | :---: |
|
||||||
|
| **argocd** | [](https://ag.hexor.cy/applications/argocd/argocd) |
|
||||||
|
...
|
||||||
|
```
|
||||||
|
|
||||||
|
## Reviewing Pull Requests
|
||||||
|
|
||||||
|
When the workflow creates a PR:
|
||||||
|
|
||||||
|
1. Check the Actions tab for the workflow run details
|
||||||
|
2. Review the PR in the Pull Requests tab
|
||||||
|
3. Verify the application list matches your k8s/ structure
|
||||||
|
4. Merge when ready
|
||||||
|
|
||||||
|
The PR will include:
|
||||||
|
- Updated application list
|
||||||
|
- Timestamp of generation
|
||||||
|
- Automatic commit message
|
||||||
|
|
||||||
|
## Troubleshooting
|
||||||
|
|
||||||
|
### No PR created
|
||||||
|
|
||||||
|
- Check if there are actually changes in README.md
|
||||||
|
- Verify secrets are configured correctly
|
||||||
|
- Check workflow logs in Actions tab
|
||||||
|
|
||||||
|
### Wrong applications listed
|
||||||
|
|
||||||
|
- Verify k8s/ directory structure
|
||||||
|
- Ensure folder names match expected application names
|
||||||
|
- Check for hidden directories (starting with `.`)
|
||||||
|
|
||||||
|
### Badge not loading
|
||||||
|
|
||||||
|
- Verify ArgoCD badge API is accessible at `https://ag.hexor.cy`
|
||||||
|
- Check application name matches ArgoCD application name
|
||||||
|
- Ensure application exists in ArgoCD
|
||||||
|
|
||||||
|
## Maintenance
|
||||||
|
|
||||||
|
### Update badge URL
|
||||||
|
|
||||||
|
If you need to change the badge URL pattern, edit:
|
||||||
|
- `.gitea/scripts/generate-readme.py` - function `generate_badge_line()`
|
||||||
|
|
||||||
|
### Change workflow trigger
|
||||||
|
|
||||||
|
To modify when the workflow runs, edit:
|
||||||
|
- `.gitea/workflows/update-readme.yaml` - `on:` section
|
||||||
|
|
||||||
|
### Add new categories
|
||||||
|
|
||||||
|
To add new categories (besides core/apps/games), edit:
|
||||||
|
- `.gitea/scripts/generate-readme.py` - function `scan_k8s_directory()` and `generate_readme_content()`
|
||||||
91
.gitea/scripts/README.md
Normal file
91
.gitea/scripts/README.md
Normal file
@@ -0,0 +1,91 @@
|
|||||||
|
# Wiki Generators for Homelab
|
||||||
|
|
||||||
|
Automated Wiki page generation scripts for documenting homelab infrastructure.
|
||||||
|
|
||||||
|
## 1. Authentik Applications Wiki Generator
|
||||||
|
|
||||||
|
Generates a Wiki page with all applications managed by Authentik from Terraform configuration.
|
||||||
|
|
||||||
|
### Files:
|
||||||
|
- `generate-apps-wiki.py` - Generates Applications.md from Terraform output
|
||||||
|
- `process-terraform-output.py` - Processes Terraform JSON output
|
||||||
|
|
||||||
|
### Workflow:
|
||||||
|
- **Trigger**: Push to `main` branch with Terraform changes
|
||||||
|
- **Workflow**: `.gitea/workflows/authentik-apps.yaml`
|
||||||
|
- **Output**: Applications Wiki page
|
||||||
|
|
||||||
|
## 2. Kubernetes Services Wiki Generator
|
||||||
|
|
||||||
|
Analyzes k8s/ directory and generates comprehensive documentation for all Kubernetes services.
|
||||||
|
|
||||||
|
### Files:
|
||||||
|
- `generate-k8s-wiki.py` - Main script for analyzing k8s services
|
||||||
|
|
||||||
|
### Features:
|
||||||
|
- **Service Types**: Detects Helm Charts, Kustomize, and YAML manifests
|
||||||
|
- **ArgoCD Integration**: Shows auto-sync status and project info
|
||||||
|
- **Service Discovery**: Lists all services, ingresses, and external secrets
|
||||||
|
- **Categorization**: Groups by apps, core, games categories
|
||||||
|
- **Detailed Analysis**: Shows deployments, containers, files
|
||||||
|
|
||||||
|
### Workflow:
|
||||||
|
- **Trigger**: Changes in `k8s/` directory
|
||||||
|
- **Workflow**: `.gitea/workflows/k8s-wiki.yaml`
|
||||||
|
- **Output**: Kubernetes-Services Wiki page
|
||||||
|
|
||||||
|
## GitHub Secrets Configuration
|
||||||
|
|
||||||
|
Required secrets in repository settings:
|
||||||
|
|
||||||
|
```
|
||||||
|
GT_URL=https://gt.hexor.cy
|
||||||
|
GT_WIKI_TOKEN=your_gitea_access_token
|
||||||
|
GT_OWNER=your_username
|
||||||
|
GT_REPO=homelab
|
||||||
|
```
|
||||||
|
|
||||||
|
## Generated Wiki Pages Structure
|
||||||
|
|
||||||
|
### Applications Page
|
||||||
|
- Table with icons (32x32), external/internal URLs
|
||||||
|
- Statistics by type (Proxy vs OAuth2)
|
||||||
|
- Grouping by categories (Core, Tools, Media, etc.)
|
||||||
|
|
||||||
|
### Kubernetes Services Page
|
||||||
|
- Overview table with service types and status
|
||||||
|
- Detailed sections by category
|
||||||
|
- ArgoCD integration status
|
||||||
|
- Service discovery information
|
||||||
|
|
||||||
|
## Local Testing
|
||||||
|
|
||||||
|
### Authentik Apps:
|
||||||
|
```bash
|
||||||
|
cd terraform/authentik
|
||||||
|
terraform output -json > terraform-output.json
|
||||||
|
python3 ../../.gitea/scripts/process-terraform-output.py terraform-output.json processed-output.json
|
||||||
|
python3 ../../.gitea/scripts/generate-apps-wiki.py processed-output.json
|
||||||
|
```
|
||||||
|
|
||||||
|
### K8s Services:
|
||||||
|
```bash
|
||||||
|
pip install pyyaml
|
||||||
|
python3 .gitea/scripts/generate-k8s-wiki.py k8s/ Kubernetes-Services.md
|
||||||
|
```
|
||||||
|
|
||||||
|
## Troubleshooting
|
||||||
|
|
||||||
|
### Common Issues:
|
||||||
|
|
||||||
|
1. **Terraform output parsing errors**
|
||||||
|
- Check for [command] prefix in output
|
||||||
|
- Verify JSON structure with debug mode
|
||||||
|
|
||||||
|
2. **Wiki upload failures**
|
||||||
|
- Verify Gitea token permissions
|
||||||
|
- Check network connectivity to Gitea instance
|
||||||
|
|
||||||
|
3. **YAML parsing errors in k8s analysis**
|
||||||
|
- Ensure valid YAML syntax in k8s files
|
||||||
|
- Check PyYAML installation
|
||||||
226
.gitea/scripts/generate-apps-wiki.py
Normal file
226
.gitea/scripts/generate-apps-wiki.py
Normal file
@@ -0,0 +1,226 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""
|
||||||
|
Script for generating Wiki page with applications list from Terraform outputs
|
||||||
|
"""
|
||||||
|
|
||||||
|
import json
|
||||||
|
import sys
|
||||||
|
import os
|
||||||
|
from datetime import datetime
|
||||||
|
|
||||||
|
def generate_markdown_table(apps_data):
|
||||||
|
"""Generates Markdown table for applications"""
|
||||||
|
|
||||||
|
# Combine all applications
|
||||||
|
all_apps = []
|
||||||
|
|
||||||
|
if 'proxy_apps' in apps_data:
|
||||||
|
for key, app in apps_data['proxy_apps'].items():
|
||||||
|
all_apps.append({
|
||||||
|
'key': key,
|
||||||
|
'name': app['name'],
|
||||||
|
'type': app['type'],
|
||||||
|
'url': app['url'],
|
||||||
|
'internal_url': app.get('internal_url', '-'),
|
||||||
|
'group': app['group'],
|
||||||
|
'description': app['description'],
|
||||||
|
'icon': app['icon'],
|
||||||
|
'slug': app['slug']
|
||||||
|
})
|
||||||
|
|
||||||
|
if 'oauth_apps' in apps_data:
|
||||||
|
for key, app in apps_data['oauth_apps'].items():
|
||||||
|
all_apps.append({
|
||||||
|
'key': key,
|
||||||
|
'name': app['name'],
|
||||||
|
'type': app['type'],
|
||||||
|
'url': app['url'],
|
||||||
|
'internal_url': '-', # OAuth apps don't have internal URLs
|
||||||
|
'group': app['group'],
|
||||||
|
'description': app['description'],
|
||||||
|
'icon': app['icon'],
|
||||||
|
'slug': app['slug']
|
||||||
|
})
|
||||||
|
|
||||||
|
# Sort by groups, then by name
|
||||||
|
all_apps.sort(key=lambda x: (x['group'], x['name']))
|
||||||
|
|
||||||
|
# Generate Markdown
|
||||||
|
markdown = []
|
||||||
|
markdown.append("# Authentik Applications")
|
||||||
|
markdown.append("")
|
||||||
|
markdown.append(f"*Automatically generated: {datetime.now().strftime('%Y-%m-%d %H:%M:%S UTC')}*")
|
||||||
|
markdown.append("")
|
||||||
|
markdown.append("## All Applications")
|
||||||
|
markdown.append("")
|
||||||
|
|
||||||
|
# Table
|
||||||
|
markdown.append("| Icon | Name | Type | External URL | Internal URL | Group | Description |")
|
||||||
|
markdown.append("|:----:|------|------|--------------|--------------|-------|-------------|")
|
||||||
|
|
||||||
|
for app in all_apps:
|
||||||
|
# Icon with size constraint
|
||||||
|
if app['icon']:
|
||||||
|
icon = f'<img src="{app["icon"]}" width="32" height="32" alt="{app["name"]}">'
|
||||||
|
else:
|
||||||
|
icon = "📱"
|
||||||
|
|
||||||
|
# External URL link
|
||||||
|
external_link = f"[🔗 {app['url'].replace('https://', '').replace('http://', '')}]({app['url']})" if app.get('url') else "-"
|
||||||
|
|
||||||
|
# Internal URL (only for proxy apps)
|
||||||
|
internal_url = app.get('internal_url', '-')
|
||||||
|
if internal_url != '-':
|
||||||
|
# Show full internal URL without shortening
|
||||||
|
internal_url = f"`{internal_url}`"
|
||||||
|
|
||||||
|
description = app['description'] if app['description'] else "-"
|
||||||
|
|
||||||
|
markdown.append(f"| {icon} | **{app['name']}** | {app['type']} | {external_link} | {internal_url} | {app['group']} | {description} |")
|
||||||
|
|
||||||
|
markdown.append("")
|
||||||
|
|
||||||
|
# Statistics
|
||||||
|
proxy_count = len(apps_data.get('proxy_apps', {}))
|
||||||
|
oauth_count = len(apps_data.get('oauth_apps', {}))
|
||||||
|
total_count = proxy_count + oauth_count
|
||||||
|
|
||||||
|
markdown.append("## Statistics")
|
||||||
|
markdown.append("")
|
||||||
|
markdown.append(f"- **Total applications**: {total_count}")
|
||||||
|
markdown.append(f"- **Proxy applications**: {proxy_count}")
|
||||||
|
markdown.append(f"- **OAuth2/OpenID applications**: {oauth_count}")
|
||||||
|
markdown.append("")
|
||||||
|
|
||||||
|
# Grouping by types
|
||||||
|
groups = {}
|
||||||
|
for app in all_apps:
|
||||||
|
group = app['group']
|
||||||
|
if group not in groups:
|
||||||
|
groups[group] = {'proxy': 0, 'oauth': 0}
|
||||||
|
if app['type'] == 'Proxy':
|
||||||
|
groups[group]['proxy'] += 1
|
||||||
|
else:
|
||||||
|
groups[group]['oauth'] += 1
|
||||||
|
|
||||||
|
markdown.append("## Applications by Groups")
|
||||||
|
markdown.append("")
|
||||||
|
for group, counts in sorted(groups.items()):
|
||||||
|
total = counts['proxy'] + counts['oauth']
|
||||||
|
markdown.append(f"- **{group}**: {total} applications (Proxy: {counts['proxy']}, OAuth: {counts['oauth']})")
|
||||||
|
|
||||||
|
markdown.append("")
|
||||||
|
markdown.append("---")
|
||||||
|
markdown.append("*This page is automatically generated via Terraform CI/CD*")
|
||||||
|
|
||||||
|
return "\n".join(markdown)
|
||||||
|
|
||||||
|
def parse_terraform_output(output_data):
|
||||||
|
"""Parse Terraform output JSON structure"""
|
||||||
|
# Check if this is a full terraform output (with value, type, sensitive fields)
|
||||||
|
if isinstance(output_data, dict) and 'applications_for_wiki' in output_data:
|
||||||
|
# This is full terraform output format
|
||||||
|
app_output = output_data.get('applications_for_wiki', {})
|
||||||
|
if isinstance(app_output, dict) and 'value' in app_output:
|
||||||
|
return app_output['value']
|
||||||
|
else:
|
||||||
|
return app_output
|
||||||
|
else:
|
||||||
|
# This is already the value extracted
|
||||||
|
return output_data
|
||||||
|
|
||||||
|
def main():
|
||||||
|
if len(sys.argv) < 2:
|
||||||
|
print("Usage: python3 generate-apps-wiki.py <terraform-output-json> [--debug]")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
output_file = sys.argv[1]
|
||||||
|
debug = "--debug" in sys.argv
|
||||||
|
|
||||||
|
try:
|
||||||
|
# Check if file exists and has content
|
||||||
|
if not os.path.exists(output_file):
|
||||||
|
print(f"ERROR: File {output_file} not found")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
file_size = os.path.getsize(output_file)
|
||||||
|
if file_size == 0:
|
||||||
|
print(f"ERROR: File {output_file} is empty")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
print(f"📄 Reading Terraform output file: {output_file} ({file_size} bytes)")
|
||||||
|
|
||||||
|
# Read file content
|
||||||
|
with open(output_file, 'r') as f:
|
||||||
|
content = f.read()
|
||||||
|
|
||||||
|
if debug:
|
||||||
|
print(f"🔍 File content preview: {content[:200]}...")
|
||||||
|
|
||||||
|
# Clean content - remove command line if present
|
||||||
|
if content.startswith('[command]'):
|
||||||
|
print("⚠️ Detected command prefix, removing...")
|
||||||
|
lines = content.split('\n', 1)
|
||||||
|
if len(lines) > 1:
|
||||||
|
content = lines[1]
|
||||||
|
if debug:
|
||||||
|
print(f"🔍 Cleaned content preview: {content[:200]}...")
|
||||||
|
else:
|
||||||
|
print("ERROR: File contains only command line, no JSON data")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
# Parse JSON
|
||||||
|
try:
|
||||||
|
terraform_output = json.loads(content)
|
||||||
|
except json.JSONDecodeError as e:
|
||||||
|
print(f"ERROR: Invalid JSON in {output_file}: {e}")
|
||||||
|
print(f"Content starts with: {repr(content[:100])}")
|
||||||
|
# Try to find where JSON starts
|
||||||
|
json_start = content.find('{')
|
||||||
|
if json_start > 0:
|
||||||
|
print(f"Found JSON starting at position {json_start}, retrying...")
|
||||||
|
content = content[json_start:]
|
||||||
|
try:
|
||||||
|
terraform_output = json.loads(content)
|
||||||
|
except json.JSONDecodeError as e2:
|
||||||
|
print(f"ERROR: Still invalid JSON: {e2}")
|
||||||
|
sys.exit(1)
|
||||||
|
else:
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
# Extract application data using helper function
|
||||||
|
apps_data = parse_terraform_output(terraform_output)
|
||||||
|
|
||||||
|
if not apps_data:
|
||||||
|
print("ERROR: No applications data found in Terraform output")
|
||||||
|
if debug:
|
||||||
|
print(f"Full output structure: {json.dumps(terraform_output, indent=2)[:500]}...")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
# Check if we have correct structure
|
||||||
|
if 'proxy_apps' not in apps_data and 'oauth_apps' not in apps_data:
|
||||||
|
print("ERROR: Expected 'proxy_apps' or 'oauth_apps' in output")
|
||||||
|
print(f"Available keys: {list(apps_data.keys())}")
|
||||||
|
if debug and apps_data:
|
||||||
|
print(f"Data structure: {json.dumps(apps_data, indent=2)[:500]}...")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
print(f"📊 Found {len(apps_data.get('proxy_apps', {}))} proxy apps, {len(apps_data.get('oauth_apps', {}))} oauth apps")
|
||||||
|
|
||||||
|
# Generate Markdown
|
||||||
|
markdown_content = generate_markdown_table(apps_data)
|
||||||
|
|
||||||
|
# Write result
|
||||||
|
wiki_file = "Applications.md"
|
||||||
|
with open(wiki_file, 'w', encoding='utf-8') as f:
|
||||||
|
f.write(markdown_content)
|
||||||
|
|
||||||
|
print(f"✅ Wiki page generated: {wiki_file}")
|
||||||
|
print(f"📊 Total applications: {len(apps_data.get('proxy_apps', {})) + len(apps_data.get('oauth_apps', {}))}")
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
print(f"ERROR: {e}")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
298
.gitea/scripts/generate-k8s-wiki.py
Normal file
298
.gitea/scripts/generate-k8s-wiki.py
Normal file
@@ -0,0 +1,298 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""
|
||||||
|
Script for generating Wiki page with Kubernetes services from k8s/ directory
|
||||||
|
"""
|
||||||
|
|
||||||
|
import os
|
||||||
|
import yaml
|
||||||
|
import json
|
||||||
|
import sys
|
||||||
|
from datetime import datetime
|
||||||
|
from collections import defaultdict
|
||||||
|
|
||||||
|
class K8sService:
|
||||||
|
def __init__(self, name, category, path):
|
||||||
|
self.name = name
|
||||||
|
self.category = category
|
||||||
|
self.path = path
|
||||||
|
self.namespace = None
|
||||||
|
self.deployment_type = "Unknown"
|
||||||
|
self.helm_charts = []
|
||||||
|
self.services = []
|
||||||
|
self.ingresses = []
|
||||||
|
self.external_secrets = []
|
||||||
|
self.deployments = []
|
||||||
|
self.pvcs = []
|
||||||
|
self.argo_app = None
|
||||||
|
self.files = []
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return f"K8sService({self.name}, {self.deployment_type})"
|
||||||
|
|
||||||
|
def parse_yaml_file(filepath):
|
||||||
|
"""Parse YAML file and return content"""
|
||||||
|
try:
|
||||||
|
with open(filepath, 'r') as f:
|
||||||
|
# Load all documents in the file
|
||||||
|
docs = list(yaml.safe_load_all(f))
|
||||||
|
return docs if len(docs) > 1 else docs[0] if docs else None
|
||||||
|
except Exception as e:
|
||||||
|
print(f" ⚠️ Error parsing {filepath}: {e}")
|
||||||
|
return None
|
||||||
|
|
||||||
|
def analyze_service_directory(service_path, service_name, category):
|
||||||
|
"""Analyze a service directory and extract information"""
|
||||||
|
service = K8sService(service_name, category, service_path)
|
||||||
|
|
||||||
|
# List all files
|
||||||
|
for file in os.listdir(service_path):
|
||||||
|
if file.endswith('.yaml') or file.endswith('.yml'):
|
||||||
|
service.files.append(file)
|
||||||
|
filepath = os.path.join(service_path, file)
|
||||||
|
|
||||||
|
# Parse YAML content
|
||||||
|
content = parse_yaml_file(filepath)
|
||||||
|
if not content:
|
||||||
|
continue
|
||||||
|
|
||||||
|
# Handle multiple documents in one file
|
||||||
|
documents = content if isinstance(content, list) else [content]
|
||||||
|
|
||||||
|
for doc in documents:
|
||||||
|
if not isinstance(doc, dict) or 'kind' not in doc:
|
||||||
|
continue
|
||||||
|
|
||||||
|
kind = doc['kind']
|
||||||
|
metadata = doc.get('metadata', {})
|
||||||
|
|
||||||
|
# ArgoCD Application
|
||||||
|
if kind == 'Application' and doc.get('apiVersion', '').startswith('argoproj.io'):
|
||||||
|
service.argo_app = {
|
||||||
|
'name': metadata.get('name', ''),
|
||||||
|
'namespace': doc.get('spec', {}).get('destination', {}).get('namespace', ''),
|
||||||
|
'project': doc.get('spec', {}).get('project', ''),
|
||||||
|
'auto_sync': doc.get('spec', {}).get('syncPolicy', {}).get('automated') is not None
|
||||||
|
}
|
||||||
|
service.namespace = service.argo_app['namespace']
|
||||||
|
|
||||||
|
# Kustomization
|
||||||
|
elif kind == 'Kustomization':
|
||||||
|
if 'helmCharts' in doc:
|
||||||
|
service.deployment_type = "Helm Chart"
|
||||||
|
for chart in doc.get('helmCharts', []):
|
||||||
|
service.helm_charts.append({
|
||||||
|
'name': chart.get('name', ''),
|
||||||
|
'repo': chart.get('repo', ''),
|
||||||
|
'version': chart.get('version', ''),
|
||||||
|
'namespace': chart.get('namespace', service.namespace)
|
||||||
|
})
|
||||||
|
else:
|
||||||
|
service.deployment_type = "Kustomize"
|
||||||
|
|
||||||
|
# Deployment
|
||||||
|
elif kind == 'Deployment':
|
||||||
|
service.deployments.append({
|
||||||
|
'name': metadata.get('name', ''),
|
||||||
|
'namespace': metadata.get('namespace', service.namespace),
|
||||||
|
'replicas': doc.get('spec', {}).get('replicas', 1),
|
||||||
|
'containers': [c.get('name', '') for c in doc.get('spec', {}).get('template', {}).get('spec', {}).get('containers', [])]
|
||||||
|
})
|
||||||
|
if service.deployment_type == "Unknown":
|
||||||
|
service.deployment_type = "YAML Manifests"
|
||||||
|
|
||||||
|
# Service
|
||||||
|
elif kind == 'Service':
|
||||||
|
svc_spec = doc.get('spec', {})
|
||||||
|
service.services.append({
|
||||||
|
'name': metadata.get('name', ''),
|
||||||
|
'type': svc_spec.get('type', 'ClusterIP'),
|
||||||
|
'ports': svc_spec.get('ports', [])
|
||||||
|
})
|
||||||
|
|
||||||
|
# Ingress
|
||||||
|
elif kind == 'Ingress':
|
||||||
|
rules = doc.get('spec', {}).get('rules', [])
|
||||||
|
hosts = []
|
||||||
|
for rule in rules:
|
||||||
|
if 'host' in rule:
|
||||||
|
hosts.append(rule['host'])
|
||||||
|
service.ingresses.append({
|
||||||
|
'name': metadata.get('name', ''),
|
||||||
|
'hosts': hosts
|
||||||
|
})
|
||||||
|
|
||||||
|
# ExternalSecret
|
||||||
|
elif kind == 'ExternalSecret':
|
||||||
|
service.external_secrets.append({
|
||||||
|
'name': metadata.get('name', ''),
|
||||||
|
'store': doc.get('spec', {}).get('secretStoreRef', {}).get('name', '')
|
||||||
|
})
|
||||||
|
|
||||||
|
# PersistentVolumeClaim
|
||||||
|
elif kind == 'PersistentVolumeClaim':
|
||||||
|
service.pvcs.append({
|
||||||
|
'name': metadata.get('name', ''),
|
||||||
|
'size': doc.get('spec', {}).get('resources', {}).get('requests', {}).get('storage', '')
|
||||||
|
})
|
||||||
|
|
||||||
|
# If no specific deployment type found but has YAML files
|
||||||
|
if service.deployment_type == "Unknown" and service.files:
|
||||||
|
service.deployment_type = "YAML Manifests"
|
||||||
|
|
||||||
|
return service
|
||||||
|
|
||||||
|
def generate_markdown_table(services):
|
||||||
|
"""Generate markdown table for services"""
|
||||||
|
markdown = []
|
||||||
|
markdown.append("# Kubernetes Services")
|
||||||
|
markdown.append("")
|
||||||
|
markdown.append(f"*Automatically generated: {datetime.now().strftime('%Y-%m-%d %H:%M:%S UTC')}*")
|
||||||
|
markdown.append("")
|
||||||
|
|
||||||
|
# Group by category
|
||||||
|
categories = defaultdict(list)
|
||||||
|
for service in services:
|
||||||
|
categories[service.category].append(service)
|
||||||
|
|
||||||
|
# Statistics
|
||||||
|
markdown.append("## Statistics")
|
||||||
|
markdown.append("")
|
||||||
|
markdown.append(f"- **Total Services**: {len(services)}")
|
||||||
|
markdown.append(f"- **Categories**: {len(categories)}")
|
||||||
|
helm_count = sum(1 for s in services if s.deployment_type == "Helm Chart")
|
||||||
|
kustomize_count = sum(1 for s in services if s.deployment_type == "Kustomize")
|
||||||
|
yaml_count = sum(1 for s in services if s.deployment_type == "YAML Manifests")
|
||||||
|
markdown.append(f"- **Helm Charts**: {helm_count}")
|
||||||
|
markdown.append(f"- **Kustomize**: {kustomize_count}")
|
||||||
|
markdown.append(f"- **YAML Manifests**: {yaml_count}")
|
||||||
|
markdown.append("")
|
||||||
|
|
||||||
|
# Main table
|
||||||
|
markdown.append("## All Services")
|
||||||
|
markdown.append("")
|
||||||
|
markdown.append("| Service | Category | Type | Namespace | Ingresses | Services | Secrets | Auto-Sync |")
|
||||||
|
markdown.append("|---------|----------|------|-----------|-----------|----------|---------|-----------|")
|
||||||
|
|
||||||
|
for category in sorted(categories.keys()):
|
||||||
|
for service in sorted(categories[category], key=lambda x: x.name):
|
||||||
|
# Service name with link to directory
|
||||||
|
name_link = f"[{service.name}](k8s/{service.category}/{service.name}/)"
|
||||||
|
|
||||||
|
# Deployment type with emoji
|
||||||
|
type_emoji = {
|
||||||
|
"Helm Chart": "🎩",
|
||||||
|
"Kustomize": "🔧",
|
||||||
|
"YAML Manifests": "📄",
|
||||||
|
"Unknown": "❓"
|
||||||
|
}
|
||||||
|
type_str = f"{type_emoji.get(service.deployment_type, '')} {service.deployment_type}"
|
||||||
|
|
||||||
|
# Ingresses
|
||||||
|
ingresses = []
|
||||||
|
for ing in service.ingresses:
|
||||||
|
for host in ing['hosts']:
|
||||||
|
ingresses.append(f"[{host}](https://{host})")
|
||||||
|
ingress_str = "<br>".join(ingresses) if ingresses else "-"
|
||||||
|
|
||||||
|
# Services
|
||||||
|
svc_list = []
|
||||||
|
for svc in service.services:
|
||||||
|
ports = [f"{p.get('port', '?')}" for p in svc['ports']]
|
||||||
|
svc_list.append(f"`{svc['name']}:{','.join(ports)}`")
|
||||||
|
svc_str = "<br>".join(svc_list) if svc_list else "-"
|
||||||
|
|
||||||
|
# External Secrets
|
||||||
|
secrets_str = f"{len(service.external_secrets)} secrets" if service.external_secrets else "-"
|
||||||
|
|
||||||
|
# Auto-sync
|
||||||
|
auto_sync = "✅" if service.argo_app and service.argo_app.get('auto_sync') else "❌"
|
||||||
|
|
||||||
|
markdown.append(f"| **{name_link}** | {category} | {type_str} | {service.namespace or '-'} | {ingress_str} | {svc_str} | {secrets_str} | {auto_sync} |")
|
||||||
|
|
||||||
|
markdown.append("")
|
||||||
|
|
||||||
|
# Detailed sections by category
|
||||||
|
for category in sorted(categories.keys()):
|
||||||
|
markdown.append(f"## {category.title()} Services")
|
||||||
|
markdown.append("")
|
||||||
|
|
||||||
|
for service in sorted(categories[category], key=lambda x: x.name):
|
||||||
|
markdown.append(f"### {service.name}")
|
||||||
|
markdown.append("")
|
||||||
|
|
||||||
|
# Basic info
|
||||||
|
markdown.append(f"- **Type**: {service.deployment_type}")
|
||||||
|
markdown.append(f"- **Namespace**: {service.namespace or 'Not specified'}")
|
||||||
|
markdown.append(f"- **Path**: `{service.path}`")
|
||||||
|
|
||||||
|
# Helm charts
|
||||||
|
if service.helm_charts:
|
||||||
|
markdown.append("- **Helm Charts**:")
|
||||||
|
for chart in service.helm_charts:
|
||||||
|
markdown.append(f" - {chart['name']} v{chart['version']} from {chart['repo']}")
|
||||||
|
|
||||||
|
# Deployments
|
||||||
|
if service.deployments:
|
||||||
|
markdown.append("- **Deployments**:")
|
||||||
|
for dep in service.deployments:
|
||||||
|
containers = ', '.join(dep['containers'])
|
||||||
|
markdown.append(f" - {dep['name']} ({dep['replicas']} replicas) - Containers: {containers}")
|
||||||
|
|
||||||
|
# Files
|
||||||
|
if service.files:
|
||||||
|
markdown.append(f"- **Files**: {', '.join(sorted(service.files))}")
|
||||||
|
|
||||||
|
markdown.append("")
|
||||||
|
|
||||||
|
markdown.append("---")
|
||||||
|
markdown.append("*This page is automatically generated from k8s/ directory via CI/CD*")
|
||||||
|
|
||||||
|
return "\n".join(markdown)
|
||||||
|
|
||||||
|
def main():
|
||||||
|
if len(sys.argv) < 2:
|
||||||
|
print("Usage: generate-k8s-wiki.py <k8s-directory> [output-file]")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
k8s_dir = sys.argv[1]
|
||||||
|
output_file = sys.argv[2] if len(sys.argv) > 2 else "Kubernetes-Services.md"
|
||||||
|
|
||||||
|
if not os.path.exists(k8s_dir):
|
||||||
|
print(f"❌ Directory {k8s_dir} not found")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
print(f"📂 Scanning {k8s_dir}...")
|
||||||
|
|
||||||
|
services = []
|
||||||
|
|
||||||
|
# Scan each category directory
|
||||||
|
for category in ['apps', 'core', 'games']:
|
||||||
|
category_path = os.path.join(k8s_dir, category)
|
||||||
|
if not os.path.exists(category_path):
|
||||||
|
print(f" ⚠️ Category {category} not found")
|
||||||
|
continue
|
||||||
|
|
||||||
|
print(f"📁 Processing {category}/...")
|
||||||
|
|
||||||
|
# Scan each service in category
|
||||||
|
for service_name in os.listdir(category_path):
|
||||||
|
service_path = os.path.join(category_path, service_name)
|
||||||
|
if os.path.isdir(service_path):
|
||||||
|
print(f" 🔍 Analyzing {service_name}...")
|
||||||
|
service = analyze_service_directory(service_path, service_name, category)
|
||||||
|
services.append(service)
|
||||||
|
|
||||||
|
print(f"\n✅ Found {len(services)} services")
|
||||||
|
|
||||||
|
# Generate markdown
|
||||||
|
markdown = generate_markdown_table(services)
|
||||||
|
|
||||||
|
# Write output
|
||||||
|
with open(output_file, 'w', encoding='utf-8') as f:
|
||||||
|
f.write(markdown)
|
||||||
|
|
||||||
|
print(f"📄 Wiki page generated: {output_file}")
|
||||||
|
print(f"📊 Total services: {len(services)}")
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
161
.gitea/scripts/generate-readme.py
Normal file
161
.gitea/scripts/generate-readme.py
Normal file
@@ -0,0 +1,161 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""
|
||||||
|
Generate README.md with ArgoCD application status badges.
|
||||||
|
Scans k8s/ directory structure to find all applications and generates badges for them.
|
||||||
|
"""
|
||||||
|
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
from pathlib import Path
|
||||||
|
from typing import Dict, List
|
||||||
|
|
||||||
|
|
||||||
|
def scan_k8s_directory(k8s_path: str) -> Dict[str, List[str]]:
|
||||||
|
"""
|
||||||
|
Scan k8s/ directory and return applications grouped by category.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
k8s_path: Path to k8s directory
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Dictionary with categories as keys and lists of app names as values
|
||||||
|
"""
|
||||||
|
apps_by_category = {
|
||||||
|
'core': [],
|
||||||
|
'apps': [],
|
||||||
|
'games': []
|
||||||
|
}
|
||||||
|
|
||||||
|
k8s_dir = Path(k8s_path)
|
||||||
|
|
||||||
|
for category in apps_by_category.keys():
|
||||||
|
category_path = k8s_dir / category
|
||||||
|
if category_path.exists() and category_path.is_dir():
|
||||||
|
# Get all subdirectories (each subdirectory is an app)
|
||||||
|
apps = [
|
||||||
|
d.name for d in category_path.iterdir()
|
||||||
|
if d.is_dir() and not d.name.startswith('.')
|
||||||
|
]
|
||||||
|
apps_by_category[category] = sorted(apps)
|
||||||
|
|
||||||
|
return apps_by_category
|
||||||
|
|
||||||
|
|
||||||
|
def generate_badge_line(app_name: str) -> str:
|
||||||
|
"""
|
||||||
|
Generate markdown line with badge for an application.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
app_name: Name of the application
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Markdown formatted string with badge
|
||||||
|
"""
|
||||||
|
badge_url = f"https://ag.hexor.cy/api/badge?name={app_name}&revision=true"
|
||||||
|
app_url = f"https://ag.hexor.cy/applications/argocd/{app_name}"
|
||||||
|
return f"| **{app_name}** | []({app_url}) |"
|
||||||
|
|
||||||
|
|
||||||
|
def generate_readme_content(apps_by_category: Dict[str, List[str]]) -> str:
|
||||||
|
"""
|
||||||
|
Generate README.md content with all applications.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
apps_by_category: Dictionary with apps grouped by category
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Complete README.md content
|
||||||
|
"""
|
||||||
|
lines = [
|
||||||
|
"# homelab",
|
||||||
|
"",
|
||||||
|
"ArgoCD homelab project",
|
||||||
|
"",
|
||||||
|
"## ArgoCD Applications Status",
|
||||||
|
"",
|
||||||
|
"<table>",
|
||||||
|
"<tr>",
|
||||||
|
"<td valign=\"top\" width=\"50%\">",
|
||||||
|
"",
|
||||||
|
"### Core Applications",
|
||||||
|
"",
|
||||||
|
"| Application | Status |",
|
||||||
|
"| :--- | :---: |"
|
||||||
|
]
|
||||||
|
|
||||||
|
# Add core applications
|
||||||
|
for app in apps_by_category.get('core', []):
|
||||||
|
lines.append(generate_badge_line(app))
|
||||||
|
|
||||||
|
lines.extend([
|
||||||
|
"",
|
||||||
|
"### Games",
|
||||||
|
"",
|
||||||
|
"| Application | Status |",
|
||||||
|
"| :--- | :---: |"
|
||||||
|
])
|
||||||
|
|
||||||
|
# Add games
|
||||||
|
for app in apps_by_category.get('games', []):
|
||||||
|
lines.append(generate_badge_line(app))
|
||||||
|
|
||||||
|
lines.extend([
|
||||||
|
"</td>",
|
||||||
|
"<td valign=\"top\" width=\"50%\">",
|
||||||
|
"",
|
||||||
|
"### Applications",
|
||||||
|
"",
|
||||||
|
"| Application | Status |",
|
||||||
|
"| :--- | :---: |"
|
||||||
|
])
|
||||||
|
|
||||||
|
# Add applications
|
||||||
|
for app in apps_by_category.get('apps', []):
|
||||||
|
lines.append(generate_badge_line(app))
|
||||||
|
|
||||||
|
lines.extend([
|
||||||
|
"",
|
||||||
|
"</td>",
|
||||||
|
"</tr>",
|
||||||
|
"</table>"
|
||||||
|
])
|
||||||
|
|
||||||
|
return '\n'.join(lines) + '\n'
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
if len(sys.argv) < 2:
|
||||||
|
print("Usage: generate-readme.py <k8s-directory> [output-file]")
|
||||||
|
print("Example: generate-readme.py k8s/ README.md")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
k8s_path = sys.argv[1]
|
||||||
|
output_file = sys.argv[2] if len(sys.argv) > 2 else "README.md"
|
||||||
|
|
||||||
|
if not os.path.exists(k8s_path):
|
||||||
|
print(f"Error: Directory {k8s_path} does not exist")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
print(f"📁 Scanning {k8s_path}...")
|
||||||
|
apps_by_category = scan_k8s_directory(k8s_path)
|
||||||
|
|
||||||
|
# Print statistics
|
||||||
|
total_apps = sum(len(apps) for apps in apps_by_category.values())
|
||||||
|
print(f"✅ Found {total_apps} applications:")
|
||||||
|
for category, apps in apps_by_category.items():
|
||||||
|
if apps:
|
||||||
|
print(f" - {category}: {len(apps)} apps")
|
||||||
|
|
||||||
|
print(f"📝 Generating {output_file}...")
|
||||||
|
readme_content = generate_readme_content(apps_by_category)
|
||||||
|
|
||||||
|
with open(output_file, 'w', encoding='utf-8') as f:
|
||||||
|
f.write(readme_content)
|
||||||
|
|
||||||
|
print(f"✅ {output_file} generated successfully")
|
||||||
|
print(f" Total lines: {len(readme_content.splitlines())}")
|
||||||
|
print(f" File size: {len(readme_content)} bytes")
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
105
.gitea/scripts/process-terraform-output.py
Normal file
105
.gitea/scripts/process-terraform-output.py
Normal file
@@ -0,0 +1,105 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""
|
||||||
|
Process Terraform output to extract applications_for_wiki data
|
||||||
|
Handles various output formats and cleans up invalid JSON
|
||||||
|
"""
|
||||||
|
|
||||||
|
import json
|
||||||
|
import sys
|
||||||
|
import os
|
||||||
|
|
||||||
|
def clean_command_prefix(content):
|
||||||
|
"""Remove [command] prefix if present"""
|
||||||
|
if content.startswith('[command]'):
|
||||||
|
lines = content.split('\n', 1)
|
||||||
|
if len(lines) > 1:
|
||||||
|
return lines[1]
|
||||||
|
return content
|
||||||
|
|
||||||
|
def extract_valid_json(content):
|
||||||
|
"""Extract valid JSON from content that might have extra data"""
|
||||||
|
# Find first { and last matching }
|
||||||
|
start = content.find('{')
|
||||||
|
if start < 0:
|
||||||
|
return None
|
||||||
|
|
||||||
|
count = 0
|
||||||
|
end = start
|
||||||
|
for i in range(start, len(content)):
|
||||||
|
if content[i] == '{':
|
||||||
|
count += 1
|
||||||
|
elif content[i] == '}':
|
||||||
|
count -= 1
|
||||||
|
if count == 0:
|
||||||
|
end = i + 1
|
||||||
|
break
|
||||||
|
|
||||||
|
if end > start and count == 0:
|
||||||
|
return content[start:end]
|
||||||
|
return None
|
||||||
|
|
||||||
|
def extract_value(data):
|
||||||
|
"""Extract value from Terraform output format"""
|
||||||
|
if isinstance(data, dict) and 'value' in data:
|
||||||
|
return data['value']
|
||||||
|
return data
|
||||||
|
|
||||||
|
def main():
|
||||||
|
if len(sys.argv) != 3:
|
||||||
|
print("Usage: process-terraform-output.py <input-file> <output-file>")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
input_file = sys.argv[1]
|
||||||
|
output_file = sys.argv[2]
|
||||||
|
|
||||||
|
try:
|
||||||
|
# Read input file
|
||||||
|
with open(input_file, 'r') as f:
|
||||||
|
content = f.read()
|
||||||
|
|
||||||
|
# Clean command prefix if present
|
||||||
|
content = clean_command_prefix(content)
|
||||||
|
|
||||||
|
# Try to parse JSON directly
|
||||||
|
try:
|
||||||
|
data = json.loads(content)
|
||||||
|
print("✅ Valid JSON parsed successfully")
|
||||||
|
except json.JSONDecodeError as e:
|
||||||
|
print(f"⚠️ Initial JSON parse failed: {e}")
|
||||||
|
print("🔍 Attempting to extract valid JSON portion...")
|
||||||
|
|
||||||
|
# Try to extract valid JSON
|
||||||
|
valid_json = extract_valid_json(content)
|
||||||
|
if valid_json:
|
||||||
|
try:
|
||||||
|
data = json.loads(valid_json)
|
||||||
|
print("✅ Extracted valid JSON successfully")
|
||||||
|
except json.JSONDecodeError as e2:
|
||||||
|
print(f"❌ Failed to parse extracted JSON: {e2}")
|
||||||
|
sys.exit(1)
|
||||||
|
else:
|
||||||
|
print("❌ Could not extract valid JSON from content")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
# Extract value if it's wrapped in Terraform output format
|
||||||
|
result = extract_value(data)
|
||||||
|
|
||||||
|
# Write output
|
||||||
|
with open(output_file, 'w') as f:
|
||||||
|
json.dump(result, f, indent=2)
|
||||||
|
|
||||||
|
print(f"✅ Processed output written to {output_file}")
|
||||||
|
|
||||||
|
# Show preview
|
||||||
|
preview = json.dumps(result, indent=2)[:200]
|
||||||
|
print(f"📄 Preview: {preview}...")
|
||||||
|
|
||||||
|
except FileNotFoundError:
|
||||||
|
print(f"❌ Input file {input_file} not found")
|
||||||
|
sys.exit(1)
|
||||||
|
except Exception as e:
|
||||||
|
print(f"❌ Error: {e}")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
139
.gitea/workflows/authentik-apps.yaml
Normal file
139
.gitea/workflows/authentik-apps.yaml
Normal file
@@ -0,0 +1,139 @@
|
|||||||
|
name: 'Terraform'
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [ "main" ]
|
||||||
|
paths:
|
||||||
|
- 'terraform/authentik/**'
|
||||||
|
pull_request:
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
terraform:
|
||||||
|
name: 'Terraform'
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
environment: production
|
||||||
|
|
||||||
|
defaults:
|
||||||
|
run:
|
||||||
|
shell: bash
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
|
||||||
|
- name: Setup Terraform
|
||||||
|
uses: hashicorp/setup-terraform@v2
|
||||||
|
with:
|
||||||
|
cli_config_credentials_token: ${{ secrets.TF_API_TOKEN }}
|
||||||
|
|
||||||
|
- name: Terraform Init
|
||||||
|
run: terraform init
|
||||||
|
working-directory: ./terraform/authentik
|
||||||
|
|
||||||
|
- name: Terraform Format
|
||||||
|
run: terraform fmt -check
|
||||||
|
continue-on-error: true
|
||||||
|
working-directory: ./terraform/authentik
|
||||||
|
|
||||||
|
- name: Terraform Apply
|
||||||
|
run: terraform apply -var-file proxy-apps.tfvars -var-file oauth2-apps.tfvars -var-file terraform.tfvars -var-file groups.tfvars -input=false -auto-approve -parallelism=100
|
||||||
|
working-directory: ./terraform/authentik
|
||||||
|
|
||||||
|
- name: Generate Wiki Content
|
||||||
|
if: success()
|
||||||
|
continue-on-error: true
|
||||||
|
run: |
|
||||||
|
echo "📋 Starting Wiki generation..."
|
||||||
|
cd ./terraform/authentik
|
||||||
|
|
||||||
|
# Get terraform output
|
||||||
|
echo "🔍 Generating Terraform output..."
|
||||||
|
terraform output -json applications_for_wiki > terraform-raw-output.json 2>&1
|
||||||
|
|
||||||
|
# Process output to extract clean JSON
|
||||||
|
echo "📤 Processing Terraform output..."
|
||||||
|
python3 ../../.gitea/scripts/process-terraform-output.py terraform-raw-output.json terraform-output.json
|
||||||
|
|
||||||
|
# Run wiki generation
|
||||||
|
echo "📊 Running wiki generation script..."
|
||||||
|
if python3 ../../.gitea/scripts/generate-apps-wiki.py terraform-output.json; then
|
||||||
|
echo "✅ Wiki content generated successfully"
|
||||||
|
else
|
||||||
|
echo "⚠️ Wiki generation failed, retrying with debug..."
|
||||||
|
python3 ../../.gitea/scripts/generate-apps-wiki.py terraform-output.json --debug || echo "⚠️ Wiki generation failed"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Check results
|
||||||
|
if [ -f "Applications.md" ]; then
|
||||||
|
echo "✅ Wiki file created: $(wc -l < Applications.md) lines"
|
||||||
|
else
|
||||||
|
echo "⚠️ Wiki content not generated"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
working-directory: ./
|
||||||
|
|
||||||
|
- name: Upload Wiki to Gitea
|
||||||
|
if: success()
|
||||||
|
continue-on-error: true
|
||||||
|
run: |
|
||||||
|
cd ./terraform/authentik
|
||||||
|
|
||||||
|
# Set variables
|
||||||
|
GITEA_URL="${{ secrets.GT_URL }}"
|
||||||
|
GITEA_TOKEN="${{ secrets.GT_WIKI_TOKEN }}"
|
||||||
|
GITEA_OWNER="${{ secrets.GT_OWNER }}"
|
||||||
|
GITEA_REPO="${{ secrets.GT_REPO }}"
|
||||||
|
|
||||||
|
# Debug variables (without exposing token)
|
||||||
|
echo "🔍 Checking variables..."
|
||||||
|
echo "GITEA_URL: ${GITEA_URL:-NOT SET}"
|
||||||
|
echo "GITEA_OWNER: ${GITEA_OWNER:-NOT SET}"
|
||||||
|
echo "GITEA_REPO: ${GITEA_REPO:-NOT SET}"
|
||||||
|
echo "GITEA_TOKEN: $(if [ -n "$GITEA_TOKEN" ]; then echo "SET"; else echo "NOT SET"; fi)"
|
||||||
|
|
||||||
|
# Check if file exists
|
||||||
|
if [ ! -f "Applications.md" ]; then
|
||||||
|
echo "⚠️ Applications.md not found, skipping wiki update"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "📤 Uploading to Gitea Wiki..."
|
||||||
|
|
||||||
|
# Encode content to base64
|
||||||
|
CONTENT=$(base64 -w 0 Applications.md)
|
||||||
|
|
||||||
|
# Check if wiki page exists
|
||||||
|
WIKI_PAGE_EXISTS=$(curl -s -o /dev/null -w "%{http_code}" \
|
||||||
|
-H "Authorization: token $GITEA_TOKEN" \
|
||||||
|
"$GITEA_URL/api/v1/repos/$GITEA_OWNER/$GITEA_REPO/wiki/page/Applications" || echo "000")
|
||||||
|
|
||||||
|
if [ "$WIKI_PAGE_EXISTS" = "200" ]; then
|
||||||
|
echo "📝 Updating existing wiki page..."
|
||||||
|
curl -X PATCH \
|
||||||
|
-H "Authorization: token $GITEA_TOKEN" \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
-d "{
|
||||||
|
\"title\": \"Applications\",
|
||||||
|
\"content_base64\": \"$CONTENT\",
|
||||||
|
\"message\": \"Update applications list from CI/CD [$(date)]\"
|
||||||
|
}" \
|
||||||
|
"$GITEA_URL/api/v1/repos/$GITEA_OWNER/$GITEA_REPO/wiki/page/Applications" || echo "⚠️ Wiki update failed"
|
||||||
|
else
|
||||||
|
echo "📄 Creating new wiki page..."
|
||||||
|
curl -X POST \
|
||||||
|
-H "Authorization: token $GITEA_TOKEN" \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
-d "{
|
||||||
|
\"title\": \"Applications\",
|
||||||
|
\"content_base64\": \"$CONTENT\",
|
||||||
|
\"message\": \"Create applications list from CI/CD [$(date)]\"
|
||||||
|
}" \
|
||||||
|
"$GITEA_URL/api/v1/repos/$GITEA_OWNER/$GITEA_REPO/wiki/new" || echo "⚠️ Wiki creation failed"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "✅ Wiki update process completed"
|
||||||
|
working-directory: ./
|
||||||
|
|
||||||
111
.gitea/workflows/k8s-wiki.yaml
Normal file
111
.gitea/workflows/k8s-wiki.yaml
Normal file
@@ -0,0 +1,111 @@
|
|||||||
|
name: 'Update Kubernetes Services Wiki'
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [ "main" ]
|
||||||
|
# paths:
|
||||||
|
# - 'k8s/**'
|
||||||
|
# - '.gitea/scripts/generate-k8s-wiki.py'
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
update-k8s-wiki:
|
||||||
|
name: 'Generate and Update K8s Wiki'
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
|
||||||
|
- name: Install Python dependencies
|
||||||
|
run: |
|
||||||
|
pip install pyyaml
|
||||||
|
|
||||||
|
- name: Generate K8s Services Wiki
|
||||||
|
run: |
|
||||||
|
echo "📋 Starting K8s wiki generation..."
|
||||||
|
python3 .gitea/scripts/generate-k8s-wiki.py k8s/ Kubernetes-Services.md
|
||||||
|
|
||||||
|
if [ -f "Kubernetes-Services.md" ]; then
|
||||||
|
echo "✅ Wiki content generated successfully"
|
||||||
|
echo "📄 File size: $(wc -c < Kubernetes-Services.md) bytes"
|
||||||
|
echo "📄 Lines: $(wc -l < Kubernetes-Services.md)"
|
||||||
|
else
|
||||||
|
echo "❌ Wiki content not generated"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
- name: Upload Wiki to Gitea
|
||||||
|
continue-on-error: true
|
||||||
|
run: |
|
||||||
|
# Set variables
|
||||||
|
GITEA_URL="${{ secrets.GT_URL }}"
|
||||||
|
GITEA_TOKEN="${{ secrets.GT_WIKI_TOKEN }}"
|
||||||
|
GITEA_OWNER="${{ secrets.GT_OWNER }}"
|
||||||
|
GITEA_REPO="${{ secrets.GT_REPO }}"
|
||||||
|
|
||||||
|
# Debug variables (without exposing token)
|
||||||
|
echo "🔍 Checking variables..."
|
||||||
|
echo "GITEA_URL: ${GITEA_URL:-NOT SET}"
|
||||||
|
echo "GITEA_OWNER: ${GITEA_OWNER:-NOT SET}"
|
||||||
|
echo "GITEA_REPO: ${GITEA_REPO:-NOT SET}"
|
||||||
|
echo "GITEA_TOKEN: $(if [ -n "$GITEA_TOKEN" ]; then echo "SET"; else echo "NOT SET"; fi)"
|
||||||
|
|
||||||
|
if [ ! -f "Kubernetes-Services.md" ]; then
|
||||||
|
echo "❌ Kubernetes-Services.md not found"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "📤 Uploading to Gitea Wiki..."
|
||||||
|
|
||||||
|
# Encode content to base64
|
||||||
|
CONTENT=$(base64 -w 0 Kubernetes-Services.md)
|
||||||
|
|
||||||
|
# Check if wiki page exists
|
||||||
|
WIKI_PAGE_EXISTS=$(curl -s -o /dev/null -w "%{http_code}" \
|
||||||
|
-H "Authorization: token $GITEA_TOKEN" \
|
||||||
|
"$GITEA_URL/api/v1/repos/$GITEA_OWNER/$GITEA_REPO/wiki/page/Kubernetes-Services" || echo "000")
|
||||||
|
|
||||||
|
if [ "$WIKI_PAGE_EXISTS" = "200" ]; then
|
||||||
|
echo "📝 Updating existing wiki page..."
|
||||||
|
curl -X PATCH \
|
||||||
|
-H "Authorization: token $GITEA_TOKEN" \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
-d "{
|
||||||
|
\"title\": \"Kubernetes-Services\",
|
||||||
|
\"content_base64\": \"$CONTENT\",
|
||||||
|
\"message\": \"Update K8s services list from CI/CD [$(date)]\"
|
||||||
|
}" \
|
||||||
|
"$GITEA_URL/api/v1/repos/$GITEA_OWNER/$GITEA_REPO/wiki/page/Kubernetes-Services" || echo "⚠️ Wiki update failed"
|
||||||
|
else
|
||||||
|
echo "📄 Creating new wiki page..."
|
||||||
|
curl -X POST \
|
||||||
|
-H "Authorization: token $GITEA_TOKEN" \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
-d "{
|
||||||
|
\"title\": \"Kubernetes-Services\",
|
||||||
|
\"content_base64\": \"$CONTENT\",
|
||||||
|
\"message\": \"Create K8s services list from CI/CD [$(date)]\"
|
||||||
|
}" \
|
||||||
|
"$GITEA_URL/api/v1/repos/$GITEA_OWNER/$GITEA_REPO/wiki/new" || echo "⚠️ Wiki creation failed"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "✅ Wiki update process completed"
|
||||||
|
echo "🔗 Wiki URL: $GITEA_URL/$GITEA_OWNER/$GITEA_REPO/wiki/Kubernetes-Services"
|
||||||
|
|
||||||
|
- name: Summary
|
||||||
|
if: always()
|
||||||
|
run: |
|
||||||
|
echo "## 📊 K8s Wiki Update Summary" >> $GITHUB_STEP_SUMMARY
|
||||||
|
if [ -f "Kubernetes-Services.md" ]; then
|
||||||
|
echo "- ✅ K8s services analyzed" >> $GITHUB_STEP_SUMMARY
|
||||||
|
echo "- ✅ Wiki page generated" >> $GITHUB_STEP_SUMMARY
|
||||||
|
echo "" >> $GITHUB_STEP_SUMMARY
|
||||||
|
echo "**Services found:** $(grep -c '^|' Kubernetes-Services.md || echo 0)" >> $GITHUB_STEP_SUMMARY
|
||||||
|
else
|
||||||
|
echo "- ❌ Wiki generation failed" >> $GITHUB_STEP_SUMMARY
|
||||||
|
fi
|
||||||
|
echo "**Generated at:** $(date)" >> $GITHUB_STEP_SUMMARY
|
||||||
@@ -1,9 +1,9 @@
|
|||||||
name: Check with kubeconform
|
name: Check with kubeconform
|
||||||
|
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
branches: [ main ]
|
branches: [ main ]
|
||||||
|
paths:
|
||||||
|
- 'k8s/**'
|
||||||
jobs:
|
jobs:
|
||||||
lint:
|
lint:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
@@ -16,15 +16,43 @@ jobs:
|
|||||||
- name: Kubeconform validation
|
- name: Kubeconform validation
|
||||||
id: kubeconform
|
id: kubeconform
|
||||||
run: |
|
run: |
|
||||||
|
# Create exclusion list - add files that should be skipped from validation
|
||||||
|
EXCLUSIONS=(
|
||||||
|
"./k8s/core/system-upgrade/crd.yaml"
|
||||||
|
# Add more files here as needed
|
||||||
|
# "./path/to/another/file.yaml"
|
||||||
|
)
|
||||||
|
|
||||||
# Create a temporary file for storing validation output
|
# Create a temporary file for storing validation output
|
||||||
VALIDATION_OUTPUT=$(mktemp)
|
VALIDATION_OUTPUT=$(mktemp)
|
||||||
|
|
||||||
# Run kubeconform and capture output
|
# Function to check if file is in exclusions
|
||||||
find . -name '*.yaml' \
|
is_excluded() {
|
||||||
|
local file="$1"
|
||||||
|
for exclusion in "${EXCLUSIONS[@]}"; do
|
||||||
|
if [[ "$file" == "$exclusion" ]]; then
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
# Find all yaml files and filter out exclusions
|
||||||
|
YAML_FILES=()
|
||||||
|
while IFS= read -r -d '' file; do
|
||||||
|
if ! is_excluded "$file"; then
|
||||||
|
YAML_FILES+=("$file")
|
||||||
|
else
|
||||||
|
echo "⚠️ Skipping excluded file: $file"
|
||||||
|
fi
|
||||||
|
done < <(find . -name '*.yaml' \
|
||||||
! -name '*values.yaml' \
|
! -name '*values.yaml' \
|
||||||
! -path './.gitea/*' \
|
! -path './.gitea/*' \
|
||||||
-print0 \
|
-print0)
|
||||||
| xargs -0 kubeconform \
|
|
||||||
|
# Run kubeconform only if there are files to validate
|
||||||
|
if [ ${#YAML_FILES[@]} -gt 0 ]; then
|
||||||
|
printf '%s\0' "${YAML_FILES[@]}" | xargs -0 kubeconform \
|
||||||
-summary \
|
-summary \
|
||||||
-verbose \
|
-verbose \
|
||||||
-output pretty \
|
-output pretty \
|
||||||
@@ -32,6 +60,9 @@ jobs:
|
|||||||
-schema-location default \
|
-schema-location default \
|
||||||
-schema-location 'https://raw.githubusercontent.com/datreeio/CRDs-catalog/main/{{.Group}}/{{.ResourceKind}}_{{.ResourceAPIVersion}}.json' \
|
-schema-location 'https://raw.githubusercontent.com/datreeio/CRDs-catalog/main/{{.Group}}/{{.ResourceKind}}_{{.ResourceAPIVersion}}.json' \
|
||||||
-schema-location 'https://raw.githubusercontent.com/SchemaStore/schemastore/refs/heads/master/src/schemas/json/kustomization.json' > $VALIDATION_OUTPUT 2>&1 || true
|
-schema-location 'https://raw.githubusercontent.com/SchemaStore/schemastore/refs/heads/master/src/schemas/json/kustomization.json' > $VALIDATION_OUTPUT 2>&1 || true
|
||||||
|
else
|
||||||
|
echo "No files to validate after applying exclusions" > $VALIDATION_OUTPUT
|
||||||
|
fi
|
||||||
|
|
||||||
# Display output in logs
|
# Display output in logs
|
||||||
cat $VALIDATION_OUTPUT
|
cat $VALIDATION_OUTPUT
|
||||||
@@ -44,7 +75,7 @@ jobs:
|
|||||||
cat invalid_files.txt
|
cat invalid_files.txt
|
||||||
exit 1
|
exit 1
|
||||||
else
|
else
|
||||||
echo "All manifests are valid!"
|
echo "✅ All manifests are valid!"
|
||||||
fi
|
fi
|
||||||
continue-on-error: true
|
continue-on-error: true
|
||||||
|
|
||||||
|
|||||||
164
.gitea/workflows/update-readme.yaml
Normal file
164
.gitea/workflows/update-readme.yaml
Normal file
@@ -0,0 +1,164 @@
|
|||||||
|
name: 'Auto-update README'
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [ "main" ]
|
||||||
|
paths:
|
||||||
|
- 'k8s/**'
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: write
|
||||||
|
pull-requests: write
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
update-readme:
|
||||||
|
name: 'Generate README and Create MR'
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
with:
|
||||||
|
fetch-depth: 0
|
||||||
|
|
||||||
|
- name: Configure Git
|
||||||
|
run: |
|
||||||
|
git config --global user.name "Gitea Actions Bot"
|
||||||
|
git config --global user.email "actions@gitea.local"
|
||||||
|
|
||||||
|
- name: Generate README
|
||||||
|
run: |
|
||||||
|
echo "📋 Starting README generation..."
|
||||||
|
python3 .gitea/scripts/generate-readme.py k8s/ README.md
|
||||||
|
|
||||||
|
if [ -f "README.md" ]; then
|
||||||
|
echo "✅ README generated successfully"
|
||||||
|
echo "📄 File size: $(wc -c < README.md) bytes"
|
||||||
|
echo "📄 Lines: $(wc -l < README.md)"
|
||||||
|
else
|
||||||
|
echo "❌ README not generated"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
- name: Check for changes
|
||||||
|
id: check_changes
|
||||||
|
run: |
|
||||||
|
if git diff --quiet README.md; then
|
||||||
|
echo "No changes detected in README.md"
|
||||||
|
echo "has_changes=false" >> $GITHUB_OUTPUT
|
||||||
|
else
|
||||||
|
echo "Changes detected in README.md"
|
||||||
|
echo "has_changes=true" >> $GITHUB_OUTPUT
|
||||||
|
fi
|
||||||
|
|
||||||
|
- name: Create Pull Request
|
||||||
|
if: steps.check_changes.outputs.has_changes == 'true'
|
||||||
|
run: |
|
||||||
|
# Set variables
|
||||||
|
GITEA_URL="${{ secrets.GT_URL }}"
|
||||||
|
GITEA_TOKEN="${{ secrets.GT_TOKEN }}"
|
||||||
|
GITEA_OWNER="${{ secrets.GT_OWNER }}"
|
||||||
|
GITEA_REPO="${{ secrets.GT_REPO }}"
|
||||||
|
BRANCH_NAME="auto-update-readme-$(date +%Y%m%d-%H%M%S)"
|
||||||
|
|
||||||
|
echo "🔍 Configuration:"
|
||||||
|
echo "GITEA_URL: ${GITEA_URL:-NOT SET}"
|
||||||
|
echo "GITEA_OWNER: ${GITEA_OWNER:-NOT SET}"
|
||||||
|
echo "GITEA_REPO: ${GITEA_REPO:-NOT SET}"
|
||||||
|
echo "BRANCH_NAME: $BRANCH_NAME"
|
||||||
|
|
||||||
|
# Create and push new branch
|
||||||
|
echo "🌿 Creating branch: $BRANCH_NAME"
|
||||||
|
git checkout -b "$BRANCH_NAME"
|
||||||
|
git add README.md
|
||||||
|
git commit -m "Auto-update README with current k8s applications" \
|
||||||
|
-m "Generated by CI/CD workflow on $(date +%Y-%m-%d\ %H:%M:%S)" \
|
||||||
|
-m "This PR updates the README.md file with the current list of applications found in the k8s/ directory structure."
|
||||||
|
|
||||||
|
# Push branch to remote
|
||||||
|
echo "📤 Pushing branch to remote..."
|
||||||
|
git push origin "$BRANCH_NAME"
|
||||||
|
|
||||||
|
# Create Pull Request using Gitea API
|
||||||
|
echo "🔀 Creating Pull Request..."
|
||||||
|
|
||||||
|
PR_TITLE="Auto-update README with k8s applications"
|
||||||
|
|
||||||
|
# Create PR body
|
||||||
|
cat > /tmp/pr_body.json <<EOF
|
||||||
|
{
|
||||||
|
"title": "$PR_TITLE",
|
||||||
|
"body": "This PR automatically updates README.md based on the current k8s/ directory structure.\n\n## Changes\n- Updated application list in README.md\n- Applications are now synced with k8s/ folders\n\n## Review\nPlease review and merge if everything looks correct.\n\n---\n🤖 This PR was automatically generated by CI/CD workflow\n⏰ Generated at: $(date '+%Y-%m-%d %H:%M:%S')",
|
||||||
|
"head": "$BRANCH_NAME",
|
||||||
|
"base": "main"
|
||||||
|
}
|
||||||
|
EOF
|
||||||
|
|
||||||
|
# Create PR via API
|
||||||
|
echo "Making API request to: $GITEA_URL/api/v1/repos/$GITEA_OWNER/$GITEA_REPO/pulls"
|
||||||
|
echo "Request body:"
|
||||||
|
cat /tmp/pr_body.json
|
||||||
|
|
||||||
|
RESPONSE=$(curl -s -w "\nHTTP_CODE:%{http_code}" -X POST \
|
||||||
|
-H "Authorization: token $GITEA_TOKEN" \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
-d @/tmp/pr_body.json \
|
||||||
|
"$GITEA_URL/api/v1/repos/$GITEA_OWNER/$GITEA_REPO/pulls")
|
||||||
|
|
||||||
|
# Extract HTTP code and response body
|
||||||
|
HTTP_CODE=$(echo "$RESPONSE" | grep "HTTP_CODE:" | cut -d':' -f2)
|
||||||
|
RESPONSE_BODY=$(echo "$RESPONSE" | sed '/HTTP_CODE:/d')
|
||||||
|
|
||||||
|
echo "API Response (HTTP $HTTP_CODE):"
|
||||||
|
echo "$RESPONSE_BODY"
|
||||||
|
|
||||||
|
# Extract PR number and URL from response
|
||||||
|
PR_NUMBER=$(echo "$RESPONSE_BODY" | grep -o '"number":[0-9]*' | head -1 | cut -d':' -f2)
|
||||||
|
|
||||||
|
if [ -n "$PR_NUMBER" ] && [ "$HTTP_CODE" = "201" ]; then
|
||||||
|
echo "✅ Pull Request created successfully!"
|
||||||
|
echo "📝 PR #$PR_NUMBER"
|
||||||
|
echo "🔗 URL: $GITEA_URL/$GITEA_OWNER/$GITEA_REPO/pulls/$PR_NUMBER"
|
||||||
|
|
||||||
|
# Save PR info for summary
|
||||||
|
echo "pr_number=$PR_NUMBER" >> $GITHUB_OUTPUT
|
||||||
|
echo "pr_url=$GITEA_URL/$GITEA_OWNER/$GITEA_REPO/pulls/$PR_NUMBER" >> $GITHUB_OUTPUT
|
||||||
|
else
|
||||||
|
echo "⚠️ Failed to create Pull Request (HTTP $HTTP_CODE)"
|
||||||
|
echo "Response: $RESPONSE_BODY"
|
||||||
|
|
||||||
|
# Check if PR already exists
|
||||||
|
if echo "$RESPONSE_BODY" | grep -q "already exists"; then
|
||||||
|
echo "ℹ️ PR already exists for this branch"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
- name: Summary
|
||||||
|
if: always()
|
||||||
|
run: |
|
||||||
|
echo "## 📊 README Update Summary" >> $GITHUB_STEP_SUMMARY
|
||||||
|
|
||||||
|
if [ -f "README.md" ]; then
|
||||||
|
echo "- ✅ README generated successfully" >> $GITHUB_STEP_SUMMARY
|
||||||
|
|
||||||
|
if [ "${{ steps.check_changes.outputs.has_changes }}" = "true" ]; then
|
||||||
|
echo "- ✅ Changes detected" >> $GITHUB_STEP_SUMMARY
|
||||||
|
echo "- ✅ Pull Request created" >> $GITHUB_STEP_SUMMARY
|
||||||
|
|
||||||
|
if [ -n "${{ steps.create_pr.outputs.pr_number }}" ]; then
|
||||||
|
echo "" >> $GITHUB_STEP_SUMMARY
|
||||||
|
echo "**PR:** [#${{ steps.create_pr.outputs.pr_number }}](${{ steps.create_pr.outputs.pr_url }})" >> $GITHUB_STEP_SUMMARY
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
echo "- ℹ️ No changes detected - README already up to date" >> $GITHUB_STEP_SUMMARY
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
echo "- ❌ README generation failed" >> $GITHUB_STEP_SUMMARY
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "" >> $GITHUB_STEP_SUMMARY
|
||||||
|
echo "**Generated at:** $(date)" >> $GITHUB_STEP_SUMMARY
|
||||||
8
.gitignore
vendored
8
.gitignore
vendored
@@ -10,13 +10,12 @@
|
|||||||
crash.log
|
crash.log
|
||||||
crash.*.log
|
crash.*.log
|
||||||
|
|
||||||
# Exclude all .tfvars files, which are likely to contain sensitive data, such as
|
|
||||||
# password, private keys, and other secrets. These should not be part of version
|
|
||||||
# control as they are data points which are potentially sensitive and subject
|
|
||||||
# to change depending on the environment.
|
|
||||||
*.tfvars
|
*.tfvars
|
||||||
*.tfvars.json
|
*.tfvars.json
|
||||||
|
!*terraform.tfvars
|
||||||
|
|
||||||
|
# claude ai
|
||||||
|
.claude/
|
||||||
# Ignore override files as they are usually used to override resources locally and so
|
# Ignore override files as they are usually used to override resources locally and so
|
||||||
# are not checked in
|
# are not checked in
|
||||||
override.tf
|
override.tf
|
||||||
@@ -58,3 +57,4 @@ tags
|
|||||||
# Persistent undo
|
# Persistent undo
|
||||||
[._]*.un~
|
[._]*.un~
|
||||||
|
|
||||||
|
.DS_Store
|
||||||
|
|||||||
56
README.md
56
README.md
@@ -1,3 +1,59 @@
|
|||||||
# homelab
|
# homelab
|
||||||
|
|
||||||
ArgoCD homelab project
|
ArgoCD homelab project
|
||||||
|
|
||||||
|
## ArgoCD Applications Status
|
||||||
|
|
||||||
|
<table>
|
||||||
|
<tr>
|
||||||
|
<td valign="top" width="50%">
|
||||||
|
|
||||||
|
### Core Applications
|
||||||
|
|
||||||
|
| Application | Status |
|
||||||
|
| :--- | :---: |
|
||||||
|
| **argocd** | [](https://ag.hexor.cy/applications/argocd/argocd) |
|
||||||
|
| **authentik** | [](https://ag.hexor.cy/applications/argocd/authentik) |
|
||||||
|
| **cert-manager** | [](https://ag.hexor.cy/applications/argocd/cert-manager) |
|
||||||
|
| **external-secrets** | [](https://ag.hexor.cy/applications/argocd/external-secrets) |
|
||||||
|
| **kube-system-custom** | [](https://ag.hexor.cy/applications/argocd/kube-system-custom) |
|
||||||
|
| **kubernetes-dashboard** | [](https://ag.hexor.cy/applications/argocd/kubernetes-dashboard) |
|
||||||
|
| **postgresql** | [](https://ag.hexor.cy/applications/argocd/postgresql) |
|
||||||
|
| **prometheus** | [](https://ag.hexor.cy/applications/argocd/prometheus) |
|
||||||
|
| **system-upgrade** | [](https://ag.hexor.cy/applications/argocd/system-upgrade) |
|
||||||
|
|
||||||
|
### Games
|
||||||
|
|
||||||
|
| Application | Status |
|
||||||
|
| :--- | :---: |
|
||||||
|
| **beam-ng** | [](https://ag.hexor.cy/applications/argocd/beam-ng) |
|
||||||
|
| **counter-strike-16** | [](https://ag.hexor.cy/applications/argocd/counter-strike-16) |
|
||||||
|
| **minecraft** | [](https://ag.hexor.cy/applications/argocd/minecraft) |
|
||||||
|
</td>
|
||||||
|
<td valign="top" width="50%">
|
||||||
|
|
||||||
|
### Applications
|
||||||
|
|
||||||
|
| Application | Status |
|
||||||
|
| :--- | :---: |
|
||||||
|
| **gitea** | [](https://ag.hexor.cy/applications/argocd/gitea) |
|
||||||
|
| **greece-notifier** | [](https://ag.hexor.cy/applications/argocd/greece-notifier) |
|
||||||
|
| **hexound** | [](https://ag.hexor.cy/applications/argocd/hexound) |
|
||||||
|
| **immich** | [](https://ag.hexor.cy/applications/argocd/immich) |
|
||||||
|
| **jellyfin** | [](https://ag.hexor.cy/applications/argocd/jellyfin) |
|
||||||
|
| **k8s-secrets** | [](https://ag.hexor.cy/applications/argocd/k8s-secrets) |
|
||||||
|
| **khm** | [](https://ag.hexor.cy/applications/argocd/khm) |
|
||||||
|
| **paperless** | [](https://ag.hexor.cy/applications/argocd/paperless) |
|
||||||
|
| **pasarguard** | [](https://ag.hexor.cy/applications/argocd/pasarguard) |
|
||||||
|
| **qbittorent-nas** | [](https://ag.hexor.cy/applications/argocd/qbittorent-nas) |
|
||||||
|
| **rustdesk** | [](https://ag.hexor.cy/applications/argocd/rustdesk) |
|
||||||
|
| **sonarr-stack** | [](https://ag.hexor.cy/applications/argocd/sonarr-stack) |
|
||||||
|
| **stirling-pdf** | [](https://ag.hexor.cy/applications/argocd/stirling-pdf) |
|
||||||
|
| **syncthing** | [](https://ag.hexor.cy/applications/argocd/syncthing) |
|
||||||
|
| **tg-bots** | [](https://ag.hexor.cy/applications/argocd/tg-bots) |
|
||||||
|
| **vaultwarden** | [](https://ag.hexor.cy/applications/argocd/vaultwarden) |
|
||||||
|
| **vpn** | [](https://ag.hexor.cy/applications/argocd/vpn) |
|
||||||
|
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
|||||||
@@ -30,6 +30,27 @@ spec:
|
|||||||
containers:
|
containers:
|
||||||
- name: gitea
|
- name: gitea
|
||||||
image: 'gitea/gitea:latest'
|
image: 'gitea/gitea:latest'
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
memory: "512Mi"
|
||||||
|
cpu: "200m"
|
||||||
|
limits:
|
||||||
|
memory: "2Gi"
|
||||||
|
cpu: "1000m"
|
||||||
|
env:
|
||||||
|
- name: GITEA__service__REGISTER_MANUAL_CONFIRM
|
||||||
|
value: "true"
|
||||||
|
- name: GITEA__service__ENABLE_CAPTCHA
|
||||||
|
value: "false"
|
||||||
|
- name: GITEA__service__REQUIRE_CAPTCHA_FOR_LOGIN
|
||||||
|
value: "true"
|
||||||
|
- name: GITEA__service__REQUIRE_EXTERNAL_REGISTRATION_CAPTCHA
|
||||||
|
value: "true"
|
||||||
|
- name: GITEA__service__CAPTCHA_TYPE
|
||||||
|
value: "hcaptcha"
|
||||||
|
envFrom:
|
||||||
|
- secretRef:
|
||||||
|
name: gitea-recapcha-creds
|
||||||
ports:
|
ports:
|
||||||
- name: http
|
- name: http
|
||||||
containerPort: 3000
|
containerPort: 3000
|
||||||
@@ -40,6 +61,7 @@ spec:
|
|||||||
volumeMounts:
|
volumeMounts:
|
||||||
- name: storage
|
- name: storage
|
||||||
mountPath: /data
|
mountPath: /data
|
||||||
|
|
||||||
---
|
---
|
||||||
apiVersion: apps/v1
|
apiVersion: apps/v1
|
||||||
kind: Deployment
|
kind: Deployment
|
||||||
@@ -56,20 +78,65 @@ spec:
|
|||||||
app: gitea-runner
|
app: gitea-runner
|
||||||
spec:
|
spec:
|
||||||
nodeSelector:
|
nodeSelector:
|
||||||
#kubernetes.io/hostname: master.tail2fe2d.ts.net
|
kubernetes.io/hostname: home.homenet
|
||||||
kubernetes.io/hostname: nas.homenet
|
|
||||||
volumes:
|
volumes:
|
||||||
- name: docker-sock
|
- name: docker-sock
|
||||||
hostPath:
|
hostPath:
|
||||||
#path: /var/run/k3s/containerd/containerd.sock
|
|
||||||
path: /var/run/docker.sock
|
path: /var/run/docker.sock
|
||||||
type: Socket
|
type: Socket
|
||||||
|
- name: runner-data
|
||||||
|
emptyDir:
|
||||||
|
sizeLimit: 30Gi
|
||||||
|
affinity:
|
||||||
|
nodeAffinity:
|
||||||
|
preferredDuringSchedulingIgnoredDuringExecution:
|
||||||
|
- weight: 3
|
||||||
|
preference:
|
||||||
|
matchExpressions:
|
||||||
|
- key: kubernetes.io/hostname
|
||||||
|
operator: In
|
||||||
|
values:
|
||||||
|
- home.homenet
|
||||||
|
- weight: 1
|
||||||
|
preference:
|
||||||
|
matchExpressions:
|
||||||
|
- key: kubernetes.io/hostname
|
||||||
|
operator: In
|
||||||
|
values:
|
||||||
|
- master.tail2fe2d.ts.net
|
||||||
|
- weight: 2
|
||||||
|
preference:
|
||||||
|
matchExpressions:
|
||||||
|
- key: kubernetes.io/hostname
|
||||||
|
operator: In
|
||||||
|
values:
|
||||||
|
- nas.homenet
|
||||||
|
requiredDuringSchedulingIgnoredDuringExecution:
|
||||||
|
nodeSelectorTerms:
|
||||||
|
- matchExpressions:
|
||||||
|
- key: kubernetes.io/hostname
|
||||||
|
operator: In
|
||||||
|
values:
|
||||||
|
- home.homenet
|
||||||
|
- nas.homenet
|
||||||
|
- master.tail2fe2d.ts.net
|
||||||
containers:
|
containers:
|
||||||
- name: gitea-runner
|
- name: gitea-runner
|
||||||
image: gitea/act_runner:nightly
|
image: gitea/act_runner:nightly
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
cpu: "100m"
|
||||||
|
memory: "256Mi"
|
||||||
|
ephemeral-storage: "1Gi" # reserve ephemeral storage
|
||||||
|
limits:
|
||||||
|
cpu: "2000m"
|
||||||
|
memory: "4Gi"
|
||||||
|
ephemeral-storage: "28Gi" # hard cap for /data usage
|
||||||
volumeMounts:
|
volumeMounts:
|
||||||
- name: docker-sock
|
- name: docker-sock
|
||||||
mountPath: /var/run/docker.sock
|
mountPath: /var/run/docker.sock
|
||||||
|
- name: runner-data
|
||||||
|
mountPath: /data
|
||||||
env:
|
env:
|
||||||
- name: GITEA_INSTANCE_URL
|
- name: GITEA_INSTANCE_URL
|
||||||
value: "https://gt.hexor.cy"
|
value: "https://gt.hexor.cy"
|
||||||
@@ -82,4 +149,3 @@ spec:
|
|||||||
value: "k8s-runner"
|
value: "k8s-runner"
|
||||||
- name: GITEA_RUNNER_LABELS
|
- name: GITEA_RUNNER_LABELS
|
||||||
value: "ubuntu-latest:docker://ghcr.io/catthehacker/ubuntu:act-latest,ubuntu-22.04:docker://ghcr.io/catthehacker/ubuntu:act-22.04,ubuntu-20.04:docker://ghcr.io/catthehacker/ubuntu:act-20.04"
|
value: "ubuntu-latest:docker://ghcr.io/catthehacker/ubuntu:act-latest,ubuntu-22.04:docker://ghcr.io/catthehacker/ubuntu:act-22.04,ubuntu-20.04:docker://ghcr.io/catthehacker/ubuntu:act-20.04"
|
||||||
|
|
||||||
|
|||||||
@@ -23,3 +23,37 @@ spec:
|
|||||||
key: e475b5ab-ea3c-48a5-bb4c-a6bc552fc064
|
key: e475b5ab-ea3c-48a5-bb4c-a6bc552fc064
|
||||||
property: login.password
|
property: login.password
|
||||||
|
|
||||||
|
---
|
||||||
|
apiVersion: external-secrets.io/v1beta1
|
||||||
|
kind: ExternalSecret
|
||||||
|
metadata:
|
||||||
|
name: gitea-recapcha-creds
|
||||||
|
spec:
|
||||||
|
refreshInterval: 1m
|
||||||
|
target:
|
||||||
|
name: gitea-recapcha-creds
|
||||||
|
deletionPolicy: Delete
|
||||||
|
template:
|
||||||
|
type: Opaque
|
||||||
|
data:
|
||||||
|
GITEA__service__HCAPTCHA_SITEKEY: |-
|
||||||
|
{{ .HCAPTCHA_SITEKEY }}
|
||||||
|
GITEA__service__HCAPTCHA_SECRET: |-
|
||||||
|
{{ .HCAPTCHA_SECRET }}
|
||||||
|
data:
|
||||||
|
- secretKey: HCAPTCHA_SITEKEY
|
||||||
|
sourceRef:
|
||||||
|
storeRef:
|
||||||
|
name: vaultwarden-login
|
||||||
|
kind: ClusterSecretStore
|
||||||
|
remoteRef:
|
||||||
|
key: 89c8d8d2-6b53-42c5-805f-38a341ef163e
|
||||||
|
property: login.username
|
||||||
|
- secretKey: HCAPTCHA_SECRET
|
||||||
|
sourceRef:
|
||||||
|
storeRef:
|
||||||
|
name: vaultwarden-login
|
||||||
|
kind: ClusterSecretStore
|
||||||
|
remoteRef:
|
||||||
|
key: 89c8d8d2-6b53-42c5-805f-38a341ef163e
|
||||||
|
property: login.password
|
||||||
21
k8s/apps/greece-notifier/app.yaml
Normal file
21
k8s/apps/greece-notifier/app.yaml
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
apiVersion: argoproj.io/v1alpha1
|
||||||
|
kind: Application
|
||||||
|
metadata:
|
||||||
|
name: greece-notifier
|
||||||
|
namespace: argocd
|
||||||
|
spec:
|
||||||
|
project: apps
|
||||||
|
destination:
|
||||||
|
namespace: greece-notifier
|
||||||
|
server: https://kubernetes.default.svc
|
||||||
|
source:
|
||||||
|
repoURL: ssh://git@gt.hexor.cy:30022/ab/homelab.git
|
||||||
|
targetRevision: HEAD
|
||||||
|
path: k8s/apps/greece-notifier
|
||||||
|
syncPolicy:
|
||||||
|
automated:
|
||||||
|
selfHeal: true
|
||||||
|
prune: true
|
||||||
|
syncOptions:
|
||||||
|
- CreateNamespace=true
|
||||||
|
|
||||||
51
k8s/apps/greece-notifier/deployment.yaml
Normal file
51
k8s/apps/greece-notifier/deployment.yaml
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
---
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: greece-notifier
|
||||||
|
spec:
|
||||||
|
replicas: 1
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
app: greece-notifier
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
app: greece-notifier
|
||||||
|
spec:
|
||||||
|
nodeSelector:
|
||||||
|
kubernetes.io/hostname: nas.homenet
|
||||||
|
volumes:
|
||||||
|
- name: data
|
||||||
|
nfs:
|
||||||
|
server: nas.homenet
|
||||||
|
path: /mnt/storage/Storage/k8s/greece-notifier/
|
||||||
|
readOnly: false
|
||||||
|
containers:
|
||||||
|
- name: greece-notifier
|
||||||
|
image: ultradesu/greece-notifier:master
|
||||||
|
imagePullPolicy: Always
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
cpu: "100m"
|
||||||
|
memory: "256Mi"
|
||||||
|
limits:
|
||||||
|
cpu: "2000m"
|
||||||
|
memory: "1Gi"
|
||||||
|
volumeMounts:
|
||||||
|
- name: data
|
||||||
|
mountPath: /data
|
||||||
|
env:
|
||||||
|
- name: RUST_LOG
|
||||||
|
value: "info"
|
||||||
|
- name: ENDPOINT_BID
|
||||||
|
value: "56" # Cyprus id
|
||||||
|
- name: UPDATE_INTERVAL_MIN_SECS
|
||||||
|
value: "270"
|
||||||
|
- name: UPDATE_INTERVAL_MAX_SECS
|
||||||
|
value: "350"
|
||||||
|
- name: TELOXIDE_TOKEN
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
name: greece-notifier-creds
|
||||||
|
key: TELOXIDE_TOKEN
|
||||||
23
k8s/apps/greece-notifier/external-secrets.yaml
Normal file
23
k8s/apps/greece-notifier/external-secrets.yaml
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
---
|
||||||
|
apiVersion: external-secrets.io/v1beta1
|
||||||
|
kind: ExternalSecret
|
||||||
|
metadata:
|
||||||
|
name: greece-notifier-creds
|
||||||
|
spec:
|
||||||
|
target:
|
||||||
|
name: greece-notifier-creds
|
||||||
|
deletionPolicy: Delete
|
||||||
|
template:
|
||||||
|
type: Opaque
|
||||||
|
data:
|
||||||
|
TELOXIDE_TOKEN: |-
|
||||||
|
{{ .token }}
|
||||||
|
data:
|
||||||
|
- secretKey: token
|
||||||
|
sourceRef:
|
||||||
|
storeRef:
|
||||||
|
name: vaultwarden-login
|
||||||
|
kind: ClusterSecretStore
|
||||||
|
remoteRef:
|
||||||
|
key: 34e8f207-27ad-4b21-b114-84d3f7460a51
|
||||||
|
property: login.password
|
||||||
6
k8s/apps/greece-notifier/kustomization.yaml
Normal file
6
k8s/apps/greece-notifier/kustomization.yaml
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
apiVersion: kustomize.config.k8s.io/v1beta1
|
||||||
|
kind: Kustomization
|
||||||
|
|
||||||
|
resources:
|
||||||
|
- ./external-secrets.yaml
|
||||||
|
- ./deployment.yaml
|
||||||
@@ -24,6 +24,13 @@ spec:
|
|||||||
initContainers:
|
initContainers:
|
||||||
- name: git-cloner
|
- name: git-cloner
|
||||||
image: alpine/git
|
image: alpine/git
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
memory: "32Mi"
|
||||||
|
cpu: "50m"
|
||||||
|
limits:
|
||||||
|
memory: "128Mi"
|
||||||
|
cpu: "200m"
|
||||||
command:
|
command:
|
||||||
- git
|
- git
|
||||||
- clone
|
- clone
|
||||||
@@ -36,6 +43,13 @@ spec:
|
|||||||
containers:
|
containers:
|
||||||
- name: hexound
|
- name: hexound
|
||||||
image: trafex/php-nginx:3.8.0
|
image: trafex/php-nginx:3.8.0
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
memory: "64Mi"
|
||||||
|
cpu: "50m"
|
||||||
|
limits:
|
||||||
|
memory: "256Mi"
|
||||||
|
cpu: "200m"
|
||||||
volumeMounts:
|
volumeMounts:
|
||||||
- name: hexound-repo
|
- name: hexound-repo
|
||||||
mountPath: /var/www/html
|
mountPath: /var/www/html
|
||||||
|
|||||||
37
k8s/apps/hexound/ingress.yaml
Normal file
37
k8s/apps/hexound/ingress.yaml
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
---
|
||||||
|
apiVersion: networking.k8s.io/v1
|
||||||
|
kind: Ingress
|
||||||
|
metadata:
|
||||||
|
name: hexound-tls-ingress
|
||||||
|
annotations:
|
||||||
|
ingressClassName: traefik
|
||||||
|
cert-manager.io/cluster-issuer: letsencrypt
|
||||||
|
traefik.ingress.kubernetes.io/router.middlewares: kube-system-https-redirect@kubernetescrd
|
||||||
|
acme.cert-manager.io/http01-edit-in-place: "true"
|
||||||
|
spec:
|
||||||
|
rules:
|
||||||
|
- host: hexound.hexor.cy
|
||||||
|
http:
|
||||||
|
paths:
|
||||||
|
- path: /
|
||||||
|
pathType: Prefix
|
||||||
|
backend:
|
||||||
|
service:
|
||||||
|
name: hexound
|
||||||
|
port:
|
||||||
|
number: 80
|
||||||
|
- host: hexound.hexor.ru
|
||||||
|
http:
|
||||||
|
paths:
|
||||||
|
- path: /
|
||||||
|
pathType: Prefix
|
||||||
|
backend:
|
||||||
|
service:
|
||||||
|
name: hexound
|
||||||
|
port:
|
||||||
|
number: 80
|
||||||
|
tls:
|
||||||
|
- secretName: hexound-tls
|
||||||
|
hosts:
|
||||||
|
- hexound.hexor.cy
|
||||||
|
- hexound.hexor.ru
|
||||||
@@ -5,4 +5,5 @@ resources:
|
|||||||
- app.yaml
|
- app.yaml
|
||||||
- deployment.yaml
|
- deployment.yaml
|
||||||
- service.yaml
|
- service.yaml
|
||||||
|
- ingress.yaml
|
||||||
|
|
||||||
|
|||||||
@@ -17,6 +17,13 @@ spec:
|
|||||||
- name: immich-server
|
- name: immich-server
|
||||||
image: ghcr.io/immich-app/immich-server:release
|
image: ghcr.io/immich-app/immich-server:release
|
||||||
imagePullPolicy: Always
|
imagePullPolicy: Always
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
memory: "1Gi"
|
||||||
|
cpu: "500m"
|
||||||
|
limits:
|
||||||
|
memory: "4Gi"
|
||||||
|
cpu: "2000m"
|
||||||
ports:
|
ports:
|
||||||
- containerPort: 2283
|
- containerPort: 2283
|
||||||
env:
|
env:
|
||||||
@@ -43,13 +50,20 @@ spec:
|
|||||||
affinity:
|
affinity:
|
||||||
nodeAffinity:
|
nodeAffinity:
|
||||||
preferredDuringSchedulingIgnoredDuringExecution:
|
preferredDuringSchedulingIgnoredDuringExecution:
|
||||||
- weight: 100
|
- weight: 90
|
||||||
preference:
|
preference:
|
||||||
matchExpressions:
|
matchExpressions:
|
||||||
- key: kubernetes.io/hostname
|
- key: kubernetes.io/hostname
|
||||||
operator: In
|
operator: In
|
||||||
values:
|
values:
|
||||||
- home.homenet
|
- home.homenet
|
||||||
|
- weight: 10
|
||||||
|
preference:
|
||||||
|
matchExpressions:
|
||||||
|
- key: kubernetes.io/hostname
|
||||||
|
operator: In
|
||||||
|
values:
|
||||||
|
- nas.homenet
|
||||||
requiredDuringSchedulingIgnoredDuringExecution:
|
requiredDuringSchedulingIgnoredDuringExecution:
|
||||||
nodeSelectorTerms:
|
nodeSelectorTerms:
|
||||||
- matchExpressions:
|
- matchExpressions:
|
||||||
@@ -72,7 +86,7 @@ spec:
|
|||||||
- name: camera
|
- name: camera
|
||||||
nfs:
|
nfs:
|
||||||
server: nas.homenet
|
server: nas.homenet
|
||||||
path: /mnt/storage/Storage/Photos/Phone/
|
path: /mnt/storage/Storage/Syncthing-repos/PhoneCamera/
|
||||||
readOnly: true
|
readOnly: true
|
||||||
- name: localtime
|
- name: localtime
|
||||||
hostPath:
|
hostPath:
|
||||||
@@ -127,7 +141,7 @@ spec:
|
|||||||
- key: kubernetes.io/hostname
|
- key: kubernetes.io/hostname
|
||||||
operator: In
|
operator: In
|
||||||
values:
|
values:
|
||||||
- home.homenet
|
- nas.homenet
|
||||||
|
|
||||||
topologySpreadConstraints:
|
topologySpreadConstraints:
|
||||||
- maxSkew: 2
|
- maxSkew: 2
|
||||||
@@ -140,6 +154,13 @@ spec:
|
|||||||
- name: immich-ml
|
- name: immich-ml
|
||||||
image: ghcr.io/immich-app/immich-machine-learning:release
|
image: ghcr.io/immich-app/immich-machine-learning:release
|
||||||
imagePullPolicy: Always
|
imagePullPolicy: Always
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
memory: "2Gi"
|
||||||
|
cpu: "1000m"
|
||||||
|
limits:
|
||||||
|
memory: "8Gi"
|
||||||
|
cpu: "4000m"
|
||||||
env:
|
env:
|
||||||
- name: TZ
|
- name: TZ
|
||||||
value: Asia/Nicosia
|
value: Asia/Nicosia
|
||||||
@@ -174,6 +195,13 @@ spec:
|
|||||||
containers:
|
containers:
|
||||||
- name: redis
|
- name: redis
|
||||||
image: redis:6.2-alpine
|
image: redis:6.2-alpine
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
memory: "128Mi"
|
||||||
|
cpu: "100m"
|
||||||
|
limits:
|
||||||
|
memory: "512Mi"
|
||||||
|
cpu: "500m"
|
||||||
readinessProbe:
|
readinessProbe:
|
||||||
exec:
|
exec:
|
||||||
command: ["redis-cli", "ping"]
|
command: ["redis-cli", "ping"]
|
||||||
|
|||||||
@@ -1,5 +1,12 @@
|
|||||||
image:
|
image:
|
||||||
tag: 10.10.7
|
tag: 10.10.7
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
memory: "2Gi"
|
||||||
|
cpu: "1000m"
|
||||||
|
limits:
|
||||||
|
memory: "8Gi"
|
||||||
|
cpu: "4000m"
|
||||||
nodeSelector:
|
nodeSelector:
|
||||||
kubernetes.io/hostname: master.tail2fe2d.ts.net
|
kubernetes.io/hostname: master.tail2fe2d.ts.net
|
||||||
persistence:
|
persistence:
|
||||||
|
|||||||
21
k8s/apps/k8s-secrets/app.yaml
Normal file
21
k8s/apps/k8s-secrets/app.yaml
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
apiVersion: argoproj.io/v1alpha1
|
||||||
|
kind: Application
|
||||||
|
metadata:
|
||||||
|
name: k8s-secrets
|
||||||
|
namespace: argocd
|
||||||
|
spec:
|
||||||
|
project: apps
|
||||||
|
destination:
|
||||||
|
namespace: k8s-secret
|
||||||
|
server: https://kubernetes.default.svc
|
||||||
|
source:
|
||||||
|
repoURL: ssh://git@gt.hexor.cy:30022/ab/homelab.git
|
||||||
|
targetRevision: HEAD
|
||||||
|
path: k8s/apps/k8s-secrets
|
||||||
|
syncPolicy:
|
||||||
|
automated:
|
||||||
|
selfHeal: true
|
||||||
|
prune: true
|
||||||
|
syncOptions:
|
||||||
|
- CreateNamespace=true
|
||||||
|
|
||||||
63
k8s/apps/k8s-secrets/deployment.yaml
Normal file
63
k8s/apps/k8s-secrets/deployment.yaml
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: secret-reader
|
||||||
|
labels:
|
||||||
|
app: secret-reader
|
||||||
|
spec:
|
||||||
|
replicas: 1
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
app: secret-reader
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
app: secret-reader
|
||||||
|
spec:
|
||||||
|
serviceAccountName: secret-reader
|
||||||
|
nodeSelector:
|
||||||
|
kubernetes.io/os: linux
|
||||||
|
containers:
|
||||||
|
- name: secret-reader
|
||||||
|
image: ultradesu/k8s-secrets:0.1.1
|
||||||
|
imagePullPolicy: Always
|
||||||
|
args:
|
||||||
|
- "--secrets"
|
||||||
|
- "openai-creds"
|
||||||
|
- "--namespace"
|
||||||
|
- "k8s-secret"
|
||||||
|
- "--port"
|
||||||
|
- "3000"
|
||||||
|
ports:
|
||||||
|
- containerPort: 3000
|
||||||
|
name: http
|
||||||
|
env:
|
||||||
|
- name: RUST_LOG
|
||||||
|
value: "info"
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
memory: "64Mi"
|
||||||
|
cpu: "50m"
|
||||||
|
limits:
|
||||||
|
memory: "128Mi"
|
||||||
|
cpu: "100m"
|
||||||
|
livenessProbe:
|
||||||
|
httpGet:
|
||||||
|
path: /health
|
||||||
|
port: http
|
||||||
|
initialDelaySeconds: 10
|
||||||
|
periodSeconds: 10
|
||||||
|
readinessProbe:
|
||||||
|
httpGet:
|
||||||
|
path: /health
|
||||||
|
port: http
|
||||||
|
initialDelaySeconds: 5
|
||||||
|
periodSeconds: 5
|
||||||
|
securityContext:
|
||||||
|
runAsNonRoot: true
|
||||||
|
runAsUser: 1000
|
||||||
|
allowPrivilegeEscalation: false
|
||||||
|
readOnlyRootFilesystem: true
|
||||||
|
capabilities:
|
||||||
|
drop:
|
||||||
|
- ALL
|
||||||
44
k8s/apps/k8s-secrets/external-secret.yaml
Normal file
44
k8s/apps/k8s-secrets/external-secret.yaml
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
---
|
||||||
|
apiVersion: external-secrets.io/v1beta1
|
||||||
|
kind: ExternalSecret
|
||||||
|
metadata:
|
||||||
|
name: openai-creds
|
||||||
|
spec:
|
||||||
|
target:
|
||||||
|
name: openai-creds
|
||||||
|
deletionPolicy: Delete
|
||||||
|
template:
|
||||||
|
type: Opaque
|
||||||
|
data:
|
||||||
|
USER: |-
|
||||||
|
{{ .user }}
|
||||||
|
PASS: |-
|
||||||
|
{{ .pass }}
|
||||||
|
TOTP: |-
|
||||||
|
{{ .totp }}
|
||||||
|
data:
|
||||||
|
- secretKey: user
|
||||||
|
sourceRef:
|
||||||
|
storeRef:
|
||||||
|
name: vaultwarden-login
|
||||||
|
kind: ClusterSecretStore
|
||||||
|
remoteRef:
|
||||||
|
key: a485f323-fd47-40ee-a5cf-40891b1f963c
|
||||||
|
property: login.username
|
||||||
|
- secretKey: pass
|
||||||
|
sourceRef:
|
||||||
|
storeRef:
|
||||||
|
name: vaultwarden-login
|
||||||
|
kind: ClusterSecretStore
|
||||||
|
remoteRef:
|
||||||
|
key: a485f323-fd47-40ee-a5cf-40891b1f963c
|
||||||
|
property: login.password
|
||||||
|
- secretKey: totp
|
||||||
|
sourceRef:
|
||||||
|
storeRef:
|
||||||
|
name: vaultwarden-login
|
||||||
|
kind: ClusterSecretStore
|
||||||
|
remoteRef:
|
||||||
|
key: a485f323-fd47-40ee-a5cf-40891b1f963c
|
||||||
|
property: login.totp
|
||||||
|
|
||||||
20
k8s/apps/k8s-secrets/rbac.yaml
Normal file
20
k8s/apps/k8s-secrets/rbac.yaml
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
apiVersion: rbac.authorization.k8s.io/v1
|
||||||
|
kind: Role
|
||||||
|
metadata:
|
||||||
|
name: secret-reader
|
||||||
|
rules:
|
||||||
|
- apiGroups: [""]
|
||||||
|
resources: ["secrets"]
|
||||||
|
verbs: ["get", "list"]
|
||||||
|
---
|
||||||
|
apiVersion: rbac.authorization.k8s.io/v1
|
||||||
|
kind: RoleBinding
|
||||||
|
metadata:
|
||||||
|
name: secret-reader
|
||||||
|
roleRef:
|
||||||
|
apiGroup: rbac.authorization.k8s.io
|
||||||
|
kind: Role
|
||||||
|
name: secret-reader
|
||||||
|
subjects:
|
||||||
|
- kind: ServiceAccount
|
||||||
|
name: secret-reader
|
||||||
6
k8s/apps/k8s-secrets/service-account.yaml
Normal file
6
k8s/apps/k8s-secrets/service-account.yaml
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
apiVersion: v1
|
||||||
|
kind: ServiceAccount
|
||||||
|
metadata:
|
||||||
|
name: secret-reader
|
||||||
|
labels:
|
||||||
|
app: secret-reader
|
||||||
15
k8s/apps/k8s-secrets/service.yaml
Normal file
15
k8s/apps/k8s-secrets/service.yaml
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
apiVersion: v1
|
||||||
|
kind: Service
|
||||||
|
metadata:
|
||||||
|
name: secret-reader
|
||||||
|
labels:
|
||||||
|
app: secret-reader
|
||||||
|
spec:
|
||||||
|
type: ClusterIP
|
||||||
|
selector:
|
||||||
|
app: secret-reader
|
||||||
|
ports:
|
||||||
|
- port: 80
|
||||||
|
targetPort: 3000
|
||||||
|
protocol: TCP
|
||||||
|
name: http
|
||||||
@@ -23,6 +23,13 @@ spec:
|
|||||||
- name: khm
|
- name: khm
|
||||||
image: 'ultradesu/khm:latest'
|
image: 'ultradesu/khm:latest'
|
||||||
imagePullPolicy: Always
|
imagePullPolicy: Always
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
memory: "256Mi"
|
||||||
|
cpu: "100m"
|
||||||
|
limits:
|
||||||
|
memory: "1Gi"
|
||||||
|
cpu: "500m"
|
||||||
command:
|
command:
|
||||||
- /bin/sh
|
- /bin/sh
|
||||||
- -c
|
- -c
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
apiVersion: external-secrets.io/v1beta1
|
apiVersion: external-secrets.io/v1beta1
|
||||||
kind: ExternalSecret
|
kind: ExternalSecret
|
||||||
metadata:
|
metadata:
|
||||||
name: postgres-creds
|
name: postgres-and-oauth-creds
|
||||||
spec:
|
spec:
|
||||||
target:
|
target:
|
||||||
name: postgres-creds
|
name: postgres-creds
|
||||||
|
|||||||
@@ -8,12 +8,12 @@ nodeSelector:
|
|||||||
kubernetes.io/hostname: nas.homenet
|
kubernetes.io/hostname: nas.homenet
|
||||||
|
|
||||||
resources:
|
resources:
|
||||||
limits:
|
|
||||||
cpu: 1000m
|
|
||||||
memory: 1Gi
|
|
||||||
requests:
|
requests:
|
||||||
cpu: 200m
|
memory: "512Mi"
|
||||||
memory: 256Mi
|
cpu: "200m"
|
||||||
|
limits:
|
||||||
|
memory: "2Gi"
|
||||||
|
cpu: "1000m"
|
||||||
|
|
||||||
service:
|
service:
|
||||||
type: ClusterIP
|
type: ClusterIP
|
||||||
|
|||||||
@@ -1,8 +1,22 @@
|
|||||||
image:
|
image:
|
||||||
tag: 2.15.3
|
tag: 2.19.3
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
memory: "1Gi"
|
||||||
|
cpu: "500m"
|
||||||
|
limits:
|
||||||
|
memory: "4Gi"
|
||||||
|
cpu: "2000m"
|
||||||
initContainers:
|
initContainers:
|
||||||
install-tesseract-langs:
|
install-tesseract-langs:
|
||||||
image: ghcr.io/paperless-ngx/paperless-ngx:2.15.1
|
image: ghcr.io/paperless-ngx/paperless-ngx:2.18.2
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
memory: "256Mi"
|
||||||
|
cpu: "100m"
|
||||||
|
limits:
|
||||||
|
memory: "1Gi"
|
||||||
|
cpu: "500m"
|
||||||
command: ["/bin/sh", "-c"]
|
command: ["/bin/sh", "-c"]
|
||||||
args:
|
args:
|
||||||
- apt-get update && apt-get install -y --reinstall tesseract-ocr-rus tesseract-ocr-jpn tesseract-ocr-chi-sim tesseract-ocr-eng tesseract-ocr-ell && cp -v -r /usr/share/tesseract-ocr/5/tessdata/* /custom-tessdata/
|
- apt-get update && apt-get install -y --reinstall tesseract-ocr-rus tesseract-ocr-jpn tesseract-ocr-chi-sim tesseract-ocr-eng tesseract-ocr-ell && cp -v -r /usr/share/tesseract-ocr/5/tessdata/* /custom-tessdata/
|
||||||
|
|||||||
@@ -8,12 +8,12 @@ nodeSelector:
|
|||||||
kubernetes.io/hostname: nas.homenet
|
kubernetes.io/hostname: nas.homenet
|
||||||
|
|
||||||
resources:
|
resources:
|
||||||
limits:
|
|
||||||
cpu: 500m
|
|
||||||
memory: 512Mi
|
|
||||||
requests:
|
requests:
|
||||||
cpu: 100m
|
memory: "256Mi"
|
||||||
memory: 128Mi
|
cpu: "100m"
|
||||||
|
limits:
|
||||||
|
memory: "1Gi"
|
||||||
|
cpu: "500m"
|
||||||
|
|
||||||
service:
|
service:
|
||||||
type: ClusterIP
|
type: ClusterIP
|
||||||
|
|||||||
21
k8s/apps/pasarguard/app.yaml
Normal file
21
k8s/apps/pasarguard/app.yaml
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
apiVersion: argoproj.io/v1alpha1
|
||||||
|
kind: Application
|
||||||
|
metadata:
|
||||||
|
name: pasarguard
|
||||||
|
namespace: argocd
|
||||||
|
spec:
|
||||||
|
project: apps
|
||||||
|
destination:
|
||||||
|
namespace: pasarguard
|
||||||
|
server: https://kubernetes.default.svc
|
||||||
|
source:
|
||||||
|
repoURL: ssh://git@gt.hexor.cy:30022/ab/homelab.git
|
||||||
|
targetRevision: HEAD
|
||||||
|
path: k8s/apps/pasarguard
|
||||||
|
syncPolicy:
|
||||||
|
automated:
|
||||||
|
selfHeal: true
|
||||||
|
prune: true
|
||||||
|
syncOptions:
|
||||||
|
- CreateNamespace=true
|
||||||
|
|
||||||
14
k8s/apps/pasarguard/certificate.yaml
Normal file
14
k8s/apps/pasarguard/certificate.yaml
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
---
|
||||||
|
apiVersion: cert-manager.io/v1
|
||||||
|
kind: Certificate
|
||||||
|
metadata:
|
||||||
|
name: pasarguard-tls
|
||||||
|
labels:
|
||||||
|
app: pasarguard
|
||||||
|
spec:
|
||||||
|
secretName: pasarguard-tls
|
||||||
|
issuerRef:
|
||||||
|
name: letsencrypt
|
||||||
|
kind: ClusterIssuer
|
||||||
|
dnsNames:
|
||||||
|
- ps.hexor.cy
|
||||||
330
k8s/apps/pasarguard/daemonset.yaml
Normal file
330
k8s/apps/pasarguard/daemonset.yaml
Normal file
@@ -0,0 +1,330 @@
|
|||||||
|
---
|
||||||
|
apiVersion: v1
|
||||||
|
kind: ServiceAccount
|
||||||
|
metadata:
|
||||||
|
name: pasarguard-node
|
||||||
|
labels:
|
||||||
|
app: pasarguard-node
|
||||||
|
---
|
||||||
|
apiVersion: rbac.authorization.k8s.io/v1
|
||||||
|
kind: Role
|
||||||
|
metadata:
|
||||||
|
name: pasarguard-node-configmap
|
||||||
|
labels:
|
||||||
|
app: pasarguard-node
|
||||||
|
rules:
|
||||||
|
- apiGroups: [""]
|
||||||
|
resources: ["configmaps"]
|
||||||
|
verbs: ["get", "list", "create", "update", "patch"]
|
||||||
|
- apiGroups: ["cert-manager.io"]
|
||||||
|
resources: ["certificates"]
|
||||||
|
verbs: ["get", "list", "create", "update", "patch", "delete"]
|
||||||
|
- apiGroups: [""]
|
||||||
|
resources: ["secrets"]
|
||||||
|
verbs: ["get", "list"]
|
||||||
|
- apiGroups: [""]
|
||||||
|
resources: ["services", "endpoints"]
|
||||||
|
verbs: ["get", "list", "create", "update", "patch", "delete"]
|
||||||
|
---
|
||||||
|
apiVersion: rbac.authorization.k8s.io/v1
|
||||||
|
kind: RoleBinding
|
||||||
|
metadata:
|
||||||
|
name: pasarguard-node-configmap
|
||||||
|
labels:
|
||||||
|
app: pasarguard-node
|
||||||
|
roleRef:
|
||||||
|
apiGroup: rbac.authorization.k8s.io
|
||||||
|
kind: Role
|
||||||
|
name: pasarguard-node-configmap
|
||||||
|
subjects:
|
||||||
|
- kind: ServiceAccount
|
||||||
|
name: pasarguard-node
|
||||||
|
---
|
||||||
|
apiVersion: rbac.authorization.k8s.io/v1
|
||||||
|
kind: ClusterRole
|
||||||
|
metadata:
|
||||||
|
name: pasarguard-node-reader
|
||||||
|
labels:
|
||||||
|
app: pasarguard-node
|
||||||
|
rules:
|
||||||
|
- apiGroups: [""]
|
||||||
|
resources: ["nodes"]
|
||||||
|
verbs: ["get", "list"]
|
||||||
|
---
|
||||||
|
apiVersion: rbac.authorization.k8s.io/v1
|
||||||
|
kind: ClusterRoleBinding
|
||||||
|
metadata:
|
||||||
|
name: pasarguard-node-reader
|
||||||
|
labels:
|
||||||
|
app: pasarguard-node
|
||||||
|
roleRef:
|
||||||
|
apiGroup: rbac.authorization.k8s.io
|
||||||
|
kind: ClusterRole
|
||||||
|
name: pasarguard-node-reader
|
||||||
|
subjects:
|
||||||
|
- kind: ServiceAccount
|
||||||
|
name: pasarguard-node
|
||||||
|
namespace: pasarguard
|
||||||
|
---
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: DaemonSet
|
||||||
|
metadata:
|
||||||
|
name: pasarguard-node
|
||||||
|
labels:
|
||||||
|
app: pasarguard-node
|
||||||
|
spec:
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
app: pasarguard-node
|
||||||
|
revisionHistoryLimit: 3
|
||||||
|
updateStrategy:
|
||||||
|
type: RollingUpdate
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
app: pasarguard-node
|
||||||
|
spec:
|
||||||
|
serviceAccountName: pasarguard-node
|
||||||
|
hostNetwork: true
|
||||||
|
affinity:
|
||||||
|
nodeAffinity:
|
||||||
|
requiredDuringSchedulingIgnoredDuringExecution:
|
||||||
|
nodeSelectorTerms:
|
||||||
|
- matchExpressions:
|
||||||
|
- key: xray-node-address
|
||||||
|
operator: Exists
|
||||||
|
initContainers:
|
||||||
|
- name: init-uuid
|
||||||
|
image: bitnami/kubectl:latest
|
||||||
|
env:
|
||||||
|
- name: GODEBUG
|
||||||
|
value: "x509sha1=1"
|
||||||
|
- name: NODE_NAME
|
||||||
|
valueFrom:
|
||||||
|
fieldRef:
|
||||||
|
fieldPath: spec.nodeName
|
||||||
|
command:
|
||||||
|
- /bin/bash
|
||||||
|
- -c
|
||||||
|
- |
|
||||||
|
set -e
|
||||||
|
echo "Started"
|
||||||
|
# NODE_NAME is already set via environment variable
|
||||||
|
NAMESPACE=$(cat /var/run/secrets/kubernetes.io/serviceaccount/namespace)
|
||||||
|
|
||||||
|
# Get DNS name from node label xray-node-address
|
||||||
|
DNS_NAME=$(kubectl get node "${NODE_NAME}" -o jsonpath='{.metadata.labels.xray-node-address}')
|
||||||
|
|
||||||
|
if [ -z "${DNS_NAME}" ]; then
|
||||||
|
echo "ERROR: Node ${NODE_NAME} does not have label 'xray-node-address'"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "Node: ${NODE_NAME}"
|
||||||
|
echo "DNS Name from label: ${DNS_NAME}"
|
||||||
|
|
||||||
|
# Use DNS name for ConfigMap name to ensure uniqueness
|
||||||
|
CONFIGMAP_NAME="node-uuid-${DNS_NAME//./-}"
|
||||||
|
|
||||||
|
echo "Checking ConfigMap: ${CONFIGMAP_NAME}"
|
||||||
|
|
||||||
|
# Check if ConfigMap exists and get UUID
|
||||||
|
if kubectl get configmap "${CONFIGMAP_NAME}" -n "${NAMESPACE}" &>/dev/null; then
|
||||||
|
echo "ConfigMap exists, reading UUID..."
|
||||||
|
API_KEY=$(kubectl get configmap "${CONFIGMAP_NAME}" -n "${NAMESPACE}" -o jsonpath='{.data.API_KEY}')
|
||||||
|
|
||||||
|
if [ -z "${API_KEY}" ]; then
|
||||||
|
echo "UUID not found in ConfigMap, generating new one..."
|
||||||
|
API_KEY=$(cat /proc/sys/kernel/random/uuid)
|
||||||
|
kubectl patch configmap "${CONFIGMAP_NAME}" -n "${NAMESPACE}" --type merge -p "{\"data\":{\"API_KEY\":\"${API_KEY}\"}}"
|
||||||
|
else
|
||||||
|
echo "Using existing UUID from ConfigMap"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
echo "ConfigMap does not exist, creating new one..."
|
||||||
|
API_KEY=$(cat /proc/sys/kernel/random/uuid)
|
||||||
|
kubectl create configmap "${CONFIGMAP_NAME}" -n "${NAMESPACE}" \
|
||||||
|
--from-literal=API_KEY="${API_KEY}" \
|
||||||
|
--from-literal=NODE_NAME="${NODE_NAME}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Save UUID and node info to shared volume for the main container
|
||||||
|
echo -n "${API_KEY}" > /shared/api-key
|
||||||
|
echo -n "${NODE_NAME}" > /shared/node-name
|
||||||
|
echo -n "${CONFIGMAP_NAME}" > /shared/configmap-name
|
||||||
|
echo "UUID initialized: ${API_KEY}"
|
||||||
|
echo "Node name: ${NODE_NAME}"
|
||||||
|
echo "ConfigMap: ${CONFIGMAP_NAME}"
|
||||||
|
|
||||||
|
# Create Certificate for this node using DNS name from label
|
||||||
|
CERT_NAME="pasarguard-node-${DNS_NAME//./-}"
|
||||||
|
|
||||||
|
echo "Creating Certificate: ${CERT_NAME} for ${DNS_NAME}"
|
||||||
|
|
||||||
|
# Check if Certificate already exists
|
||||||
|
if ! kubectl get certificate "${CERT_NAME}" -n "${NAMESPACE}" &>/dev/null; then
|
||||||
|
echo "Certificate does not exist, creating..."
|
||||||
|
cat <<EOF | kubectl apply -f -
|
||||||
|
apiVersion: cert-manager.io/v1
|
||||||
|
kind: Certificate
|
||||||
|
metadata:
|
||||||
|
name: ${CERT_NAME}
|
||||||
|
namespace: ${NAMESPACE}
|
||||||
|
spec:
|
||||||
|
secretName: ${CERT_NAME}-tls
|
||||||
|
issuerRef:
|
||||||
|
name: letsencrypt
|
||||||
|
kind: ClusterIssuer
|
||||||
|
dnsNames:
|
||||||
|
- ${DNS_NAME}
|
||||||
|
EOF
|
||||||
|
else
|
||||||
|
echo "Certificate already exists"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Wait for certificate to be ready
|
||||||
|
|
||||||
|
echo "Waiting for certificate to be ready..."
|
||||||
|
for i in {1..600}; do
|
||||||
|
if kubectl get secret "${CERT_NAME}-tls" -n "${NAMESPACE}" &>/dev/null; then
|
||||||
|
echo "Certificate secret is ready!"
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
echo "Waiting for certificate... ($i/600)"
|
||||||
|
sleep 1
|
||||||
|
done
|
||||||
|
|
||||||
|
if ! kubectl get secret "${CERT_NAME}-tls" -n "${NAMESPACE}" &>/dev/null; then
|
||||||
|
echo "WARNING: Certificate secret not ready after 600 seconds"
|
||||||
|
else
|
||||||
|
# Extract certificate and key from secret to shared volume
|
||||||
|
echo "Extracting certificate and key..."
|
||||||
|
kubectl get secret "${CERT_NAME}-tls" -n "${NAMESPACE}" -o jsonpath='{.data.tls\.crt}' | base64 -d > /shared/tls.crt
|
||||||
|
kubectl get secret "${CERT_NAME}-tls" -n "${NAMESPACE}" -o jsonpath='{.data.tls\.key}' | base64 -d > /shared/tls.key
|
||||||
|
echo "Certificate and key extracted successfully."
|
||||||
|
cat /shared/tls.crt
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Create individual Service and Endpoints for this node
|
||||||
|
# Take only first part of node name before first dot
|
||||||
|
NODE_SHORT_NAME="${NODE_NAME%%.*}"
|
||||||
|
SERVICE_NAME="${NODE_SHORT_NAME}"
|
||||||
|
|
||||||
|
# Get node internal IP (take only first IP if multiple)
|
||||||
|
NODE_IP=$(kubectl get node "${NODE_NAME}" -o jsonpath='{.status.addresses[?(@.type=="InternalIP")].address}' | awk '{print $1}')
|
||||||
|
|
||||||
|
echo "Creating Service: ${SERVICE_NAME} for node ${NODE_NAME} (short: ${NODE_SHORT_NAME}) with IP ${NODE_IP}"
|
||||||
|
|
||||||
|
# Create Service without selector
|
||||||
|
cat <<EOF | kubectl apply -f -
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Service
|
||||||
|
metadata:
|
||||||
|
name: ${SERVICE_NAME}
|
||||||
|
namespace: ${NAMESPACE}
|
||||||
|
labels:
|
||||||
|
app: pasarguard-node
|
||||||
|
node: ${NODE_NAME}
|
||||||
|
spec:
|
||||||
|
clusterIP: None
|
||||||
|
ports:
|
||||||
|
- name: api
|
||||||
|
port: 62050
|
||||||
|
protocol: TCP
|
||||||
|
targetPort: 62050
|
||||||
|
---
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Endpoints
|
||||||
|
metadata:
|
||||||
|
name: ${SERVICE_NAME}
|
||||||
|
namespace: ${NAMESPACE}
|
||||||
|
labels:
|
||||||
|
app: pasarguard-node
|
||||||
|
node: ${NODE_NAME}
|
||||||
|
subsets:
|
||||||
|
- addresses:
|
||||||
|
- ip: ${NODE_IP}
|
||||||
|
nodeName: ${NODE_NAME}
|
||||||
|
ports:
|
||||||
|
- name: api
|
||||||
|
port: 62050
|
||||||
|
protocol: TCP
|
||||||
|
EOF
|
||||||
|
|
||||||
|
echo "Service created: ${SERVICE_NAME}.${NAMESPACE}.svc.cluster.local -> ${NODE_IP}:62050"
|
||||||
|
volumeMounts:
|
||||||
|
- name: shared-data
|
||||||
|
mountPath: /shared
|
||||||
|
containers:
|
||||||
|
- name: pasarguard-node
|
||||||
|
image: 'pasarguard/node:v0.1.1'
|
||||||
|
imagePullPolicy: Always
|
||||||
|
command:
|
||||||
|
- /bin/sh
|
||||||
|
- -c
|
||||||
|
- |
|
||||||
|
# Read API_KEY from shared volume created by init container
|
||||||
|
if [ -f /shared/api-key ]; then
|
||||||
|
export API_KEY=$(cat /shared/api-key)
|
||||||
|
echo "Loaded API_KEY from shared volume"
|
||||||
|
else
|
||||||
|
echo "WARNING: API_KEY file not found, using default"
|
||||||
|
fi
|
||||||
|
|
||||||
|
cd /app
|
||||||
|
exec ./main
|
||||||
|
ports:
|
||||||
|
- name: api
|
||||||
|
containerPort: 62050
|
||||||
|
protocol: TCP
|
||||||
|
env:
|
||||||
|
- name: NODE_NAME
|
||||||
|
valueFrom:
|
||||||
|
fieldRef:
|
||||||
|
fieldPath: spec.nodeName
|
||||||
|
- name: NODE_HOST
|
||||||
|
value: "0.0.0.0"
|
||||||
|
- name: SERVICE_PORT
|
||||||
|
value: "62050"
|
||||||
|
- name: SERVICE_PROTOCOL
|
||||||
|
value: "grpc"
|
||||||
|
- name: DEBUG
|
||||||
|
value: "true"
|
||||||
|
- name: SSL_CERT_FILE
|
||||||
|
value: "/shared/tls.crt"
|
||||||
|
- name: SSL_KEY_FILE
|
||||||
|
value: "/shared/tls.key"
|
||||||
|
- name: XRAY_EXECUTABLE_PATH
|
||||||
|
value: "/usr/local/bin/xray"
|
||||||
|
- name: XRAY_ASSETS_PATH
|
||||||
|
value: "/usr/local/share/xray"
|
||||||
|
- name: API_KEY
|
||||||
|
value: "change-this-to-a-secure-uuid"
|
||||||
|
livenessProbe:
|
||||||
|
tcpSocket:
|
||||||
|
port: 62050
|
||||||
|
initialDelaySeconds: 30
|
||||||
|
periodSeconds: 10
|
||||||
|
timeoutSeconds: 5
|
||||||
|
failureThreshold: 3
|
||||||
|
readinessProbe:
|
||||||
|
tcpSocket:
|
||||||
|
port: 62050
|
||||||
|
initialDelaySeconds: 10
|
||||||
|
periodSeconds: 5
|
||||||
|
timeoutSeconds: 3
|
||||||
|
failureThreshold: 3
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
memory: "128Mi"
|
||||||
|
cpu: "100m"
|
||||||
|
limits:
|
||||||
|
memory: "512Mi"
|
||||||
|
cpu: "500m"
|
||||||
|
volumeMounts:
|
||||||
|
- name: shared-data
|
||||||
|
mountPath: /shared
|
||||||
|
readOnly: true
|
||||||
|
volumes:
|
||||||
|
- name: shared-data
|
||||||
|
emptyDir: {}
|
||||||
84
k8s/apps/pasarguard/deployment.yaml
Normal file
84
k8s/apps/pasarguard/deployment.yaml
Normal file
@@ -0,0 +1,84 @@
|
|||||||
|
---
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: pasarguard
|
||||||
|
labels:
|
||||||
|
app: pasarguard
|
||||||
|
annotations:
|
||||||
|
reloader.stakater.com/auto: "true"
|
||||||
|
spec:
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
app: pasarguard
|
||||||
|
replicas: 1
|
||||||
|
strategy:
|
||||||
|
type: RollingUpdate
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
app: pasarguard
|
||||||
|
spec:
|
||||||
|
nodeSelector:
|
||||||
|
kubernetes.io/hostname: master.tail2fe2d.ts.net
|
||||||
|
initContainers:
|
||||||
|
- name: download-template
|
||||||
|
image: busybox:latest
|
||||||
|
command:
|
||||||
|
- sh
|
||||||
|
- -c
|
||||||
|
- |
|
||||||
|
wget -O /templates/subscription/index.html https://github.com/PasarGuard/subscription-template/releases/latest/download/index.html
|
||||||
|
volumeMounts:
|
||||||
|
- name: subscription-template
|
||||||
|
mountPath: /templates/subscription
|
||||||
|
containers:
|
||||||
|
- name: pasarguard-web
|
||||||
|
image: 'pasarguard/panel:v1.4.1'
|
||||||
|
imagePullPolicy: Always
|
||||||
|
envFrom:
|
||||||
|
- secretRef:
|
||||||
|
name: pasarguard-secrets
|
||||||
|
env:
|
||||||
|
- name: UVICORN_HOST
|
||||||
|
value: "0.0.0.0"
|
||||||
|
- name: UVICORN_PORT
|
||||||
|
value: "8000"
|
||||||
|
- name: DOCS
|
||||||
|
value: "true"
|
||||||
|
- name: UVICORN_SSL_CERTFILE
|
||||||
|
value: "/app/tls/tls.crt"
|
||||||
|
- name: UVICORN_SSL_KEYFILE
|
||||||
|
value: "/app/tls/tls.key"
|
||||||
|
- name: CUSTOM_TEMPLATES_DIRECTORY
|
||||||
|
value: "/code/app/templates/"
|
||||||
|
- name: SUBSCRIPTION_PAGE_TEMPLATE
|
||||||
|
value: "subscription/index.html"
|
||||||
|
ports:
|
||||||
|
- name: http
|
||||||
|
containerPort: 8000
|
||||||
|
protocol: TCP
|
||||||
|
volumeMounts:
|
||||||
|
- name: tls
|
||||||
|
mountPath: /app/tls
|
||||||
|
readOnly: true
|
||||||
|
- name: subscription-template
|
||||||
|
mountPath: /code/app/templates/subscription
|
||||||
|
volumes:
|
||||||
|
- name: tls
|
||||||
|
secret:
|
||||||
|
secretName: pasarguard-tls
|
||||||
|
- name: subscription-template
|
||||||
|
emptyDir: {}
|
||||||
|
---
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Service
|
||||||
|
metadata:
|
||||||
|
name: pasarguard
|
||||||
|
spec:
|
||||||
|
selector:
|
||||||
|
app: pasarguard
|
||||||
|
ports:
|
||||||
|
- protocol: TCP
|
||||||
|
port: 80
|
||||||
|
targetPort: 8000
|
||||||
44
k8s/apps/pasarguard/external-secrets.yaml
Normal file
44
k8s/apps/pasarguard/external-secrets.yaml
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
---
|
||||||
|
apiVersion: external-secrets.io/v1beta1
|
||||||
|
kind: ExternalSecret
|
||||||
|
metadata:
|
||||||
|
name: pasarguard-secrets
|
||||||
|
spec:
|
||||||
|
target:
|
||||||
|
name: pasarguard-secrets
|
||||||
|
deletionPolicy: Delete
|
||||||
|
template:
|
||||||
|
type: Opaque
|
||||||
|
data:
|
||||||
|
SUDO_PASSWORD: |-
|
||||||
|
{{ .admin_password }}
|
||||||
|
SUDO_USERNAME: |-
|
||||||
|
{{ .admin_username }}
|
||||||
|
SQLALCHEMY_DATABASE_URL : |-
|
||||||
|
postgresql+asyncpg://pasarguard:{{ .pg_pass }}@psql.psql.svc:5432/pasarguard
|
||||||
|
|
||||||
|
data:
|
||||||
|
- secretKey: pg_pass
|
||||||
|
sourceRef:
|
||||||
|
storeRef:
|
||||||
|
name: vaultwarden-login
|
||||||
|
kind: ClusterSecretStore
|
||||||
|
remoteRef:
|
||||||
|
key: 2a9deb39-ef22-433e-a1be-df1555625e22
|
||||||
|
property: fields[9].value
|
||||||
|
- secretKey: admin_password
|
||||||
|
sourceRef:
|
||||||
|
storeRef:
|
||||||
|
name: vaultwarden-login
|
||||||
|
kind: ClusterSecretStore
|
||||||
|
remoteRef:
|
||||||
|
key: 35ec5880-2576-401b-a89a-3c9d56b9c1de
|
||||||
|
property: login.password
|
||||||
|
- secretKey: admin_username
|
||||||
|
sourceRef:
|
||||||
|
storeRef:
|
||||||
|
name: vaultwarden-login
|
||||||
|
kind: ClusterSecretStore
|
||||||
|
remoteRef:
|
||||||
|
key: 35ec5880-2576-401b-a89a-3c9d56b9c1de
|
||||||
|
property: login.username
|
||||||
11
k8s/apps/pasarguard/kustomization.yaml
Normal file
11
k8s/apps/pasarguard/kustomization.yaml
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
apiVersion: kustomize.config.k8s.io/v1beta1
|
||||||
|
kind: Kustomization
|
||||||
|
|
||||||
|
resources:
|
||||||
|
- ./app.yaml
|
||||||
|
- ./external-secrets.yaml
|
||||||
|
- ./deployment.yaml
|
||||||
|
- ./daemonset.yaml
|
||||||
|
- ./certificate.yaml
|
||||||
|
|
||||||
|
|
||||||
134
k8s/apps/rustdesk/deployment.yaml
Normal file
134
k8s/apps/rustdesk/deployment.yaml
Normal file
@@ -0,0 +1,134 @@
|
|||||||
|
---
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: rustdesk-hbbs
|
||||||
|
labels:
|
||||||
|
app: rustdesk-hbbs
|
||||||
|
spec:
|
||||||
|
replicas: 1
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
app: rustdesk-hbbs
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
app: rustdesk-hbbs
|
||||||
|
spec:
|
||||||
|
nodeSelector:
|
||||||
|
kubernetes.io/hostname: master.tail2fe2d.ts.net
|
||||||
|
containers:
|
||||||
|
- name: hbbs
|
||||||
|
image: rustdesk/rustdesk-server:latest
|
||||||
|
imagePullPolicy: Always
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
memory: "128Mi"
|
||||||
|
cpu: "100m"
|
||||||
|
limits:
|
||||||
|
memory: "512Mi"
|
||||||
|
cpu: "500m"
|
||||||
|
command: ["hbbs"]
|
||||||
|
args:
|
||||||
|
- "--relay-servers"
|
||||||
|
- "rd.hexor.cy:21117"
|
||||||
|
- "--port"
|
||||||
|
- "21116"
|
||||||
|
ports:
|
||||||
|
- name: registry
|
||||||
|
containerPort: 21116
|
||||||
|
protocol: TCP
|
||||||
|
- name: nat
|
||||||
|
containerPort: 21115
|
||||||
|
protocol: TCP
|
||||||
|
volumeMounts:
|
||||||
|
- name: keys
|
||||||
|
mountPath: /data
|
||||||
|
readOnly: true
|
||||||
|
- name: data
|
||||||
|
mountPath: /data-persistent
|
||||||
|
env:
|
||||||
|
- name: RUST_LOG
|
||||||
|
value: "info"
|
||||||
|
- name: DB_URL
|
||||||
|
value: "/data-persistent/db_v2.sqlite3"
|
||||||
|
workingDir: /data
|
||||||
|
volumes:
|
||||||
|
- name: keys
|
||||||
|
secret:
|
||||||
|
secretName: rustdesk-keys
|
||||||
|
items:
|
||||||
|
- key: id_ed25519
|
||||||
|
path: id_ed25519
|
||||||
|
mode: 0600
|
||||||
|
- key: id_ed25519.pub
|
||||||
|
path: id_ed25519.pub
|
||||||
|
mode: 0644
|
||||||
|
- name: data
|
||||||
|
hostPath:
|
||||||
|
path: /k8s/rustdesk/hbbs
|
||||||
|
type: DirectoryOrCreate
|
||||||
|
|
||||||
|
---
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: rustdesk-hbbr
|
||||||
|
labels:
|
||||||
|
app: rustdesk-hbbr
|
||||||
|
spec:
|
||||||
|
replicas: 1
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
app: rustdesk-hbbr
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
app: rustdesk-hbbr
|
||||||
|
spec:
|
||||||
|
nodeSelector:
|
||||||
|
kubernetes.io/hostname: master.tail2fe2d.ts.net
|
||||||
|
containers:
|
||||||
|
- name: hbbr
|
||||||
|
image: rustdesk/rustdesk-server:latest
|
||||||
|
imagePullPolicy: Always
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
memory: "128Mi"
|
||||||
|
cpu: "100m"
|
||||||
|
limits:
|
||||||
|
memory: "512Mi"
|
||||||
|
cpu: "500m"
|
||||||
|
command: ["hbbr"]
|
||||||
|
args:
|
||||||
|
- "--port"
|
||||||
|
- "21117"
|
||||||
|
ports:
|
||||||
|
- name: relay
|
||||||
|
containerPort: 21117
|
||||||
|
protocol: TCP
|
||||||
|
volumeMounts:
|
||||||
|
- name: keys
|
||||||
|
mountPath: /data
|
||||||
|
readOnly: true
|
||||||
|
- name: data
|
||||||
|
mountPath: /data-persistent
|
||||||
|
env:
|
||||||
|
- name: RUST_LOG
|
||||||
|
value: "info"
|
||||||
|
workingDir: /data
|
||||||
|
volumes:
|
||||||
|
- name: keys
|
||||||
|
secret:
|
||||||
|
secretName: rustdesk-keys
|
||||||
|
items:
|
||||||
|
- key: id_ed25519
|
||||||
|
path: id_ed25519
|
||||||
|
mode: 0600
|
||||||
|
- key: id_ed25519.pub
|
||||||
|
path: id_ed25519.pub
|
||||||
|
mode: 0644
|
||||||
|
- name: data
|
||||||
|
hostPath:
|
||||||
|
path: /k8s/rustdesk/hbbr
|
||||||
|
type: DirectoryOrCreate
|
||||||
@@ -2,65 +2,33 @@
|
|||||||
apiVersion: external-secrets.io/v1beta1
|
apiVersion: external-secrets.io/v1beta1
|
||||||
kind: ExternalSecret
|
kind: ExternalSecret
|
||||||
metadata:
|
metadata:
|
||||||
name: postgres-creds
|
name: rustdesk-keys
|
||||||
spec:
|
spec:
|
||||||
target:
|
target:
|
||||||
name: postgres-creds
|
name: rustdesk-keys
|
||||||
deletionPolicy: Delete
|
deletionPolicy: Delete
|
||||||
template:
|
template:
|
||||||
type: Opaque
|
type: Opaque
|
||||||
data:
|
data:
|
||||||
psql_user: paperless
|
id_ed25519: |-
|
||||||
psql_pass: |-
|
{{ .private_key }}
|
||||||
{{ .psql_pass }}
|
id_ed25519.pub: |-
|
||||||
oauth_config: |-
|
{{ .public_key }}
|
||||||
{
|
|
||||||
"openid_connect": {
|
|
||||||
"APPS": [
|
|
||||||
{
|
|
||||||
"provider_id": "authentik",
|
|
||||||
"name": "Authentik",
|
|
||||||
"client_id": "{{ .oauth_id }}",
|
|
||||||
"secret": "{{ .oauth_secret }}",
|
|
||||||
"settings": {
|
|
||||||
"server_url": "{{ .server_url }}"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"OAUTH_PKCE_ENABLED": "True"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
data:
|
data:
|
||||||
- secretKey: psql_pass
|
- secretKey: private_key
|
||||||
sourceRef:
|
sourceRef:
|
||||||
storeRef:
|
storeRef:
|
||||||
name: vaultwarden-login
|
name: vaultwarden-login
|
||||||
kind: ClusterSecretStore
|
kind: ClusterSecretStore
|
||||||
remoteRef:
|
remoteRef:
|
||||||
key: 2a9deb39-ef22-433e-a1be-df1555625e22
|
key: f5591dfd-a0ab-4101-a2d7-e06380d3dcc9
|
||||||
property: fields[5].value
|
|
||||||
- secretKey: oauth_id
|
|
||||||
sourceRef:
|
|
||||||
storeRef:
|
|
||||||
name: vaultwarden-login
|
|
||||||
kind: ClusterSecretStore
|
|
||||||
remoteRef:
|
|
||||||
key: 07d4efd9-597c-4a4c-a78d-13bfc43e6055
|
|
||||||
property: fields[0].value
|
property: fields[0].value
|
||||||
- secretKey: oauth_secret
|
- secretKey: public_key
|
||||||
sourceRef:
|
sourceRef:
|
||||||
storeRef:
|
storeRef:
|
||||||
name: vaultwarden-login
|
name: vaultwarden-login
|
||||||
kind: ClusterSecretStore
|
kind: ClusterSecretStore
|
||||||
remoteRef:
|
remoteRef:
|
||||||
key: 07d4efd9-597c-4a4c-a78d-13bfc43e6055
|
key: f5591dfd-a0ab-4101-a2d7-e06380d3dcc9
|
||||||
property: fields[1].value
|
property: fields[1].value
|
||||||
- secretKey: server_url
|
|
||||||
sourceRef:
|
|
||||||
storeRef:
|
|
||||||
name: vaultwarden-login
|
|
||||||
kind: ClusterSecretStore
|
|
||||||
remoteRef:
|
|
||||||
key: 07d4efd9-597c-4a4c-a78d-13bfc43e6055
|
|
||||||
property: fields[2].value
|
|
||||||
|
|
||||||
|
|||||||
66
k8s/apps/rustdesk/external-secrets.yaml.backup
Normal file
66
k8s/apps/rustdesk/external-secrets.yaml.backup
Normal file
@@ -0,0 +1,66 @@
|
|||||||
|
---
|
||||||
|
apiVersion: external-secrets.io/v1beta1
|
||||||
|
kind: ExternalSecret
|
||||||
|
metadata:
|
||||||
|
name: postgres-creds
|
||||||
|
spec:
|
||||||
|
target:
|
||||||
|
name: postgres-creds
|
||||||
|
deletionPolicy: Delete
|
||||||
|
template:
|
||||||
|
type: Opaque
|
||||||
|
data:
|
||||||
|
psql_user: paperless
|
||||||
|
psql_pass: |-
|
||||||
|
{{ .psql_pass }}
|
||||||
|
oauth_config: |-
|
||||||
|
{
|
||||||
|
"openid_connect": {
|
||||||
|
"APPS": [
|
||||||
|
{
|
||||||
|
"provider_id": "authentik",
|
||||||
|
"name": "Authentik",
|
||||||
|
"client_id": "{{ .oauth_id }}",
|
||||||
|
"secret": "{{ .oauth_secret }}",
|
||||||
|
"settings": {
|
||||||
|
"server_url": "{{ .server_url }}"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"OAUTH_PKCE_ENABLED": "True"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
data:
|
||||||
|
- secretKey: psql_pass
|
||||||
|
sourceRef:
|
||||||
|
storeRef:
|
||||||
|
name: vaultwarden-login
|
||||||
|
kind: ClusterSecretStore
|
||||||
|
remoteRef:
|
||||||
|
key: 2a9deb39-ef22-433e-a1be-df1555625e22
|
||||||
|
property: fields[5].value
|
||||||
|
- secretKey: oauth_id
|
||||||
|
sourceRef:
|
||||||
|
storeRef:
|
||||||
|
name: vaultwarden-login
|
||||||
|
kind: ClusterSecretStore
|
||||||
|
remoteRef:
|
||||||
|
key: 07d4efd9-597c-4a4c-a78d-13bfc43e6055
|
||||||
|
property: fields[0].value
|
||||||
|
- secretKey: oauth_secret
|
||||||
|
sourceRef:
|
||||||
|
storeRef:
|
||||||
|
name: vaultwarden-login
|
||||||
|
kind: ClusterSecretStore
|
||||||
|
remoteRef:
|
||||||
|
key: 07d4efd9-597c-4a4c-a78d-13bfc43e6055
|
||||||
|
property: fields[1].value
|
||||||
|
- secretKey: server_url
|
||||||
|
sourceRef:
|
||||||
|
storeRef:
|
||||||
|
name: vaultwarden-login
|
||||||
|
kind: ClusterSecretStore
|
||||||
|
remoteRef:
|
||||||
|
key: 07d4efd9-597c-4a4c-a78d-13bfc43e6055
|
||||||
|
property: fields[2].value
|
||||||
|
|
||||||
@@ -3,14 +3,8 @@ kind: Kustomization
|
|||||||
|
|
||||||
resources:
|
resources:
|
||||||
- app.yaml
|
- app.yaml
|
||||||
#- external-secrets.yaml
|
- deployment.yaml
|
||||||
|
- service.yaml
|
||||||
helmCharts:
|
- external-secrets.yaml
|
||||||
- name: rustdesk-server-oss
|
- network-policy.yaml
|
||||||
repo: https://schich.tel/helm-charts
|
|
||||||
version: 0.2.2
|
|
||||||
releaseName: rustdesk
|
|
||||||
namespace: rustdesk
|
|
||||||
valuesFile: values.yaml
|
|
||||||
includeCRDs: true
|
|
||||||
|
|
||||||
|
|||||||
73
k8s/apps/rustdesk/network-policy.yaml
Normal file
73
k8s/apps/rustdesk/network-policy.yaml
Normal file
@@ -0,0 +1,73 @@
|
|||||||
|
---
|
||||||
|
apiVersion: networking.k8s.io/v1
|
||||||
|
kind: NetworkPolicy
|
||||||
|
metadata:
|
||||||
|
name: rustdesk-network-policy
|
||||||
|
spec:
|
||||||
|
podSelector:
|
||||||
|
matchLabels:
|
||||||
|
app: rustdesk-hbbs
|
||||||
|
policyTypes:
|
||||||
|
- Ingress
|
||||||
|
- Egress
|
||||||
|
ingress:
|
||||||
|
# Allow all incoming connections to RustDesk ports
|
||||||
|
- from: []
|
||||||
|
ports:
|
||||||
|
- protocol: TCP
|
||||||
|
port: 21115
|
||||||
|
- protocol: TCP
|
||||||
|
port: 21116
|
||||||
|
- protocol: UDP
|
||||||
|
port: 21116
|
||||||
|
egress:
|
||||||
|
# Allow DNS
|
||||||
|
- to: []
|
||||||
|
ports:
|
||||||
|
- protocol: UDP
|
||||||
|
port: 53
|
||||||
|
- protocol: TCP
|
||||||
|
port: 53
|
||||||
|
# Allow communication between HBBS and HBBR
|
||||||
|
- to:
|
||||||
|
- podSelector:
|
||||||
|
matchLabels:
|
||||||
|
app: rustdesk-hbbr
|
||||||
|
ports:
|
||||||
|
- protocol: TCP
|
||||||
|
port: 21117
|
||||||
|
|
||||||
|
---
|
||||||
|
apiVersion: networking.k8s.io/v1
|
||||||
|
kind: NetworkPolicy
|
||||||
|
metadata:
|
||||||
|
name: rustdesk-hbbr-network-policy
|
||||||
|
spec:
|
||||||
|
podSelector:
|
||||||
|
matchLabels:
|
||||||
|
app: rustdesk-hbbr
|
||||||
|
policyTypes:
|
||||||
|
- Ingress
|
||||||
|
- Egress
|
||||||
|
ingress:
|
||||||
|
# Allow all incoming connections to relay port
|
||||||
|
- from: []
|
||||||
|
ports:
|
||||||
|
- protocol: TCP
|
||||||
|
port: 21117
|
||||||
|
# Allow connections from HBBS
|
||||||
|
- from:
|
||||||
|
- podSelector:
|
||||||
|
matchLabels:
|
||||||
|
app: rustdesk-hbbs
|
||||||
|
ports:
|
||||||
|
- protocol: TCP
|
||||||
|
port: 21117
|
||||||
|
egress:
|
||||||
|
# Allow DNS
|
||||||
|
- to: []
|
||||||
|
ports:
|
||||||
|
- protocol: UDP
|
||||||
|
port: 53
|
||||||
|
- protocol: TCP
|
||||||
|
port: 53
|
||||||
57
k8s/apps/rustdesk/service.yaml
Normal file
57
k8s/apps/rustdesk/service.yaml
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
---
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Service
|
||||||
|
metadata:
|
||||||
|
name: rustdesk-hbbs
|
||||||
|
labels:
|
||||||
|
app: rustdesk-hbbs
|
||||||
|
spec:
|
||||||
|
type: LoadBalancer
|
||||||
|
externalTrafficPolicy: Local
|
||||||
|
selector:
|
||||||
|
app: rustdesk-hbbs
|
||||||
|
ports:
|
||||||
|
- name: registry-tcp
|
||||||
|
port: 21116
|
||||||
|
targetPort: 21116
|
||||||
|
protocol: TCP
|
||||||
|
- name: nat
|
||||||
|
port: 21115
|
||||||
|
targetPort: 21115
|
||||||
|
protocol: TCP
|
||||||
|
|
||||||
|
---
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Service
|
||||||
|
metadata:
|
||||||
|
name: rustdesk-hbbs-udp
|
||||||
|
labels:
|
||||||
|
app: rustdesk-hbbs
|
||||||
|
spec:
|
||||||
|
type: LoadBalancer
|
||||||
|
externalTrafficPolicy: Local
|
||||||
|
selector:
|
||||||
|
app: rustdesk-hbbs
|
||||||
|
ports:
|
||||||
|
- name: registry-udp
|
||||||
|
port: 21116
|
||||||
|
targetPort: 21116
|
||||||
|
protocol: UDP
|
||||||
|
|
||||||
|
---
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Service
|
||||||
|
metadata:
|
||||||
|
name: rustdesk-hbbr
|
||||||
|
labels:
|
||||||
|
app: rustdesk-hbbr
|
||||||
|
spec:
|
||||||
|
type: LoadBalancer
|
||||||
|
externalTrafficPolicy: Local
|
||||||
|
selector:
|
||||||
|
app: rustdesk-hbbr
|
||||||
|
ports:
|
||||||
|
- name: relay
|
||||||
|
port: 21117
|
||||||
|
targetPort: 21117
|
||||||
|
protocol: TCP
|
||||||
@@ -1,87 +0,0 @@
|
|||||||
replicaCount: 1
|
|
||||||
|
|
||||||
image:
|
|
||||||
repository: docker.io/rustdesk/rustdesk-server
|
|
||||||
pullPolicy: IfNotPresent
|
|
||||||
tag: 1
|
|
||||||
|
|
||||||
nodeSelector:
|
|
||||||
kubernetes.io/hostname: master.tail2fe2d.ts.net
|
|
||||||
|
|
||||||
ingress:
|
|
||||||
enabled: true
|
|
||||||
className: "traefik"
|
|
||||||
annotations:
|
|
||||||
ingressClassName: traefik
|
|
||||||
cert-manager.io/cluster-issuer: letsencrypt
|
|
||||||
traefik.ingress.kubernetes.io/router.middlewares: kube-system-https-redirect@kubernetescrd
|
|
||||||
acme.cert-manager.io/http01-edit-in-place: "true"
|
|
||||||
hosts:
|
|
||||||
- rd.hexor.cy
|
|
||||||
tls:
|
|
||||||
- secretName: rustdesk-tls
|
|
||||||
hosts:
|
|
||||||
- rd.hexor.cy
|
|
||||||
|
|
||||||
service:
|
|
||||||
type: LoadBalancer
|
|
||||||
externalTrafficPolicy: Cluster
|
|
||||||
loadBalancerIP: null
|
|
||||||
enableWebClientSupport: false
|
|
||||||
hbbr:
|
|
||||||
replayPort:
|
|
||||||
port: 21117
|
|
||||||
targetPort: 21117
|
|
||||||
clientPort:
|
|
||||||
port: 21119
|
|
||||||
targetPort: 21119
|
|
||||||
hbbs:
|
|
||||||
natPort:
|
|
||||||
port: 21115
|
|
||||||
targetPort: 21115
|
|
||||||
registryPort:
|
|
||||||
port: 21116
|
|
||||||
targetPort: 21116
|
|
||||||
heartbeatPort:
|
|
||||||
port: 21116
|
|
||||||
targetPort: 21116
|
|
||||||
webPort:
|
|
||||||
port: 21118
|
|
||||||
targetPort: 21118
|
|
||||||
|
|
||||||
resources:
|
|
||||||
hbbrResource: {}
|
|
||||||
# We usually recommend not to specify default resources and to leave this as a conscious
|
|
||||||
# choice for the user. This also increases chances charts run on environments with little
|
|
||||||
# resources, such as Minikube. If you do want to specify resources, uncomment the following
|
|
||||||
# lines, adjust them as necessary, and remove the curly braces after 'resources:'.
|
|
||||||
# limits:
|
|
||||||
# cpu: 100m
|
|
||||||
# memory: 128Mi
|
|
||||||
# requests:
|
|
||||||
# cpu: 100m
|
|
||||||
# memory: 128Mi
|
|
||||||
hbbsResource: {}
|
|
||||||
# We usually recommend not to specify default resources and to leave this as a conscious
|
|
||||||
# choice for the user. This also increases chances charts run on environments with little
|
|
||||||
# resources, such as Minikube. If you do want to specify resources, uncomment the following
|
|
||||||
# lines, adjust them as necessary, and remove the curly braces after 'resources:'.
|
|
||||||
# limits:
|
|
||||||
# cpu: 100m
|
|
||||||
# memory: 128Mi
|
|
||||||
# requests:
|
|
||||||
# cpu: 100m
|
|
||||||
# memory: 128Mi
|
|
||||||
|
|
||||||
# Additional volumes on the output Deployment definition.
|
|
||||||
volume: {}
|
|
||||||
|
|
||||||
# - name: foo
|
|
||||||
# secret:
|
|
||||||
# secretName: mysecret
|
|
||||||
# optional: false
|
|
||||||
|
|
||||||
# - name: foo
|
|
||||||
# mountPath: "/etc/foo"
|
|
||||||
# readOnly: true
|
|
||||||
|
|
||||||
@@ -1,3 +1,10 @@
|
|||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
memory: "256Mi"
|
||||||
|
cpu: "100m"
|
||||||
|
limits:
|
||||||
|
memory: "1Gi"
|
||||||
|
cpu: "500m"
|
||||||
nodeSelector:
|
nodeSelector:
|
||||||
kubernetes.io/hostname: master.tail2fe2d.ts.net
|
kubernetes.io/hostname: master.tail2fe2d.ts.net
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,12 @@
|
|||||||
env:
|
env:
|
||||||
TZ: Asia/Nicosia
|
TZ: Asia/Nicosia
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
memory: "256Mi"
|
||||||
|
cpu: "100m"
|
||||||
|
limits:
|
||||||
|
memory: "1Gi"
|
||||||
|
cpu: "500m"
|
||||||
nodeSelector:
|
nodeSelector:
|
||||||
kubernetes.io/hostname: master.tail2fe2d.ts.net
|
kubernetes.io/hostname: master.tail2fe2d.ts.net
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,12 @@
|
|||||||
env:
|
env:
|
||||||
TZ: Asia/Nicosia
|
TZ: Asia/Nicosia
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
memory: "512Mi"
|
||||||
|
cpu: "200m"
|
||||||
|
limits:
|
||||||
|
memory: "2Gi"
|
||||||
|
cpu: "1000m"
|
||||||
nodeSelector:
|
nodeSelector:
|
||||||
kubernetes.io/hostname: master.tail2fe2d.ts.net
|
kubernetes.io/hostname: master.tail2fe2d.ts.net
|
||||||
|
|
||||||
|
|||||||
@@ -28,12 +28,12 @@ ingress:
|
|||||||
tlsSecret: pdf-hexor-cy-tls
|
tlsSecret: pdf-hexor-cy-tls
|
||||||
|
|
||||||
resources:
|
resources:
|
||||||
limits:
|
|
||||||
cpu: 500m
|
|
||||||
memory: 512Mi
|
|
||||||
requests:
|
requests:
|
||||||
cpu: 250m
|
memory: "512Mi"
|
||||||
memory: 256Mi
|
cpu: "200m"
|
||||||
|
limits:
|
||||||
|
memory: "2Gi"
|
||||||
|
cpu: "1000m"
|
||||||
|
|
||||||
probes:
|
probes:
|
||||||
liveness:
|
liveness:
|
||||||
|
|||||||
@@ -4,6 +4,8 @@ kind: Kustomization
|
|||||||
|
|
||||||
resources:
|
resources:
|
||||||
- app.yaml
|
- app.yaml
|
||||||
|
- nginx-router.yaml
|
||||||
|
- traefik-simple.yaml
|
||||||
|
|
||||||
helmCharts:
|
helmCharts:
|
||||||
- name: syncthing
|
- name: syncthing
|
||||||
@@ -21,3 +23,11 @@ helmCharts:
|
|||||||
namespace: syncthing
|
namespace: syncthing
|
||||||
valuesFile: syncthing-khv.yaml
|
valuesFile: syncthing-khv.yaml
|
||||||
includeCRDs: true
|
includeCRDs: true
|
||||||
|
|
||||||
|
- name: syncthing
|
||||||
|
repo: https://k8s-home-lab.github.io/helm-charts
|
||||||
|
version: 4.0.0
|
||||||
|
releaseName: syncthing-nas
|
||||||
|
namespace: syncthing
|
||||||
|
valuesFile: syncthing-nas.yaml
|
||||||
|
includeCRDs: true
|
||||||
276
k8s/apps/syncthing/nginx-router.yaml
Normal file
276
k8s/apps/syncthing/nginx-router.yaml
Normal file
@@ -0,0 +1,276 @@
|
|||||||
|
apiVersion: v1
|
||||||
|
kind: ConfigMap
|
||||||
|
metadata:
|
||||||
|
name: nginx-config
|
||||||
|
namespace: syncthing
|
||||||
|
data:
|
||||||
|
default.conf: |
|
||||||
|
map $http_upgrade $connection_upgrade {
|
||||||
|
default upgrade;
|
||||||
|
'' close;
|
||||||
|
}
|
||||||
|
|
||||||
|
server {
|
||||||
|
listen 80;
|
||||||
|
server_name _;
|
||||||
|
|
||||||
|
# Landing page
|
||||||
|
location = / {
|
||||||
|
root /usr/share/nginx/html;
|
||||||
|
try_files /index.html =404;
|
||||||
|
}
|
||||||
|
|
||||||
|
# NAS instance
|
||||||
|
location /nas {
|
||||||
|
rewrite ^/nas$ /nas/ permanent;
|
||||||
|
}
|
||||||
|
|
||||||
|
# NAS API endpoints
|
||||||
|
location ~ ^/nas/(rest|meta)/ {
|
||||||
|
rewrite ^/nas/(.*) /$1 break;
|
||||||
|
proxy_pass http://syncthing-nas:8384;
|
||||||
|
|
||||||
|
proxy_set_header Host $host;
|
||||||
|
proxy_set_header X-Real-IP $remote_addr;
|
||||||
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||||
|
proxy_set_header X-Forwarded-Proto $scheme;
|
||||||
|
|
||||||
|
# Handle websockets
|
||||||
|
proxy_http_version 1.1;
|
||||||
|
proxy_set_header Upgrade $http_upgrade;
|
||||||
|
proxy_set_header Connection $connection_upgrade;
|
||||||
|
proxy_read_timeout 86400;
|
||||||
|
}
|
||||||
|
|
||||||
|
location /nas/ {
|
||||||
|
proxy_pass http://syncthing-nas:8384/;
|
||||||
|
|
||||||
|
# Important: tell syncthing that we're using /nas as base path
|
||||||
|
proxy_set_header Host $host;
|
||||||
|
proxy_set_header X-Real-IP $remote_addr;
|
||||||
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||||
|
proxy_set_header X-Forwarded-Proto $scheme;
|
||||||
|
|
||||||
|
# Handle websockets
|
||||||
|
proxy_http_version 1.1;
|
||||||
|
proxy_set_header Upgrade $http_upgrade;
|
||||||
|
proxy_set_header Connection $connection_upgrade;
|
||||||
|
proxy_read_timeout 86400;
|
||||||
|
|
||||||
|
# Sub filter to fix asset paths
|
||||||
|
sub_filter 'href="/' 'href="/nas/';
|
||||||
|
sub_filter 'src="/' 'src="/nas/';
|
||||||
|
sub_filter 'url(/' 'url(/nas/';
|
||||||
|
sub_filter '"/meta' '"/nas/meta';
|
||||||
|
sub_filter '"/rest' '"/nas/rest';
|
||||||
|
sub_filter '"/vendor' '"/nas/vendor';
|
||||||
|
sub_filter '"/theme-assets' '"/nas/theme-assets';
|
||||||
|
sub_filter '"/syncthing' '"/nas/syncthing';
|
||||||
|
sub_filter_once off;
|
||||||
|
sub_filter_types text/html text/css application/javascript;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
# Master instance
|
||||||
|
location /master {
|
||||||
|
rewrite ^/master$ /master/ permanent;
|
||||||
|
}
|
||||||
|
|
||||||
|
# Master API endpoints
|
||||||
|
location ~ ^/master/(rest|meta)/ {
|
||||||
|
rewrite ^/master/(.*) /$1 break;
|
||||||
|
proxy_pass http://syncthing-master:8384;
|
||||||
|
|
||||||
|
proxy_set_header Host $host;
|
||||||
|
proxy_set_header X-Real-IP $remote_addr;
|
||||||
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||||
|
proxy_set_header X-Forwarded-Proto $scheme;
|
||||||
|
|
||||||
|
# Handle websockets
|
||||||
|
proxy_http_version 1.1;
|
||||||
|
proxy_set_header Upgrade $http_upgrade;
|
||||||
|
proxy_set_header Connection $connection_upgrade;
|
||||||
|
proxy_read_timeout 86400;
|
||||||
|
}
|
||||||
|
|
||||||
|
location /master/ {
|
||||||
|
proxy_pass http://syncthing-master:8384/;
|
||||||
|
|
||||||
|
proxy_set_header Host $host;
|
||||||
|
proxy_set_header X-Real-IP $remote_addr;
|
||||||
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||||
|
proxy_set_header X-Forwarded-Proto $scheme;
|
||||||
|
|
||||||
|
proxy_http_version 1.1;
|
||||||
|
proxy_set_header Upgrade $http_upgrade;
|
||||||
|
proxy_set_header Connection "upgrade";
|
||||||
|
|
||||||
|
sub_filter 'href="/' 'href="/master/';
|
||||||
|
sub_filter 'src="/' 'src="/master/';
|
||||||
|
sub_filter 'url(/' 'url(/master/';
|
||||||
|
sub_filter '"/meta' '"/master/meta';
|
||||||
|
sub_filter '"/rest' '"/master/rest';
|
||||||
|
sub_filter '"/vendor' '"/master/vendor';
|
||||||
|
sub_filter '"/theme-assets' '"/master/theme-assets';
|
||||||
|
sub_filter '"/syncthing' '"/master/syncthing';
|
||||||
|
sub_filter_once off;
|
||||||
|
sub_filter_types text/html text/css application/javascript;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
# Iris instance
|
||||||
|
location /iris {
|
||||||
|
rewrite ^/iris$ /iris/ permanent;
|
||||||
|
}
|
||||||
|
|
||||||
|
# Iris API endpoints
|
||||||
|
location ~ ^/iris/(rest|meta)/ {
|
||||||
|
rewrite ^/iris/(.*) /$1 break;
|
||||||
|
proxy_pass http://syncthing-khv:8384;
|
||||||
|
|
||||||
|
proxy_set_header Host $host;
|
||||||
|
proxy_set_header X-Real-IP $remote_addr;
|
||||||
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||||
|
proxy_set_header X-Forwarded-Proto $scheme;
|
||||||
|
|
||||||
|
# Handle websockets
|
||||||
|
proxy_http_version 1.1;
|
||||||
|
proxy_set_header Upgrade $http_upgrade;
|
||||||
|
proxy_set_header Connection $connection_upgrade;
|
||||||
|
proxy_read_timeout 86400;
|
||||||
|
}
|
||||||
|
|
||||||
|
location /iris/ {
|
||||||
|
proxy_pass http://syncthing-khv:8384/;
|
||||||
|
|
||||||
|
proxy_set_header Host $host;
|
||||||
|
proxy_set_header X-Real-IP $remote_addr;
|
||||||
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||||
|
proxy_set_header X-Forwarded-Proto $scheme;
|
||||||
|
|
||||||
|
proxy_http_version 1.1;
|
||||||
|
proxy_set_header Upgrade $http_upgrade;
|
||||||
|
proxy_set_header Connection "upgrade";
|
||||||
|
|
||||||
|
sub_filter 'href="/' 'href="/iris/';
|
||||||
|
sub_filter 'src="/' 'src="/iris/';
|
||||||
|
sub_filter 'url(/' 'url(/iris/';
|
||||||
|
sub_filter '"/meta' '"/iris/meta';
|
||||||
|
sub_filter '"/rest' '"/iris/rest';
|
||||||
|
sub_filter '"/vendor' '"/iris/vendor';
|
||||||
|
sub_filter '"/theme-assets' '"/iris/theme-assets';
|
||||||
|
sub_filter '"/syncthing' '"/iris/syncthing';
|
||||||
|
sub_filter_once off;
|
||||||
|
sub_filter_types text/html text/css application/javascript;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
index.html: |
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>Syncthing Instances</title>
|
||||||
|
<style>
|
||||||
|
body {
|
||||||
|
font-family: Arial, sans-serif;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
height: 100vh;
|
||||||
|
margin: 0;
|
||||||
|
background-color: #f0f0f0;
|
||||||
|
}
|
||||||
|
.container {
|
||||||
|
text-align: center;
|
||||||
|
background: white;
|
||||||
|
padding: 40px;
|
||||||
|
border-radius: 10px;
|
||||||
|
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
|
||||||
|
}
|
||||||
|
h1 {
|
||||||
|
color: #333;
|
||||||
|
margin-bottom: 30px;
|
||||||
|
}
|
||||||
|
.links {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 15px;
|
||||||
|
}
|
||||||
|
a {
|
||||||
|
display: inline-block;
|
||||||
|
padding: 15px 30px;
|
||||||
|
background-color: #0078e7;
|
||||||
|
color: white;
|
||||||
|
text-decoration: none;
|
||||||
|
border-radius: 5px;
|
||||||
|
transition: background-color 0.3s;
|
||||||
|
}
|
||||||
|
a:hover {
|
||||||
|
background-color: #0056b3;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="container">
|
||||||
|
<h1>Syncthing Instances</h1>
|
||||||
|
<div class="links">
|
||||||
|
<a href="/nas/">NAS Instance</a>
|
||||||
|
<a href="/master/">Master Instance</a>
|
||||||
|
<a href="/iris/">Iris Instance</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
---
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: syncthing-router
|
||||||
|
namespace: syncthing
|
||||||
|
spec:
|
||||||
|
replicas: 1
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
app: syncthing-router
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
app: syncthing-router
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- name: nginx
|
||||||
|
image: nginx:alpine
|
||||||
|
ports:
|
||||||
|
- containerPort: 80
|
||||||
|
volumeMounts:
|
||||||
|
- name: config
|
||||||
|
mountPath: /etc/nginx/conf.d
|
||||||
|
- name: html
|
||||||
|
mountPath: /usr/share/nginx/html
|
||||||
|
volumes:
|
||||||
|
- name: config
|
||||||
|
configMap:
|
||||||
|
name: nginx-config
|
||||||
|
items:
|
||||||
|
- key: default.conf
|
||||||
|
path: default.conf
|
||||||
|
- name: html
|
||||||
|
configMap:
|
||||||
|
name: nginx-config
|
||||||
|
items:
|
||||||
|
- key: index.html
|
||||||
|
path: index.html
|
||||||
|
---
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Service
|
||||||
|
metadata:
|
||||||
|
name: syncthing-router
|
||||||
|
namespace: syncthing
|
||||||
|
spec:
|
||||||
|
selector:
|
||||||
|
app: syncthing-router
|
||||||
|
ports:
|
||||||
|
- protocol: TCP
|
||||||
|
port: 80
|
||||||
|
targetPort: 80
|
||||||
@@ -4,13 +4,8 @@ persistence:
|
|||||||
config:
|
config:
|
||||||
enabled: true
|
enabled: true
|
||||||
type: hostPath
|
type: hostPath
|
||||||
hostPath: "/k8s/syncthing"
|
hostPath: "/k8s/Syncthing"
|
||||||
mountPath: "/var/syncthing"
|
mountPath: "/var/syncthing"
|
||||||
storage:
|
|
||||||
enabled: true
|
|
||||||
type: hostPath
|
|
||||||
hostPath: "/home/share"
|
|
||||||
mountPath: "/storage"
|
|
||||||
nodeSelector:
|
nodeSelector:
|
||||||
kubernetes.io/hostname: iris.khv
|
kubernetes.io/hostname: iris.khv
|
||||||
service:
|
service:
|
||||||
@@ -20,23 +15,24 @@ service:
|
|||||||
port: 8384
|
port: 8384
|
||||||
listen:
|
listen:
|
||||||
enabled: true
|
enabled: true
|
||||||
type: LoadBalancer
|
type: NodePort
|
||||||
|
externalTrafficPolicy: Local
|
||||||
ports:
|
ports:
|
||||||
listen:
|
listen:
|
||||||
enabled: true
|
enabled: true
|
||||||
port: 30023
|
port: 22000
|
||||||
protocol: TCP
|
protocol: TCP
|
||||||
targetPort: 22000
|
targetPort: 22000
|
||||||
selector:
|
|
||||||
app.kubernetes.io/name: syncthing
|
|
||||||
discovery:
|
discovery:
|
||||||
enabled: true
|
enabled: true
|
||||||
type: NodePort
|
type: NodePort
|
||||||
externalTrafficPolicy: Cluster
|
externalTrafficPolicy: Local
|
||||||
ports:
|
ports:
|
||||||
discovery:
|
discovery:
|
||||||
enabled: true
|
enabled: true
|
||||||
port: 21027
|
port: 21027
|
||||||
protocol: UDP
|
protocol: UDP
|
||||||
targetPort: 21027
|
targetPort: 21027
|
||||||
|
port: 21027
|
||||||
|
protocol: UDP
|
||||||
|
targetPort: 21027
|
||||||
@@ -5,13 +5,13 @@ persistence:
|
|||||||
config:
|
config:
|
||||||
enabled: true
|
enabled: true
|
||||||
type: hostPath
|
type: hostPath
|
||||||
hostPath: "/k8s/syncthing"
|
hostPath: "/k8s/syncthing-config"
|
||||||
mountPath: "/var/syncthing"
|
mountPath: "/var/syncthing"
|
||||||
storage:
|
storage:
|
||||||
enabled: true
|
enabled: true
|
||||||
type: hostPath
|
type: hostPath
|
||||||
hostPath: "/k8s/"
|
hostPath: "/k8s/Syncthing-repos"
|
||||||
mountPath: "/storage"
|
mountPath: "/Syncthing-repos"
|
||||||
nodeSelector:
|
nodeSelector:
|
||||||
kubernetes.io/hostname: master.tail2fe2d.ts.net
|
kubernetes.io/hostname: master.tail2fe2d.ts.net
|
||||||
service:
|
service:
|
||||||
@@ -21,23 +21,24 @@ service:
|
|||||||
port: 8384
|
port: 8384
|
||||||
listen:
|
listen:
|
||||||
enabled: true
|
enabled: true
|
||||||
type: LoadBalancer
|
type: NodePort
|
||||||
|
externalTrafficPolicy: Local
|
||||||
ports:
|
ports:
|
||||||
listen:
|
listen:
|
||||||
enabled: true
|
enabled: true
|
||||||
port: 30023
|
port: 22000
|
||||||
protocol: TCP
|
protocol: TCP
|
||||||
targetPort: 22000
|
targetPort: 22000
|
||||||
selector:
|
|
||||||
app.kubernetes.io/name: syncthing
|
|
||||||
discovery:
|
discovery:
|
||||||
enabled: true
|
enabled: true
|
||||||
type: NodePort
|
type: NodePort
|
||||||
externalTrafficPolicy: Cluster
|
externalTrafficPolicy: Local
|
||||||
ports:
|
ports:
|
||||||
discovery:
|
discovery:
|
||||||
enabled: true
|
enabled: true
|
||||||
port: 21027
|
port: 21027
|
||||||
protocol: UDP
|
protocol: UDP
|
||||||
targetPort: 21027
|
targetPort: 21027
|
||||||
|
port: 21027
|
||||||
|
protocol: UDP
|
||||||
|
targetPort: 21027
|
||||||
44
k8s/apps/syncthing/syncthing-nas.yaml
Normal file
44
k8s/apps/syncthing/syncthing-nas.yaml
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
image:
|
||||||
|
tag: latest
|
||||||
|
persistence:
|
||||||
|
config:
|
||||||
|
enabled: true
|
||||||
|
type: hostPath
|
||||||
|
hostPath: "/mnt/storage/Storage/syncthing-config"
|
||||||
|
mountPath: "/var/syncthing"
|
||||||
|
storage:
|
||||||
|
enabled: true
|
||||||
|
type: hostPath
|
||||||
|
hostPath: "/mnt/storage/Storage/Syncthing-repos"
|
||||||
|
mountPath: "/Syncthing-repos"
|
||||||
|
nodeSelector:
|
||||||
|
kubernetes.io/hostname: nas.homenet
|
||||||
|
service:
|
||||||
|
main:
|
||||||
|
ports:
|
||||||
|
http:
|
||||||
|
port: 8384
|
||||||
|
listen:
|
||||||
|
enabled: true
|
||||||
|
type: NodePort
|
||||||
|
externalTrafficPolicy: Local
|
||||||
|
ports:
|
||||||
|
listen:
|
||||||
|
enabled: true
|
||||||
|
port: 22000
|
||||||
|
protocol: TCP
|
||||||
|
targetPort: 22000
|
||||||
|
discovery:
|
||||||
|
enabled: true
|
||||||
|
type: NodePort
|
||||||
|
externalTrafficPolicy: Local
|
||||||
|
ports:
|
||||||
|
discovery:
|
||||||
|
enabled: true
|
||||||
|
port: 21027
|
||||||
|
protocol: UDP
|
||||||
|
targetPort: 21027
|
||||||
|
port: 21027
|
||||||
|
protocol: UDP
|
||||||
|
targetPort: 21027
|
||||||
|
|
||||||
36
k8s/apps/syncthing/traefik-simple.yaml
Normal file
36
k8s/apps/syncthing/traefik-simple.yaml
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
---
|
||||||
|
apiVersion: traefik.io/v1alpha1
|
||||||
|
kind: IngressRoute
|
||||||
|
metadata:
|
||||||
|
name: syncthing-ingressroute
|
||||||
|
namespace: syncthing
|
||||||
|
spec:
|
||||||
|
entryPoints:
|
||||||
|
- websecure
|
||||||
|
routes:
|
||||||
|
- match: Host(`ss.hexor.cy`)
|
||||||
|
kind: Rule
|
||||||
|
services:
|
||||||
|
- name: syncthing-router
|
||||||
|
port: 80
|
||||||
|
middlewares:
|
||||||
|
- name: authentik-forward-auth
|
||||||
|
namespace: syncthing
|
||||||
|
tls:
|
||||||
|
secretName: syncthing-tls
|
||||||
|
---
|
||||||
|
apiVersion: traefik.io/v1alpha1
|
||||||
|
kind: Middleware
|
||||||
|
metadata:
|
||||||
|
name: authentik-forward-auth
|
||||||
|
namespace: syncthing
|
||||||
|
spec:
|
||||||
|
forwardAuth:
|
||||||
|
address: http://authentik-server.authentik.svc.cluster.local/outpost.goauthentik.io/auth/traefik
|
||||||
|
trustForwardHeader: true
|
||||||
|
authResponseHeaders:
|
||||||
|
- X-authentik-username
|
||||||
|
- X-authentik-groups
|
||||||
|
- X-authentik-email
|
||||||
|
- X-authentik-name
|
||||||
|
- X-authentik-uid
|
||||||
21
k8s/apps/tg-bots/app.yaml
Normal file
21
k8s/apps/tg-bots/app.yaml
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
apiVersion: argoproj.io/v1alpha1
|
||||||
|
kind: Application
|
||||||
|
metadata:
|
||||||
|
name: tg-bots
|
||||||
|
namespace: argocd
|
||||||
|
spec:
|
||||||
|
project: apps
|
||||||
|
destination:
|
||||||
|
namespace: tg-bots
|
||||||
|
server: https://kubernetes.default.svc
|
||||||
|
source:
|
||||||
|
repoURL: ssh://git@gt.hexor.cy:30022/ab/homelab.git
|
||||||
|
targetRevision: HEAD
|
||||||
|
path: k8s/apps/tg-bots
|
||||||
|
syncPolicy:
|
||||||
|
automated:
|
||||||
|
selfHeal: true
|
||||||
|
prune: true
|
||||||
|
syncOptions:
|
||||||
|
- CreateNamespace=true
|
||||||
|
|
||||||
42
k8s/apps/tg-bots/desubot.yaml
Normal file
42
k8s/apps/tg-bots/desubot.yaml
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
---
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: desubot
|
||||||
|
labels:
|
||||||
|
app: desubot
|
||||||
|
annotations:
|
||||||
|
reloader.stakater.com/auto: "true"
|
||||||
|
spec:
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
app: desubot
|
||||||
|
replicas: 1
|
||||||
|
strategy:
|
||||||
|
type: RollingUpdate
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
app: desubot
|
||||||
|
spec:
|
||||||
|
nodeSelector:
|
||||||
|
kubernetes.io/hostname: home.homenet
|
||||||
|
containers:
|
||||||
|
- name: desubot
|
||||||
|
image: 'ultradesu/desubot:latest'
|
||||||
|
imagePullPolicy: Always
|
||||||
|
envFrom:
|
||||||
|
- secretRef:
|
||||||
|
name: desubot
|
||||||
|
env:
|
||||||
|
- name: RUST_LOG
|
||||||
|
value: "info"
|
||||||
|
volumeMounts:
|
||||||
|
- mountPath: /storage
|
||||||
|
name: storage
|
||||||
|
volumes:
|
||||||
|
- name: storage
|
||||||
|
nfs:
|
||||||
|
server: nas.homenet
|
||||||
|
path: /mnt/storage/Storage/k8s/desubot/
|
||||||
|
readOnly: false
|
||||||
49
k8s/apps/tg-bots/external-secrets.yaml
Normal file
49
k8s/apps/tg-bots/external-secrets.yaml
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
---
|
||||||
|
apiVersion: external-secrets.io/v1beta1
|
||||||
|
kind: ExternalSecret
|
||||||
|
metadata:
|
||||||
|
name: get-id-bot
|
||||||
|
spec:
|
||||||
|
target:
|
||||||
|
name: get-id-bot
|
||||||
|
deletionPolicy: Delete
|
||||||
|
template:
|
||||||
|
type: Opaque
|
||||||
|
data:
|
||||||
|
TELOXIDE_TOKEN: |-
|
||||||
|
{{ .token }}
|
||||||
|
|
||||||
|
data:
|
||||||
|
- secretKey: token
|
||||||
|
sourceRef:
|
||||||
|
storeRef:
|
||||||
|
name: vaultwarden-login
|
||||||
|
kind: ClusterSecretStore
|
||||||
|
remoteRef:
|
||||||
|
key: 97bd0af9-54ab-429a-b060-09626525f4cd
|
||||||
|
property: fields[0].value
|
||||||
|
|
||||||
|
---
|
||||||
|
apiVersion: external-secrets.io/v1beta1
|
||||||
|
kind: ExternalSecret
|
||||||
|
metadata:
|
||||||
|
name: desubot
|
||||||
|
spec:
|
||||||
|
target:
|
||||||
|
name: desubot
|
||||||
|
deletionPolicy: Delete
|
||||||
|
template:
|
||||||
|
type: Opaque
|
||||||
|
data:
|
||||||
|
TELEGRAM_BOT_TOKEN: |-
|
||||||
|
{{ .token }}
|
||||||
|
|
||||||
|
data:
|
||||||
|
- secretKey: token
|
||||||
|
sourceRef:
|
||||||
|
storeRef:
|
||||||
|
name: vaultwarden-login
|
||||||
|
kind: ClusterSecretStore
|
||||||
|
remoteRef:
|
||||||
|
key: 97bd0af9-54ab-429a-b060-09626525f4cd
|
||||||
|
property: fields[1].value
|
||||||
36
k8s/apps/tg-bots/get-id-bot.yaml
Normal file
36
k8s/apps/tg-bots/get-id-bot.yaml
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
---
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: get-id-bot
|
||||||
|
labels:
|
||||||
|
app: get-id-bot
|
||||||
|
annotations:
|
||||||
|
reloader.stakater.com/auto: "true"
|
||||||
|
spec:
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
app: get-id-bot
|
||||||
|
replicas: 1
|
||||||
|
strategy:
|
||||||
|
type: RollingUpdate
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
app: get-id-bot
|
||||||
|
spec:
|
||||||
|
nodeSelector:
|
||||||
|
kubernetes.io/hostname: master.tail2fe2d.ts.net
|
||||||
|
containers:
|
||||||
|
- name: get-id-bot
|
||||||
|
image: 'ghcr.io/house-of-vanity/get_id_bot:main'
|
||||||
|
imagePullPolicy: Always
|
||||||
|
envFrom:
|
||||||
|
- secretRef:
|
||||||
|
name: get-id-bot
|
||||||
|
env:
|
||||||
|
- name: RUST_LOG
|
||||||
|
value: "info"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
9
k8s/apps/tg-bots/kustomization.yaml
Normal file
9
k8s/apps/tg-bots/kustomization.yaml
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
---
|
||||||
|
apiVersion: kustomize.config.k8s.io/v1beta1
|
||||||
|
kind: Kustomization
|
||||||
|
|
||||||
|
resources:
|
||||||
|
- app.yaml
|
||||||
|
- get-id-bot.yaml
|
||||||
|
- external-secrets.yaml
|
||||||
|
- desubot.yaml
|
||||||
@@ -31,6 +31,13 @@ spec:
|
|||||||
- name: vaultwarden
|
- name: vaultwarden
|
||||||
image: 'vaultwarden/server:latest'
|
image: 'vaultwarden/server:latest'
|
||||||
imagePullPolicy: Always
|
imagePullPolicy: Always
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
memory: "256Mi"
|
||||||
|
cpu: "100m"
|
||||||
|
limits:
|
||||||
|
memory: "1Gi"
|
||||||
|
cpu: "500m"
|
||||||
env:
|
env:
|
||||||
- name: DOMAIN
|
- name: DOMAIN
|
||||||
value: https://vw.hexor.cy
|
value: https://vw.hexor.cy
|
||||||
|
|||||||
25
k8s/apps/vpn/config.yaml
Normal file
25
k8s/apps/vpn/config.yaml
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
apiVersion: v1
|
||||||
|
kind: ConfigMap
|
||||||
|
metadata:
|
||||||
|
name: outfleet-rs-config
|
||||||
|
data:
|
||||||
|
config.toml: |-
|
||||||
|
[database]
|
||||||
|
url = "postgres://outfleet_rs:FMj#bA0XW14Pd2@psql.psql.svc:5432/outfleet_rs"
|
||||||
|
|
||||||
|
[web]
|
||||||
|
host = "0.0.0.0"
|
||||||
|
port = 8080
|
||||||
|
base_url = "https://vpn.hexor.cy"
|
||||||
|
|
||||||
|
[telegram]
|
||||||
|
enabled = false
|
||||||
|
admin_chat_ids = []
|
||||||
|
allowed_users = []
|
||||||
|
|
||||||
|
[xray]
|
||||||
|
config_path = "./templates"
|
||||||
|
|
||||||
|
[log]
|
||||||
|
level = "debug"
|
||||||
|
|
||||||
@@ -6,4 +6,7 @@ resources:
|
|||||||
- ./external-secrets.yaml
|
- ./external-secrets.yaml
|
||||||
- ./outfleet.yaml
|
- ./outfleet.yaml
|
||||||
- ./shadowsocks.yaml
|
- ./shadowsocks.yaml
|
||||||
|
- ./outfleet-rs.yaml
|
||||||
|
- ./config.yaml
|
||||||
|
- ./xray.yaml
|
||||||
|
|
||||||
|
|||||||
66
k8s/apps/vpn/outfleet-rs.yaml
Normal file
66
k8s/apps/vpn/outfleet-rs.yaml
Normal file
@@ -0,0 +1,66 @@
|
|||||||
|
---
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: outfleet-rs
|
||||||
|
labels:
|
||||||
|
app: outfleet-rs
|
||||||
|
annotations:
|
||||||
|
reloader.stakater.com/auto: "true"
|
||||||
|
spec:
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
app: outfleet-rs
|
||||||
|
replicas: 1
|
||||||
|
strategy:
|
||||||
|
type: RollingUpdate
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
app: outfleet-rs
|
||||||
|
spec:
|
||||||
|
hostname: outfleet-rs
|
||||||
|
nodeSelector:
|
||||||
|
kubernetes.io/hostname: master.tail2fe2d.ts.net
|
||||||
|
containers:
|
||||||
|
- name: outfleet-rs
|
||||||
|
image: 'ultradesu/outfleet:rs-0.1.3'
|
||||||
|
imagePullPolicy: Always
|
||||||
|
command: ["/bin/sh"]
|
||||||
|
args:
|
||||||
|
- "-c"
|
||||||
|
- |
|
||||||
|
set -x
|
||||||
|
/app/xray-admin --host 0.0.0.0 --port 8080
|
||||||
|
ports:
|
||||||
|
- name: http
|
||||||
|
containerPort: 8080
|
||||||
|
protocol: TCP
|
||||||
|
env:
|
||||||
|
- name: RUST_LOG
|
||||||
|
value: "info"
|
||||||
|
volumeMounts:
|
||||||
|
- name: outfleet-config
|
||||||
|
mountPath: /app/config.toml # <-- target path inside container
|
||||||
|
subPath: config.toml # <-- use the specific key as a file
|
||||||
|
readOnly: true
|
||||||
|
volumes:
|
||||||
|
- name: outfleet-config
|
||||||
|
configMap:
|
||||||
|
name: outfleet-rs-config
|
||||||
|
items:
|
||||||
|
- key: config.toml
|
||||||
|
path: config.toml
|
||||||
|
|
||||||
|
---
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Service
|
||||||
|
metadata:
|
||||||
|
name: outfleet-rs
|
||||||
|
spec:
|
||||||
|
selector:
|
||||||
|
app: outfleet-rs
|
||||||
|
ports:
|
||||||
|
- protocol: TCP
|
||||||
|
port: 80
|
||||||
|
targetPort: 8080
|
||||||
@@ -30,8 +30,11 @@ spec:
|
|||||||
args:
|
args:
|
||||||
- "-c"
|
- "-c"
|
||||||
- |
|
- |
|
||||||
python ./manage.py makemigrations vpn
|
set -x
|
||||||
|
#python ./manage.py makemigrations
|
||||||
|
#python ./manage.py makemigrations vpn
|
||||||
python ./manage.py migrate
|
python ./manage.py migrate
|
||||||
|
python ./manage.py migrate vpn
|
||||||
python ./manage.py create_admin
|
python ./manage.py create_admin
|
||||||
python ./manage.py runserver 0.0.0.0:8000
|
python ./manage.py runserver 0.0.0.0:8000
|
||||||
envFrom:
|
envFrom:
|
||||||
|
|||||||
209
k8s/apps/vpn/xray.yaml
Normal file
209
k8s/apps/vpn/xray.yaml
Normal file
@@ -0,0 +1,209 @@
|
|||||||
|
---
|
||||||
|
apiVersion: v1
|
||||||
|
kind: ConfigMap
|
||||||
|
metadata:
|
||||||
|
name: xray-config-template
|
||||||
|
data:
|
||||||
|
config.json.template: |
|
||||||
|
{
|
||||||
|
"log": {
|
||||||
|
"loglevel": "warning"
|
||||||
|
},
|
||||||
|
"api": {
|
||||||
|
"tag": "api",
|
||||||
|
"listen": "TAILSCALE_IP:10086",
|
||||||
|
"services": [
|
||||||
|
"HandlerService",
|
||||||
|
"StatsService",
|
||||||
|
"LoggerService",
|
||||||
|
"RoutingService",
|
||||||
|
"ReflectionService"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"stats": {},
|
||||||
|
"policy": {
|
||||||
|
"system": {
|
||||||
|
"statsInboundDownlink": true,
|
||||||
|
"statsInboundUplink": true,
|
||||||
|
"statsOutboundDownlink": true,
|
||||||
|
"statsOutboundUplink": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"inbounds": [],
|
||||||
|
"outbounds": [
|
||||||
|
{
|
||||||
|
"tag": "direct",
|
||||||
|
"protocol": "freedom",
|
||||||
|
"settings": {}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"routing": {
|
||||||
|
"rules": []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
---
|
||||||
|
apiVersion: v1
|
||||||
|
kind: ConfigMap
|
||||||
|
metadata:
|
||||||
|
name: xray-init-script
|
||||||
|
data:
|
||||||
|
init.sh: |
|
||||||
|
#!/bin/sh
|
||||||
|
set -e
|
||||||
|
|
||||||
|
echo "Starting Xray configuration setup..."
|
||||||
|
|
||||||
|
# Find xray binary location
|
||||||
|
XRAY_BIN=""
|
||||||
|
for path in /usr/bin/xray /usr/local/bin/xray /bin/xray /opt/xray/xray; do
|
||||||
|
if [ -x "$path" ]; then
|
||||||
|
XRAY_BIN="$path"
|
||||||
|
echo "Found Xray binary at: $XRAY_BIN"
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
if [ -z "$XRAY_BIN" ]; then
|
||||||
|
echo "Error: Xray binary not found"
|
||||||
|
echo "Available files in common locations:"
|
||||||
|
ls -la /usr/bin/xray* 2>/dev/null || echo "No xray in /usr/bin/"
|
||||||
|
ls -la /usr/local/bin/xray* 2>/dev/null || echo "No xray in /usr/local/bin/"
|
||||||
|
ls -la /bin/xray* 2>/dev/null || echo "No xray in /bin/"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Get Tailscale IP address
|
||||||
|
TAILSCALE_IP=""
|
||||||
|
|
||||||
|
# Try different ways to get Tailscale IP
|
||||||
|
if command -v ip >/dev/null 2>&1; then
|
||||||
|
TAILSCALE_IP=$(ip addr show tailscale0 2>/dev/null | grep 'inet ' | awk '{print $2}' | cut -d'/' -f1 | head -n1)
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Fallback: try to find any interface with 100.x.x.x IP (typical Tailscale range)
|
||||||
|
if [ -z "$TAILSCALE_IP" ]; then
|
||||||
|
TAILSCALE_IP=$(ip route get 8.8.8.8 2>/dev/null | grep -o 'src [0-9\.]*' | grep '100\.' | awk '{print $2}' | head -n1)
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Another fallback: check all interfaces for 100.x.x.x
|
||||||
|
if [ -z "$TAILSCALE_IP" ]; then
|
||||||
|
TAILSCALE_IP=$(ip addr show 2>/dev/null | grep -o 'inet 100\.[0-9\.]*' | awk '{print $2}' | head -n1)
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Final fallback: use localhost if no Tailscale IP found
|
||||||
|
if [ -z "$TAILSCALE_IP" ]; then
|
||||||
|
echo "Warning: Could not find Tailscale IP, using 127.0.0.1"
|
||||||
|
TAILSCALE_IP="127.0.0.1"
|
||||||
|
else
|
||||||
|
echo "Found Tailscale IP: $TAILSCALE_IP"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Create config directory
|
||||||
|
mkdir -p /usr/local/etc/xray
|
||||||
|
|
||||||
|
# Replace TAILSCALE_IP placeholder in config template
|
||||||
|
sed "s/TAILSCALE_IP/$TAILSCALE_IP/g" /config-template/config.json.template > /usr/local/etc/xray/config.json
|
||||||
|
|
||||||
|
echo "Generated Xray config:"
|
||||||
|
cat /usr/local/etc/xray/config.json
|
||||||
|
|
||||||
|
# Increase file descriptor limits
|
||||||
|
ulimit -n 65536 2>/dev/null || echo "Warning: Could not increase file descriptor limit"
|
||||||
|
|
||||||
|
echo "Starting Xray with binary: $XRAY_BIN"
|
||||||
|
exec "$XRAY_BIN" run -c /usr/local/etc/xray/config.json
|
||||||
|
|
||||||
|
---
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: DaemonSet
|
||||||
|
metadata:
|
||||||
|
name: xray-daemon
|
||||||
|
labels:
|
||||||
|
app: xray
|
||||||
|
spec:
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
app: xray
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
app: xray
|
||||||
|
spec:
|
||||||
|
hostNetwork: true
|
||||||
|
dnsPolicy: ClusterFirstWithHostNet
|
||||||
|
nodeSelector:
|
||||||
|
xray: "true"
|
||||||
|
tolerations:
|
||||||
|
- operator: Exists
|
||||||
|
effect: NoSchedule
|
||||||
|
containers:
|
||||||
|
- name: xray
|
||||||
|
image: teddysun/xray:25.7.26
|
||||||
|
command: ["/bin/sh"]
|
||||||
|
args: ["/scripts/init.sh"]
|
||||||
|
securityContext:
|
||||||
|
privileged: true
|
||||||
|
capabilities:
|
||||||
|
add:
|
||||||
|
- NET_ADMIN
|
||||||
|
- NET_RAW
|
||||||
|
volumeMounts:
|
||||||
|
- name: config-template
|
||||||
|
mountPath: /config-template
|
||||||
|
readOnly: true
|
||||||
|
- name: init-script
|
||||||
|
mountPath: /scripts
|
||||||
|
readOnly: true
|
||||||
|
- name: xray-config
|
||||||
|
mountPath: /usr/local/etc/xray
|
||||||
|
ports:
|
||||||
|
- containerPort: 10086
|
||||||
|
protocol: TCP
|
||||||
|
name: api
|
||||||
|
livenessProbe:
|
||||||
|
tcpSocket:
|
||||||
|
port: 10086
|
||||||
|
initialDelaySeconds: 30
|
||||||
|
periodSeconds: 10
|
||||||
|
readinessProbe:
|
||||||
|
tcpSocket:
|
||||||
|
port: 10086
|
||||||
|
initialDelaySeconds: 5
|
||||||
|
periodSeconds: 5
|
||||||
|
resources:
|
||||||
|
limits:
|
||||||
|
memory: "512Mi"
|
||||||
|
cpu: "500m"
|
||||||
|
requests:
|
||||||
|
memory: "256Mi"
|
||||||
|
cpu: "250m"
|
||||||
|
volumes:
|
||||||
|
- name: config-template
|
||||||
|
configMap:
|
||||||
|
name: xray-config-template
|
||||||
|
defaultMode: 0644
|
||||||
|
- name: init-script
|
||||||
|
configMap:
|
||||||
|
name: xray-init-script
|
||||||
|
defaultMode: 0755
|
||||||
|
- name: xray-config
|
||||||
|
emptyDir: {}
|
||||||
|
restartPolicy: Always
|
||||||
|
|
||||||
|
---
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Service
|
||||||
|
metadata:
|
||||||
|
name: xray-api-service
|
||||||
|
labels:
|
||||||
|
app: xray
|
||||||
|
spec:
|
||||||
|
type: ClusterIP
|
||||||
|
ports:
|
||||||
|
- port: 10086
|
||||||
|
targetPort: 10086
|
||||||
|
protocol: TCP
|
||||||
|
name: api
|
||||||
|
selector:
|
||||||
|
app: xray
|
||||||
@@ -14,8 +14,8 @@ spec:
|
|||||||
labels:
|
labels:
|
||||||
app.kubernetes.io/part-of: argocd
|
app.kubernetes.io/part-of: argocd
|
||||||
data:
|
data:
|
||||||
id: "{{ .client_id | quote }}"
|
id: "{{ .client_id }}"
|
||||||
secret: "{{ .client_secret | quote }}"
|
secret: "{{ .client_secret }}"
|
||||||
data:
|
data:
|
||||||
- secretKey: client_id
|
- secretKey: client_id
|
||||||
sourceRef:
|
sourceRef:
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ resources:
|
|||||||
helmCharts:
|
helmCharts:
|
||||||
- name: argo-cd
|
- name: argo-cd
|
||||||
repo: https://argoproj.github.io/argo-helm
|
repo: https://argoproj.github.io/argo-helm
|
||||||
version: 7.8.26
|
version: 8.1.3
|
||||||
releaseName: argocd
|
releaseName: argocd
|
||||||
namespace: argocd
|
namespace: argocd
|
||||||
valuesFile: values.yaml
|
valuesFile: values.yaml
|
||||||
|
|||||||
@@ -17,9 +17,11 @@ configs:
|
|||||||
server.insecure: "true"
|
server.insecure: "true"
|
||||||
cm:
|
cm:
|
||||||
create: true
|
create: true
|
||||||
|
exec.enabled: true
|
||||||
kustomize.buildOptions: --enable-helm
|
kustomize.buildOptions: --enable-helm
|
||||||
application.instanceLabelKey: argocd.argoproj.io/instance
|
application.instanceLabelKey: argocd.argoproj.io/instance
|
||||||
admin.enabled: true
|
admin.enabled: false
|
||||||
|
statusbadge.enabled: true
|
||||||
timeout.reconciliation: 60s
|
timeout.reconciliation: 60s
|
||||||
oidc.config: |
|
oidc.config: |
|
||||||
name: Authentik
|
name: Authentik
|
||||||
@@ -32,7 +34,20 @@ configs:
|
|||||||
create: true
|
create: true
|
||||||
policy.default: ""
|
policy.default: ""
|
||||||
policy.csv: |
|
policy.csv: |
|
||||||
g, k8s_dashboard, role:admin
|
# Bound OIDC Group and internal role
|
||||||
|
g, Game Servers Managers, GameServersManagersRole
|
||||||
|
# Role permissions
|
||||||
|
p, GameServersManagersRole, applications, get, games/*, allow
|
||||||
|
p, GameServersManagersRole, applications, update, games/*, allow
|
||||||
|
p, GameServersManagersRole, applications, sync, games/*, allow
|
||||||
|
p, GameServersManagersRole, applications, override, games/*, allow
|
||||||
|
p, GameServersManagersRole, applications, action/*, games/*, allow
|
||||||
|
p, GameServersManagersRole, exec, create, games/*, allow
|
||||||
|
p, GameServersManagersRole, logs, get, games/*, allow
|
||||||
|
p, GameServersManagersRole, applications, delete, games/*, deny
|
||||||
|
|
||||||
|
# Admin policy
|
||||||
|
g, ArgoCD Admins, role:admin
|
||||||
|
|
||||||
secret:
|
secret:
|
||||||
createSecret: true
|
createSecret: true
|
||||||
|
|||||||
@@ -5,11 +5,12 @@ resources:
|
|||||||
- app.yaml
|
- app.yaml
|
||||||
- external-secrets.yaml
|
- external-secrets.yaml
|
||||||
- https-middleware.yaml
|
- https-middleware.yaml
|
||||||
|
- worker-restart.yaml
|
||||||
|
|
||||||
helmCharts:
|
helmCharts:
|
||||||
- name: authentik
|
- name: authentik
|
||||||
repo: https://charts.goauthentik.io
|
repo: https://charts.goauthentik.io
|
||||||
version: 2025.2.3
|
version: 2025.8.1
|
||||||
releaseName: authentik
|
releaseName: authentik
|
||||||
namespace: authentik
|
namespace: authentik
|
||||||
valuesFile: values.yaml
|
valuesFile: values.yaml
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
global:
|
global:
|
||||||
image:
|
image:
|
||||||
tag: "2025.4.1"
|
tag: "2025.8.1"
|
||||||
nodeSelector:
|
nodeSelector:
|
||||||
kubernetes.io/hostname: master.tail2fe2d.ts.net
|
kubernetes.io/hostname: master.tail2fe2d.ts.net
|
||||||
|
|
||||||
@@ -15,6 +15,14 @@ worker:
|
|||||||
envFrom:
|
envFrom:
|
||||||
- secretRef:
|
- secretRef:
|
||||||
name: authentik-creds
|
name: authentik-creds
|
||||||
|
volumes:
|
||||||
|
- name: dshm
|
||||||
|
emptyDir:
|
||||||
|
medium: Memory
|
||||||
|
sizeLimit: 512Mi
|
||||||
|
volumeMounts:
|
||||||
|
- name: dshm
|
||||||
|
mountPath: /dev/shm
|
||||||
server:
|
server:
|
||||||
envFrom:
|
envFrom:
|
||||||
- secretRef:
|
- secretRef:
|
||||||
@@ -30,15 +38,15 @@ server:
|
|||||||
- nas.hexor.cy # TrueNAS Limassol
|
- nas.hexor.cy # TrueNAS Limassol
|
||||||
- nc.hexor.cy # NaxtCloud
|
- nc.hexor.cy # NaxtCloud
|
||||||
- of.hexor.cy # Outfleet-v2
|
- of.hexor.cy # Outfleet-v2
|
||||||
- master.hexor.cy # k8s dashboard
|
- k8s.hexor.cy # k8s dashboard
|
||||||
- qbt.hexor.cy # qBittorent for Jellyfin
|
- qbt.hexor.cy # qBittorent for Jellyfin
|
||||||
- prom.hexor.cy # Prometheus
|
- prom.hexor.cy # Prometheus
|
||||||
- ss.hexor.cy # Syncthing UI
|
|
||||||
- khm.hexor.cy # Known Hosts keys Manager
|
- khm.hexor.cy # Known Hosts keys Manager
|
||||||
- backup.hexor.cy # Kopia Backup UI
|
- backup.hexor.cy # Kopia Backup UI
|
||||||
- fm.hexor.cy # Filemanager
|
- fm.hexor.cy # Filemanager
|
||||||
- hexound.hexor.cy # Hexound
|
|
||||||
- minecraft.hexor.cy # Minecraft UI and server
|
- minecraft.hexor.cy # Minecraft UI and server
|
||||||
|
- pass.hexor.cy # k8s-secret for openai
|
||||||
|
- ps.hexor.cy # pasarguard UI
|
||||||
tls:
|
tls:
|
||||||
- secretName: idm-tls
|
- secretName: idm-tls
|
||||||
hosts:
|
hosts:
|
||||||
|
|||||||
55
k8s/core/authentik/worker-restart.yaml
Normal file
55
k8s/core/authentik/worker-restart.yaml
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
---
|
||||||
|
apiVersion: v1
|
||||||
|
kind: ServiceAccount
|
||||||
|
metadata:
|
||||||
|
name: worker-restart-sa
|
||||||
|
|
||||||
|
---
|
||||||
|
apiVersion: rbac.authorization.k8s.io/v1
|
||||||
|
kind: Role
|
||||||
|
metadata:
|
||||||
|
name: worker-restart-role
|
||||||
|
rules:
|
||||||
|
- apiGroups: ["apps"]
|
||||||
|
resources: ["deployments"]
|
||||||
|
verbs: ["get", "patch"]
|
||||||
|
|
||||||
|
---
|
||||||
|
apiVersion: rbac.authorization.k8s.io/v1
|
||||||
|
kind: RoleBinding
|
||||||
|
metadata:
|
||||||
|
name: worker-restart-rb
|
||||||
|
subjects:
|
||||||
|
- kind: ServiceAccount
|
||||||
|
name: worker-restart-sa
|
||||||
|
roleRef:
|
||||||
|
apiGroup: rbac.authorization.k8s.io
|
||||||
|
kind: Role
|
||||||
|
name: worker-restart-role
|
||||||
|
|
||||||
|
---
|
||||||
|
apiVersion: batch/v1
|
||||||
|
kind: CronJob
|
||||||
|
metadata:
|
||||||
|
name: worker-daily-restart
|
||||||
|
spec:
|
||||||
|
schedule: "0 * * * *" # every day at 04:00
|
||||||
|
jobTemplate:
|
||||||
|
spec:
|
||||||
|
template:
|
||||||
|
spec:
|
||||||
|
serviceAccountName: worker-restart-sa
|
||||||
|
restartPolicy: OnFailure
|
||||||
|
containers:
|
||||||
|
- name: kubectl
|
||||||
|
image: bitnami/kubectl:latest
|
||||||
|
env:
|
||||||
|
- name: POD_NAMESPACE
|
||||||
|
valueFrom:
|
||||||
|
fieldRef:
|
||||||
|
fieldPath: metadata.namespace
|
||||||
|
command:
|
||||||
|
- /bin/sh
|
||||||
|
- -c
|
||||||
|
- |
|
||||||
|
kubectl -n "$POD_NAMESPACE" rollout restart deployment/authentik-worker
|
||||||
@@ -39,6 +39,13 @@ spec:
|
|||||||
- name: bitwarden-cli
|
- name: bitwarden-cli
|
||||||
image: ultradesu/bitwarden-client:2025.5.0
|
image: ultradesu/bitwarden-client:2025.5.0
|
||||||
imagePullPolicy: Always
|
imagePullPolicy: Always
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
memory: "128Mi"
|
||||||
|
cpu: "100m"
|
||||||
|
limits:
|
||||||
|
memory: "512Mi"
|
||||||
|
cpu: "500m"
|
||||||
env:
|
env:
|
||||||
- name: BW_HOST
|
- name: BW_HOST
|
||||||
valueFrom:
|
valueFrom:
|
||||||
|
|||||||
18
k8s/core/kube-system-custom/app.yaml
Normal file
18
k8s/core/kube-system-custom/app.yaml
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
apiVersion: argoproj.io/v1alpha1
|
||||||
|
kind: Application
|
||||||
|
metadata:
|
||||||
|
name: kube-system-custom
|
||||||
|
namespace: argocd
|
||||||
|
spec:
|
||||||
|
project: core
|
||||||
|
destination:
|
||||||
|
namespace: kube-system
|
||||||
|
server: https://kubernetes.default.svc
|
||||||
|
source:
|
||||||
|
repoURL: ssh://git@gt.hexor.cy:30022/ab/homelab.git
|
||||||
|
targetRevision: HEAD
|
||||||
|
path: k8s/core/kube-system-custom
|
||||||
|
syncPolicy:
|
||||||
|
syncOptions:
|
||||||
|
- CreateNamespace=false
|
||||||
|
|
||||||
25
k8s/core/kube-system-custom/coredns-internal-resolve.yaml
Normal file
25
k8s/core/kube-system-custom/coredns-internal-resolve.yaml
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
apiVersion: v1
|
||||||
|
kind: ConfigMap
|
||||||
|
metadata:
|
||||||
|
annotations:
|
||||||
|
name: coredns-custom
|
||||||
|
namespace: kube-system
|
||||||
|
data:
|
||||||
|
homenet.server: |
|
||||||
|
homenet:53 {
|
||||||
|
errors
|
||||||
|
cache 30
|
||||||
|
forward . 10.0.5.1
|
||||||
|
}
|
||||||
|
khv.server: |
|
||||||
|
khv:53 {
|
||||||
|
errors
|
||||||
|
cache 30
|
||||||
|
forward . 10.0.5.1
|
||||||
|
}
|
||||||
|
tailscale.server: |
|
||||||
|
tail2fe2d.ts.net:53 {
|
||||||
|
errors
|
||||||
|
cache 30
|
||||||
|
forward . 100.100.100.100
|
||||||
|
}
|
||||||
7
k8s/core/kube-system-custom/kustomization.yaml
Normal file
7
k8s/core/kube-system-custom/kustomization.yaml
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
apiVersion: kustomize.config.k8s.io/v1beta1
|
||||||
|
kind: Kustomization
|
||||||
|
|
||||||
|
resources:
|
||||||
|
- app.yaml
|
||||||
|
- coredns-internal-resolve.yaml
|
||||||
|
|
||||||
@@ -20,6 +20,13 @@ spec:
|
|||||||
- name: kubernetes-dashboard
|
- name: kubernetes-dashboard
|
||||||
image: kubernetesui/dashboard:v2.7.0
|
image: kubernetesui/dashboard:v2.7.0
|
||||||
imagePullPolicy: Always
|
imagePullPolicy: Always
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
memory: "128Mi"
|
||||||
|
cpu: "100m"
|
||||||
|
limits:
|
||||||
|
memory: "512Mi"
|
||||||
|
cpu: "500m"
|
||||||
ports:
|
ports:
|
||||||
- containerPort: 8443
|
- containerPort: 8443
|
||||||
protocol: TCP
|
protocol: TCP
|
||||||
@@ -87,6 +94,13 @@ spec:
|
|||||||
containers:
|
containers:
|
||||||
- name: dashboard-metrics-scraper
|
- name: dashboard-metrics-scraper
|
||||||
image: kubernetesui/metrics-scraper:v1.0.6
|
image: kubernetesui/metrics-scraper:v1.0.6
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
memory: "64Mi"
|
||||||
|
cpu: "50m"
|
||||||
|
limits:
|
||||||
|
memory: "256Mi"
|
||||||
|
cpu: "200m"
|
||||||
ports:
|
ports:
|
||||||
- containerPort: 8000
|
- containerPort: 8000
|
||||||
protocol: TCP
|
protocol: TCP
|
||||||
|
|||||||
@@ -13,9 +13,7 @@ spec:
|
|||||||
targetRevision: HEAD
|
targetRevision: HEAD
|
||||||
path: k8s/core/postgresql
|
path: k8s/core/postgresql
|
||||||
syncPolicy:
|
syncPolicy:
|
||||||
automated:
|
|
||||||
selfHeal: true
|
|
||||||
prune: true
|
|
||||||
syncOptions:
|
syncOptions:
|
||||||
- CreateNamespace=true
|
- CreateNamespace=true
|
||||||
|
- ServerSideApply=true
|
||||||
|
|
||||||
|
|||||||
@@ -40,6 +40,9 @@ spec:
|
|||||||
name: vaultwarden-login
|
name: vaultwarden-login
|
||||||
kind: ClusterSecretStore
|
kind: ClusterSecretStore
|
||||||
remoteRef:
|
remoteRef:
|
||||||
|
conversionStrategy: Default
|
||||||
|
decodingStrategy: None
|
||||||
|
metadataPolicy: None
|
||||||
key: 832042b9-7edb-4f4c-9254-3c8884ba9733
|
key: 832042b9-7edb-4f4c-9254-3c8884ba9733
|
||||||
property: login.username
|
property: login.username
|
||||||
- secretKey: password
|
- secretKey: password
|
||||||
@@ -48,6 +51,9 @@ spec:
|
|||||||
name: vaultwarden-login
|
name: vaultwarden-login
|
||||||
kind: ClusterSecretStore
|
kind: ClusterSecretStore
|
||||||
remoteRef:
|
remoteRef:
|
||||||
|
conversionStrategy: Default
|
||||||
|
decodingStrategy: None
|
||||||
|
metadataPolicy: None
|
||||||
key: 832042b9-7edb-4f4c-9254-3c8884ba9733
|
key: 832042b9-7edb-4f4c-9254-3c8884ba9733
|
||||||
property: login.password
|
property: login.password
|
||||||
- secretKey: client_id
|
- secretKey: client_id
|
||||||
@@ -56,6 +62,9 @@ spec:
|
|||||||
name: vaultwarden-login
|
name: vaultwarden-login
|
||||||
kind: ClusterSecretStore
|
kind: ClusterSecretStore
|
||||||
remoteRef:
|
remoteRef:
|
||||||
|
conversionStrategy: Default
|
||||||
|
decodingStrategy: None
|
||||||
|
metadataPolicy: None
|
||||||
key: 832042b9-7edb-4f4c-9254-3c8884ba9733
|
key: 832042b9-7edb-4f4c-9254-3c8884ba9733
|
||||||
property: fields[0].value
|
property: fields[0].value
|
||||||
- secretKey: client_secret
|
- secretKey: client_secret
|
||||||
@@ -64,6 +73,9 @@ spec:
|
|||||||
name: vaultwarden-login
|
name: vaultwarden-login
|
||||||
kind: ClusterSecretStore
|
kind: ClusterSecretStore
|
||||||
remoteRef:
|
remoteRef:
|
||||||
|
conversionStrategy: Default
|
||||||
|
decodingStrategy: None
|
||||||
|
metadataPolicy: None
|
||||||
key: 832042b9-7edb-4f4c-9254-3c8884ba9733
|
key: 832042b9-7edb-4f4c-9254-3c8884ba9733
|
||||||
property: fields[1].value
|
property: fields[1].value
|
||||||
- secretKey: pgadmin_url
|
- secretKey: pgadmin_url
|
||||||
@@ -72,6 +84,9 @@ spec:
|
|||||||
name: vaultwarden-login
|
name: vaultwarden-login
|
||||||
kind: ClusterSecretStore
|
kind: ClusterSecretStore
|
||||||
remoteRef:
|
remoteRef:
|
||||||
|
conversionStrategy: Default
|
||||||
|
decodingStrategy: None
|
||||||
|
metadataPolicy: None
|
||||||
key: 832042b9-7edb-4f4c-9254-3c8884ba9733
|
key: 832042b9-7edb-4f4c-9254-3c8884ba9733
|
||||||
property: fields[2].value
|
property: fields[2].value
|
||||||
---
|
---
|
||||||
@@ -98,6 +113,12 @@ spec:
|
|||||||
{{ .grafana }}
|
{{ .grafana }}
|
||||||
USER_khm: |-
|
USER_khm: |-
|
||||||
{{ .khm }}
|
{{ .khm }}
|
||||||
|
USER_kanjai: |-
|
||||||
|
{{ .kanjai }}
|
||||||
|
USER_outfleet_rs: |-
|
||||||
|
{{ .outfleet_rs }}
|
||||||
|
USER_pasarguard: |-
|
||||||
|
{{ .pasarguard }}
|
||||||
data:
|
data:
|
||||||
- secretKey: authentik
|
- secretKey: authentik
|
||||||
sourceRef:
|
sourceRef:
|
||||||
@@ -105,6 +126,9 @@ spec:
|
|||||||
name: vaultwarden-login
|
name: vaultwarden-login
|
||||||
kind: ClusterSecretStore
|
kind: ClusterSecretStore
|
||||||
remoteRef:
|
remoteRef:
|
||||||
|
conversionStrategy: Default
|
||||||
|
decodingStrategy: None
|
||||||
|
metadataPolicy: None
|
||||||
key: 2a9deb39-ef22-433e-a1be-df1555625e22
|
key: 2a9deb39-ef22-433e-a1be-df1555625e22
|
||||||
property: fields[0].value
|
property: fields[0].value
|
||||||
- secretKey: outfleet
|
- secretKey: outfleet
|
||||||
@@ -113,6 +137,9 @@ spec:
|
|||||||
name: vaultwarden-login
|
name: vaultwarden-login
|
||||||
kind: ClusterSecretStore
|
kind: ClusterSecretStore
|
||||||
remoteRef:
|
remoteRef:
|
||||||
|
conversionStrategy: Default
|
||||||
|
decodingStrategy: None
|
||||||
|
metadataPolicy: None
|
||||||
key: 2a9deb39-ef22-433e-a1be-df1555625e22
|
key: 2a9deb39-ef22-433e-a1be-df1555625e22
|
||||||
property: fields[1].value
|
property: fields[1].value
|
||||||
- secretKey: grafana
|
- secretKey: grafana
|
||||||
@@ -121,6 +148,9 @@ spec:
|
|||||||
name: vaultwarden-login
|
name: vaultwarden-login
|
||||||
kind: ClusterSecretStore
|
kind: ClusterSecretStore
|
||||||
remoteRef:
|
remoteRef:
|
||||||
|
conversionStrategy: Default
|
||||||
|
decodingStrategy: None
|
||||||
|
metadataPolicy: None
|
||||||
key: 2a9deb39-ef22-433e-a1be-df1555625e22
|
key: 2a9deb39-ef22-433e-a1be-df1555625e22
|
||||||
property: fields[2].value
|
property: fields[2].value
|
||||||
- secretKey: khm
|
- secretKey: khm
|
||||||
@@ -129,6 +159,9 @@ spec:
|
|||||||
name: vaultwarden-login
|
name: vaultwarden-login
|
||||||
kind: ClusterSecretStore
|
kind: ClusterSecretStore
|
||||||
remoteRef:
|
remoteRef:
|
||||||
|
conversionStrategy: Default
|
||||||
|
decodingStrategy: None
|
||||||
|
metadataPolicy: None
|
||||||
key: 2a9deb39-ef22-433e-a1be-df1555625e22
|
key: 2a9deb39-ef22-433e-a1be-df1555625e22
|
||||||
property: fields[3].value
|
property: fields[3].value
|
||||||
- secretKey: nextcloud
|
- secretKey: nextcloud
|
||||||
@@ -137,6 +170,9 @@ spec:
|
|||||||
name: vaultwarden-login
|
name: vaultwarden-login
|
||||||
kind: ClusterSecretStore
|
kind: ClusterSecretStore
|
||||||
remoteRef:
|
remoteRef:
|
||||||
|
conversionStrategy: Default
|
||||||
|
decodingStrategy: None
|
||||||
|
metadataPolicy: None
|
||||||
key: 2a9deb39-ef22-433e-a1be-df1555625e22
|
key: 2a9deb39-ef22-433e-a1be-df1555625e22
|
||||||
property: fields[4].value
|
property: fields[4].value
|
||||||
- secretKey: paperless
|
- secretKey: paperless
|
||||||
@@ -145,5 +181,41 @@ spec:
|
|||||||
name: vaultwarden-login
|
name: vaultwarden-login
|
||||||
kind: ClusterSecretStore
|
kind: ClusterSecretStore
|
||||||
remoteRef:
|
remoteRef:
|
||||||
|
conversionStrategy: Default
|
||||||
|
decodingStrategy: None
|
||||||
|
metadataPolicy: None
|
||||||
key: 2a9deb39-ef22-433e-a1be-df1555625e22
|
key: 2a9deb39-ef22-433e-a1be-df1555625e22
|
||||||
property: fields[5].value
|
property: fields[5].value
|
||||||
|
- secretKey: kanjai
|
||||||
|
sourceRef:
|
||||||
|
storeRef:
|
||||||
|
name: vaultwarden-login
|
||||||
|
kind: ClusterSecretStore
|
||||||
|
remoteRef:
|
||||||
|
conversionStrategy: Default
|
||||||
|
decodingStrategy: None
|
||||||
|
metadataPolicy: None
|
||||||
|
key: 2a9deb39-ef22-433e-a1be-df1555625e22
|
||||||
|
property: fields[7].value
|
||||||
|
- secretKey: outfleet_rs
|
||||||
|
sourceRef:
|
||||||
|
storeRef:
|
||||||
|
name: vaultwarden-login
|
||||||
|
kind: ClusterSecretStore
|
||||||
|
remoteRef:
|
||||||
|
conversionStrategy: Default
|
||||||
|
decodingStrategy: None
|
||||||
|
metadataPolicy: None
|
||||||
|
key: 2a9deb39-ef22-433e-a1be-df1555625e22
|
||||||
|
property: fields[8].value
|
||||||
|
- secretKey: pasarguard
|
||||||
|
sourceRef:
|
||||||
|
storeRef:
|
||||||
|
name: vaultwarden-login
|
||||||
|
kind: ClusterSecretStore
|
||||||
|
remoteRef:
|
||||||
|
conversionStrategy: Default
|
||||||
|
decodingStrategy: None
|
||||||
|
metadataPolicy: None
|
||||||
|
key: 2a9deb39-ef22-433e-a1be-df1555625e22
|
||||||
|
property: fields[9].value
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ resources:
|
|||||||
helmCharts:
|
helmCharts:
|
||||||
- name: pgadmin4
|
- name: pgadmin4
|
||||||
repo: https://helm.runix.net
|
repo: https://helm.runix.net
|
||||||
version: 1.37.0
|
version: 1.50.0
|
||||||
releaseName: pgmanager
|
releaseName: pgmanager
|
||||||
namespace: psql
|
namespace: psql
|
||||||
valuesFile: pgadmin4-values.yaml
|
valuesFile: pgadmin4-values.yaml
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ metadata:
|
|||||||
namespace: immich
|
namespace: immich
|
||||||
spec:
|
spec:
|
||||||
capacity:
|
capacity:
|
||||||
storage: 50Gi
|
storage: 55Gi
|
||||||
accessModes:
|
accessModes:
|
||||||
- ReadWriteOnce
|
- ReadWriteOnce
|
||||||
persistentVolumeReclaimPolicy: Retain
|
persistentVolumeReclaimPolicy: Retain
|
||||||
@@ -79,14 +79,14 @@ spec:
|
|||||||
- CREATE EXTENSION IF NOT EXISTS earthdistance;
|
- CREATE EXTENSION IF NOT EXISTS earthdistance;
|
||||||
|
|
||||||
storage:
|
storage:
|
||||||
size: 50Gi
|
size: 55Gi
|
||||||
storageClass: nfs-storage
|
storageClass: nfs-storage
|
||||||
pvcTemplate:
|
pvcTemplate:
|
||||||
accessModes:
|
accessModes:
|
||||||
- ReadWriteOnce
|
- ReadWriteOnce
|
||||||
resources:
|
resources:
|
||||||
requests:
|
requests:
|
||||||
storage: 50Gi
|
storage: 55Gi
|
||||||
storageClassName: nfs-storage
|
storageClassName: nfs-storage
|
||||||
volumeMode: Filesystem
|
volumeMode: Filesystem
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
image:
|
image:
|
||||||
tag: "9.3"
|
tag: "9.9"
|
||||||
pullPolicy: Always
|
pullPolicy: Always
|
||||||
env:
|
env:
|
||||||
email: "postgres@hexor.cy"
|
email: "postgres@hexor.cy"
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ admin:
|
|||||||
grafana.ini:
|
grafana.ini:
|
||||||
auth:
|
auth:
|
||||||
signout_redirect_url: https://idm.hexor.cy/application/o/grafana/end-session/
|
signout_redirect_url: https://idm.hexor.cy/application/o/grafana/end-session/
|
||||||
oauth_auto_login: true
|
# oauth_auto_login: true
|
||||||
auth.generic_oauth:
|
auth.generic_oauth:
|
||||||
name: authentik
|
name: authentik
|
||||||
enabled: true
|
enabled: true
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ metadata:
|
|||||||
name: prometheus-pv
|
name: prometheus-pv
|
||||||
spec:
|
spec:
|
||||||
capacity:
|
capacity:
|
||||||
storage: 200Gi
|
storage: 400Gi
|
||||||
accessModes:
|
accessModes:
|
||||||
- ReadWriteOnce
|
- ReadWriteOnce
|
||||||
hostPath:
|
hostPath:
|
||||||
|
|||||||
@@ -14,16 +14,10 @@ prometheus:
|
|||||||
labels: {instance: jp}
|
labels: {instance: jp}
|
||||||
- targets: ['100.117.24.104:9098']
|
- targets: ['100.117.24.104:9098']
|
||||||
labels: {instance: bg}
|
labels: {instance: bg}
|
||||||
- targets: ['100.117.24.104:9099']
|
- job_name: cs_16_server
|
||||||
labels: {instance: fi}
|
|
||||||
|
|
||||||
- job_name: term_humid_sensors
|
|
||||||
static_configs:
|
static_configs:
|
||||||
- targets: ['100.117.24.104:7536']
|
- targets: ['prom-a2s-exporter.counter-strike.svc:9841']
|
||||||
- job_name: win_exporter
|
labels: {instance: master}
|
||||||
static_configs:
|
|
||||||
- targets: ['10.0.5.100:9182']
|
|
||||||
labels: {instance: win.homenet}
|
|
||||||
|
|
||||||
retention: "99999d"
|
retention: "99999d"
|
||||||
retentionSize: "0"
|
retentionSize: "0"
|
||||||
@@ -36,5 +30,5 @@ prometheus:
|
|||||||
accessModes: ["ReadWriteOnce"]
|
accessModes: ["ReadWriteOnce"]
|
||||||
resources:
|
resources:
|
||||||
requests:
|
requests:
|
||||||
storage: 200Gi
|
storage: 400Gi
|
||||||
|
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ spec:
|
|||||||
kind: Plan
|
kind: Plan
|
||||||
plural: plans
|
plural: plans
|
||||||
singular: plan
|
singular: plan
|
||||||
preserveUnknownFields: false
|
#preserveUnknownFields: false
|
||||||
scope: Namespaced
|
scope: Namespaced
|
||||||
versions:
|
versions:
|
||||||
- additionalPrinterColumns:
|
- additionalPrinterColumns:
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ spec:
|
|||||||
serviceAccountName: system-upgrade
|
serviceAccountName: system-upgrade
|
||||||
upgrade:
|
upgrade:
|
||||||
image: rancher/k3s-upgrade
|
image: rancher/k3s-upgrade
|
||||||
version: v1.33.1+k3s1
|
version: v1.34.1+k3s1
|
||||||
---
|
---
|
||||||
# Agent plan
|
# Agent plan
|
||||||
apiVersion: upgrade.cattle.io/v1
|
apiVersion: upgrade.cattle.io/v1
|
||||||
@@ -39,5 +39,5 @@ spec:
|
|||||||
serviceAccountName: system-upgrade
|
serviceAccountName: system-upgrade
|
||||||
upgrade:
|
upgrade:
|
||||||
image: rancher/k3s-upgrade
|
image: rancher/k3s-upgrade
|
||||||
version: v1.33.1+k3s1
|
version: v1.34.1+k3s1
|
||||||
|
|
||||||
|
|||||||
21
k8s/games/beam-ng/app.yaml
Normal file
21
k8s/games/beam-ng/app.yaml
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
apiVersion: argoproj.io/v1alpha1
|
||||||
|
kind: Application
|
||||||
|
metadata:
|
||||||
|
name: beam-ng
|
||||||
|
namespace: argocd
|
||||||
|
spec:
|
||||||
|
project: games
|
||||||
|
destination:
|
||||||
|
namespace: beam-ng
|
||||||
|
server: https://kubernetes.default.svc
|
||||||
|
source:
|
||||||
|
repoURL: ssh://git@gt.hexor.cy:30022/ab/homelab.git
|
||||||
|
targetRevision: HEAD
|
||||||
|
path: k8s/games/beam-ng
|
||||||
|
syncPolicy:
|
||||||
|
automated:
|
||||||
|
selfHeal: true
|
||||||
|
prune: true
|
||||||
|
syncOptions:
|
||||||
|
- CreateNamespace=true
|
||||||
|
|
||||||
46
k8s/games/beam-ng/deployments.yaml
Normal file
46
k8s/games/beam-ng/deployments.yaml
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
---
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: beam-ng
|
||||||
|
labels:
|
||||||
|
app: beam-ng
|
||||||
|
spec:
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
app: beam-ng
|
||||||
|
replicas: 1
|
||||||
|
strategy:
|
||||||
|
type: RollingUpdate
|
||||||
|
rollingUpdate:
|
||||||
|
maxSurge: 1
|
||||||
|
maxUnavailable: 0
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
app: beam-ng
|
||||||
|
spec:
|
||||||
|
nodeSelector:
|
||||||
|
kubernetes.io/hostname: master.tail2fe2d.ts.net
|
||||||
|
containers:
|
||||||
|
- name: beam-ng
|
||||||
|
image: 'rouhim/beammp-server'
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
memory: "1Gi"
|
||||||
|
cpu: "500m"
|
||||||
|
limits:
|
||||||
|
memory: "4Gi"
|
||||||
|
cpu: "2000m"
|
||||||
|
env:
|
||||||
|
- name: BEAMMP_NAME
|
||||||
|
value: 'Anal Hexor'
|
||||||
|
- name: BEAMMP_AUTH_KEY
|
||||||
|
value: '1488_228'
|
||||||
|
ports:
|
||||||
|
- name: udp
|
||||||
|
containerPort: 30814
|
||||||
|
protocol: UDP
|
||||||
|
- containerPort: 30814
|
||||||
|
name: tcp
|
||||||
|
protocol: TCP
|
||||||
8
k8s/games/beam-ng/kustomization.yaml
Normal file
8
k8s/games/beam-ng/kustomization.yaml
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
apiVersion: kustomize.config.k8s.io/v1beta1
|
||||||
|
kind: Kustomization
|
||||||
|
|
||||||
|
resources:
|
||||||
|
- app.yaml
|
||||||
|
- deployments.yaml
|
||||||
|
- services.yaml
|
||||||
|
|
||||||
20
k8s/games/beam-ng/services.yaml
Normal file
20
k8s/games/beam-ng/services.yaml
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
---
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Service
|
||||||
|
metadata:
|
||||||
|
name: beam-ng
|
||||||
|
spec:
|
||||||
|
externalIPs:
|
||||||
|
- 138.201.61.182
|
||||||
|
selector:
|
||||||
|
app: beam-ng
|
||||||
|
ports:
|
||||||
|
- protocol: TCP
|
||||||
|
name: tcp
|
||||||
|
port: 30814
|
||||||
|
targetPort: 30814
|
||||||
|
- protocol: UDP
|
||||||
|
name: udp
|
||||||
|
port: 30814
|
||||||
|
targetPort: 30814
|
||||||
|
|
||||||
21
k8s/games/counter-strike-16/app.yaml
Normal file
21
k8s/games/counter-strike-16/app.yaml
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
apiVersion: argoproj.io/v1alpha1
|
||||||
|
kind: Application
|
||||||
|
metadata:
|
||||||
|
name: counter-strike-16
|
||||||
|
namespace: argocd
|
||||||
|
spec:
|
||||||
|
project: games
|
||||||
|
destination:
|
||||||
|
namespace: counter-strike
|
||||||
|
server: https://kubernetes.default.svc
|
||||||
|
source:
|
||||||
|
repoURL: ssh://git@gt.hexor.cy:30022/ab/homelab.git
|
||||||
|
targetRevision: HEAD
|
||||||
|
path: k8s/games/counter-strike-16
|
||||||
|
syncPolicy:
|
||||||
|
automated:
|
||||||
|
selfHeal: true
|
||||||
|
prune: true
|
||||||
|
syncOptions:
|
||||||
|
- CreateNamespace=true
|
||||||
|
|
||||||
81
k8s/games/counter-strike-16/deployments.yaml
Normal file
81
k8s/games/counter-strike-16/deployments.yaml
Normal file
@@ -0,0 +1,81 @@
|
|||||||
|
---
|
||||||
|
apiVersion: v1
|
||||||
|
kind: ConfigMap
|
||||||
|
metadata:
|
||||||
|
name: cs16-server-config
|
||||||
|
data:
|
||||||
|
MAXPLAYERS: "10"
|
||||||
|
START_MAP: "fy_pool_day"
|
||||||
|
SERVER_NAME: "GEYMERSKIY SOYUZ"
|
||||||
|
START_MONEY: "1000"
|
||||||
|
BUY_TIME: "0.25"
|
||||||
|
FRIENDLY_FIRE: "1"
|
||||||
|
SERVER_PASSWORD: ""
|
||||||
|
RCON_PASSWORD: ""
|
||||||
|
ADMIN_STEAM: "0:0:27591350"
|
||||||
|
RESTART_ON_FAIL: "true"
|
||||||
|
|
||||||
|
---
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: counter-strike-16
|
||||||
|
labels:
|
||||||
|
app: counter-strike-16
|
||||||
|
spec:
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
app: counter-strike-16
|
||||||
|
replicas: 1
|
||||||
|
strategy:
|
||||||
|
type: Recreate
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
app: counter-strike-16
|
||||||
|
spec:
|
||||||
|
nodeSelector:
|
||||||
|
#kubernetes.io/hostname: home.homenet
|
||||||
|
kubernetes.io/hostname: master.tail2fe2d.ts.net
|
||||||
|
terminationGracePeriodSeconds: 10
|
||||||
|
containers:
|
||||||
|
- name: prom-a2s-exporter
|
||||||
|
image: armsnyder/a2s-exporter:latest
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
memory: "32Mi"
|
||||||
|
cpu: "50m"
|
||||||
|
limits:
|
||||||
|
memory: "128Mi"
|
||||||
|
cpu: "200m"
|
||||||
|
ports:
|
||||||
|
- containerPort: 9841
|
||||||
|
protocol: TCP
|
||||||
|
args:
|
||||||
|
- --address
|
||||||
|
- cs.hexor.cy:30015
|
||||||
|
- name: counter-strike-16
|
||||||
|
image: 'kingk0der/counter-strike-1.6:latest'
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
memory: "512Mi"
|
||||||
|
cpu: "200m"
|
||||||
|
limits:
|
||||||
|
memory: "2Gi"
|
||||||
|
cpu: "1000m"
|
||||||
|
args:
|
||||||
|
- +log
|
||||||
|
- -port
|
||||||
|
- "30015"
|
||||||
|
envFrom:
|
||||||
|
- configMapRef:
|
||||||
|
name: cs16-server-config
|
||||||
|
ports:
|
||||||
|
- containerPort: 26900
|
||||||
|
protocol: UDP
|
||||||
|
- containerPort: 27020
|
||||||
|
protocol: UDP
|
||||||
|
- containerPort: 30015
|
||||||
|
protocol: UDP
|
||||||
|
- containerPort: 30015
|
||||||
|
protocol: TCP
|
||||||
8
k8s/games/counter-strike-16/kustomization.yaml
Normal file
8
k8s/games/counter-strike-16/kustomization.yaml
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
apiVersion: kustomize.config.k8s.io/v1beta1
|
||||||
|
kind: Kustomization
|
||||||
|
|
||||||
|
resources:
|
||||||
|
- app.yaml
|
||||||
|
- deployments.yaml
|
||||||
|
- services.yaml
|
||||||
|
- restart-job.yaml
|
||||||
55
k8s/games/counter-strike-16/restart-job.yaml
Normal file
55
k8s/games/counter-strike-16/restart-job.yaml
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
---
|
||||||
|
apiVersion: v1
|
||||||
|
kind: ServiceAccount
|
||||||
|
metadata:
|
||||||
|
name: cs16-restart-sa
|
||||||
|
|
||||||
|
---
|
||||||
|
apiVersion: rbac.authorization.k8s.io/v1
|
||||||
|
kind: Role
|
||||||
|
metadata:
|
||||||
|
name: cs16-restart-role
|
||||||
|
rules:
|
||||||
|
- apiGroups: ["apps"]
|
||||||
|
resources: ["deployments"]
|
||||||
|
verbs: ["get", "patch"]
|
||||||
|
|
||||||
|
---
|
||||||
|
apiVersion: rbac.authorization.k8s.io/v1
|
||||||
|
kind: RoleBinding
|
||||||
|
metadata:
|
||||||
|
name: cs16-restart-rb
|
||||||
|
subjects:
|
||||||
|
- kind: ServiceAccount
|
||||||
|
name: cs16-restart-sa
|
||||||
|
roleRef:
|
||||||
|
apiGroup: rbac.authorization.k8s.io
|
||||||
|
kind: Role
|
||||||
|
name: cs16-restart-role
|
||||||
|
|
||||||
|
---
|
||||||
|
apiVersion: batch/v1
|
||||||
|
kind: CronJob
|
||||||
|
metadata:
|
||||||
|
name: cs16-daily-restart
|
||||||
|
spec:
|
||||||
|
schedule: "0 4 * * *" # every day at 04:00
|
||||||
|
jobTemplate:
|
||||||
|
spec:
|
||||||
|
template:
|
||||||
|
spec:
|
||||||
|
serviceAccountName: cs16-restart-sa
|
||||||
|
restartPolicy: OnFailure
|
||||||
|
containers:
|
||||||
|
- name: kubectl
|
||||||
|
image: bitnami/kubectl:latest
|
||||||
|
env:
|
||||||
|
- name: POD_NAMESPACE
|
||||||
|
valueFrom:
|
||||||
|
fieldRef:
|
||||||
|
fieldPath: metadata.namespace
|
||||||
|
command:
|
||||||
|
- /bin/sh
|
||||||
|
- -c
|
||||||
|
- |
|
||||||
|
kubectl -n "$POD_NAMESPACE" rollout restart deployment/counter-strike-16
|
||||||
47
k8s/games/counter-strike-16/services.yaml
Normal file
47
k8s/games/counter-strike-16/services.yaml
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
---
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Service
|
||||||
|
metadata:
|
||||||
|
name: counter-strike-16-lb
|
||||||
|
spec:
|
||||||
|
type: LoadBalancer
|
||||||
|
selector:
|
||||||
|
app: counter-strike-16
|
||||||
|
ports:
|
||||||
|
- name: game-udp
|
||||||
|
port: 30015
|
||||||
|
targetPort: 30015
|
||||||
|
protocol: UDP
|
||||||
|
nodePort: 30015
|
||||||
|
- name: game-tcp
|
||||||
|
port: 30015
|
||||||
|
targetPort: 30015
|
||||||
|
protocol: TCP
|
||||||
|
nodePort: 30015
|
||||||
|
- name: rcon
|
||||||
|
port: 27020
|
||||||
|
targetPort: 27020
|
||||||
|
protocol: UDP
|
||||||
|
nodePort: 30020
|
||||||
|
- name: hltv
|
||||||
|
port: 26900
|
||||||
|
targetPort: 26900
|
||||||
|
protocol: UDP
|
||||||
|
nodePort: 30900
|
||||||
|
|
||||||
|
---
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Service
|
||||||
|
metadata:
|
||||||
|
name: prom-a2s-exporter
|
||||||
|
labels:
|
||||||
|
app: counter-strike-16
|
||||||
|
spec:
|
||||||
|
selector:
|
||||||
|
app: counter-strike-16
|
||||||
|
ports:
|
||||||
|
- name: metrics
|
||||||
|
port: 9841
|
||||||
|
targetPort: 9841
|
||||||
|
protocol: TCP
|
||||||
|
type: ClusterIP
|
||||||
@@ -8,33 +8,62 @@ data:
|
|||||||
nginx.conf: |
|
nginx.conf: |
|
||||||
user nginx;
|
user nginx;
|
||||||
worker_processes 1;
|
worker_processes 1;
|
||||||
|
error_log /var/log/nginx/error.log warn;
|
||||||
|
pid /var/run/nginx.pid;
|
||||||
|
|
||||||
events {
|
events {
|
||||||
worker_connections 1024;
|
worker_connections 1024;
|
||||||
}
|
}
|
||||||
|
|
||||||
http {
|
http {
|
||||||
|
include /etc/nginx/mime.types;
|
||||||
|
default_type application/octet-stream;
|
||||||
|
|
||||||
server {
|
server {
|
||||||
listen 80;
|
listen 80;
|
||||||
|
|
||||||
|
# Custom 502 error page with auto-refresh
|
||||||
|
error_page 502 /502.html;
|
||||||
|
location = /502.html {
|
||||||
|
internal;
|
||||||
|
return 200 '<!DOCTYPE html><html><head><meta charset="utf-8"><title>Server Loading</title><style>body{font-family:Arial,sans-serif;text-align:center;margin-top:100px;background:#f0f0f0}h1{color:#333}p{color:#666;font-size:18px}</style></head><body><h1>Server is loading probably...</h1><p>Please wait a moment and try refreshing the page.</p><script>setTimeout(function(){window.location.reload();}, 10000);</script></body></html>';
|
||||||
|
add_header Content-Type text/html;
|
||||||
|
}
|
||||||
|
|
||||||
|
# Main location - proxy to Minecraft Dynmap
|
||||||
location / {
|
location / {
|
||||||
|
# Proxy configuration for Dynmap server
|
||||||
proxy_pass http://localhost:8123;
|
proxy_pass http://localhost:8123;
|
||||||
|
proxy_set_header Host $host;
|
||||||
|
proxy_set_header X-Real-IP $remote_addr;
|
||||||
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||||
|
proxy_set_header X-Forwarded-Proto $scheme;
|
||||||
|
|
||||||
|
# Inject user authentication meta tag into HTML head
|
||||||
|
sub_filter '<head>' '<head><meta name="remote-user" content="$http_x_authentik_username">';
|
||||||
|
|
||||||
|
# Replace default Dynmap title with custom server name
|
||||||
sub_filter 'Minecraft Dynamic Map' "Hexor's MC server";
|
sub_filter 'Minecraft Dynamic Map' "Hexor's MC server";
|
||||||
sub_filter "</body>" '<p style="background-color: #CEC6CB; color: black; padding: 10px 10px; text-align: center; font-size: large; text-decoration: none; display: inline-block; border-radius: 4px; position: absolute; top: 10px; left: 150px;">Get <a href="https://github.com/PrismLauncher/PrismLauncher/releases/tag/8.4" >Prism Launcher</a> and <a href="/clients/1.12.2.zip" >client.zip</a> for this server. Server address <b>minecraft.hexor.cy:30565</b></p></body>';
|
|
||||||
|
# Inject all custom content before closing body tag (single replacement)
|
||||||
|
sub_filter "</body>" '<script>function getUsername(){var headers=document.querySelectorAll("meta");for(var i=0;i<headers.length;i++){if(headers[i].getAttribute("name")==="remote-user"){return headers[i].getAttribute("content");}}var jwt=document.cookie.split("; ").find(row=>row.startsWith("authentik_session="));if(jwt){try{var token=jwt.split("=")[1];var payload=JSON.parse(atob(token.split(".")[1]));return payload.sub||payload.username||"web-user";}catch(e){}}return "web-user";}var username=getUsername();console.log("Username found:", username);if(username && username!=="web-user" && window.location.search.indexOf("playername=")===-1){var currentUrl=new URL(window.location.href);currentUrl.searchParams.set("playername",username);console.log("Redirecting to:", currentUrl.href);window.location.href=currentUrl.href;}document.addEventListener("DOMContentLoaded",function(){var userBlock=document.createElement("div");userBlock.style.cssText="background-color: #CEC6CB; color: black; padding: 8px; text-align: center; font-size: medium; border-radius: 4px; position: absolute; top: 10px; right: 150px; max-width: 200px;";userBlock.innerHTML="Logged in as: <b>"+username+"</b>";document.body.appendChild(userBlock);});</script><p style="background-color: #CEC6CB; color: black; padding: 10px 10px; text-align: center; font-size: large; text-decoration: none; display: inline-block; border-radius: 4px; position: absolute; top: 10px; left: 150px;">GEYMERSKIY SOYUZ Server <br>Get <a href="https://github.com/PrismLauncher/PrismLauncher/releases/tag/8.4" >Prism Launcher</a> and <a href="/clients/1.12.2.zip" >client.zip</a> for this server. Server address <b>minecraft.hexor.cy:30565</b><br><br><a href="#" onclick="showInstallModal(); return false;" style="color: black; text-decoration: underline;">Windows Install Script</a></p><div id="installModal" style="display: none; position: fixed; z-index: 1000; left: 0; top: 0; width: 100%; height: 100%; background-color: rgba(0,0,0,0.5);"><div style="background-color: #CEC6CB; margin: 15% auto; padding: 10px; border-radius: 4px; width: 70%; max-width: 500px; text-align: center; color: black; font-size: large;"><h3 style="margin-top: 0; color: black;">Windows Installation</h3><p style="color: black;">Copy and paste this command into PowerShell:</p><textarea id="scriptCommand" readonly style="width: 90%; height: 60px; font-family: monospace; padding: 8px; border: 1px solid #888; border-radius: 4px; resize: none; background-color: white; color: black;">iwr -useb https://minecraft.hexor.cy/clients/win-install.ps1 | iex</textarea><br><br><button id="copyButton" onclick="copyToClipboard()" style="background-color: #CEC6CB; color: black; padding: 10px 15px; border: 1px solid #888; border-radius: 4px; cursor: pointer; margin-right: 10px; font-size: large; text-decoration: none;">Copy</button><button onclick="closeInstallModal()" style="background-color: #CEC6CB; color: black; padding: 10px 15px; border: 1px solid #888; border-radius: 4px; cursor: pointer; font-size: large; text-decoration: none;">Close</button></div></div><script>function showInstallModal() { document.getElementById("installModal").style.display = "block"; } function closeInstallModal() { document.getElementById("installModal").style.display = "none"; } function copyToClipboard() { var textarea = document.getElementById("scriptCommand"); textarea.select(); textarea.setSelectionRange(0, 99999); if (document.execCommand("copy")) { var button = document.getElementById("copyButton"); button.style.borderColor = "#4CAF50"; setTimeout(function() { button.style.borderColor = "#888"; }, 2000); } } window.onclick = function(event) { var modal = document.getElementById("installModal"); if (event.target == modal) { closeInstallModal(); } }</script></body>';
|
||||||
|
|
||||||
|
# Apply sub_filter replacements globally (not just once)
|
||||||
sub_filter_once off;
|
sub_filter_once off;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Static file serving for client downloads
|
||||||
location /clients/ {
|
location /clients/ {
|
||||||
types { }
|
|
||||||
sendfile on;
|
|
||||||
tcp_nopush on;
|
|
||||||
tcp_nodelay on;
|
|
||||||
keepalive_timeout 65;
|
|
||||||
sendfile_max_chunk 1m;
|
|
||||||
default_type application/zip;
|
|
||||||
add_header Content-Disposition "attachment";
|
|
||||||
alias /mc/clients/;
|
alias /mc/clients/;
|
||||||
autoindex on;
|
sendfile on; # Enable efficient file serving
|
||||||
|
add_header Content-Disposition "attachment"; # Force download
|
||||||
|
autoindex on; # Enable directory listing
|
||||||
|
gzip off; # Disable compression for downloads
|
||||||
|
chunked_transfer_encoding off; # Disable chunked encoding
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
---
|
---
|
||||||
apiVersion: apps/v1
|
apiVersion: apps/v1
|
||||||
kind: Deployment
|
kind: Deployment
|
||||||
@@ -68,22 +97,12 @@ spec:
|
|||||||
|
|
||||||
terminationGracePeriodSeconds: 10
|
terminationGracePeriodSeconds: 10
|
||||||
containers:
|
containers:
|
||||||
- name: nginx
|
|
||||||
image: nginx:latest
|
|
||||||
ports:
|
|
||||||
- containerPort: 80
|
|
||||||
volumeMounts:
|
|
||||||
- name: nginx-config
|
|
||||||
mountPath: /etc/nginx/nginx.conf
|
|
||||||
subPath: nginx.conf
|
|
||||||
- name: storage
|
|
||||||
mountPath: /mc
|
|
||||||
- name: minecraft
|
- name: minecraft
|
||||||
image: 'openjdk:8-jdk-alpine'
|
image: 'openjdk:8-jdk-alpine'
|
||||||
command: ["java"]
|
command: ["java"]
|
||||||
args:
|
args:
|
||||||
- -Xms12G
|
- -Xms4G
|
||||||
- -Xmx12G
|
- -Xmx4G
|
||||||
- -XX:+UseG1GC
|
- -XX:+UseG1GC
|
||||||
- -XX:+ParallelRefProcEnabled
|
- -XX:+ParallelRefProcEnabled
|
||||||
- -XX:MaxGCPauseMillis=200
|
- -XX:MaxGCPauseMillis=200
|
||||||
@@ -107,12 +126,12 @@ spec:
|
|||||||
- nogui
|
- nogui
|
||||||
workingDir: /mc/
|
workingDir: /mc/
|
||||||
resources:
|
resources:
|
||||||
limits:
|
|
||||||
memory: 15Gi
|
|
||||||
#cpu: 1
|
|
||||||
requests:
|
requests:
|
||||||
memory: 10Gi
|
memory: "8Gi"
|
||||||
#cpu: 100m
|
cpu: "2000m"
|
||||||
|
limits:
|
||||||
|
memory: "12Gi"
|
||||||
|
cpu: "4000m"
|
||||||
ports:
|
ports:
|
||||||
- name: game
|
- name: game
|
||||||
containerPort: 25565
|
containerPort: 25565
|
||||||
@@ -120,9 +139,29 @@ spec:
|
|||||||
- name: dynmap
|
- name: dynmap
|
||||||
containerPort: 8123
|
containerPort: 8123
|
||||||
protocol: TCP
|
protocol: TCP
|
||||||
|
- name: webstatus-mod
|
||||||
|
containerPort: 8080
|
||||||
|
protocol: TCP
|
||||||
volumeMounts:
|
volumeMounts:
|
||||||
- name: storage
|
- name: storage
|
||||||
mountPath: /mc
|
mountPath: /mc
|
||||||
|
- name: nginx
|
||||||
|
image: nginx:latest
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
memory: "64Mi"
|
||||||
|
cpu: "50m"
|
||||||
|
limits:
|
||||||
|
memory: "256Mi"
|
||||||
|
cpu: "200m"
|
||||||
|
ports:
|
||||||
|
- containerPort: 80
|
||||||
|
volumeMounts:
|
||||||
|
- name: nginx-config
|
||||||
|
mountPath: /etc/nginx/nginx.conf
|
||||||
|
subPath: nginx.conf
|
||||||
|
- name: storage
|
||||||
|
mountPath: /mc
|
||||||
|
|
||||||
---
|
---
|
||||||
apiVersion: v1
|
apiVersion: v1
|
||||||
|
|||||||
27
k8s/games/minecraft/ingress.yaml
Normal file
27
k8s/games/minecraft/ingress.yaml
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
---
|
||||||
|
apiVersion: networking.k8s.io/v1
|
||||||
|
kind: Ingress
|
||||||
|
metadata:
|
||||||
|
name: dynmap-tls-ingress
|
||||||
|
annotations:
|
||||||
|
ingressClassName: traefik
|
||||||
|
cert-manager.io/cluster-issuer: letsencrypt
|
||||||
|
traefik.ingress.kubernetes.io/router.middlewares: kube-system-https-redirect@kubernetescrd
|
||||||
|
acme.cert-manager.io/http01-edit-in-place: "true"
|
||||||
|
spec:
|
||||||
|
rules:
|
||||||
|
- host: minecraft.hexor.cy
|
||||||
|
http:
|
||||||
|
paths:
|
||||||
|
- path: /clients/
|
||||||
|
pathType: Prefix
|
||||||
|
backend:
|
||||||
|
service:
|
||||||
|
name: minecraft
|
||||||
|
port:
|
||||||
|
number: 80
|
||||||
|
tls:
|
||||||
|
- secretName: dynmap-tls
|
||||||
|
hosts:
|
||||||
|
- minecraft.hexor.cy
|
||||||
|
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user