microsoft / DockerTools

Tools For Docker, including Visual Studio Provisioning and Publishing
Other
175 stars 26 forks source link

Custom ENTRYPOINT ignored by VS2017 when using docker-compose #9

Open oleksii-udovychenko opened 7 years ago

oleksii-udovychenko commented 7 years ago

Introduction

I've tried to launch supervisord in a container to run both webpack-dev-server and .NET Core Web App at the same time (for development purposes).

I've created the following Dockerfile:

FROM microsoft/aspnetcore:1.1

(... omitted for brevity ...)

ENTRYPOINT ["supervisord"]

and the following supervisord.conf file:

[supervisord]
nodaemon=true

(... omitted for brevity ...)

[program:frontend]
command=/bin/bash -c "cd wwwroot && npm start"

[program:backend]
command=/bin/bash -c "dotnet App.dll"

When I hit F5, I see that supervisor doesn't start, so frontend and backend apps shouldn't start. The weird thing is that my App.dll starts successfuly. When I started supervisor manually from the container itself, I noticed that backend (which is my App.dll) can't be started (because it is already running), but frontend works fine:

image

After few more tries I realized that VS2017 starts my app behind the scenes and ignores my ENTRYPOINT because docker-compose.vs.debug.yml overrides the ENTRYPOINT with the following command:

entrypoint: tail -f /dev/null

Changing entrypoint in docker-compose.vs.debug.yml doesn't help, it seems that tail -f /dev/null command is required.

Problem

The problem is that I can't find where and how my app starts. Also, it would be great to know a way to change default VS2017 behavior, so I can stop VS2017 from launching my app and launch supervisord instead.

Maybe I am missing something?

I was able to isolate and reproduce this issue(?).

Steps to reproduce

  1. Create a new solution using standard "Console App (.NET Core)" template
  2. Right-click on a new console app and select "Add => Docker Support"
  3. Open Dockerfile and change ENTRYPOINT to something that should cause an error.
FROM microsoft/dotnet:1.1-runtime
ARG source
WORKDIR /app
COPY ${source:-obj/Docker/publish} .
ENTRYPOINT ["DOESNOTEXIST"]
  1. Hit F5

EXPECTED RESULT: Console app doesn't start.

ACTUAL RESULT: image

dazhao-msft commented 7 years ago

The challenge is that we'd need to teach VS debugger to launch the app in the way defined above and then it'd need to figure out which processes to attach. This is something we don't support today.

oleksii-udovychenko commented 7 years ago

This is something we don't support today.

Will support this in future? I am working on a large enterprise project that consists of front-end (express + react) and back-end (asp.net webapi services + lots of cloud services). I am trying to migrate it to the docker containers on linux and it is imposible with the current state of tooling.

Are there any way to teach visual studio debugger attach window to connect to docker images and allow developers manually choose processes that they want to debug? As far as I see there is no way of doing this. I also tried to connect to docker containers using SSH but it didn't work for me (maybe I am missing something).

pbering commented 7 years ago

I have the same issue when I set the entrypoint in the compose file, it is always overridden by the entrypoint in docker-compose.vs.debug.g.yml. Is there a way to tell the tooling not to override this or some way defining which compose files that the tooling uses when building / starting? Right now I can't use the tooling since I need the ability to set the entrypoint during development.

dweggemans commented 7 years ago

Is there any workaround available? I have a case where I have to run some 3rd party software in the project container. I am able to download and install it in the docker file, but I am unable to run its services on container startup in any way. It just executes my project and ignores whatever I've configured as CMD or ENTRYPOINT.

MikhailTymchukDX commented 6 years ago

Same problem. I have simple .NET Core console app which expects some args. But this .yml files just overrides entrypoint and it seems specifying command does not work too (@dazhao-msft correct me if I wrong).

I found kind of workaround here: https://stackoverflow.com/a/40730210/644496 In short, we have to set environment variables in docker compose and read it at the start:

docker-compose.yml

version: '3'

services:
  app:
    environment:
      arg1: 'value1'
      arg2: 123

Program code:

class Program
{
    static void Main(string[] args)
    {
        var arg1 = Environment.GetEnvironmentVariables()["org"].ToString();
        var arg2 = Convert.ToInt32(Environment.GetEnvironmentVariables()["arg3"]);
    }
}}
JoostvdB94 commented 6 years ago

@oleksii-udovychenko Did you find a working workaround? I'm using a custom entrypoint.sh to do some adjustments in the hosts file of my docker container (at runtime), so i need this entrypoint too.

oleksii-udovychenko commented 6 years ago

@JoostvdB94 I don't use visual studio for building and running containerised projects. I just run them through docker-compose from the console and then attach debugger to one of the containers.

brad-jones commented 6 years ago

@oleksii-udovychenko do you have any pointers for attaching the debugger with Visual Studio? It's easy as with Visual Studio Code, eg:

"pipeTransport":
{
    "pipeProgram": "docker",
    "pipeCwd": "${workspaceRoot}",
    "pipeArgs": ["exec", "-i", "foo"],
    "debuggerPath": "/opt/vsdbg/vsdbg",
    "quoteArgs": false
}

Just trying to figure out how to do it with Visual Studio for my Windows buddies (I'm predominantly a Linux dev).

dbreshears commented 6 years ago

@brad-jones , you should be able to create a file named "docker-compose.vs.debug.yml and add this to the docker-compose project, overriding the entrypoint as necessary.. You can start by grabbing the \obj\Docker\docker-compose.vs.debug.g.yml and renaming it to remove the ".g" file. If this is found in the project we will pass along to docker-compose after the other arguments.

labarilem commented 6 years ago

@dbreshears , I have added a docker-compose.vs.debug.yml file in my docker-compose project:

<ItemGroup>
    <None Include="docker-compose.override.yml">
      <DependentUpon>docker-compose.yml</DependentUpon>
    </None>
    <None Include="docker-compose.vs.debug.yml">
      <DependentUpon>docker-compose.yml</DependentUpon>
    </None>
    <None Include="docker-compose.yml" />
    <None Include=".dockerignore" />
  </ItemGroup>

Its content is based on the \obj\Docker\docker-compose.vs.debug.g.yml file you mentioned. The only difference is the entrypoint property, which I have edited manually.

Still, the issue persists: when debugging with Docker, VS uses the \obj\Docker\docker-compose.vs.debug.g.yml file which is the same as before (i.e. does not take into account the entrypoint property that I manually edited).

Am I doing something wrong?

dbreshears commented 6 years ago

That certainly looks correct. Can you ensure your startup project is the docker-compose project. In 15.8 we added a single project docker experience, when I unloaded and reloaded docker-compose project when testing this just now, it gets reset to my WebApplication and therefore just does docker run in stead of compose. Also, are you on "Debug" solution config in VS when you F5? Can you share your build output. You should see something like this where the last "-f" argument to compose is docker-compose.vs.debug.yml

2>docker-compose -f "C:\Users\devinb\source\repos\WebApplication3\docker-compose.yml" -f "C:\Users\devinb\source\repos\WebApplication3\docker-compose.override.yml" -f "C:\Users\devinb\source\repos\WebApplication3\obj\Docker\docker-compose.vs.debug.g.yml" -f "C:\Users\devinb\source\repos\WebApplication3\docker-compose.vs.debug.yml" -p dockercompose14141838616008167745 --no-ansi config

watsonsong commented 5 years ago

I met the similar error, I use the visual studio docker tools, can add some argument to the ENTRYPOINT like this: ENTRYPOINT ["dotnet", "MyApp.dll", "-e", "CONFIG_"]

But when I start to debug, the arguments I add is missing

watsonsong commented 5 years ago

So the entrypoint is replaced by the docker-compose.vs.debug.g.yml to tail -f /dev/null, it means when I launch by docker-compose in visual studio, it actually not run on docker at all?

bwateratmsft commented 5 years ago

@watsonsong When we launch the container in VS, we use that "tail -f /dev/null" command as a way to keep the container alive indefinitely. The app really is running in the container, but it is done via a "docker exec" call rather than the entrypoint. In the case of F5 (debug), we docker exec VSDBG and instruct it to run the app; in the case of Ctrl+F5 (launch w/o debug), we docker exec the app directly.

watsonsong commented 5 years ago

@bwateratmsft So is there a way I can modity the docker-compose.vs.debug.yml and edit the command line argument for my app?

bwateratmsft commented 5 years ago

@haniamr Do you know of a way to do that?

lesscodetxm commented 5 years ago

I have the same issue. I'm trying to run a script for my entry point that does a kinit for a Kerberos ticket before doing the dotnet command. This works fine if I docker run the image manually without overriding the entry point, but works not at all with the command that VS wants to run. With VS the app runs but the kinit does not, so whatever tail -f /dev/null magic is happening, it must be running the app directly and not the as-configured entry point in the Dockerfile.

lesscodetxm commented 5 years ago

@oleksii-udovychenko How do you "attach debugger to one of the containers"?

mikesigs commented 5 years ago

So I managed to get this working. It's kind of annoying having to manage yet another docker override file just for VS, but it's at least a solution. The reason this is required is because VS starts your containers at the moment you open the solution (and cleans them up when you close). It isn't until you run or debug the solution that VS will try to start your app in the container using docker exec. It uses the settings configured in the following labels of the docker-compose.vs.{env}.g.yml file in order to start your app:

      com.microsoft.visualstudio.debuggee.program
      com.microsoft.visualstudio.debuggee.arguments
      com.microsoft.visualstudio.debuggee.workingdirectory
      com.microsoft.visualstudio.debuggee.killprogram

You simply need to set these labels to the proper values to tell the debugger how to start your app in the container. To do this, you need to create a new file next to your docker-compose.yml called docker-compose.vs.debug.yml with the following contents:

Here's an example:

version: '3.4'

services:
  my-service:
    labels:
      com.microsoft.visualstudio.debuggee.program: "/bin/sh"
      com.microsoft.visualstudio.debuggee.arguments: "-c your_command --with-args"
      com.microsoft.visualstudio.debuggee.workingdirectory: "/app"
      com.microsoft.visualstudio.debuggee.killprogram: "/bin/sh -c \"if PID=$$(pidof your_command); then kill $$PID; fi\""

Note that you cannot use environment variables in the above labels. They for whatever reason always resolve to empty.

Also, the easiest way to create the docker-compose.vs.debug.yml file is to copy the existing docker-compose.vs.debug.g.yml file (from /obj/Docker) and rename it to remove the .g.

Hope that helps, and is clear enough to get some people unstuck.

Wycza commented 4 years ago

@mikesigs

Thanks for your post. Recently in my free time I started to learn docker and one of tutorials I did was https://docs.microsoft.com/en-us/visualstudio/containers/tutorial-multicontainer?view=vs-2019. After I complete tutorial I wanted to add docker watch but I didn't know how to force VS to respect my ENTRYPOINT from Dockerfile.

I finally managed to combine dotnet watch + VS debugger + docker-compose. As mentioned earlier, docker-compose.vs.debug.yml must be override and placed in the same folder where docker-compose.yml is located.

version: '3.4'

services:
  dockertest-webapi:
    labels:
      com.microsoft.visualstudio.debuggee.program: "dotnet"
      com.microsoft.visualstudio.debuggee.arguments: "--additionalProbingPath /root/.nuget/packages --additionalProbingPath /root/.nuget/fallbackpackages \"/app/bin/local/Debug/netcoreapp3.1/DockerTest-WebApi.dll\" & dotnet watch -p /code/app/api/DockerTest-WebApi run --urls=\"http://+:80;https://+:443\""
      com.microsoft.visualstudio.debuggee.workingdirectory: "/code/app/api/DockerTest-WebApi"
      com.microsoft.visualstudio.debuggee.killprogram: "/bin/sh -c \"if PID=$$(pidof your_command); then kill $$PID; fi\""

  dockertest-webfrontend:
    labels:
      com.microsoft.visualstudio.debuggee.program: "dotnet"
      com.microsoft.visualstudio.debuggee.arguments: " --additionalProbingPath /root/.nuget/packages --additionalProbingPath /root/.nuget/fallbackpackages \"/app/bin/local/Debug/netcoreapp3.1/DockerTest-WebFrontend.dll\" & dotnet watch -p /code/app/web/DockerTest-WebFrontend run --urls=\"http://+:80;https://+:443\""
      com.microsoft.visualstudio.debuggee.workingdirectory: "/code/app/web/DockerTest-WebFrontend"
      com.microsoft.visualstudio.debuggee.killprogram: "/bin/sh -c \"if PID=$$(pidof your_command); then kill $$PID; fi\""

More information about docker-compose.vs.debug.yml can be found here: https://docs.microsoft.com/en-us/visualstudio/containers/docker-compose-properties?view=vs-2019

ckteebe commented 3 years ago

Hello,

I'm happy to find this issue, so I know I'm not alone, but obviously in a very exclusive club. ;)

I use Docker and docker-compose to start several API projects in one Visual Studio solution.

Since the Docker parameter depends_on does not wait for those other containers/services to start healthy it is hard to control the order of container execution.

I could override the entrypoint of one container with a script to check the existence/running of his dependencies. Docker officially recommends using this bash script "https://github.com/vishnubob/wait-for-it"

Problem (1): It is a bash script, how could I use it in a windows container based on mcr.microsoft.com/dotnet/core/aspnet:3.1 ... So I wrote an old-school batch file to curl/ping the url of the dependent service.

Problem (2): this issue, open since 2017 (!)

My question: What is the best way in Visual Studio (Debug Mode with docker-compose) to ensure a dependent container is running before starting the actual container ?

... and is there any progress on this issue, since I cannot believe I am the only one who wants control over the entrypoint in a more easy way.

Thanks, Sascha

peterbozso commented 3 years ago

Commenting just to raise more awareness to this. I have the same issue.

In my case, I am trying to run two Linux-based containers with Compose: an ASP.NET Core app and a MySQL database that the app depends on. The former needs to wait for the latter to start up.

ravipal commented 3 years ago

To the question on starting dependent containers, we added a new feature (https://devblogs.microsoft.com/visualstudio/visual-studio-2019-v16-10-preview-2/#run-launch-services-defined-in-your-compose-files) which allows creating a profile to start specific set of services in a compose project. Using this feature, a profile can be created to start just the dependent services and another profile that starts the main development services. Ctrl+F5 on depended service profile will start the dependent service and then use the other profile for debugging the main services.

ioerrors commented 1 year ago

I'm pretty new at this, so I hope you'll forgive if I have some misunderstandings. But after a few hours working on why my docker setup in Visual Studio was behaving differently than my commandline docker setup, I have a few thoughts, from a newbie's perspective:

Violation of Docker Intuition: As a docker newbie, I expect a container that is in a running state to be running my application logic, 1 running container == 1 running process, which I think is a docker principle. Instead sometimes container is just waiting for the debugger to start(especially if I stopped debugging recently).

If I am not debugging actively, but the container is online--I expect my integration tests/api calls from other projects to interact with the application process inside the running container--but because I'm not debugging--the application isn't running, causing misleading test failures until I realize container running != process running.

Inconsistency with Production: The debugging approach introduces deviations from the production runtime behavior. This divergence can result in "it works on my machine" scenarios, contrary to one of Docker's key benefits: consistency across environments.

Lack of Transparency(aka maybe I'm just ignorant): The automated adjustments, such as overriding the entrypoint, lack transparency in my view. Developers familiar with Docker's paradigms expect certain behaviors that Visual Studio's tooling unexpectedly modifies. I eventually found out what was going wrong in my setup from this page: https://learn.microsoft.com/en-us/visualstudio/containers/container-build?view=vs-2022#container-entry-point The entry point is tail -f /dev/null, which is an infinite wait to keep the container running. When the app is launched through the debugger, it is the debugger that is responsible to run the app (that is, dotnet webapp.dll). If launched without debugging, the tooling runs a docker exec -i {containerId} dotnet webapp.dll to run the app.

And this ticket. But nothing in Visual Studio warned me about what I see as unusual(for docker) behavior.

In essence, while Visual Studio aims to provide a seamless debugging experience, it compromises the foundational principles of containerization. A debugging toolset that both respects Docker's best practices and offers a smooth developer experience would be much appreciated. I understand this is probably more complicated than I think it is, but just wanted to add my story to this issue, in case it moves the needle priority-wise for anyone.