Anaconda is een krachtig Python-platform voor data-analyse en wetenschappelijk rekenen. In een Docker-context blijkt de standaard Anaconda-image echter beperkingen te hebben, met name rond reproduceerbaarheid, beveiliging en operationeel beheer. In dit artikel beschrijf ik de opzet van een aangepaste Anaconda Docker image, hoe deze is configureerd en hoe ik deze op een Jupyter Notebook veilig en gebruiksvriendelijk beschikbaar heb gemaakt via anaconda.adagia.eu achter een login scherm.
1. Wat is Anaconda en waarom is het handig bij het testen van Python-code?
Anaconda is een distributie van Python (en R) die specifiek is ontworpen voor data science, analytics en wetenschappelijk rekenen. De belangrijkste kenmerken zijn:
- Een uitgebreide set vooraf geïnstalleerde packages (NumPy, pandas, SciPy, matplotlib, etc.)
- Een geïntegreerde package manager (
conda) - Ondersteuning voor geïsoleerde omgevingen
- Nauwe integratie met Jupyter Notebook
Voor het testen en ontwikkelen van Python-code is Anaconda bijzonder geschikt omdat:
- afhankelijkheden expliciet en reproduceerbaar beheerd kunnen worden;
- complexe C/C++-afhankelijke libraries probleemloos te installeren zijn;
- notebooks snelle iteratie en documentatie combineren (code, output en toelichting).
In combinatie met Docker ontstaat bovendien een volledig geïsoleerde en reproduceerbare ontwikkelomgeving, onafhankelijk van het onderliggende besturingssysteem.
2. Problemen met de standaard Anaconda Docker image
De officiële continuumio/anaconda3 image is functioneel correct, maar in de praktijk loop ik tegen meerdere beperkingen aan:
- Geen vooraf ingestelde authenticatie voor Jupyter. Jupyter start standaard met een token of zonder wachtwoord, wat ongeschikt is voor publieke of semi-publieke omgevingen.
- Onvoldoende controle over configuratie tijdens runtime. Veel instellingen moeten handmatig of via runtime-parameters worden geregeld, wat foutgevoelig is.
- Geen duidelijke scheiding tussen build-time en run-time configuratie. Dit bemoeilijkt beheer, auditing en hergebruik.
- Niet optimaal voor productie-achtige omgevingen. Zaken als healthchecks, vaste volumes en resourcebegrenzing zijn niet standaard ingericht.
3. Waarom een aangepaste Anaconda image?
Voor adagia.eu wilde ik een omgeving die:
- reproduceerbaar is (zelfde gedrag na herstart of migratie);
- veilig is (wachtwoord ingesteld, geen tokens nodig);
- geschikt is voor langdurig gebruik;
- eenvoudig te beheren is via Docker Compose en Portainer;
- vermijden van herinstallatie en herconfiguratie bij upgrade van de anaconda image of bouw van de container bij herstart van de NAS.
Bij het ontwerp is bewust gekozen voor een custom Anaconda-image in plaats van runtime-configuratie via Docker Compose. Door het Jupyter-wachtwoord al tijdens de image build vast te leggen, ontstaat een stabiele omgeving die direct inzetbaar is zonder handmatige stappen na deploy. Persistente volumes scheiden code, data en logs van de container, waardoor updates van de image geen invloed hebben op notebooks of resultaten. Het uitschakelen van tokens en het gebruik van een vaste poort vereenvoudigt integratie met een reverse proxy en maakt de omgeving geschikt voor structureel gebruik en testen, zonder de complexiteit van dynamische authenticatie of tijdelijke configuraties.
4. Hoe bouw je een aangepaste Anaconda image?
De basis is de officiële image:
FROM continuumio/anaconda3
Vervolgens worden werkdirectory, tijdzone en omgevingsvariabelen ingesteld:
WORKDIR /opt/notebooks
ENV TZ=Europe/Amsterdam
ENV JUPYTER_PASSWORD="*********"
Daarna installeren we expliciet de benodigde componenten:
RUN conda install -y notebook jupyter --quiet && \
pip install --no-cache-dir psycopg2-binary && \
conda clean -afy
Hiermee houden we de image compact en beheersbaar.
5. Wachtwoord vooraf instellen in de image
Een belangrijk punt is dat de gebruiker bij het openen van anaconda.adagia.eu alleen nog hoeft in te loggen, zonder tokens of setup-stappen.
Dit realiseren we met een klein Python-script dat tijdens de build wordt uitgevoerd.
Naam: jupyter_setup.py
import os
import json
from jupyter_server.auth import passwd
os.makedirs('/root/.jupyter', exist_ok=True)
pw_hash = passwd(os.environ['JUPYTER_PASSWORD'])
cfg = {'NotebookApp': {'password': pw_hash}}
with open('/root/.jupyter/jupyter_notebook_config.json', 'w') as f:
json.dump(cfg, f)
In de Dockerfile:
COPY jupyter_setup.py /tmp/jupyter_setup.py
RUN python /tmp/jupyter_setup.py
Hiermee wordt het wachtwoord gehashed opgeslagen, conform de beveiligingsstandaarden van Jupyter.
6. Docker Compose configuratie
De container wordt aangestuurd via Docker Compose:
services:
anaconda3:
container_name: anaconda3
image: anaconda3:latest
restart: unless-stopped
tty: true
stdin_open: true
mem_limit: 8g
cpu_shares: 2048
shm_size: 4g
environment:
TZ: Europe/Amsterdam
JUPYTER_PASSWORD: "********"
ports:
- "8888:8888"
volumes:
- /volume1/Hoofdmap/OneDrive/Bart_Actueel/Interesse/Python/programma:/opt/notebooks:rw
- /volume1/Hoofdmap/OneDrive/Bart_Actueel/Interesse/Python:/python:rw
- /volume1/docker/anaconda/logs:/opt/notebooks/logs:rw
- /dev/shm:/dev/shm
command:
- jupyter
- notebook
- --notebook-dir=/opt/notebooks
- --ip=0.0.0.0
- --port=8888
- --no-browser
- --allow-root
- --NotebookApp.token=''
healthcheck:
test: ["CMD-SHELL", "curl -f http://127.0.0.1:8888/ || exit 1"]
interval: 60s
retries: 5
start_period: 30s
labels:
com.centurylinklabs.watchtower.enable: "false"
Belangrijke aandachtspunten:
- volumes zorgen voor persistente notebooks;
- healthcheck maakt monitoring mogelijk;
- resource limits voorkomen verstoring van andere containers;
- tokens zijn expliciet uitgeschakeld omdat authenticatie via wachtwoord verloopt.
Aanbeveling
De standaard image van anaconda werkt hartstikke goed. Waar ik tegenaan liep, is dat ik in de docker-compose moest vastleggen om een bepaalde librarypsycopg2-binary bij elke containerstart moest laden via het command:-blok. Dat werkt technisch, maar is niet robuust en niet best practice: bij elke herstart installeer ik opnieuw packages, wat traag is en foutgevoelig. Daarnaast moest ik het wachtwoord opnieuw instellen zodra de container opnieuw opgebouwd werd.
Voor mij was de juiste oplossing om de library en de wachtwoordconfiguratie in het image vast te leggen (Dockerfile). Mijn advies is om:
- na te gaan of de standaard image voldoet aan je wensen. Zo niet, om een custom image m.b.v. Dockerfile aan te maken;
- build-time configuratie te verkiezen boven runtime-aanpassingen;
- beveiliging (wachtwoorden, geen tokens) expliciet te regelen;
- Docker Compose te gebruiken voor beheer en herstartbaarheid.
Een aangepaste Anaconda image levert meer controle, hogere betrouwbaarheid en minder operationele verrassingen op.
(Verouderde) handmatige configuratie van Jupyter Notebook
Let op: onderstaande stappen zijn niet langer nodig sinds het gebruik van de custom Anaconda Docker image. Ze zijn opgenomen ter illustratie van de oorspronkelijke werkwijze.
Log in op de host en open een shell in de draaiende container:
jupyter notebook password
Verlaat de container:
Het opnieuw starten van de stack creëert een nieuwe container, waardoor deze handmatige configuratie verloren gaat.
Na herstart is toegang tot Jupyter Notebook mogelijk met alleen het ingestelde wachtwoord (zonder token).
Bronnen
- Anaconda Documentation – https://docs.anaconda.com
- Docker Documentation – https://docs.docker.com
- Jupyter Notebook Security – https://jupyter-notebook.readthedocs.io/en/stable/security.html
- Docker Best Practices – https://docs.docker.com/develop/develop-images/dockerfile_best-practices/

