[Python] How to run a fully container-based Python dev environment in VSCode

Discussão em 'Python' iniciado por Stack, Abril 8, 2025.

  1. Stack

    Stack Membro Participativo

    TL;DR: Why does this need to be started twice before it works?

    I am trying to set up a Python development environment in my VSCode. The app will run in a container in production, so why hassle with Python versions, virtualenvs and so on on my dev machine, when my editor is able to also use that very same container environment to actually develop the app? So I used some of VSCode's auto-created config files plus crawled a couple of tutorials. It sort of works, but with one major drawback: I need to hit "Start debugging (F5)" twice, before the debugger manages to connect to the container.

    This is only an example project. In my real Python project I can not even get it to connect at all. I assume this setup is not quite optimal yet, so I am herewith asking for help to get this straight. Here is what I have:

    Dockerfile:

    # For more information, please refer to https://aka.ms/vscode-docker-python
    FROM python:3.10-slim

    # Keeps Python from generating .pyc files in the container
    ENV PYTHONDONTWRITEBYTECODE=1

    # Turns off buffering for easier container logging
    ENV PYTHONUNBUFFERED=1

    # Install pip requirements
    COPY requirements.txt .
    RUN python -m pip install --upgrade pip && \
    python -m pip install -r requirements.txt

    WORKDIR /app
    COPY . /app

    # Creates a non-root user with an explicit UID and adds permission to access the /app folder
    # For more info, please refer to https://aka.ms/vscode-docker-python-configure-containers
    RUN adduser -u 5678 --disabled-password --gecos "" appuser && chown -R appuser /app
    USER appuser

    # During debugging, this entry point will be overridden. For more information, please refer to https://aka.ms/vscode-docker-python-debug
    CMD ["python", "-m", "testproj"]

    EXPOSE 80


    docker-compose.debug.yml:

    version: '3.4'

    services:
    testtasks:
    image: testtasks
    build:
    context: .
    dockerfile: ./Dockerfile
    command:
    [
    "sh",
    "-c",
    "pip install debugpy -t /tmp && python /tmp/debugpy --wait-for-client --listen 0.0.0.0:5678 -m uvicorn testproj.testproj:app --host 0.0.0.0 --port 80 --reload"
    ]
    ports:
    - 80:80
    - 5678:5678
    volumes:
    - ${PWD}:/app


    requirements.txt

    fastapi
    uvicorn


    testproj/__main__.py:

    import uvicorn
    uvicorn.run("testproj.testproj:app", host="0.0.0.0", port=80)


    testproj/testproj.py:

    from typing import Union
    from fastapi import FastAPI
    app = FastAPI()

    @app.get("/")
    async def read_root():
    return {"Hello": "World"}


    .vscode/tasks.json:

    {
    "version": "2.0.0",
    "tasks": [
    {
    "type": "docker-build",
    "label": "docker-build",
    "platform": "python",
    "dockerBuild": {
    "tag": "testtasks:latest",
    "dockerfile": "${workspaceFolder}/Dockerfile",
    "context": "${workspaceFolder}",
    "pull": true
    }
    },
    {
    "label": "Run compose up",
    "type": "docker-compose",
    "dockerCompose": {
    "up": {
    "detached": true,
    "build": true
    },
    "files": [
    "${workspaceFolder}/docker-compose.debug.yml"
    ]
    }
    },
    {
    "label": "Run compose down",
    "type": "docker-compose",
    "dockerCompose": {
    "down": {},
    "files": [
    "${workspaceFolder}/docker-compose.debug.yml"
    ]
    }
    }
    ]
    }


    .vscode/launch.json:

    {
    "configurations": [
    {
    "name": "Python: Remote Attach",
    "type": "python",
    "request": "attach",
    "connect": {
    "host": "localhost",
    "port": 5678
    },
    "pathMappings": [
    {
    "localRoot": "${workspaceFolder}",
    "remoteRoot": "/app"
    }
    ],
    "preLaunchTask": "Run compose up",
    "postDebugTask": "Run compose down",
    "justMyCode": true
    }
    ]
    }


    The entire test project is also available here to clone, improve and request merges: https://gitlab.com/mcnesium/testtasks

    And here is a screencast with me trying to run this: https://imgur.com/a2UkRy7 The first hit on the green play button in the top left causes the container to launch, but it fails to connect the debugger to it, as far as I understand this. Then (at about 14sec of the video) with the second hit of the play button it does connect, indicated by the footer bar turning red. The task to stop the entire thing seems to work as expected:

    Thanks in advance for any suggestions. Also, please feel free to improve this question's readability.

    Continue reading...

Compartilhe esta Página