Files
foxhunt/docs/guides/GITLAB_CI_DOCKER_SETUP_GUIDE.md
jgrusewski e393a8af89 chore(cleanup): Cleanup Wave 3 - Archive reports, organize docs, fix security issues
## Summary
Third major cleanup wave after investigating 287 remaining root files.
Archived historical reports, organized documentation, removed regeneratable
artifacts, and fixed critical security issue.

## Files Cleaned (119 total)
- Archived: 78 files (7 WAVE reports + 71 summaries) → docs/archive/
- Archived: 7 build logs → docs/archive/build_logs/
- Organized: 10 markdown files → docs/guides/ + docs/checklists/
- Deleted: 17 test/coverage artifacts (regeneratable)
- Deleted: 7 empty/obsolete files (docker override, clippy baselines)
- Deleted: 3 large files (119MB - .venv, ppo_hyperopt_output.txt, backup)

## Space Recovered
- Total: ~120.7 MB
- Large files: 119.25 MB (.venv, ppo_hyperopt_output.txt)
- Archives: 1.04 MB (summaries + build logs)
- Test artifacts: 980 KB

## Security Fix (CRITICAL)
- Fixed: certs/security.env removed from git tracking (contained JWT secrets)
- Updated: .gitignore to prevent future tracking of sensitive cert files
- Removed: 4 files from git history (security.env, production.env.template, *.serial)

## Documentation Organization
- Created: docs/archive/ (wave_reports/, summaries/, build_logs/)
- Created: docs/guides/ (7 detailed implementation guides)
- Created: docs/checklists/ (3 operational checklists)
- Retained: 30 essential .md files in root (quick refs, CLAUDE.md)

## Investigation Reports Created
- MARKDOWN_ORGANIZATION_REPORT.md
- TXT_FILES_INVENTORY_AND_ARCHIVAL_PLAN.md
- ROOT_CONFIG_FILES_ANALYSIS_REPORT.md
- DOCKER_ROOT_FILES_ANALYSIS.md
- DATABASE_INITIALIZATION_AND_SETUP_ANALYSIS.md
- (6 additional investigation/index files)

## Cleanup Wave Progress
- Wave 1: 899 files deleted (1,071,884 lines)
- Wave 2: 543 files archived/deleted (~34GB)
- Wave 3: 119 files archived/deleted/organized (~121MB)
- Total: 1,561 files cleaned, ~35.1GB space recovered

## Result
Root directory: 287 files → ~180 files (excluding investigation reports)
Clean, organized, production-ready structure maintained.

Related: Second cleanup wave (previous commit)
2025-10-30 01:46:39 +01:00

503 lines
17 KiB
Markdown

# GitLab CI/CD Docker Build Setup Guide
**Created**: 2025-10-29
**Purpose**: Production-ready GitLab CI/CD pipeline for automated Foxhunt Docker builds
**Registry**: Docker Hub (jgrusewski/foxhunt) - PRIVATE repository
**Target**: Runpod GPU deployment with CUDA 12.4.1 + cuDNN 9
---
## Quick Start
### 1. Prerequisites
- GitLab repository with CI/CD enabled
- Docker Hub account with PRIVATE repository `jgrusewski/foxhunt`
- GitLab runner with Docker executor enabled
### 2. Configure GitLab CI/CD Variables
Navigate to: **Settings > CI/CD > Variables**
Add the following variables:
| Variable | Value | Protected | Masked | Description |
|---|---|---|---|---|
| `DOCKER_HUB_USERNAME` | `jgrusewski` | ✓ | ✓ | Docker Hub username |
| `DOCKER_HUB_PASSWORD` | `<token>` | ✓ | ✓ | Docker Hub access token (NOT password) |
**To create Docker Hub access token**:
1. Login to [hub.docker.com](https://hub.docker.com)
2. Account Settings > Security > **New Access Token**
3. Name: `GitLab CI/CD`
4. Permissions: **Read, Write, Delete**
5. Copy token to GitLab CI/CD variable `DOCKER_HUB_PASSWORD`
6. Mark variable as **Masked** and **Protected** in GitLab
**CRITICAL**: Ensure Docker Hub repository `jgrusewski/foxhunt` is set to **PRIVATE**
### 3. Push to Main Branch
The pipeline auto-triggers on push to `main` branch:
```bash
git add .gitlab-ci.yml
git commit -m "feat(ci): Add production-ready GitLab CI/CD Docker build pipeline"
git push origin main
```
### 4. Monitor Pipeline
- Navigate to **CI/CD > Pipelines** in GitLab
- Pipeline stages: **build****test****deploy**
- Build time: ~2-3 minutes (cached), ~5-8 minutes (clean build)
- Auto-deployment to staging after tests pass
- Manual approval required for production deployment
---
## Pipeline Architecture
### Stages
```
┌──────────────────────────────────────────────────────────┐
│ STAGE 1: BUILD │
├──────────────────────────────────────────────────────────┤
│ • Build Docker image with BuildKit │
│ • Enable layer caching (--cache-from) │
│ • Tag with commit SHA + 'latest' │
│ • Push to Docker Hub │
│ • Artifacts: image-metadata.json │
└──────────────────────────────────────────────────────────┘
┌──────────────────────────────────────────────────────────┐
│ STAGE 2: TEST │
├──────────────────────────────────────────────────────────┤
│ test:glibc-validation │
│ • Verify GLIBC version (ldd --version) │
│ • Check GLIBC symbols for binaries │
│ • Validate system libraries (libstdc++, libgcc_s) │
│ • Verify ca-certificates │
├──────────────────────────────────────────────────────────┤
│ test:cuda-validation │
│ • Verify CUDA installation │
│ • Check CUDA libraries (libcuda, libcurand, libcublas) │
│ • Verify cuDNN 9 installation │
│ • Validate CUDA environment variables │
│ • Check CUDA compat libraries (driver compatibility) │
├──────────────────────────────────────────────────────────┤
│ test:entrypoint-validation │
│ • Verify entrypoint scripts exist │
│ • Check executable permissions │
│ • Test entrypoint help command │
└──────────────────────────────────────────────────────────┘
┌──────────────────────────────────────────────────────────┐
│ STAGE 3: DEPLOY │
├──────────────────────────────────────────────────────────┤
│ deploy:runpod-staging (AUTO) │
│ • Auto-deploys to staging after tests pass │
│ • Environment: staging/runpod │
│ • Auto-stop in 1 hour │
├──────────────────────────────────────────────────────────┤
│ deploy:runpod (MANUAL) │
│ • Manual approval required │
│ • Environment: production/runpod │
│ • Displays deployment instructions │
│ • Links to Runpod console │
└──────────────────────────────────────────────────────────┘
```
### Triggers
- **Push to `main` branch**: Auto-build + auto-test + auto-staging + manual production
- **Merge requests**: Pipeline disabled (no builds on MRs)
- **Manual cleanup**: `cleanup:docker-hub` job for old image removal
---
## Docker Image Details
### Build Configuration
- **Dockerfile**: `Dockerfile.runpod`
- **Base image**: `nvidia/cuda:12.4.1-cudnn-devel-ubuntu22.04`
- **Image size**: ~4.8GB (CUDA 12.4.1 + cuDNN 9 + Ubuntu 22.04)
- **BuildKit**: Enabled for layer caching
- **Cache strategy**: `--cache-from jgrusewski/foxhunt:latest`
### Image Tags
| Tag | Description | Usage |
|---|---|---|
| `jgrusewski/foxhunt:latest` | Latest production image | Runpod default deployment |
| `jgrusewski/foxhunt:<commit-sha>` | Specific commit build | Version pinning, rollback |
### OCI Labels
```yaml
org.opencontainers.image.created: <BUILD_DATE>
org.opencontainers.image.revision: <GIT_COMMIT>
org.opencontainers.image.source: <CI_PROJECT_URL>
org.opencontainers.image.title: Foxhunt HFT Trading System
org.opencontainers.image.description: CUDA 12.4.1 + cuDNN 9 runtime for Runpod GPU deployment
```
---
## Deployment to Runpod
### Option 1: Manual Deployment (GitLab UI)
1. Navigate to **CI/CD > Pipelines** in GitLab
2. Click on latest successful pipeline
3. Go to **Deploy** stage
4. Click **play** button on `deploy:runpod` job
5. Follow deployment instructions in job output
### Option 2: Automated Deployment (Python Script)
Use the automated deployment script with the built image:
```bash
# Get image tag from pipeline
IMAGE_TAG="jgrusewski/foxhunt:a1b2c3d" # Replace with commit SHA
# Deploy to Runpod
python3 scripts/runpod_deploy.py \
--gpu-type "RTX A4000" \
--image $IMAGE_TAG
```
### Option 3: Runpod Web Console (Manual)
1. Login to [runpod.io](https://www.runpod.io/console/pods)
2. Deploy GPU Pod:
- **Region**: EUR-IS-1 (required for volume mount)
- **GPU**: RTX A4000 (16GB, $0.25/hr) or Tesla V100 (16GB, $0.10/hr)
- **Docker Image**: `jgrusewski/foxhunt:latest` (or specific commit SHA)
- **Container Registry Auth**: Select Docker Hub credentials
- **Volume Mount**: `/runpod-volume` (select existing network volume)
3. Pod will auto-start training from `/runpod-volume/binaries/`
4. Models saved to `/runpod-volume/models/` (auto-synced to S3)
---
## Validation Tests
### GLIBC Validation
Tests ensure binary compatibility with Ubuntu 22.04 (GLIBC 2.35):
```bash
# Test 1: Verify GLIBC version
docker run --rm jgrusewski/foxhunt:latest ldd --version
# Test 2: Check GLIBC symbols for binaries
docker run --rm jgrusewski/foxhunt:latest ldd /runpod-volume/binaries/hyperopt_mamba2_demo | grep "GLIBC_2"
# Test 3: Verify system libraries
docker run --rm jgrusewski/foxhunt:latest ldconfig -p | grep -E "(libstdc\+\+|libgcc_s)"
```
### CUDA Validation
Tests ensure CUDA 12.4.1 + cuDNN 9 runtime:
```bash
# Test 1: Verify CUDA libraries
docker run --rm jgrusewski/foxhunt:latest ls -la /usr/local/cuda/lib64/ | grep -E "(libcuda|libcurand|libcublas)"
# Test 2: Verify cuDNN 9
docker run --rm jgrusewski/foxhunt:latest find /usr -name "libcudnn*"
# Test 3: Verify CUDA environment
docker run --rm jgrusewski/foxhunt:latest env | grep -E "(CUDA_HOME|LD_LIBRARY_PATH)"
```
### Entrypoint Validation
Tests ensure entrypoint scripts are executable:
```bash
# Test 1: Verify scripts exist
docker run --rm jgrusewski/foxhunt:latest ls -la /entrypoint.sh /entrypoint-generic.sh
# Test 2: Verify executable
docker run --rm jgrusewski/foxhunt:latest sh -c "test -x /entrypoint.sh && echo 'OK'"
# Test 3: Run help
docker run --rm jgrusewski/foxhunt:latest --help
```
---
## Cost Analysis
### GitLab CI/CD
- **Free Tier**: 400 CI/CD minutes/month
- **Build time**: ~2-3 minutes (cached), ~5-8 minutes (clean build)
- **Estimated monthly usage**: ~20-50 minutes (10-20 builds)
- **Cost**: **$0** (within free tier)
### Docker Hub
- **Free Tier**: 1 private repository, unlimited pulls
- **Image size**: ~4.8GB
- **Storage**: Free (1 private repo)
- **Bandwidth**: Unlimited pulls
- **Cost**: **$0** (within free tier)
### Runpod GPU
- **RTX A4000 (16GB)**: $0.25/hr
- **Tesla V100 (16GB)**: $0.10/hr
- **Estimated training time**: ~2-10 minutes per model
- **Cost per build**: **$0.004 - $0.04** (negligible)
**Total Monthly Cost**: **~$0** (excluding GPU training time)
---
## Troubleshooting
### Problem: Pipeline fails on `docker login`
**Cause**: Missing or incorrect Docker Hub credentials
**Solution**:
1. Verify `DOCKER_HUB_USERNAME` and `DOCKER_HUB_PASSWORD` in GitLab CI/CD Variables
2. Ensure `DOCKER_HUB_PASSWORD` is an **access token** (not password)
3. Check variables are marked as **Masked** and **Protected**
### Problem: Image push fails with "authentication required"
**Cause**: Docker Hub repository not accessible
**Solution**:
1. Verify Docker Hub repository exists: `jgrusewski/foxhunt`
2. Ensure repository is set to **PRIVATE**
3. Check Docker Hub access token has **Read, Write, Delete** permissions
### Problem: Test stage fails with "binary not found"
**Cause**: Binaries are stored on Runpod volume, not in Docker image
**Solution**:
- This is expected behavior in CI environment
- Test gracefully handles missing binaries with message: "Binary not found on volume (expected in CI)"
- Binaries are validated during actual Runpod deployment
### Problem: Build cache not working
**Cause**: Layer caching not enabled or `latest` tag not found
**Solution**:
1. Ensure `DOCKER_BUILDKIT=1` is set (enabled by default)
2. Run at least one successful build to create `latest` tag
3. Check Docker Hub has `jgrusewski/foxhunt:latest` tag
4. Verify `--cache-from` argument in build script
### Problem: Pipeline timeout
**Cause**: Build taking too long (>30 minutes)
**Solution**:
1. Check Docker layer caching is enabled
2. Verify network connectivity to Docker Hub
3. Consider increasing `timeout` in `.gitlab-ci.yml`
4. Use faster GitLab runner if available
---
## Security Best Practices
### 1. Docker Hub Repository
- **ALWAYS** use **PRIVATE** repository for production images
- **NEVER** commit Docker Hub credentials to git
- Use **access tokens** instead of passwords
- Rotate access tokens every 90 days
### 2. GitLab CI/CD Variables
- Mark `DOCKER_HUB_PASSWORD` as **Masked** (hides in logs)
- Mark variables as **Protected** (only available on protected branches)
- Use **Environment-specific variables** for staging/production separation
### 3. Image Scanning
- Enable Trivy/Clair image scanning (commented out in pipeline)
- Review vulnerability reports before deployment
- Update base image regularly (CUDA security patches)
### 4. Access Control
- Limit GitLab CI/CD permissions to CI/CD maintainers only
- Use **Manual deployment approval** for production (enabled by default)
- Review deployment logs before approving
---
## Maintenance
### Update Docker Base Image
When CUDA updates are released:
1. Update `Dockerfile.runpod` base image:
```dockerfile
FROM nvidia/cuda:12.5.0-cudnn-devel-ubuntu22.04
```
2. Rebuild locally and test:
```bash
docker build -f Dockerfile.runpod -t jgrusewski/foxhunt:test .
docker run --rm jgrusewski/foxhunt:test nvidia-smi
```
3. Push to main branch to trigger CI/CD pipeline
4. Verify all tests pass before production deployment
### Cleanup Old Images
Manually cleanup old images on Docker Hub:
1. Navigate to **CI/CD > Pipelines** in GitLab
2. Find `cleanup:docker-hub` job in deploy stage
3. Click **play** button to trigger manual cleanup
4. Follow instructions in job output
**Recommendation**: Keep last 10-20 commit tags, always keep `latest`
---
## Performance Optimization
### Build Speed
| Optimization | Impact | Status |
|---|---|---|
| BuildKit enabled | 30-50% faster | ✓ Enabled |
| Layer caching | 60-80% faster (cached builds) | ✓ Enabled |
| Multi-stage builds | N/A (single-stage runtime image) | N/A |
| Parallel stages | Tests run in parallel | ✓ Enabled |
**Current performance**:
- Clean build: ~5-8 minutes
- Cached build: ~2-3 minutes
- Test stage: ~5-10 minutes
- Total pipeline: ~10-15 minutes
### Cache Hit Rate
Monitor cache hit rate in build logs:
```
CACHED [1/5] FROM nvidia/cuda:12.4.1-cudnn-devel-ubuntu22.04
CACHED [2/5] RUN apt-get update && apt-get install -y ca-certificates wget
CACHED [3/5] COPY entrypoint-generic.sh /entrypoint-generic.sh
```
**Target**: 80%+ cache hit rate for subsequent builds
---
## Integration with Existing Workflows
### GitHub Actions Migration
If migrating from GitHub Actions, this pipeline is equivalent to:
```yaml
# .github/workflows/docker-build.yml equivalent
name: Docker Build and Push
on:
push:
branches: [main]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: docker/setup-buildx-action@v2
- uses: docker/login-action@v2
- uses: docker/build-push-action@v4
```
Key differences:
- GitLab uses `services: docker:dind` instead of GitHub's `docker/setup-buildx-action`
- GitLab CI/CD Variables vs GitHub Secrets
- GitLab Manual deployments vs GitHub Environments
### CI/CD Metrics
Track pipeline metrics in GitLab:
- **CI/CD > Analytics > CI/CD Analytics**
- Monitor build success rate (target: >95%)
- Track average build duration (target: <5 minutes)
- Review deployment frequency
---
## Support and Resources
### Documentation
- **GitLab CI/CD Docs**: https://docs.gitlab.com/ee/ci/
- **Docker BuildKit**: https://docs.docker.com/build/buildkit/
- **Runpod Deployment**: [scripts/runpod_deploy.py](/home/jgrusewski/Work/foxhunt/scripts/runpod_deploy.py)
- **CUDA.md**: Project-specific CUDA configuration
### Quick Commands
```bash
# Validate GitLab CI/CD YAML syntax
python3 -c "import yaml; yaml.safe_load(open('.gitlab-ci.yml'))"
# Test Docker build locally
docker build -f Dockerfile.runpod -t jgrusewski/foxhunt:test .
# Inspect built image
docker inspect jgrusewski/foxhunt:latest
# View pipeline history
git log --oneline --grep="ci:"
# Check Docker Hub tags
curl -s https://hub.docker.com/v2/repositories/jgrusewski/foxhunt/tags/ | jq .
```
---
## Changelog
### 2025-10-29: Initial Release
**Features**:
- ✓ Automated Docker builds on push to main
- ✓ BuildKit enabled with layer caching
- ✓ Automatic versioning (commit SHA + timestamp)
- ✓ Push to Docker Hub (PRIVATE registry)
- ✓ GLIBC validation tests
- ✓ CUDA 12.4.1 + cuDNN 9 validation tests
- ✓ Entrypoint script validation
- ✓ Manual production deployment approval
- ✓ Auto-staging deployment with 1-hour auto-stop
- ✓ Manual Docker Hub cleanup job
**Configuration**:
- Base image: `nvidia/cuda:12.4.1-cudnn-devel-ubuntu22.04`
- Image size: ~4.8GB
- Build time: ~2-3 minutes (cached)
- Test coverage: GLIBC + CUDA + entrypoint validation
- Deployment: Manual approval for production
---
**Status**: ✅ **PRODUCTION READY**
**Next Steps**: Configure GitLab CI/CD Variables and push to main branch