diff --git a/README.md b/README.md index a6e25166..4cd8f836 100755 --- a/README.md +++ b/README.md @@ -3,6 +3,22 @@ [![Build](https://github.com/FNNDSC/ChRIS_ultron_backEnd/actions/workflows/ci.yml/badge.svg)](https://github.com/FNNDSC/ChRIS_ultron_backEnd/actions/workflows/ci.yml) [![License](https://img.shields.io/github/license/fnndsc/ChRIS_ultron_backEnd.svg)](./LICENSE) +## TL;DR + +To quick start _ChRIS Ultron Back End_ development: + +``` +./docker-compose-dev.sh +``` + +To shutdown: + +``` +./docker-compose-down.sh +``` + +## Introduction + _ChRIS_ is an open-source platform for containerized medical compute. The _ChRIS_ backend, a.k.a. _ChRIS Ultron Backend_ or _**CUBE**_ for short, is a component of the _ChRIS_ system. @@ -38,8 +54,8 @@ macOS is fully supported as a host platform for _CUBE_. Please note that you **m In a word, **don't** (ok, that's technically two words). _CUBE_ is ideally meant to be deployed on Linux/*nix systems. **Windows is not officially supported nor recommended as the host environment**. If you insist on trying on Windows you can consult some unmaintained documentation on attempts to deploy _CUBE_ using the Windows Subsystem for Linux (WSL) [here](https://github.com/FNNDSC/CHRIS_docs/blob/master/workflows/ChRIS_on_WSL.asciidoc). This probably will break. Note that currently no one on the core development uses Windows in much of any capacity so interest or knowledge to help questions about Windows support is low. Nonetheless, we would welcome any brave soul though who has the time and inclination to fully investigate _CUBE_ on Windows deployment. - -#### Install latest Docker and Docker Compose. + +#### Install latest Docker and Docker Compose. Currently tested platforms: * ``Docker 18.06.0+`` @@ -111,6 +127,23 @@ Please refer to https://github.com/FNNDSC/khris-helm ### Development +#### Quick Start with Docker-compose: + +Use `docker-compose-dev.sh` to start: + +``` +./docker-compose-dev.sh +``` + +To shutdown: + +``` +./docker-compose-down.sh +``` + +##### _CAVEAT_ for mac or linux/arm64 users: + * Some docker images are not available yet. You need to compile the docker images on your own and tag the images as specified in `docker-compose-dev.yml`. + #### Docker Swarm-based development environment: Start a local Docker Swarm cluster if not already started: @@ -126,7 +159,7 @@ git clone https://github.com/FNNDSC/ChRIS_ultron_backEnd.git cd ChRIS_ultron_backEnd ./make.sh ``` -All the steps performed by the above script are properly documented in the script itself. +All the steps performed by the above script are properly documented in the script itself. After running this script all the automated tests should have successfully run and a Django development server should be running in interactive mode in this terminal. Later you can stop and remove CUBE services and storage space by running the following bash script from the repository source directory: @@ -143,8 +176,8 @@ docker swarm leave --force #### Kubernetes-based development environment: -Install single-node Kubernetes cluster. -On MAC OS Docker Desktop includes a standalone Kubernetes server and client. +Install single-node Kubernetes cluster. +On MAC OS Docker Desktop includes a standalone Kubernetes server and client. Consult this page https://docs.docker.com/desktop/kubernetes/. On Linux there is a simple MicroK8s installation. Consult this page https://microk8s.io. Then create the required alias: @@ -201,7 +234,7 @@ docker compose -f docker-compose_dev.yml exec chris_dev python manage.py test -- To run all the tests: ```bash -docker compose -f docker-compose_dev.yml exec chris_dev python manage.py test +docker compose -f docker-compose_dev.yml exec chris_dev python manage.py test ``` After running the Integration tests the ``./CHRIS_REMOTE_FS`` directory **must** be empty otherwise it means some error has occurred and you should manually empty it. @@ -215,7 +248,7 @@ docker compose -f docker-compose_dev.yml exec chris_dev coverage run --source=fe docker compose -f docker-compose_dev.yml exec chris_dev coverage report ``` -#### Using [HTTPie](https://httpie.org/) client to play with the REST API +#### Using [HTTPie](https://httpie.org/) client to play with the REST API A simple GET request to retrieve the user-specific list of feeds: ```bash http -a cube:cube1234 http://localhost:8000/api/v1/ diff --git a/chrisomatic/chrisomatic.yml b/chrisomatic/chrisomatic.yml index ef2520dd..820eb65d 100755 --- a/chrisomatic/chrisomatic.yml +++ b/chrisomatic/chrisomatic.yml @@ -1,30 +1,25 @@ version: 1.2 on: - cube_url: http://chrisdev.local:8000/api/v1/ + cube_url: http://chris:8000/api/v1/ chris_superuser: username: chris password: chris1234 - email: dev@babymri.org cube: - users: - - username: cube - password: cube1234 - email: cube@babymri.org - compute_resource: - name: host - url: "http://pfcon.remote:30005/api/v1/" + url: http://pfcon.host:5005/api/v1/ username: pfcon password: pfcon1234 - description: host Description - innetwork: false - + description: Local compute environment + innetwork: true plugins: - name: pl-simplefsapp - name: pl-dircopy + - name: pl-tsdircopy - name: pl-topologicalcopy + - name: pl-unstack-folders # these two are hard-coded in make.sh to be part of example pipelines - dock_image: fnndsc/pl-simpledsapp diff --git a/docker-compose-dev.sh b/docker-compose-dev.sh new file mode 100755 index 00000000..d562a77c --- /dev/null +++ b/docker-compose-dev.sh @@ -0,0 +1,8 @@ +#!/bin/bash + +# change to directory where this script lives +cd "$(dirname "$(readlink -f "$0")")" + +set -ex +docker compose -f docker-compose-dev.yml up -d +exec docker compose -f docker-compose-dev.yml run --rm $notty chrisomatic diff --git a/docker-compose-dev.yml b/docker-compose-dev.yml new file mode 100644 index 00000000..c14838b7 --- /dev/null +++ b/docker-compose-dev.yml @@ -0,0 +1,338 @@ +# an ephemeral instance of ChRIS backend services for local development +# +# warning: /var/run/docker.sock is mounted into some services (notably pman) + +services: + chrisomatic: + image: ghcr.io/fnndsc/chrisomatic:0.8.2 + profiles: + - tools + volumes: + - "./chrisomatic/chrisomatic.yml:/chrisomatic.yml:ro" + - "/var/run/docker.sock:/var/run/docker.sock:rw" + userns_mode: host + depends_on: + - chris + networks: + - local + + cube_local: + image: cube:latest-local + build: + context: . + dockerfile_inline: | + FROM ghcr.io/fnndsc/cube:latest + + RUN mkdir -p /opt + COPY ./requirements /opt/requirements + RUN pip install -r /opt/requirements/local.txt + command: sh -c 'exit 0' + + db_migrate: + image: cube:latest-local + command: + - sh + - -c + - python manage.py migrate --noinput + volumes: + - chris_files:/var/chris:rw + - ./chris_backend:/opt/app-root/src:ro + - .:/opt/ChRIS_ultron_backEnd:ro + environment: + - DJANGO_SETTINGS_MODULE=config.settings.local + - STORAGE_ENV=fslink + depends_on: + cube_local: + condition: service_completed_successfully + chris_dev_db: + condition: service_healthy + networks: + - local + + chris: + container_name: chris + image: cube:latest-local + command: + - sh + - -c + - python manage.py runserver 0.0.0.0:8000 + ports: + - "8000:8000" + volumes: + - chris_files:/var/chris:rw + - ./chris_backend:/opt/app-root/src:ro + - .:/opt/ChRIS_ultron_backEnd:ro + environment: + - DJANGO_SETTINGS_MODULE=config.settings.local + - STORAGE_ENV=fslink + depends_on: + cube_local: + condition: service_completed_successfully + db_migrate: + condition: service_completed_successfully + queue: + condition: service_started + networks: + - local + labels: + org.chrisproject.role: "ChRIS_ultron_backEnd" + worker: + image: cube:latest-local + command: + - sh + - -c + - celery -A core worker -c 4 -l info -Q main1,main2 + volumes: + - chris_files:/var/chris:rw + - ./chris_backend:/opt/app-root/src:ro + - .:/opt/ChRIS_ultron_backEnd:ro + environment: + - DJANGO_SETTINGS_MODULE=config.settings.local + - STORAGE_ENV=fslink + depends_on: + db_migrate: + condition: service_completed_successfully + queue: + condition: service_started + pfcon: + condition: service_started + restart: unless-stopped + networks: + - local + worker_periodic: + image: cube:latest-local + command: + - sh + - -c + - celery -A core worker -c 2 -l info -Q periodic + volumes: + - chris_files:/var/chris:rw + - ./chris_backend:/opt/app-root/src:ro + - .:/opt/ChRIS_ultron_backEnd:ro + environment: + - DJANGO_SETTINGS_MODULE=config.settings.local + - STORAGE_ENV=fslink + depends_on: + cube_local: + condition: service_completed_successfully + db_migrate: + condition: service_completed_successfully + queue: + condition: service_started + restart: unless-stopped + networks: + - local + scheduler: + image: cube:latest-local + command: + - sh + - -c + - celery -A core beat -l info --scheduler django_celery_beat.schedulers:DatabaseScheduler + volumes: + - chris_files:/var/chris:rw + - ./chris_backend:/opt/app-root/src:ro + - .:/opt/ChRIS_ultron_backEnd:ro + environment: + - DJANGO_SETTINGS_MODULE=config.settings.local + - STORAGE_ENV=fslink + depends_on: + cube_local: + condition: service_completed_successfully + db_migrate: + condition: service_completed_successfully + queue: + condition: service_started + restart: unless-stopped + networks: + - local + chris_dev_db: + image: docker.io/library/postgres:16 + restart: unless-stopped + volumes: + - db_data:/var/lib/postgresql/data + environment: + - POSTGRES_DB=chris_dev + - POSTGRES_USER=chris + - POSTGRES_PASSWORD=Chris1234 + networks: + - local + healthcheck: + test: ["CMD", "pg_isready"] + interval: 2s + timeout: 4s + retries: 3 + start_period: 60s + queue: + image: docker.io/library/rabbitmq:3 + restart: unless-stopped + networks: + - local + + pfcon: + container_name: pfcon + image: ghcr.io/fnndsc/pfcon:5.2.2 + environment: + COMPUTE_SERVICE_URL: http://pman:5010/api/v1/ + SECRET_KEY: secret + PFCON_USER: pfcon + PFCON_PASSWORD: pfcon1234 + PFCON_INNETWORK: "true" + STORAGE_ENV: filesystem + STOREBASE_MOUNT: /var/local/storeBase + ports: + - "5005:5005" + volumes: + - chris_files:/var/local/storeBase + networks: + local: + aliases: + - pfcon.host + remote: + labels: + org.chrisproject.role: "pfcon" + user: "1001" + + pman: + image: ghcr.io/fnndsc/pman:6.2.0 + container_name: pman + environment: + CONTAINER_ENV: docker + CONTAINER_USER: "1001:" + ENABLE_HOME_WORKAROUND: "yes" + JOB_LABELS: "org.chrisproject.miniChRIS=plugininstance" + SECRET_KEY: secret + REMOVE_JOBS: "yes" + volumes: + - /var/run/docker.sock:/var/run/docker.sock:rw + depends_on: + - pfcon + ports: + - "5010:5010" + networks: + remote: + userns_mode: "host" + labels: + org.chrisproject.role: "pman" + + chris_ui: + image: ghcr.io/fnndsc/chris_ui:latest-staging + command: sirv --host --single + environment: + VITE_APP_CHRIS_UI_URL: http://localhost:8000/api/v1/ + VITE_APP_PFDCM_URL: http://localhost:4005/ + ports: + - "8020:3000" + + orthanc: + image: docker.io/jodogne/orthanc-plugins:1.12.3 + volumes: + - ./orthanc.json:/etc/orthanc/orthanc.json:ro + - orthanc:/var/lib/orthanc/db + ports: + - "4242:4242" + - "8042:8042" + networks: + - pacs + profiles: + - pacs + - orthanc + + pfdcm: + image: ghcr.io/fnndsc/pfdcm:3.1.22 + container_name: pfdcm + environment: + MAX_WORKERS: 1 + volumes: + - pfdcm:/home/dicom:rw + - ./pfdcm-services:/home/dicom/services:ro + - chris_files:/chris_files:rw + ports: + - "4005:4005" + networks: + - pacs + user: "1001" + profiles: + - pacs + pfbridge: + image: docker.io/fnndsc/pfbridge:3.7.8 + container_name: pfbridge + environment: + MAX_WORKERS: 1 + PFLINK_USERNAME: pflink + PFLINK_PASSWORD: pflink1234 + NAME: PFDCMLOCAL + PACSNAME: orthanc + CUBEANDSWIFTKEY: local + ports: + - "33333:33333" + networks: + local: + pflink: + profiles: + - pflink + + pflink: + image: docker.io/fnndsc/pflink:4.0.6 + container_name: pflink + restart: unless-stopped + environment: + PFDCM_NAME: "NOTPFDCMLOCAL" # work around for hard-coded edge case + PFLINK_MONGODB: "mongodb://pflink-db:27017" + PFLINK_PFDCM: "http://pfdcm:4005" + PFLINK_PORT: "4010" + ports: + - "4010:4010" + networks: + local: + pflink: + depends_on: + - pflink-db + profiles: + - pflink + + pflink-db: + image: mongo + environment: + - PUID=1000 + - PGID=1000 + volumes: + - pflink-db-data:/data/db + restart: unless-stopped + networks: + pflink: + profiles: + - pflink + + # Non-root container user workarounds + + cube-nonroot-user-volume-fix: + image: docker.io/library/alpine:latest + volumes: + - chris_files:/data:rw + user: root + command: chmod g+rwx /data + restart: "no" + + pfdcm-nonroot-user-volume-fix: + image: docker.io/library/alpine:latest + volumes: + - pfdcm:/home/dicom:rw + user: root + command: chown 1001 /home/dicom + restart: "no" + +networks: + local: + remote: + pacs: + monitoring: + pflink: + +volumes: + chris_files: + db_data: + orthanc: + pfdcm: + grafana_data: + openobserve_data: + pflink-db-data: diff --git a/docker-compose-down.sh b/docker-compose-down.sh new file mode 100755 index 00000000..8b795f82 --- /dev/null +++ b/docker-compose-down.sh @@ -0,0 +1,13 @@ +#!/bin/bash + +# change to directory where this script lives +cd "$(dirname "$(readlink -f "$0")")" + +set -ex + +# remove all plugin instance jobs +pls=$(docker ps -q -a -f 'label=org.chrisproject.miniChRIS=plugininstance') +[ -z "$pls" ] || docker rm -fv $pls + +# stop and remove everything +docker compose -f docker-compose-dev.yml --profile pacs --profile pflink down -v