I am trying to access a Jupyter Notebook created with the shell_plus command from django-extensions in a Docker container.
docker-compose -f local.yml run --rm django python manage.py shell_plus --notebook
My configuration is based on the answers of #RobM and #Mark Chackerian to this Stack Overflow question. I.e. I installed and configured a custom kernel and my Django apps config file has the constant NOTEBOOK_ARGUMENTS set to:
NOTEBOOK_ARGUMENTS = [
'--ip', '0.0.0.0',
'--port', '8888',
'--allow-root',
'--no-browser',
]
I can see the container starting successfully in the logs:
[I 12:58:54.877 NotebookApp] The Jupyter Notebook is running at:
[I 12:58:54.877 NotebookApp] http://10d56bab37fc:8888/?token=b2678617ff4dcac7245d236b6302e57ba83a71cb6ea558c6
[I 12:58:54.877 NotebookApp] or http://127.0.0.1:8888/?token=b2678617ff4dcac7245d236b6302e57ba83a71cb6ea558c6
But I can't open the url. I have forwarded the port 8888 in my docker-compose, tried to use localhost instead of 127.0.0.1 and also tried to use the containers IP w/o success.
It feels like I am missing the obvious here … Any help is appreciated.
For the sake of records as of 2020, I managed to have a working django setup with Postgresql in docker-compose:
development.py (settings.py)
INSTALLED_APPS += [
"django_extensions",
]
SHELL_PLUS = "ipython"
SHELL_PLUS_PRINT_SQL = True
NOTEBOOK_ARGUMENTS = [
"--ip",
"0.0.0.0",
"--port",
"8888",
"--allow-root",
"--no-browser",
]
IPYTHON_ARGUMENTS = [
"--ext",
"django_extensions.management.notebook_extension",
"--debug",
]
IPYTHON_KERNEL_DISPLAY_NAME = "Django Shell-Plus"
SHELL_PLUS_POST_IMPORTS = [ # extra things to import in notebook
("module1.submodule", ("func1", "func2", "class1", "etc")),
("module2.submodule", ("func1", "func2", "class1", "etc"))
]
os.environ["DJANGO_ALLOW_ASYNC_UNSAFE"] = "true" # only use in development
requirements.txt
django-extensions
jupyter
notebook
Werkzeug # needed for runserver_plus
...
docker-compose.yml
version: "3"
services:
db:
image: postgres:13
environment:
- POSTGRES_HOST_AUTH_METHOD=trust
restart: always
ports:
- "5432:5432"
volumes:
- postgres_data:/var/lib/postgresql/data/
web:
build: .
environment:
- DJANGO_SETTINGS_MODULE=settings.development
command:
- scripts/startup.sh
volumes:
- ...
ports:
- "8000:8000" # webserver
- "8888:8888" # ipython notebook
depends_on:
- db
volumes:
postgres_data:
From your host terminal run this command:
docker-compose exec web python manage.py shell_plus --notebook
Finally navigate to http://localhost:8888/?token=<xxxx> in the web browser of host.
Got it to work, but why it does so is beyond me. Exposing the ports in the docker-compose run command did the trick.
docker-compose -f local.yml run --rm -p 8888:8888 django python manage.py shell_plus --notebook
I was under the impression exposing ports in my local.yml would open them also in containers started by run.
The compose run command will per default not expose the defined service ports. From the documentation at https://docs.docker.com/compose/reference/run/
The [...] difference is that the docker-compose run command does not
create any of the ports specified in the service configuration. This
prevents port collisions with already-open ports. If you do want the
service’s ports to be created and mapped to the host, specify the
--service-ports flag:
docker-compose run --service-ports web python manage.py shell
You will therefore need to run
docker-compose -f local.yml run --rm --service-ports django python manage.py shell_plus --notebook
It might also be that the default 8888 port is already used by a local jupyter server (e.g. one spun up by VS Code's jupyter notebook implementation. I therefore usually map to a different port in the settings.py NOTEBOOK_ARGUMENTS list. (In this case the port mapping in the compose file needs to be adjusted as well, of course, and there must not be another container running in the background with the same service definition as this might also occupy the port.)
If you want to use jupyter notebook like separated service:
jupyter_notebook:
build:
context: .
dockerfile: docker/dev/web/Dockerfile
command: python manage.py shell_plus --notebook
depends_on:
- web
ports:
- 8888:8888 # ipython notebook
env_file:
- .env
after:
docker-compose logs -f 'jupyter_notebook'
and you will get access token in logs
Related
Few days ago I asked a question about a Postgres error.
I followed your suggestions and they helped a bit but in addition to not solving my problem some new problems arose.
I have a django-postgres app which works locally with no problems. When I try to build a docker image it builds but when I try to set up the container I have the following error:
django.db.utils.OperationalError: could not translate host name "db" to address: Name or service not known
I'll show you my Dockerfile:
# Origin image
FROM python:3.8
RUN apt-get update
# Define directory
RUN mkdir /project
WORKDIR /project
# Install requirements
RUN apt-get install -y vim
RUN python -m pip install --upgrade pip
COPY requirements.txt /project/
RUN pip install -r requirements.txt
COPY . /project/
# Expose some ports
EXPOSE 22 5432 8080 8009 8000
# default command
CMD ["python", "manage.py", "runserver", "0.0.0.0:8000"]
And here is my docker-compose file:
version: "3.3"
services:
db:
image: postgres
volumes:
- ./data/db:/var/lib/postgresql/data
ports:
- "5432:5432"
environment:
- POSTGRES_NAME=plataforma
- POSTGRES_USER=admin
- POSTGRES_PASSWORD=administrador
web:
build: .
command: python manage.py runserver 0.0.0.0:8000
volumes:
- .:/code
ports:
- "8000:8000"
environment:
- POSTGRES_NAME=plataforma
- POSTGRES_USER=admin
- POSTGRES_PASSWORD=administrador
depends_on:
- db
env_file:
- ./plataforma/.env
On settings.py I configure the database on this way:
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.postgresql',
'NAME': env('POSTGRESQL_NAME'),
'USER': env('POSTGRESQL_USER'),
'PASSWORD': env('POSTGRESQL_PASS'),
'HOST': env('POSTGRESQL_HOST'),
'PORT': env('POSTGRESQL_PORT'),
}
}
And this is my .env file:
POSTGRESQL_NAME=plataforma
POSTGRESQL_USER=admin
POSTGRESQL_PASS=administrador
POSTGRESQL_HOST=db
POSTGRESQL_PORT=5432
When I run my app locally I use localhost instead db for POSTGRESQL_HOST.
Now, when I run $ sudo docker-compose run web python manage.py runserver . the image builds and the database container is running, but the app container is stopped. If I run $ docker start container-name it doesn't start.
If I run $ docker run -d --restart always --name new-container-name image-name a new container starts correctly and if I get inside it and try to make django migrations, i have the same error:
/usr/local/lib/python3.8/site-packages/django/core/management/commands/makemigrations.py:105: RuntimeWarning: Got an error checking a consistent migration history performed for database connection 'default': could not translate host name "db" to address: Name or service not known
Maybe I am using the docker-compose file in a wrong way. I've tried to install postgres from Dockerfile direct but there I have the error from my last question:
django.db.utils.OperationalError: could not connect to server: Connection refused
Is the server running on host "localhost" (127.0.0.1) and accepting
TCP/IP connections on port 5432?
could not connect to server: Cannot assign requested address
Is the server running on host "localhost" (::1) and accepting
TCP/IP connections on port 5432?
Also I tried this solution and this solution but they didn't work either.
So, I am literally lost. I also have read this docker Quickstart but I don't figure out of what I'm doing wrong.
Can anyone help me?
Sorry if I'm misunderstanding some stackoverflow rules, but I'm still figuring out how it works.
Thankyou!
EDIT: Thanks to #DavidMaze 's help we found out what the problem was!
David said:
The postgres image accepts an environment variable POSTGRES_DB to set the initial database name, not POSTGRES_NAME; does changing this (and deleting the ./data/db host directory) help?
So I Changed POSTGRES_NAME variable to POSTGRES_DB and erased /data folder (and purged images and containers list) and ran docker-compose up
At the beginning when I run that command for the first time it seems like it try to setup first the web container and fails (with OperationalError), but when I run the same command again it works without errors.
Thank you so much for the help!
I'm trying to set up a dockerized Python server named Bullet Train on my local machine:
It has 3 components:
A Postgres database
A Python server
A React frontend
All of these 3 need to work together to get the server up and running, so this is the docker-compose file which sits at the top level of both the frontend and api-server:
version: '3'
services:
db:
image: postgres
environment:
POSTGRES_PASSWORD: password
POSTGRES_DB: bullettrain
ports:
- "5432:5432"
api:
build:
context: ./bullet-train-api
dockerfile: docker/Dockerfile
command: bash -c "pipenv run python manage.py migrate --noinput
&& pipenv run python manage.py collectstatic --noinput
&& pipenv run gunicorn --bind 0.0.0.0:8000 -w 3 app.wsgi
&& pipenv run python src/manage.py createsuperuser"
environment:
DJANGO_DB_NAME: bullettrain
DJANGO_DB_USER: postgres
DJANGO_DB_PASSWORD: password
DJANGO_DB_PORT: 5432
DJANGO_ALLOWED_HOSTS: localhost
ports:
- "8000:8000"
depends_on:
- db
links:
- db:db
frontend:
build:
context: ./bullet-train-frontend
dockerfile: Dockerfile
ports:
- "8080:8080"
This way, all the 3 components run in parallel. So far so good! Now to initialize it, I run the createsuperuser as stated here by following these steps:
docker exec -it research_api_1 bash ## go to the context of the API server terminal
run python manage.py createsuperuser ## run the createsuperuser command
The command runs successfully and I get this output:
To confirm, I went to the database:
docker exec -it research_db_1 bash ## go to the database instance
psql bullettrain postgres ## connect to the bullettrain database
select * from public.users_ffadminuser; ## check if the super user is created
The results show that the user is indeed created:
Now, if I go to the admin panel as per the docs, nothing happens and the server logs always throw Session data corrupted:
I have been working with Docker previously using services to run a website made with Django.
Now I would like to know how I should create a Docker to just run Python scripts without a web server and any service related with websited.
An example of normal docker which I am used to work is:
version: '2'
services:
nginx:
image: nginx:latest
container_name: nz01
ports:
- "8001:8000"
volumes:
- ./src:/src
- ./config/nginx:/etc/nginx/conf.d
depends_on:
- web
web:
build: .
container_name: dz01
depends_on:
- db
volumes:
- ./src:/src
expose:
- "8000"
db:
image: postgres:latest
container_name: pz01
ports:
- "5433:5432"
volumes:
- postgres_database:/var/lib/postgresql/data:Z
volumes:
postgres_database:
external: true
How should be the docker-compose.yml file?
Simply remove everything from your Dockerfile that has nothing to do with your script and start with something simple, like
FROM python:3
ADD my_script.py /
CMD [ "python", "./my_script.py" ]
You do not need Docker compose for containerizing a single python script.
The example is taken from this simple tutorial about containerizing Python applications: https://runnable.com/docker/python/dockerize-your-python-application
You can easily overwrite the command specified in the Dockerfile (via CMD) when starting a container from the image. Just append the desired command to your docker run command, e.g:
docker run IMAGE /path/to/script.py
You can easily run Python interactively without even having to build a container:
docker run -it python
If you want to have access to some code you have written within the container, simply change that to:
docker run -it -v /path/to/code:/app: python
Making a Dockerfile is unnecessary for this simple application.
Most Linux distributions come with Python preinstalled. Using Docker here adds significant complexity and I'd pretty strongly advise against Docker just to run a simple script. You can use a virtual environment to isolate a particular Python package's dependencies from the rest of the system.
(There is a pretty consistent stream of SO questions around getting filesystem permissions and user IDs right for scripts that principally want to interact with the host system. Also remember that running docker anything implies root-equivalent permissions. If you don't want Docker's filesystem and user namespace isolation, IMHO it's easier to just not use Docker where it doesn't make sense.)
I am working on a localhost django webserver http://localhost:8000, which works fine.
Meanwhile i need ngrok to do the port forwarding, ngrok http 8000, which works fine too.
Then I want to put ngrok, postgres, redis, maildev, etc all in docker containers, all others works fine, except ngrok.
ngrok failed to contain to localhost:8000.
I understand why, i suppose because ngrok is running on a seperate 'server 'and the localhost on that server does not have web server running.
I am wondering how i can fix it.
I tried in my docker-compose file with
network_mode: "host", it is not working (MacOS).
I tried to use host.docker.internal, but as I am a free plan user, ngrok does not allow me to specify a hostname.
any help is appreciated! Thanks.
here is my docker-compose file:
ngrok:
image: wernight/ngrok
ports:
- '4040:4040'
environment:
- NGROK_PORT=8000
- NGROK_AUTH=${NGROK_AUTH_TOKEN}
network_mode: "host"
UPDATE:
stripe has a new tool [stripe-cli][1], which can do the same thing.
just do as below
stripe-cli:
image: stripe/stripe-cli
command: listen --api-key $STRIPE_SECRET_KEY
--load-from-webhooks-api
--forward-to host.docker.internal:8000/api/webhook/
I ended up getting rid of ngrok, using serveo instead to solve the problem,
here is the code, in case anyone run into the same problem
serveo:
image: taichunmin/serveo
tty: true
stdin_open: true
command: "ssh -o ServerAliveInterval=60 -R 80:host.docker.internal:8000 -o \"StrictHostKeyChecking no\" serveo.net"
I was able to get it to work by doing the following:
Instruct Django to bind to port 8000 with the following command: python manage.py runserver 0.0.0.0:8000
Instruct ngrok to connect to the web docker service in my docker compose file by passing in web:8000 as the NGROK_PORT environment variable.
I've pasted truncated versions of my settings below.
docker-compose.yml:
version: '3.7'
services:
ngrok:
image: wernight/ngrok
depends_on:
- web
env_file:
- ./ngrok/.env
ports:
- 4040:4040
web:
build:
context: ./app
dockerfile: Dockerfile.dev
command: python manage.py runserver 0.0.0.0:8000
env_file:
- ./app/django-project/settings/.env
ports:
- 8000:8000
volumes:
- ./app/:/app/
And here is the env file referenced above (i.e. ./ngrok/.env):
NGROK_AUTH=your-auth-token-here
NGROK_DEBUG=1
NGROK_PORT=web:8000
NGROK_SUBDOMAIN=(optional)-your-subdomain-here
You can leave out the subdomain and auth fields. I figured this out by looking through their docker entrypoint
Edit
Adding --ipv6 to the command, while not properly configured for, seem to surpass the point where the process hangs.
Problem
Calling docker-compose up executes runserver but hangs at some point after printing the current time.
Calling docker-compose run -p 8000:8000 web python manage.py runserver 0.0.0.0:8000 also execute the server, but does so succesfully and can be reached at 192.168.99.100:8000.
Questions
How come I can run the server directly from docker-compose in my shell but not from the .yml file?
To me, the content of the .yml file and the docker-compose run line from the shell are strikingly similar.
The only difference I can think of would perhaps be permissions at some level required to properly start a django server, but I don't know how to address that. Docker runs on a windows 8.1 machine. The shared folder for my virtual machine is the default c:\Users.
Files
My folder contain a fresh django project as well as these docker files. I've tampered with different versions of python and django but the result is the same. I've cleaned up my images and containers between attempts using
docker rm $(docker ps -a -q)
docker rmi $(docker images -q)
docker-compose.yml
version: '3'
services:
web:
build: .
command: python manage.py runserver 0.0.0.0:8000
volumes:
- .:/code
ports:
- "8000:8000"
Dockerfile
FROM python:3.6-alpine
ENV PYTHONUNBUFFERED 1
RUN mkdir /code
WORKDIR /code
ADD requirements.txt /code/
RUN pip install -r requirements.txt
ADD . /code/
requirements.txt
Django>=1.8,<2.0
System
My operative system is windows 8.1
I was hit by this issue myself and it seems that you need to allocate a tty and a stdin to your container in order to make runserver work:
python:
image: my-image:latest
stdin_open: true # docker run -i
tty: true # docker run -t
build:
context: ..
dockerfile: docker/Dockerfile
I had the same issue and could not get it to do anything else. However when i went to the ip of the docker machine docker-machine ip it returned 192.168.99.100, then by going to 192.168.99.100:8000 my docker container started receiving the requests