diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json new file mode 100644 index 00000000..e8f58c2e --- /dev/null +++ b/.devcontainer/devcontainer.json @@ -0,0 +1,44 @@ +// devcontainer.json +// For format details, see https://aka.ms/vscode-remote/devcontainer.json or this file's README at: +// https://github.com/microsoft/vscode-dev-containers/tree/v0.112.0/containers/docker-existing-docker-compose +// If you want to run as a non-root user in the container, see .devcontainer/docker-compose.yml. +{ + "name": "Existing Docker Compose (Extend)", + // Update the 'dockerComposeFile' list if you have more compose files or use different names. + // The .devcontainer/docker-compose.yml file contains any overrides you need/want to make. + "dockerComposeFile": ["../smdb/debug.yml"], + // The 'service' property is the name of the service for the container that VS Code should + // use. Update this value and .devcontainer/docker-compose.yml to the real service name. + "service": "django", + // The optional 'workspaceFolder' property is the path VS Code should open by default when + // connected. This is typically a file mount in .devcontainer/docker-compose.yml + "workspaceFolder": "/app", + // Set *default* container specific settings.json values on container create. + "settings": { + // Deprecated - use `#terminal.integrated.defaultProfile.windows#` in settings.json instead + //"terminal.integrated.shell.linux": "/bin/zsh", + "[python]": { + "editor.rulers": [120] + }, + "editor.formatOnSave": true, + "python.pythonPath": "/usr/local/bin/python", + "python.linting.pylintEnabled": true, + "python.formatting.provider": "black", + "python.linting.flake8Enabled": true, + "python.linting.mypyEnabled": true + }, + // Add the IDs of extensions you want installed when the container is created. + "extensions": [ + "ms-python.python", + "visualstudioexptteam.vscodeintellicode", + "esbenp.prettier-vscode" + ], + // Uncomment the next line if you want start specific services in your Docker Compose config. + "runServices": ["postgres", "node"], + // Uncomment the next line if you want to keep your containers running after VS Code shuts down. + // "shutdownAction": "none", + // Uncomment the next line to run commands after the container is created - for example installing git. + "postCreateCommand": "wget https://github.com/robbyrussell/oh-my-zsh/raw/master/tools/install.sh -O - | zsh || true && echo 'source /entrypoint' >> ~/.zshrc && echo 'source /entrypoint' >> ~/.bashrc" + // Uncomment to connect as a non-root user. See https://aka.ms/vscode-remote/containers/non-root. + // "remoteUser": "vscode" +} diff --git a/.devcontainer/docker-compose.override.yml b/.devcontainer/docker-compose.override.yml new file mode 100644 index 00000000..66f2a712 --- /dev/null +++ b/.devcontainer/docker-compose.override.yml @@ -0,0 +1,7 @@ +version: "3.0" + +services: + django: + volumes: + - ./.devcontainer/.zshrc:/root/.zshrc + diff --git a/README.md b/README.md index 49968dc6..b22a0b81 100644 --- a/README.md +++ b/README.md @@ -70,6 +70,29 @@ Mount `smb://titan.shore.mbari.org/SeafloorMapping` and load initial Mission dat docker-compose run --rm -u -v /Volumes/SeafloorMapping:/mbari/SeafloorMapping django scripts/load.py -v ``` +### Work on the code with VS Code + +1. Install [VS Code](https://code.visualstudio.com/download) and the +[Remote-Containers](https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.remote-containers) +extension. + +2. From VS Code: File -> Open and select your SMDB_HOME directory. The devcontainer.json +file will be detected and you will be prompted to "Reopen in Container". Click the button +and wait for the containers to build and run. + +3. Run an IPython shell giving access through Django to the database: + + In the Debug panel click the play button next to the "manage.py shell_plus" item in the pick list at top. + A "In [1]:" prompt should appear in the Terminal pane - test by printing all the Missions in the database: +``` + In [1]: Mission.objects.all() +``` + +4. Run the server in VS Code's debugger: + + In the Debug panel click the play button next to the "Debug runserver_plus" item in the pick list at top. + You may set breakpoints and examine variables while the application's view code executes web requests. + ### Deploy a production instance of smdb diff --git a/smdb/.dockerignore b/smdb/.dockerignore index d01db04a..6225f6b7 100644 --- a/smdb/.dockerignore +++ b/smdb/.dockerignore @@ -7,3 +7,30 @@ .pre-commit-config.yaml .readthedocs.yml .travis.yml +**/__pycache__ +**/.classpath +**/.dockerignore +**/.env +**/.git +**/.gitignore +**/.project +**/.settings +**/.toolstarget +**/.vs +**/.vscode +**/*.*proj.user +**/*.dbmdl +**/*.jfm +**/azds.yaml +**/bin +**/charts +**/docker-compose* +# Build in VS Code fails with '**/compose*: https://github.com/mbari-org/SeafloorMappingDB/issues/21#issuecomment-883648752 +##**/compose* +**/Dockerfile* +**/node_modules +**/npm-debug.log +**/obj +**/secrets.dev.yaml +**/values.dev.yaml +README.md diff --git a/smdb/.vscode/launch.json b/smdb/.vscode/launch.json new file mode 100644 index 00000000..882b590c --- /dev/null +++ b/smdb/.vscode/launch.json @@ -0,0 +1,25 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Django runserver_plus", + "type": "python", + "request": "launch", + "program": "${workspaceFolder}/manage.py", + "args": ["runserver_plus", "0.0.0.0:8000"], + "django": true + }, + { + "name": "manage.py shell_plus", + "type": "python", + "request": "launch", + "program": "${workspaceFolder}/manage.py", + "console": "integratedTerminal", + "args": ["shell_plus"], + "justMyCode": false + } + ] +} diff --git a/smdb/.vscode/settings.json b/smdb/.vscode/settings.json new file mode 100644 index 00000000..ebd79310 --- /dev/null +++ b/smdb/.vscode/settings.json @@ -0,0 +1,4 @@ +{ + "python.pythonPath": "/bin/python" + "terminal.integrated.defaultProfile.linux": "zsh" +} diff --git a/smdb/compose/debug/django/Dockerfile b/smdb/compose/debug/django/Dockerfile new file mode 100644 index 00000000..db8e1852 --- /dev/null +++ b/smdb/compose/debug/django/Dockerfile @@ -0,0 +1,80 @@ +# Base the build off of recent stable GDAL image +FROM osgeo/gdal:ubuntu-small-3.3.0 as python + +# Python build stage +FROM python as python-build-stage + +ARG BUILD_ENVIRONMENT=local + +# Install apt packages +RUN apt-get update && apt-get install --no-install-recommends -y \ + # dependencies for building Python packages + build-essential \ + graphviz-dev \ + # psycopg2 dependencies + libpq-dev \ + python3-dev \ + python3-pip + +# Requirements are installed here to ensure they will be cached. +COPY ./requirements . + +# Create Python Dependency and Sub-Dependency Wheels. +RUN pip wheel --wheel-dir /usr/src/app/wheels \ + -r local.txt + + +# Python 'run' stage +FROM python as python-run-stage + +ARG BUILD_ENVIRONMENT=debug +ARG APP_HOME=/app + +ENV PYTHONUNBUFFERED 1 +ENV PYTHONDONTWRITEBYTECODE 1 +ENV BUILD_ENV ${BUILD_ENVIRONMENT} + +WORKDIR ${APP_HOME} + +# Install required system dependencies +RUN apt-get update && apt-get install --no-install-recommends -y \ + graphviz \ + graphviz-dev \ + # psycopg2 dependencies + libpq-dev \ + # Translations dependencies + gettext \ + postgresql-client \ + python3-pip \ + # For quicker SeafloorMapping file finds + mlocate \ + # Install here rather than from .devcontainer/devcontainer.json + git less wget zsh \ + # cleaning up unused files + && apt-get purge -y --auto-remove -o APT::AutoRemove::RecommendsImportant=false \ + && rm -rf /var/lib/apt/lists/* + +# All absolute dir copies ignore workdir instruction. All relative dir copies are wrt to the workdir instruction +# copy python dependency wheels from python-build-stage +COPY --from=python-build-stage /usr/src/app/wheels /wheels/ +COPY --from=python-build-stage /usr/lib/libgdal* /usr/lib/ +RUN ldconfig + +# use wheels to install python dependencies +RUN pip install --no-cache-dir --no-index --find-links=/wheels/ /wheels/* \ + && rm -rf /wheels/ + +COPY ./compose/production/django/entrypoint /entrypoint +RUN sed -i 's/\r$//g' /entrypoint +RUN chmod +x /entrypoint + +COPY ./compose/debug/django/start /start +RUN sed -i 's/\r$//g' /start +RUN chmod +x /start + + + +# copy application code to WORKDIR +COPY . ${APP_HOME} + +ENTRYPOINT ["/entrypoint"] diff --git a/smdb/compose/debug/django/start b/smdb/compose/debug/django/start new file mode 100644 index 00000000..95bb8713 --- /dev/null +++ b/smdb/compose/debug/django/start @@ -0,0 +1,9 @@ +#!/bin/bash + +set -o errexit +set -o pipefail +set -o nounset + + +python manage.py migrate +python manage.py runserver_plus 0.0.0.0:8001 diff --git a/smdb/compose/production/django/entrypoint b/smdb/compose/production/django/entrypoint index 2c5bec8f..be2ba56a 100644 --- a/smdb/compose/production/django/entrypoint +++ b/smdb/compose/production/django/entrypoint @@ -1,8 +1,8 @@ #!/bin/bash -set -o errexit -set -o pipefail -set -o nounset +##set -o errexit +##set -o pipefail +##set -o nounset diff --git a/smdb/debug.yml b/smdb/debug.yml new file mode 100644 index 00000000..b8554b43 --- /dev/null +++ b/smdb/debug.yml @@ -0,0 +1,81 @@ +version: '3' + +volumes: + local_postgres_data: {} + local_postgres_data_backups: {} + +services: + django: + build: + context: . + dockerfile: ./compose/debug/django/Dockerfile + image: smdb_debug_django + container_name: django + depends_on: + - postgres + - mailhog + volumes: + # Edit to use directory on your host + - /Users/mccann/docker_smdb_vol:/etc/smdb:z + - .:/app:z + env_file: + - ./.envs/.local/.django + - ./.envs/.local/.postgres + ports: + # VS Code debug launch uses 8000, command: /start uses 8001 + - "8000:8000" + - "8001:8001" + - "5678:5678" + command: /start + + postgres: + build: + context: . + dockerfile: ./compose/production/postgres/Dockerfile + image: smdb_production_postgres + container_name: postgres + volumes: + - local_postgres_data:/var/lib/postgresql/data:Z + - local_postgres_data_backups:/backups:z + env_file: + - ./.envs/.local/.postgres + +## docs: +## image: smdb_local_docs +## container_name: docs +## build: +## context: . +## dockerfile: ./compose/local/docs/Dockerfile +## env_file: +## - ./.envs/.local/.django +## volumes: +## - ./docs:/docs:z +## - ./config:/app/config:z +## - ./smdb:/app/smdb:z +## ports: +## - "7000:7000" +## command: /start-docs + + mailhog: + image: mailhog/mailhog:v1.0.0 + container_name: mailhog + ports: + - "8025:8025" + + node: + build: + context: . + dockerfile: ./compose/local/node/Dockerfile + image: smdb_local_node + container_name: node + depends_on: + - django + volumes: + - .:/app:z + # http://jdlm.info/articles/2016/03/06/lessons-building-node-app-docker.html + - /app/node_modules + command: npm run dev + ports: + - "3000:3000" + # Expose browsersync UI: https://www.browsersync.io/docs/options/#option-ui + - "3001:3001" diff --git a/smdb/requirements.txt b/smdb/requirements.txt new file mode 100644 index 00000000..de052006 --- /dev/null +++ b/smdb/requirements.txt @@ -0,0 +1,3 @@ +# To ensure app dependencies are ported from your virtual environment/host machine into your container, run 'pip freeze > requirements.txt' in the terminal to overwrite this file +django==3.1.1 +gunicorn==20.0.4 diff --git a/smdb/scripts/load.py b/smdb/scripts/load.py index 0ca36fb1..186799ea 100755 --- a/smdb/scripts/load.py +++ b/smdb/scripts/load.py @@ -34,8 +34,10 @@ cd SeafloorMappingDB export SMDB_HOME=$(pwd) export COMPOSE_FILE=$SMDB_HOME/smdb/local.yml - docker-compose run --rm -u 399 -v /mbari/SeafloorMapping:/mbari/SeafloorMapping django {__file__} -v - (Replace '399' with your MBARI user id, what `id -u` returns.) + docker-compose run --rm -u $UID -v /Volumes/SeafloorMapping:/mbari/SeafloorMapping django {__file__} -v + -- or, on production -- + export COMPOSE_FILE=$SMDB_HOME/smdb/production.yml + docker-compose run --rm -u $UID -v /mbari/SeafloorMapping:/mbari/SeafloorMapping django {__file__} -v """