I've just recently begun trying to wrap my head around Docker and have managed to get a development machine up and running. What i'm now trying to do is to be able to use the debugger in Visual Studio Code in my python application (specifically Django).
I've tried following the limited documentation of the python extension for VS Code which explains the parameters for remote debugging.
Dockerfile
FROM python:3.5.2
RUN apt-get update \
--no-install-recommends && rm -rf /var/lib/apt/lists/* \
&& mkdir -p /code \
EXPOSE 8000
WORKDIR /code
COPY requirements.txt /code
RUN /bin/bash --login -c "pip install -r requirements.txt"
ADD . /code
CMD []
docker-compose.yml
version: '2'
services:
db:
image: postgres
web:
build: .
volumes:
- .:/code
ports:
- "8000:8000"
command: bash -c "./wait-for-it.sh db:5432 && python manage.py migrate && python manage.py runserver 0.0.0.0:8000 --noreload"
depends_on:
- db
launch.json
{
"name": "Attach (Remote Debug)",
"type": "python",
"request": "attach",
"localRoot": "${workspaceRoot}",
"remoteRoot": "/code",
"port": 8000,
"secret": "debug_secret",
"host": "localhost"
}
I've also added the line ptvsd.enable_attach("debug_secret", address = ('0.0.0.0', 8000)) to one of the project files
The Issue
When ever I start the debugger nothing happens and it looks like VS Code is waiting for a breakpoint to hit. But it never does.
Any ideas?
EDIT: Minor update
I have tried using different ports for the debugger aswell as exposing the new ports in docker-compose.yml without any success. It looks like the attach is successfull because the debugger doesn't crash but no breakpoint is triggered. I'm really stuck on this one.
Solution
See answer from theBarkman.
I'll add that I was unable to use a secret to get this working. I did the following:
manage.py
import ptvsd
ptvsd.enable_attach(secret=None, address=('0.0.0.0', '3000'))
launch.json
{
"name": "Attach Vagrant",
"type": "python",
"request": "attach",
"localRoot": "${workspaceRoot}",
"remoteRoot": "/code",
"port": 3000,
"secret": "",
"host":"localhost"
}
I've had the most success remote debugging dockerized Django projects by throwing the ptvsd code into my manage.py file and turning off Django's live code reload.
Since Django essentially spins up 2 servers when you runserver (one for that live code reloading, and the other for the actual app server`, ptvsd seems to get really confused which server it should watch. I could sort of get it to work by waiting for attachment, try/excepting the enable_attach method or breaking into the debugger - but breakpoints would never work, and I could only seem to debug a single file at a time.
If you use the django flag --noreload when spinning up the server, you can throw the ptvsd inside the manage.py file without all the waiting / breaking into the debugger nonsense, and enjoy a much more robust debugging experience.
manage.py:
import ptvsd
ptvsd.enable_attach(secret='mah_secret', address=('0.0.0.0', 3000))
run teh server:
python manage.py runserver 0.0.0.0:8000 --noreload
Hope this helps!
I was trying to do something very similar to you and came across this issue/comment:
https://github.com/DonJayamanne/pythonVSCode/issues/252#issuecomment-245566383
In there it describes that in order to use breakpoints you need to use the ptvsd.break_into_debugger() function.
As an example:
import ptvsd
ptvsd.enable_attach(secret='my_secret',address = ('0.0.0.0', 3000))
ptvsd.wait_for_attach()
ptvsd.break_into_debugger()
As soon as I added this in my python script, my breakpoints worked. Hopefully it's of some use.
Edit Jan 24, 2017
In my DockerFile I installed ptvsd:
FROM kaixhin/theano
RUN pip install ptvsd
WORKDIR /src
EXPOSE 3000
ENTRYPOINT ["python","src/app.py"]
COPY . /src
It looks like your installing dependencies via your requirements.txt file, is ptvsd in your requirements.txt?
a couple trouble shooting tips:
1) make sure your debug port is open. run this from your host.
nc -zv test.example.com 30302
2) make sure your webserve does not reload your app automatically. That will break the debugger connection. Put a print or log statement in your code which runs at startup time to make sure your app is not being loaded twice. This is for socketio running on flask. but django and other webservers have something similar.
socketio.run(app, host="0.0.0.0", port=5000, debug=True, use_reloader=False)
Related
So I am a beginner in docker and Django. What I have here is a django app which I am trying to dockerize and run. My requirements.txt has only django and gunicorn as the packages.
I am getting the below in terminal after building and running the docker image:
Watching for file changes with StatReloader
Performing system checks...
System check identified no issues (0 silenced).
August 26, 2021 - 06:57:22
Django version 3.2.6, using settings 'myproject.settings'
Starting development server at http://0.0.0.0:8000/
Quit the server with CONTROL-C.
Below is my Dockerfile:
FROM python:3.6-slim
ENV PYTHONUNBUFFERED=1
RUN mkdir /Django
WORKDIR /Django
ADD . /Django
RUN pip install -r requirements.txt
EXPOSE 8000
CMD python manage.py runserver 0.0.0.0:8000
The commands I am using are:
docker build . -t myproj
docker run -p 8000:8000 myproj
I have tried adding allowedhosts = ['127.0.0.1'] in settings.py but still I am getting "The site can't be reached. 127.0.0.1 refused to connect.
Not able to see the "Congratulations" screen.
Please help me out with this.
P.s: I am using windows machine
Updates
I tried running the below line and got the following output:
docker exec 8e6c4e4a58db curl 127.0.0.1:8000
OCI runtime exec failed: exec failed: container_linux.go:349: starting container process caused "exec: \"curl\": executable file not found in $PATH": unknown
Without your settings.py, this can be hard to figure out. You say you have allowedhosts = ['127.0.0.1'] in there and that should definitely not be necessary. It might actually be what's blocking your host, since requests from your host come from a different IP address.
I've made the following Dockerfile that creates a starter project and runs it
FROM python:latest
RUN python -m pip install Django
RUN django-admin startproject mysite
WORKDIR /mysite
EXPOSE 8000
CMD python manage.py runserver 0.0.0.0:8000
If I build it and run it with
docker build -t mysite .
docker run -d -p 8000:8000 mysite
I can connect to http://localhost:8000/ on my machine and get the default page (I'm on Windows too).
I hope that helps you to locate your issue.
PS: Your curl command fails because curl isn't installed in your image, so it failing has nothing to do with your issue.
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
First time using Docker(version 19.03.5) and trying this tutorial
I'm stuck on step 2.3.4 Running an image
When I go to http://localhost:8888 I see
Internal Server Error
The server encountered an internal error and was unable to complete your request. Either the server is overloaded or there is an error in the application.
I updated Dockerfile to this to match my directory:
# our base image
FROM alpine:3.5
# Install python and pip
RUN apk add --update py2-pip
# install Python modules needed by the Python app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
# copy files required for the app to run
COPY app.py .
COPY templates/index.html templates
# tell the port number the container should expose
EXPOSE 5000
# run the application
CMD ["python", "app.py"]
On my command line I have
C:\Users\user\docker\flask-app>docker run -p 8888:5000 --name flask-app 11111111/flask-app
* Running on http://0.0.0.0:5000/ (Press CTRL+C to quit)
When I visit the page I see on the prompt
172.17.0.1 - - [05/Jan/2020 07:14:34] "GET / HTTP/1.1" 500 -
I have this in my app.py
from flask import Flask, render_template
import random
app = Flask(__name__)
# list of cat images
images = [
"http://img.buzzfeed.com/buzzfeed-static/static/2013-10/enhanced/webdr05/15/9/anigif_enhanced-buzz-26388-1381844103-11.gif",
"http://img.buzzfeed.com/buzzfeed-static/static/2013-10/enhanced/webdr01/15/9/anigif_enhanced-buzz-31540-1381844535-8.gif",
"http://img.buzzfeed.com/buzzfeed-static/static/2013-10/enhanced/webdr05/15/9/anigif_enhanced-buzz-26390-1381844163-18.gif",
"http://img.buzzfeed.com/buzzfeed-static/static/2013-10/enhanced/webdr06/15/10/anigif_enhanced-buzz-1376-1381846217-0.gif",
"http://img.buzzfeed.com/buzzfeed-static/static/2013-10/enhanced/webdr03/15/9/anigif_enhanced-buzz-3391-1381844336-26.gif",
"http://img.buzzfeed.com/buzzfeed-static/static/2013-10/enhanced/webdr06/15/10/anigif_enhanced-buzz-29111-1381845968-0.gif",
"http://img.buzzfeed.com/buzzfeed-static/static/2013-10/enhanced/webdr03/15/9/anigif_enhanced-buzz-3409-1381844582-13.gif",
"http://img.buzzfeed.com/buzzfeed-static/static/2013-10/enhanced/webdr02/15/9/anigif_enhanced-buzz-19667-1381844937-10.gif",
"http://img.buzzfeed.com/buzzfeed-static/static/2013-10/enhanced/webdr05/15/9/anigif_enhanced-buzz-26358-1381845043-13.gif",
"http://img.buzzfeed.com/buzzfeed-static/static/2013-10/enhanced/webdr06/15/9/anigif_enhanced-buzz-18774-1381844645-6.gif",
"http://img.buzzfeed.com/buzzfeed-static/static/2013-10/enhanced/webdr06/15/9/anigif_enhanced-buzz-25158-1381844793-0.gif",
"http://img.buzzfeed.com/buzzfeed-static/static/2013-10/enhanced/webdr03/15/10/anigif_enhanced-buzz-11980-1381846269-1.gif"
]
#app.route('/')
def index():
url = random.choice(images)
return render_template('index.html', url=url)
if __name__ == "__main__":
app.run(host="0.0.0.0")
I can't figure out why my page isnt loading. Any help would be appreciated.
Note: I have WAMP installed and this might be conflicting but not sure if thats the case and/or how to fix it.
Flask might be unable to locate your templates. Try changing
COPY templates/index.html templates
to
COPY templates templates
to copy everything inside ./templates to <WORKDIR>/templates.
Using COPY templates/index.html templates will copy index.html as a file at path <WORKDIR>/templates, not copy it under that directory.
How to debug your Flask application in Docker:
Turn on Flask debugger by adding ENV FLASK_DEBUG=1 to your Dockerfile
Try to run the Flask app outside of Docker. It may be easier to set breakpoints inside your IDE (VSCode or PyCharm) and debug the app.
Try pdb to debug the app inside the container. It may be hard for a beginner, but in general, it's an essential skill. Check Debugging a Python Flask Application in a Docker Container for a step-by-step guide.
Note: This is more aimed at the question "How do I debug". It was unclear that the OP actually wanted a solution, not a way to solve the problem.
First thing to do is to start the container without the app in it. For that, you replace the CMD ["python", "app.py"] with CMD ["sleep", "inf"]. Now, after starting the container, you can get a shell in the container using docker exec -it flask-app /bin/bash to get a shell. In the shell, you can then use the regular Python debugger to set a breakpoint in the / handler and then single-step through the code to track down what Python's doing.
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
I have a docker image that was build. I want to run it on localhost and see the project on my local machine. When i run the image, i see it in the docker ps. when i go to localhost, I get nothing. I am not sure if it is the port that i am trying to run or permissions, or something like that...
here is the command i am running:
λ docker run -p 5050:80 opentab
here is after the image was built:
Successfully built 7e995fbdf2ea
Successfully tagged opentab:latest
SECURITY WARNING: You are building a Docker image from Windows against a non-Windows Docker host. All files and directories added to build context will have '-rwxr-xr-x' permissions. It is recommended to double check and reset permissions for sensitive files and directories.
here is the docker file:
FROM python:3
WORKDIR /usr/src/app
COPY requirements.txt ./
EXPOSE 80
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
CMD ["python", "manage.py", "runserver"]
I had to remove the following from the requirements file because they were causing errors:
python
sqlite
tk
zx
Two things:
1) manage.py runserver will bind to localhost only by default. This localhost is INSIDE the container, not on your computer. As such, you want to bind the application to all interfaces like this:
python manage.py runserver 0.0.0.0
2) manage.py runserver will bind to port 8000 by default. So, two options. One, you can make manage.py runserver bind to port 80, like so:
python manage.py runserver 0.0.0.0.0:80
Or, you would change your dockerfile, replacing EXPOSE 80 with EXPOSE 8000, and change your docker command to docker run -p 5050:8000 opentab