# Best Practices for Running LabNow AI Docker Images in Production Environments

> Deploy LabNow AI Docker images in production with best practices: pin tags, use non-root users, and manage persistent data. Optimize your LabNow AI deployments today.

- Repository: [LabNow.ai/lab-foundation](https://github.com/labnow-ai/lab-foundation)
- Tags: best-practices
- Published: 2026-03-05

---

**Pin exact image tags, run containers as the non-root `labnow` user, mount persistent volumes for data, and use Docker Compose to orchestrate multi-service stacks when deploying LabNow AI containers in production.**

The labnow-ai/lab-foundation repository provides a modular container stack designed for reproducible AI and data science workflows. By leveraging its layered architecture—from the minimal Ubuntu base to specialized GPU and database images—you can build secure, scalable production environments that maintain consistency across development and deployment.

## Understanding the LabNow AI Container Architecture

LabNow AI ships a layered container stack that lets you compose a production-ready AI/Data-Science runtime from small, purpose-built images. Each layer builds upon the previous one, enabling precise control over your production environment.

### The Four Container Layers

- **Base Layer**: The foundation located in `docker_base/Dockerfile` provides a minimal Ubuntu image with a full Conda installation, system-Python replacement, and essential utilities. This layer establishes the `labnow` non-root user and core environment.

- **Core Layer**: Defined in `docker_core/Dockerfile`, this adds language runtimes (Python, R, Julia, Go, Node) and scientific packages via the **script-setup** toolkit. It uses **ARG** variables (`ARG_PROFILE_PYTHON`, `ARG_PROFILE_R`, `ARG_PROFILE_JAVA`) to control which language stacks install without rebuilding the entire stack.

- **Atom Layer**: The `docker_atom/Dockerfile` builds an Ubuntu "noble" image bundling the *script-setup* helpers and OS tools. This serves as the entry point for custom images and houses the automation scripts in `docker_atom/work/`.

- **Specialized Layers**: Production-specific variants including CUDA support (`docker_cuda/nvidia-cuda.Dockerfile`) and PostgreSQL (`docker_db_postgres/postgres-ext.Dockerfile`) extend the core stack for GPU computing and database workloads.

### The Script-Setup Automation Toolkit

The **script-setup** collection under `docker_atom/work/` and `docker_core/work/` automates dependency installation and enforces reproducible versions. Key components include:

- [`script-setup.sh`](https://github.com/labnow-ai/lab-foundation/blob/main/script-setup.sh): The entry-point installer for Conda, Mamba, and language runtimes.
- [`script-setup-R.sh`](https://github.com/labnow-ai/lab-foundation/blob/main/script-setup-R.sh): Pulls R, CRAN key, and base R packages.
- [`script-setup-node.sh`](https://github.com/labnow-ai/lab-foundation/blob/main/script-setup-node.sh): Fetches the latest Node LTS and configures `npm`.

These scripts write environment files sourced at container startup, ensuring consistent runtime configurations across deployments.

## Production Deployment Best Practices

### Pin Exact Image Tags

Prevent surprise upgrades when `latest` changes by specifying immutable tags. The LabNow registry uses dated tags (e.g., `labnow/core:python3.12-datascience-20241010`) that guarantee repeatable builds.

```bash
docker pull labnow/atom:ubuntu-noble-20241010

```

### Run as Non-Root User

Reduce attack surface by using the `labnow` user created in `docker_base/Dockerfile`. The images explicitly set `USER labnow` to enforce non-privileged execution.

```bash
docker run --user labnow labnow/core:python3.12-datascience-20241010

```

### Mount Persistent Volumes

Keep notebooks, models, and database data across container restarts by mounting host directories to container paths.

```bash
docker run -v /srv/labnow/data:/opt/data -v /srv/labnow/config:/opt/config labnow/core:latest

```

### Set Resource Limits

Avoid noisy-neighbor problems in shared clusters by constraining CPU and memory allocation.

```bash
docker run --cpus="4" --memory="8g" labnow/core:python3.12-datascience-20241010

```

### Use Docker Compose for Multi-Service Stacks

Orchestrate database and AI services together with proper networking and health checks. The following configuration demonstrates a production-ready stack using `labnow/core` with PostgreSQL:

```yaml
version: "3.9"
services:
  labnow:
    image: labnow/core:python3.12-datascience-20241010
    container_name: labnow-app
    user: labnow
    ports: ["8888:8888"]
    environment:
      - JUPYTER_TOKEN=${JUPYTER_TOKEN}
    volumes:
      - ./workspace:/opt/workspace
    depends_on:
      - pg
    command: jupyter lab --ip=0.0.0.0 --no-browser
  pg:
    image: labnow/postgres:15-20241010
    container_name: labnow-pg
    environment:
      POSTGRES_PASSWORD: ${PG_PASSWORD}
      POSTGRES_USER: labnow
      POSTGRES_DB: labnow_db
    volumes:
      - pg_data:/var/lib/postgresql/data
volumes:
  pg_data:

```

Start the stack with:

```bash
docker compose up -d

```

### Secure Credential Management

Supply API keys and passwords via Docker secrets or environment files rather than baking them into images. The Docker-Kit README demonstrates env-var injection patterns that apply to production services.

```bash
docker run --env-file .env.prod labnow/core:python3.12-datascience-20241010

```

### Implement CVE Scanning

Regularly scan images for vulnerabilities using tools like Trivy or Clair. LabNow images contain many binaries across language runtimes, making automated scanning essential.

```bash
trivy image labnow/core:python3.12-datascience-20241010

```

### Configure Health Checks

Enable orchestrators to restart unhealthy containers by adding `HEALTHCHECK` instructions that verify runtime functionality. Simple checks like `conda list` or `python -c "import pandas"` ensure the scientific stack loads correctly.

Add to your Dockerfile or compose configuration:

```dockerfile
HEALTHCHECK CMD python -c "import pandas"

```

### Optimize CI/CD Layer Caching

Keep `ARG_PROFILE_*` variables stable across builds so Docker can reuse layers. Store profile lists in CI variables and pass them unchanged to minimize rebuild times.

## Practical Implementation Examples

### Running a Core AI Image with Jupyter

Deploy a fully-featured data science environment with JupyterLab exposed on port 8888:

```bash

# Pull the base + core image with Python, R, and Julia

docker pull labnow/core:python3.12-datascience-20241010

# Run it as a non-root user, expose Jupyter, and mount a workspace

docker run -d \
  --name labnow-ai \
  --user labnow \
  -p 8888:8888 \
  -v "$PWD/workspace:/opt/workspace" \
  -e JUPYTER_TOKEN=securetoken \
  labnow/core:python3.12-datascience-20241010 \
  jupyter lab --ip=0.0.0.0 --no-browser --NotebookApp.token=$JUPYTER_TOKEN

```

### GPU-Enabled CUDA Workloads

For machine learning workloads requiring NVIDIA GPUs, use the CUDA-specific image:

```bash
docker pull labnow/cuda:nvidia-ctk-20241010

docker run -d \
  --gpus all \
  --name labnow-gpu \
  -p 8888:8888 \
  -v "$PWD/models:/opt/models" \
  labnow/cuda:nvidia-ctk-20241010 \
  jupyter notebook --ip=0.0.0.0 --no-browser

```

### Cross-Registry Image Synchronization

Use Docker-Kit to sync images between registries, referencing the documentation in [`docker_docker_kit/README.md`](https://github.com/labnow-ai/lab-foundation/blob/main/docker_docker_kit/README.md):

```bash
docker run --rm \
  -e DOCKER_REGISTRY_USERNAME=YOUR_USER \
  -e DOCKER_REGISTRY_PASSWORD=YOUR_PASS \
  -e DOCKER_MIRROR_REGISTRY_USERNAME=YOUR_MIRROR_USER \
  -e DOCKER_MIRROR_REGISTRY_PASSWORD=YOUR_MIRROR_PASS \
  labnow/docker-kit \
  python /opt/utils/image-syncer/run_sync.py library/ubuntu \
  --source-registry='quay.io' \
  --target-registry='docker.io'

```

## Summary

- **Pin exact image tags** like `labnow/core:python3.12-datascience-20241010` to ensure reproducible deployments and prevent unexpected updates.
- **Run as the `labnow` user** created in `docker_base/Dockerfile` to minimize security risks in production environments.
- **Mount persistent volumes** for `/opt/data` and `/opt/config` to maintain state across container restarts.
- **Use Docker Compose** to orchestrate multi-service stacks, particularly when combining Core images with PostgreSQL or other data stores.
- **Implement health checks** using simple Python import statements to verify runtime integrity.
- **Scan images regularly** for CVEs using Trivy, given the extensive binary footprint across Conda, Python, R, and Node.js runtimes.

## Frequently Asked Questions

### How do I choose between LabNow Base, Core, and Atom images for production?

**Use the Base image** (`docker_base/Dockerfile`) when you need a minimal Ubuntu foundation with Conda but plan to install custom runtimes yourself. **Choose the Core image** (`docker_core/Dockerfile`) for full data science stacks including Python, R, and Julia, controlled via `ARG_PROFILE_*` build arguments. **Select the Atom image** (`docker_atom/Dockerfile`) when you want the script-setup toolkit without the full language runtime suite, ideal for lightweight custom builds.

### What security measures are built into LabNow Docker images?

The images implement **defense in depth** through multiple mechanisms. The `docker_base/Dockerfile` creates and switches to a `labnow` non-root user via `USER labnow`, reducing container escape risks. The **script-setup** toolkit installs packages from verified repositories only, and the layered architecture allows you to audit specific components like [`docker_atom/work/script-setup.sh`](https://github.com/labnow-ai/lab-foundation/blob/main/docker_atom/work/script-setup.sh) before deployment.

### How do I enable GPU support for LabNow AI containers?

Pull the CUDA-specific variant from the Specialized layer, such as `labnow/cuda:nvidia-ctk-20241010`, and run with the `--gpus all` flag. This image extends the Core layer with NVIDIA Container Toolkit support, enabling PyTorch and TensorFlow to access host GPUs while maintaining the same `labnow` user security model and Conda environment structure.

### Can I customize which programming languages are installed in LabNow images?

Yes. The `docker_core/Dockerfile` accepts **ARG** variables including `ARG_PROFILE_PYTHON`, `ARG_PROFILE_R`, `ARG_PROFILE_JAVA`, and `ARG_PROFILE_JULIA`. By passing specific values at build time (e.g., `--build-arg ARG_PROFILE_PYTHON=3.12`), you control which language stacks install without rebuilding the entire Ubuntu base layer, optimizing both image size and build speed.