소스 정보
- 저장소
- lebiraja/skills4agents
- 최근 소스 활동
- 2026년 4월 11일 14:03
- 감지된 SKILL.md 언어
- 영어
- 스타
- 1
- 포크
- 0
설치 방법
기본적으로 소스를 먼저 확인하는 Prompt가 선택됩니다. 직접 명령으로 전환하거나 로컬 사본을 다운로드할 수도 있습니다.
소스 파일 검토
설치 여부를 결정하기 전에 SKILL.md와 SkillsMP에 표시된 보조 파일을 읽어 보세요.
메뉴
기본적으로 소스를 먼저 확인하는 Prompt가 선택됩니다. 직접 명령으로 전환하거나 로컬 사본을 다운로드할 수도 있습니다.
설치 여부를 결정하기 전에 SKILL.md와 SkillsMP에 표시된 보조 파일을 읽어 보세요.
SOC 직업 분류 기준
Codex 또는 Claude로 설치 이 Prompt를 복사해 Codex, Claude 또는 다른 어시스턴트에 붙여 넣으면 Skill 페이지를 검토하고 설치를 진행할 수 있습니다.
직접 명령은 검토 Prompt를 거치지 않습니다. 실행하기 전에 소스를 확인하세요.
npx skills add https://github.com/lebiraja/skills4agents --skill agent-module-docker-ml-deployment명령은 한 줄로 유지됩니다. 복사하기 전에 가로로 스크롤해 전체 내용을 확인하세요.
로컬 사본을 원하시나요? SkillsMP에서 현재 제공할 수 있는 파일을 다운로드하세요.
SKILL.md 표시 중
Module: Autonomous Academic Research and Paper Production Pipeline
Module: Comprehensive citation management for academic research. Search Google Scholar and PubMed for papers, extract accurate metadata, validate citations, and generate properly formatted BibTeX entries. This skill should be used when you need to find papers, verify citation information, convert DOIs to BibTeX, or ensure reference accuracy in scientific writing.
Module: Universal deep research agent team. 13-agent pipeline for rigorous academic research on any topic. 7 modes: full research, quick brief, paper review, lit-review, fact-check, Socratic guided research dialogue, and systematic review with optional meta-analysis. Covers research question formulation, Socratic mentoring, methodology design, systematic literature search, source verification, cross-source synthesis, risk of bias assessment, meta-analysis, APA 7.0 report compilation, editorial review, devil's advocate challenges, ethics review, and post-research literature monitoring. Triggers on: research, deep research, literature review, systematic review, meta-analysis, PRISMA, evidence synthesis, fact-check, guide my research, help me think through, 研究, 深度研究, 文獻回顧, 文獻探討, 系統性回顧, 後設分析, 事實查核, 引導我的研究, 幫我釐清, 幫我想想, 我不確定要研究什麼, 研究方向, 研究主題.
| name | agent-module-docker-ml-deployment |
| description | Module: Docker + ML Service Deployment Standard |
agent.module.docker-ml-deployment1.0.0productionUse this module when deploying any ML-backed service using Docker Compose or a similar container orchestration layer, with a REST API serving model inference.
Apply when:
Do not apply when:
Multi-Service Docker Compose with ML Artifact Volume Mountfrontend (static/nginx), backend (ML API), cache (Redis), model-trainer (one-off job)..pkl, .pt, .onnx, .safetensors) are mounted as read-only volumes into the inference container — never baked into the image.profile (--profile training) so it is never started by accident on docker compose up.condition: service_healthy to prevent startup races.max-size: 10m, max-file: 5)..env files; no secrets are hardcoded or committed.┌─────────────────────────────────────────────────┐
│ Cloud VM / Server │
│ │
│ ┌──────────┐ ┌──────────────┐ ┌──────────┐ │
│ │ frontend │──▶│ backend │─▶│ cache │ │
│ │ (nginx) │ │ (ML API) │ │ (Redis) │ │
│ │ :80/443 │ │ :8000 │ │ :6379 │ │
│ └──────────┘ └──────┬───────┘ └──────────┘ │
│ │ │
│ ┌──────▼──────┐ │
│ │ ML Models │ │
│ │ /app/models/│ │
│ │ (vol. mount)│ │
│ └─────────────┘ │
└─────────────────────────────────────────────────┘
Service roles:
| Service | Image Base | Port | Purpose |
|---|---|---|---|
backend | python:3.11-slim (two-stage) | 8000 | ML inference REST API |
frontend | node:20 → nginx:alpine (two-stage) | 80 / 443 | Static UI + API proxy |
cache | redis:7-alpine | 6379 (internal) | Prediction result cache |
model-trainer | Same as backend | — | One-off training job (profile-gated) |
backend/, frontend/, docker-compose.yml, backend/.env.example.backend/.env from .env.example:
cp backend/.env.example backend/.env
SECRET_KEY:
python3 -c "import secrets; print(secrets.token_hex(32))"
ENVIRONMENT=production, LOG_LEVEL=INFO, and CORS_ORIGINS with your actual domain in backend/.env.backend/.env is listed in .gitignore:
grep "\.env" .gitignore
If missing: echo "backend/.env" >> .gitignore.env contract for the project and commit .env.example with all keys present (values blank or placeholder).Minimum .env contract (adapt per project):
# Application
ENVIRONMENT=production
LOG_LEVEL=INFO
SECRET_KEY=<generate with secrets.token_hex(32)>
# ML model paths (inside container — match volume mount target)
MODEL_PATH=/app/models/<primary_model>.pkl
SCALER_PATH=/app/models/scaler.pkl
PREPROCESSOR_PATH=/app/models/preprocessor.pkl
MODEL_VERSION=1.0.0
# Cache
REDIS_URL=redis://cache:6379/0
CACHE_ENABLED=true
CACHE_TTL=300
# CORS — always include production domain
CORS_ORIGINS=["https://yourdomain.com"]
# Rate limiting
API_RATE_LIMIT=100/hour
Exit criteria:
backend/.env exists and is not tracked by git..env.example.SECRET_KEY is non-default and >= 32 bytes.backend/models/:
ls -lh backend/models/
# Option A — Docker (recommended for reproducibility)
docker compose --profile training run --rm model-trainer
# Option B — local Python
cd backend && pip install -r requirements.txt && python train_model.py
ls backend/models/*.pkl # or *.pt, *.onnx, etc.
VERSION="v1.0.0"
DATE=$(date +%Y%m%d)
for f in backend/models/<primary>.pkl backend/models/scaler.pkl backend/models/preprocessor.pkl; do
cp "$f" "${f%.pkl}_${VERSION}_${DATE}.pkl"
done
Model file naming convention:
<model_name>_v<MAJOR>.<MINOR>.<PATCH>_<YYYYMMDD>.pkl
# Example: gradient_boosting_model_v1.2.0_20260411.pkl
Exit criteria:
backend/models/.docker compose build --no-cache
docker compose up -d
docker compose ps
curl http://localhost:8000/api/v1/health
# Expected: {"status": "healthy", "model_loaded": true, "version": "1.0.0"}
curl -X POST http://localhost:8000/api/v1/predict \
-H "Content-Type: application/json" \
-d '<minimal_valid_payload_for_your_model>'
curl -s -o /dev/null -w "%{http_code}" http://localhost:80
# Expected: 200
docker compose exec cache redis-cli ping
# Expected: PONG
Key Docker commands reference:
# Rebuild after code changes
docker compose build --no-cache && docker compose up -d
# Follow logs
docker compose logs -f backend
docker compose logs -f frontend
# Enter a container for debugging
docker compose exec backend bash
# Stop and clean up
docker compose down
docker compose down -v # also wipes cache volumes
Exit criteria:
docker compose ps.model_loaded: true.Enforce two-stage builds for both backend and frontend.
Backend two-stage pattern:
# Stage 1: install Python dependencies
FROM python:3.11-slim AS builder
WORKDIR /build
COPY requirements.txt .
RUN pip install --user --no-cache-dir -r requirements.txt
# Stage 2: production image
FROM python:3.11-slim AS production
# Install runtime system libs (e.g., OpenBLAS/LAPACK for numpy/scikit-learn)
RUN apt-get update && apt-get install -y --no-install-recommends \
libopenblas-dev liblapack-dev && \
rm -rf /var/lib/apt/lists/*
# Copy installed packages from builder
COPY --from=builder /root/.local /root/.local
# Copy application code (no model artifacts — they come via volume mount)
COPY app/ /app/app/
WORKDIR /app
# Run as non-root
RUN useradd -m appuser && chown -R appuser /app
USER appuser
CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8000", "--workers", "4"]
Frontend two-stage pattern:
# Stage 1: build React/Vue/etc. static assets
FROM node:20-alpine AS builder
WORKDIR /app
COPY package*.json .
RUN npm ci
COPY . .
RUN npm run build
# Stage 2: serve with nginx
FROM nginx:alpine AS production
COPY --from=builder /app/dist /usr/share/nginx/html
COPY nginx.conf /etc/nginx/conf.d/default.conf
nginx.conf API proxy pattern:
server {
listen 80;
root /usr/share/nginx/html;
index index.html;
# SPA fallback
location / {
try_files $uri $uri/ /index.html;
}
# Proxy API requests to backend container
location /api/ {
proxy_pass http://backend:8000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_read_timeout 60s;
}
}
Exit criteria:
Instance sizing (EC2 reference):
| Use Case | Type | vCPU | RAM | Est. Cost |
|---|---|---|---|---|
| Dev / Test | t3.small | 2 | 2 GB | ~$15/mo |
| Production | t3.medium | 2 | 4 GB | ~$30/mo |
| High Traffic | t3.large | 2 | 8 GB | ~$60/mo |
Security group / firewall rules:
| Port | Protocol | Source | Purpose |
|---|---|---|---|
| 22 | TCP | Your IP only | SSH |
| 80 | TCP | 0.0.0.0/0 | HTTP |
| 443 | TCP | 0.0.0.0/0 | HTTPS |
| 8000 | TCP | 0.0.0.0/0 | Direct API (optional, dev only) |
Docker installation (Ubuntu):
sudo apt-get update && sudo apt-get upgrade -y
sudo apt-get install -y ca-certificates curl gnupg
sudo install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | \
sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
sudo chmod a+r /etc/apt/keyrings/docker.gpg
echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] \
https://download.docker.com/linux/ubuntu $(. /etc/os-release && echo $VERSION_CODENAME) stable" | \
sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
apt-get update
apt-get install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
usermod -aG docker && newgrp docker
Exit criteria:
docker compose ps.model_loaded: true from the cloud VM.Add GitHub repository secrets:
| Secret | Value | Source |
|---|---|---|
EC2_SSH_KEY | Full .pem key content (including headers) | cat your-key.pem |
EC2_HOST | Public IP or domain of server | Cloud console |
EC2_USERNAME | OS user (e.g., ubuntu) | VM configuration |
Create .github/workflows/deploy.yml:
name: Deploy to Production
on:
push:
branches: [main]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Deploy via SSH
uses: appleboy/ssh-action@v1
with:
host: ${{ secrets.EC2_HOST }}
username: ${{ secrets.EC2_USERNAME }}
key: ${{ secrets.EC2_SSH_KEY }}
script:
Exit criteria:
main triggers automatic deployment.sudo apt-get install -y certbot python3-certbot-nginx
docker compose stop frontend
sudo certbot certonly --standalone -d yourdomain.com -d www.yourdomain.com
docker compose start frontend
frontend/nginx.conf:
server {
listen 80;
server_name yourdomain.com;
return 301 https://$server_name$request_uri;
}
server {
listen 443 ssl;
server_name yourdomain.com;
ssl_certificate /etc/letsencrypt/live/yourdomain.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/yourdomain.com/privkey.pem;
# ... existing location blocks
}
docker-compose.yml:
frontend:
volumes:
- /etc/letsencrypt:/etc/letsencrypt:ro
ports:
- "80:80"
- "443:443"
CORS_ORIGINS in backend/.env:
CORS_ORIGINS=["https://yourdomain.com","https://www.yourdomain.com"]
sudo certbot renew --dry-run
sudo certbot renew --post-hook "docker compose -f ~/app/docker-compose.yml restart frontend"
sudo systemctl status certbot.timer
Exit criteria:
https://yourdomain.com returns HTTP 200.This is the most critical operational procedure. Follow exactly.
Standard model update workflow:
1. Train new model (Docker or local)
2. Record metrics — confirm improvement or acceptability
3. Backup current production artifacts with version suffix
4. Replace model files in backend/models/
5. Commit to git (or upload to S3)
6. Push to main → CI/CD deploys
7. Verify health endpoint after deploy
8. Monitor error logs for 15 minutes
Step-by-step:
# Step 1: Train
docker compose --profile training run --rm model-trainer
# Note: record printed metrics (RMSE, R², accuracy, etc.)
# Step 2: Backup current production model
VERSION="v1.0.0"
DATE=$(date +%Y%m%d)
cd backend/models
cp <primary_model>.pkl <primary_model>_${VERSION}_${DATE}.pkl
cp scaler.pkl scaler_${VERSION}_${DATE}.pkl
cp preprocessor.pkl preprocessor_${VERSION}_${DATE}.pkl
# Step 3: Commit new model
cd /path/to/repo
git add backend/models/<primary_model>.pkl backend/models/scaler.pkl backend/models/preprocessor.pkl
git commit -m "model: update to v1.1.0 — R2=0.951, RMSE=2.12"
git push origin main
# CI/CD deploys automatically
# Step 4: Verify post-deploy
curl https://yourdomain.com/api/v1/health
curl -X POST https://yourdomain.com/api/v1/predict \
-H "Content-Type: application/json" \
-d '<minimal_valid_payload>'
Rollback procedure (if deploy fails):
# On the server
cd ~/app/backend/models
cp <primary_model>_v1.0.0_<date>.pkl <primary_model>.pkl
cp scaler_v1.0.0_<date>.pkl scaler.pkl
cp preprocessor_v1.0.0_<date>.pkl preprocessor.pkl
# Restart backend to reload model
docker compose restart backend
# Verify
curl http://localhost:8000/api/v1/health
Model storage strategy by size:
| Model Size | Storage Strategy |
|---|---|
| < 50 MB | Commit to git alongside code |
| 50 MB – 2 GB | Store in S3; download on deploy via CI/CD step |
| > 2 GB | Git LFS (git lfs track "*.pkl") or S3 + streaming load |
Exit criteria:
/api/v1/health response.| Decision Area | Preferred Option | Alternative | Selection Rule |
|---|---|---|---|
| Model artifact delivery | Volume mount (read-only) | Baked into Docker image | Volume mount: model updates don't require image rebuild. Bake in only if immutability is required. |
| Model storage (< 50 MB) | Commit to git | S3 | Git is simpler; use S3 only when files exceed GitHub LFS limits or build times become unacceptable. |
| Scaling strategy | Multiple Uvicorn workers (same container) | Multiple container replicas | Workers for I/O-bound routes; replicas only when CPU/memory is the bottleneck. |
| Cache strategy | Redis with TTL per prediction input hash | In-memory dict | Redis survives container restarts; use in-memory dict only for stateless/ephemeral deployments. |
| CI/CD trigger | Push to main branch | Manual SSH deploy | Automated on push reduces operator error; use manual only for regulated environments with change gates. |
| SSL termination | Certbot + nginx (in container) | Cloud load balancer TLS | LB TLS preferred for production HA; nginx TLS acceptable for single-VM deployments. |
| Backend API framework | FastAPI | Flask, Django REST | FastAPI for async ML workloads and OpenAPI auto-docs; Flask if team preference or existing codebase. |
| Zero-downtime model reload | Restart with volume swap | Hot-reload admin endpoint | Volume swap + restart is simpler and safe; hot-reload endpoint adds surface area but avoids brief downtime. |
GET /api/v1/health returns {"status": "healthy", "model_loaded": true} after every deployment.<title> tag or a known HTML landmark.PONG from redis-cli ping.healthy in docker compose ps.backend/.env and confirm compose fails with a readable error (not a null-key panic).docker compose stop cache) and confirm API continues serving (degraded, no cache) without crashing.restart: unless-stopped).grep -r "SECRET_KEY" .git returns no results (secret never committed).docker compose exec backend whoami returns non-root user (e.g., appuser).docker compose config | grep 6379 confirms Redis port is NOT mapped to 0.0.0.0 (only internal).curl http://yourdomain.com/api/v1/health redirects to HTTPS (301).<= 200 ms at p95<= 500 ms at p95 for tabular ML models; <= 2 s for deep learning models>= 99.5% monthly for single-VM production deploymentsdocker compose restart backend: <= 30 s for models < 500 MB<= 5 minutes<= 10 minutes>= 80% under steady-state traffic<= 256 MB for prediction cache (enforce with maxmemory policy)>= 80% triggers prune (docker system prune -f)Risk: Model artifact files missing or corrupted at startup.
@app.on_event("startup")) loads and validates all model files; health endpoint immediately reports model_loaded: false; container restarts on health check failure.Risk: .env file committed to git, leaking secrets.
.env in .gitignore; pre-commit hook or CI secret scan (e.g., gitleaks, truffleHog); audit git log --all -- backend/.env periodically.Risk: Deploying an untested model that degrades prediction quality.
Risk: Disk full on VM halts containers.
docker system prune -f via cron; df -h / alert at 80%; EBS volume sized with 50% headroom for model backups and logs.Risk: CI/CD deploys broken code and health check not caught.
curl -f http://localhost:8000/api/v1/health || exit 1 at end of deploy script; CI job fails and sends alert; rollback is manual but documented.Risk: Redis exposed publicly and accessed by external actors.
127.0.0.1 (or not mapped at all); security group blocks 6379/6380 from internet; confirm with docker compose config | grep "6379".Risk: Model version mismatch between scaler/preprocessor and primary model.
MODEL_VERSION env var ties to git tag; rollback restores all three files together.Risk: SSL certificate expires and site goes down.
certbot.timer systemd service enabled; certbot renew --post-hook restarts nginx; expiry alert via uptime monitor (UptimeRobot, BetterUptime, Pingdom).backend/.env created from .env.example with real SECRET_KEY (not default).backend/.env confirmed absent from git history.CORS_ORIGINS set to include the production domain.backend/models/.docker compose build --no-cache).docker compose ps.model_loaded: true.PONG confirmed.main triggers deploy).docker compose logs backend
# Check for: missing model file, missing .env, Redis not ready
ls backend/models/<primary>.pkl
ls backend/.env
docker compose logs cache
# Fix:
docker compose down && docker compose up -d --build
model_loaded: false from health endpointdocker compose exec backend ls -la /app/models/
docker compose config | grep -A5 volumes
docker compose logs backend | grep -i "error\|model\|pkl\|onnx"
docker compose logs backend | grep -A10 "500\|ERROR\|Exception"
# Common causes: input shape mismatch, scaler/model version mismatch, memory exhaustion
docker stats --no-stream
docker compose exec cache redis-cli ping
grep REDIS_URL backend/.env
# REDIS_URL must use Docker service name: redis://cache:6379/0
docker compose restart cache
df -h /
docker system prune -f
docker compose exec backend find /app/logs -name "*.log.*" -delete
du -sh backend/models/* backend/data/* 2>/dev/null | sort -rh | head -20
# Check GitHub Actions logs: Repository → Actions → (failed run)
# Common causes:
# 1. EC2_SSH_KEY missing header/footer lines
# 2. Security group blocks port 22 from GitHub Actions IPs
# 3. Disk full on VM: docker system prune -f on EC2, re-run
sudo certbot renew --dry-run
sudo systemctl status certbot.timer
# If timer is inactive: sudo systemctl enable --now certbot.timer
This module is reusable across all Docker + ML service deployments. Adapt only:
MODEL_PATH, SCALER_PATH, PREPROCESSOR_PATH env keys).libopenblas-dev for scikit-learn; libgomp1 for XGBoost; CUDA base image for GPU inference).train_model.py → your actual script name).model_loaded boolean consistent).appleboy/ssh-action with your preferred action or deployment service).Initial deployment:
git clone <repo-url> ~/app
cd ~/app
cp backend/.env.example backend/.env
# Edit backend/.env: set SECRET_KEY, CORS_ORIGINS with real domain
nano backend/.env
# If model files not in repo, train them first
docker compose --profile training run --rm model-trainer
# Build and start
docker compose build --no-cache
docker compose up -d
docker compose ps
curl http://localhost:8000/api/v1/health
If model files are stored in S3 (not git), add download step before build:
- name: Download models from S3
uses: appleboy/ssh-action@v1
with:
host: ${{ secrets.EC2_HOST }}
username: ${{ secrets.EC2_USERNAME }}
key: ${{ secrets.EC2_SSH_KEY }}
script: |
aws s3 cp s3://<your-bucket>/models/ ~/app/backend/models/ --recursive
Verify the health endpoint is called at the end of every deploy job; use || exit 1 to fail the pipeline if the API is unhealthy after deploy.
docker system prune -fmax-size: "10m", max-file: "5" in compose logging block).