feat(k8s): 新增 core 真应用(前端+Django API+Celery worker)构建与部署

- core/frontend: Vite 多阶段镜像 + nginx 同源反代 /api,/admin,/static(零 CORS)
- core/backend: Django gunicorn 镜像 + entrypoint(自动 migrate/collectstatic)+ WhiteNoise
- k8s/core: api/worker/web Deployment+Service + ingress(airshelf-web.airlabs.art)
- workflow: 追加 core 前后端 build/push,从 core/backend/.env 套生产覆盖生成 env Secret 后部署
- .gitignore 放行 core/backend/.env;.env 白名单加入 airshelf-web 域名
- 含前端 WIP 还原改动

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
zyc
2026-06-05 10:21:41 +08:00
co-authored by Claude Opus 4.8
parent cfdcd84a30
commit d41e487f08
37 changed files with 4108 additions and 456 deletions
+10
View File
@@ -0,0 +1,10 @@
.venv/
**/__pycache__/
*.pyc
db.sqlite3
.env
.env.*
!.env.example
tests/
*.md
staticfiles/
+24
View File
@@ -0,0 +1,24 @@
DJANGO_SETTINGS_MODULE=airshelf.settings.development
DJANGO_SECRET_KEY=S2GYXa8YC21lmnFfVwC+6cyFNhCCSoclhpylOmSAm16vKflUgQi398VQQSM+Rbit
DJANGO_DEBUG=true
DJANGO_ALLOWED_HOSTS=airshelf-web.airlabs.art,airshelf-web.test.airlabs.art,localhost,127.0.0.1,192.168.124.86
DJANGO_CSRF_TRUSTED_ORIGINS=https://airshelf-web.airlabs.art,https://airshelf-web.test.airlabs.art,https://airshelf.airlabs.art,https://api.airshelf.airlabs.art,http://localhost:3000,http://127.0.0.1:3000,http://localhost:5173,http://127.0.0.1:5173,http://192.168.124.86:5173
CORS_ALLOWED_ORIGINS=https://airshelf-web.airlabs.art,https://airshelf-web.test.airlabs.art,https://airshelf.airlabs.art,http://localhost:3000,http://127.0.0.1:3000,http://localhost:5173,http://127.0.0.1:5173,http://192.168.124.86:5173
DB_ENGINE=mysql
DB_NAME=airshelf_test
DB_USER=airshelf_app
DB_PASSWORD=d5020f4d41e0e4c52a371ecb913be3d1f1ab2b85
DB_HOST=14.103.27.192
DB_PORT=3306
DB_BIND_ADDRESS=192.168.124.86
REDIS_CACHE_URL=redis://zyc:Zyc188208@redis-shzlsczo52dft8mia.redis.volces.com:6379/0
CELERY_BROKER_URL=redis://zyc:Zyc188208@redis-shzlsczo52dft8mia.redis.volces.com:6379/1
CELERY_RESULT_BACKEND=redis://zyc:Zyc188208@redis-shzlsczo52dft8mia.redis.volces.com:6379/2
REDIS_LOCK_URL=redis://zyc:Zyc188208@redis-shzlsczo52dft8mia.redis.volces.com:6379/3
TOS_ENDPOINT=https://tos-s3-cn-shanghai.volces.com
TOS_BUCKET=airshelf
TOS_ACCESS_KEY_ID=AKLTODVhY2U1NzY1MTU3NDA4NThiYzk2ZDMyZDNjYmZhZGY
TOS_SECRET_ACCESS_KEY=TWpjNVpqVm1NbVkzTWprNE5ESXlZMkUyT1dNNFlqVmtaRGRoTVdNME5qRQ==
VOLCANO_ARK_API_KEY=ark-24d5627e-28e4-4412-8679-46a6e9f26aab-6e951
VOLCANO_ARK_BASE_URL=https://ark.cn-beijing.volces.com/api/v3
DEFAULT_TRIAL_CREDITS=1000.0000
+26
View File
@@ -0,0 +1,26 @@
# ---- AirShelf core backend: Django + DRF + gunicorn / celery ----
FROM docker.m.daocloud.io/python:3.12-slim
ENV PYTHONUNBUFFERED=1 \
PYTHONDONTWRITEBYTECODE=1 \
PIP_NO_CACHE_DIR=1 \
PIP_INDEX_URL=https://mirrors.aliyun.com/pypi/simple/
WORKDIR /app
# PyMySQL is pure-python (install_as_MySQLdb), boto3/gunicorn need no C deps,
# so the slim image is enough — no build-essential required.
COPY requirements.txt .
RUN pip install --upgrade pip && pip install -r requirements.txt
COPY . .
# Collected admin/static lands here; served by WhiteNoise (see settings/production.py)
RUN mkdir -p /app/staticfiles
COPY docker-entrypoint.sh /usr/local/bin/docker-entrypoint.sh
RUN chmod +x /usr/local/bin/docker-entrypoint.sh
EXPOSE 8000
ENTRYPOINT ["docker-entrypoint.sh"]
CMD ["gunicorn", "airshelf.wsgi:application", "--bind", "0.0.0.0:8000", "--workers", "3", "--timeout", "120"]
@@ -1,4 +1,7 @@
from pathlib import Path
from .base import * # noqa: F403
from .base import BASE_DIR, MIDDLEWARE
DEBUG = False
@@ -6,3 +9,16 @@ SECURE_PROXY_SSL_HEADER = ("HTTP_X_FORWARDED_PROTO", "https")
SESSION_COOKIE_SECURE = True
CSRF_COOKIE_SECURE = True
# Serve admin/static behind gunicorn with DEBUG=False (no nginx static mount needed).
# WhiteNoise sits right after SecurityMiddleware.
MIDDLEWARE = (
MIDDLEWARE[:1]
+ ["whitenoise.middleware.WhiteNoiseMiddleware"]
+ MIDDLEWARE[1:]
)
STATIC_ROOT = Path(BASE_DIR) / "staticfiles"
STORAGES = {
"default": {"BACKEND": "django.core.files.storage.FileSystemStorage"},
"staticfiles": {"BACKEND": "whitenoise.storage.CompressedManifestStaticFilesStorage"},
}
+15
View File
@@ -0,0 +1,15 @@
#!/bin/sh
set -e
# Only the web (gunicorn) container should run migrations / collectstatic.
# The celery worker shares this image but skips DB schema mutation to avoid races.
case "$1" in
gunicorn)
echo "[entrypoint] running migrations..."
python manage.py migrate --noinput
echo "[entrypoint] collecting static..."
python manage.py collectstatic --noinput
;;
esac
exec "$@"
+1
View File
@@ -8,4 +8,5 @@ python-dotenv>=1.0,<2.0
boto3>=1.34,<2.0
requests>=2.31,<3.0
gunicorn>=21.2,<23.0
whitenoise>=6.6,<7.0