|
| 1 | +# rsafd-docker |
| 2 | + |
| 3 | +Multi-architecture (linux/amd64 + linux/arm64) Jupyter environment with both Python and R kernels and the `Rsafd` R package pre-installed. |
| 4 | + |
| 5 | +Includes: |
| 6 | +* R: rsafd (GitHub clone), IRkernel, reticulate + supporting deps |
| 7 | +* Python: TensorFlow, Keras, scientific stack (numpy, pandas, scipy, scikit-learn, matplotlib, seaborn) |
| 8 | +* Interop: reticulate wired to the Python virtualenv |
| 9 | +* Healthcheck: validates TensorFlow + Rsafd + reticulate bridge |
| 10 | + |
| 11 | +## Feature Matrix |
| 12 | + |
| 13 | +| Capability | Details | |
| 14 | +|------------|---------| |
| 15 | +| Auth token | Random secure token by default (can disable) | |
| 16 | +| UI modes | Switch between JupyterLab or classic Notebook via `JUPYTER_UI` | |
| 17 | +| Quiet modes | Single-line plain or link-only output for scripting | |
| 18 | +| Rsafd install | Direct repo clone into site library (non-CRAN) | |
| 19 | +| Healthcheck | `/usr/local/bin/healthcheck` (wired into Docker HEALTHCHECK) | |
| 20 | +| CI Workflow | `.github/workflows/docker-multi-arch.yml` pushes multi-tag images to GHCR | |
| 21 | + |
| 22 | +## Quick Start |
| 23 | + |
| 24 | +```bash |
| 25 | +IMAGE=ghcr.io/OWNER/rsafd-docker:latest # replace OWNER |
| 26 | +docker run -p 8888:8888 $IMAGE |
| 27 | +# Terminal prints: OPEN THIS URL: http://127.0.0.1:8888/lab?token=.... |
| 28 | +``` |
| 29 | + |
| 30 | +Open the printed URL in a browser; both Python and R kernels appear. |
| 31 | + |
| 32 | +### Student Usage (Pull & Run) |
| 33 | + |
| 34 | +Give students only these two commands (replace OWNER beforehand): |
| 35 | + |
| 36 | +```bash |
| 37 | +docker pull ghcr.io/OWNER/rsafd-docker:latest |
| 38 | +docker run -p 8888:8888 ghcr.io/OWNER/rsafd-docker:latest |
| 39 | +``` |
| 40 | + |
| 41 | +They copy the printed OPEN THIS URL line into a browser. Architecture (Intel vs Apple Silicon) is chosen automatically by Docker. |
| 42 | + |
| 43 | +Pin to a stable build (date tag example): |
| 44 | +```bash |
| 45 | +docker pull ghcr.io/OWNER/rsafd-docker:20250827 |
| 46 | +``` |
| 47 | + |
| 48 | +If the image is private, instruct them to authenticate first (PAT with `read:packages`): |
| 49 | +```bash |
| 50 | +echo "$GITHUB_PAT" | docker login ghcr.io -u GITHUB_USERNAME --password-stdin |
| 51 | +``` |
| 52 | + |
| 53 | +### Choose UI (Lab vs Notebook) |
| 54 | + |
| 55 | +```bash |
| 56 | +# Classic Notebook (default) |
| 57 | +docker run -p 8888:8888 -e JUPYTER_UI=notebook $IMAGE |
| 58 | + |
| 59 | +# JupyterLab |
| 60 | +docker run -p 8888:8888 -e JUPYTER_UI=lab $IMAGE |
| 61 | +``` |
| 62 | + |
| 63 | +### Output Modes |
| 64 | + |
| 65 | +| Mode | Variables | Output | |
| 66 | +|------|-----------|--------| |
| 67 | +| Full banner | (default) | Colored banner + two URLs | |
| 68 | +| Link only (colored) | `JUPYTER_LINK_ONLY=1` | One colored OPEN THIS URL line, silent server logs | |
| 69 | +| Plain single line | `JUPYTER_PLAIN_URL=1` | Bare URL (good for scripts / copy) | |
| 70 | + |
| 71 | +### Token Control |
| 72 | + |
| 73 | +| Scenario | Setting | |
| 74 | +|----------|---------| |
| 75 | +| Random secure (default) | no vars needed | |
| 76 | +| Provide explicit | `-e JUPYTER_TOKEN=yourtoken` | |
| 77 | +| Disable (INSECURE) | `-e JUPYTER_DISABLE_TOKEN=1` | |
| 78 | + |
| 79 | +When disabled, anyone with port access can use the server—only for trusted local use. |
| 80 | + |
| 81 | +### Mount Data / Notebooks |
| 82 | + |
| 83 | +```bash |
| 84 | +docker run --rm -p 8888:8888 \ |
| 85 | + -v "$PWD":/workspace/notebooks \ |
| 86 | + -v "$HOME":/home/developer/hosthome \ |
| 87 | + $IMAGE |
| 88 | +``` |
| 89 | + |
| 90 | +### Environment Variable Summary |
| 91 | + |
| 92 | +| Var | Default | Purpose | |
| 93 | +|-----|---------|---------| |
| 94 | +| JUPYTER_PORT | 8888 | Server port | |
| 95 | +| JUPYTER_UI | lab | 'lab' or 'notebook' UI | |
| 96 | +| JUPYTER_TOKEN | (blank -> random) | Explicit token override | |
| 97 | +| JUPYTER_DISABLE_TOKEN | 0 | Set 1 to disable auth token (insecure) | |
| 98 | +| JUPYTER_PLAIN_URL | 0 | Print only plain URL (keep logs) | |
| 99 | +| JUPYTER_LINK_ONLY | 0 | Print one colored URL line and silence logs | |
| 100 | +| JUPYTER_LAB_ARGS | (empty) | Extra args appended to server command | |
| 101 | +| JUPYTER_DISABLE_LSP | 1 | Attempt to disable LSP noise | |
| 102 | + |
| 103 | +### Healthcheck |
| 104 | + |
| 105 | +Docker HEALTHCHECK runs `/usr/local/bin/healthcheck` every 2 minutes (after a 30s start period) ensuring: |
| 106 | +1. Python TensorFlow imports |
| 107 | +2. R can load Rsafd |
| 108 | +3. reticulate sees TensorFlow |
| 109 | + |
| 110 | +Manual run inside container: |
| 111 | +```bash |
| 112 | +/usr/local/bin/healthcheck |
| 113 | +``` |
| 114 | + |
| 115 | +Container status turns `unhealthy` if these fail (view with `docker inspect` or `docker ps`). |
| 116 | + |
| 117 | +### Build Locally (Multi-Arch) |
| 118 | + |
| 119 | +```bash |
| 120 | +IMAGE=ghcr.io/OWNER/rsafd-docker:latest |
| 121 | +docker buildx create --name rsafd-builder --use 2>/dev/null || true |
| 122 | +docker buildx inspect --bootstrap |
| 123 | +docker buildx build --platform linux/amd64,linux/arm64 -t $IMAGE --push . |
| 124 | +``` |
| 125 | + |
| 126 | +### GitHub Actions Workflow |
| 127 | + |
| 128 | +`.github/workflows/docker-multi-arch.yml` auto-builds on pushes to `main` and manual dispatch. Tags produced: |
| 129 | +* `latest` |
| 130 | +* Date stamp (`YYYYMMDD`) |
| 131 | +* Short SHA (12 chars) |
| 132 | +* Optional manual input tag |
| 133 | + |
| 134 | +### Runtime Smoke Tests |
| 135 | + |
| 136 | +Python: |
| 137 | +```python |
| 138 | +import tensorflow as tf, keras |
| 139 | +print(tf.__version__) |
| 140 | +``` |
| 141 | + |
| 142 | +R: |
| 143 | +```r |
| 144 | +library(Rsafd) |
| 145 | +library(reticulate) |
| 146 | +py <- import('tensorflow') |
| 147 | +py$`__version__` |
| 148 | +``` |
| 149 | + |
| 150 | +### Extending |
| 151 | + |
| 152 | +Add R packages (example): |
| 153 | +```dockerfile |
| 154 | +RUN R -q -e "install.packages('xts', repos='https://cloud.r-project.org', dependencies=TRUE)" |
| 155 | +``` |
| 156 | + |
| 157 | +Add Python packages: |
| 158 | +```dockerfile |
| 159 | +RUN /opt/venv/bin/pip install --no-cache-dir xgboost |
| 160 | +``` |
| 161 | + |
| 162 | +### Notes |
| 163 | + |
| 164 | +* Rsafd is cloned directly (non-CRAN); updates require rebuilding. |
0 commit comments