Skip to content

add detach plugin#320

Merged
tfoote merged 5 commits intoosrf:mainfrom
YuqiHuai:features/detach-plugin
Feb 19, 2025
Merged

add detach plugin#320
tfoote merged 5 commits intoosrf:mainfrom
YuqiHuai:features/detach-plugin

Conversation

@YuqiHuai
Copy link
Contributor

@YuqiHuai YuqiHuai commented Feb 14, 2025

When rocker launches a docker container, there was no option to run it in detached mode. I added a plugin and a test case for this plugin that allows rocker to run container in detached mode.

All test cases in test_extension.py passes.

❯ python3 -m pytest test/test_extension.py
============================================= test session starts ==============================================
platform linux -- Python 3.13.1, pytest-8.3.4, pluggy-1.5.0
rootdir: /home/yuqi/ResearchWorkspace/rocker
configfile: setup.cfg
plugins: ament-flake8-0.12.11, ament-copyright-0.12.11, launch-testing-ros-0.19.7, ament-pep257-0.12.11, ament-lint-0.12.11, ament-xmllint-0.12.11, launch-testing-1.0.6, cov-6.0.0
collected 19 items                                                                                             

test/test_extension.py ...................                                                               [100%]

============================================= 19 passed in 23.75s ==============================================
~/ResearchWorkspace/rocker main ❯    

@YuqiHuai YuqiHuai requested a review from tfoote as a code owner February 14, 2025 22:54
Copy link
Collaborator

@tfoote tfoote left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for this submission, it looks great to be able to provide this option. I had a few stylistic requests.

Can you explain a bit about how you're using this? I want to connect this to the mode setting and potentially force NON-INTERACTIVE in this case, or error if the mode is set explicitly to interactive.

@YuqiHuai
Copy link
Contributor Author

Hi @tfoote . Thank you for your reply! Sorry, I was not aware that extensions should be in alphabetical order, and I have made the correction in the latest commit.

I am using rocker for an autonomous driving system project (https://github.com/autowarefoundation/autoware/blob/2025.02/docker/Dockerfile). I want to be able to launch this container in the background, which is normally done through --detach when using docker by itself. When using rocker, if I set the mode to non-interactive, the container will not be running in the background (it seems like the container is just stopped and removed). After adding the detach plugin, I can launch this container in the background.

To reproduce my use case, run rocker --nvidia --privileged --x11 --user --mode non-interactive -- ghcr.io/autowarefoundation/autoware:20240903-devel-cuda-amd64. (The image is large)

…ode for detach and no-tty present.

Signed-off-by: Tully Foote <tullyfoote@intrinsic.ai>
…ommand

Signed-off-by: Tully Foote <tullyfoote@intrinsic.ai>
@tfoote
Copy link
Collaborator

tfoote commented Feb 18, 2025

Thanks for reordering, I have tweaked the command line parsing to handle mutual exclusion of --detach and interactive mode: YuqiHuai#1

Can you validate that works for you and then I think this will be good to go.

@YuqiHuai
Copy link
Contributor Author

@tfoote Thanks for making these changes! Unfortunately, with those changes, detach no longer works properly for my purpose. Setting --detach seems to automatically activate the non-interactive mode, and the container I am trying to get running doesn't run in the background when the mode is set to non-interactive.

I am going to test a bit more to find the root cause.

@tfoote
Copy link
Collaborator

tfoote commented Feb 18, 2025

Interesting, I guess that maybe your program is detecting the pseudo tty of the pexpect interface and doing something different. I've been testing with:

rocker --mode interactive ros:jazzy sleep 10 Run normally
rocker --detach ros:jazzy sleep 10 Detach and run in the background for 10 seconds (visible via docker ps)
echo foo | rocker ros:jazzy sleep 10 Trigger no-tty fallback

Errors:
rocker --mode interactive --detach ros:jazzy sleep 10 # Interactive and detach are not compatible
echo foo | rocker --mode interactive ros:jazzy sleep 10 # no-tty and interactive are not compatible

I guess it would be possible to continue to keep the pexpect invocation but this seems like an odd edge case. And the intent of the interactive environment is to connect the users' keyboard. And when you're running headless it seems like if the executable is running or expecting user inputs that's not going to get very far.

@YuqiHuai
Copy link
Contributor Author

@tfoote I created a test image

FROM ubuntu:18.04
CMD ["/bin/bash"]

and tried to run different docker commands to see how I can achieve my goal (launching a container without necessarily entering it). It turns out I need flags -itd (both interactive and detached). I am not sure, from a design perspective of rocker, whether "interactive" and "detach" should be mutually exclusive since docker actually allows it. (See example https://github.com/ApolloAuto/apollo/blob/463fb82f9e979d02dcb25044e60931293ab2dba0/docker/scripts/dev_start.sh#L384)

After removing your changes of setting mode to non-interactive when detach is set, and adding code to set default to interactive, things are working as how I expect it to run.

@YuqiHuai
Copy link
Contributor Author

YuqiHuai commented Feb 18, 2025

@tfoote I Just saw your comment after I posted the previous comment. I think the use case of -it and -d is different for everyone. Perhaps some users are trying to run an executable in a container and they don't need to keep the container up and running after the executable finishes (e.g., docker run --rm --detach ros:jazzy sleep 10). For my purpose, I want to keep the container up and running, so there needs to be a detached interactive session with the -its flag (e.g., docker run --rm -itd XXX /bin/bash).


Edit: Perhaps the best thing to do is default mode to non-interactive, no detach, but allow interactive and detach at the same time, I believe this would mean rocker uses default flags for docker.

@tfoote
Copy link
Collaborator

tfoote commented Feb 18, 2025

None of these cases keep the container running after the executable finishes. Some applications will finish after stdin is disconnected, and the only common example I know of this is interpreters like bash. For example /bin/bash without -i will terminate when the bash script reaches the end of the inputs which is nothing, so it will immediately end.

I found a good overview of the distinctions here: https://stackoverflow.com/questions/47753047/docker-detached-and-interactive

I see from your linked dev_start.sh what you're relying on is not the executable, but that you want the dev envrionment to be just running in the background. You should change the last line from /bin/bash to sleep infinity which will mean that it just waits. Right now you're relying on /bin/bash waiting infinitely on stdin which is good if you want to interact, but in a non-interactive case is not a good way to express that you want to wait forever.

Usually the end of your docker command would be run my "service" aka a web server or the like. And the setup beforehand is to make sure all the dependencies are running in the container.

To stop it from immediately ending you can pass a command like sleep infinity

rocker --nvidia --privileged --x11 --user --mode non-interactive -- ghcr.io/autowarefoundation/autoware:20240903-devel-cuda-amd64 sleep infinity which will pass sleep infinity to the bash instance to keep it alive.

This is the same as the default commands in ros:jazzy if you just run rocker -d ros:jazzy it will exit immediately because bash finishes. However rocker -d ros:jazzy sleep infinity will run until it's killed.

I'm downloading your image but it's going to be a while to finish and be able to reproduce.

@YuqiHuai
Copy link
Contributor Author

@tfoote Thanks for taking a close look at the specific use case! I think your characterization of "I want the dev environment to be just running in the background" is accurate. Your example of using non-interactive mode with an additional "sleep infinity" command looks like it will achieve my goal but block the main terminal at the same time.

I think we already understood the situation pretty well (i.e., using -itd and /bin/bash to keep a container running in the background without doing anything). You might not need to download the image. They are indeed large :'(

Back to this PR, I still believe having a detach flag helps, but making it mutually exclusive with interactive might be problematic because it is supported by docker. Do you think this detach plugin still contributes to rocker without making it mutually exclusive w.r.t. mode?

@tfoote
Copy link
Collaborator

tfoote commented Feb 19, 2025

The detach capability is something that I have other use cases that could be leveraged for example: https://github.com/opencv/bpc

However I think that detached and interactive in the rocker sense are mutually exclusive, you cannot interact with a detached instance. There's a question of if the program things that there's still a stdin, which docker calls "interactive" this is an interesting distinction that I'm not sure I agree with.

Your example of using non-interactive mode with an additional "sleep infinity" command looks like it will achieve my goal but block the main terminal at the same time.

The expectation of a non-interactive process is that it will run to completion. And if you want it to run in the background detached it does the same. We could add the -i --interactive option to do the stdin mounting separately from the --mode mechanism.

Looking a little deeper it would be great to also enable rocker to keep track of the container and enable attach as well to the container, either reconnecting to an rocker interactive session or to pipe in a specific input to the detached instance.

Implementing conflict feedback and resolution for default operating mode for detach and no-tty present
@YuqiHuai
Copy link
Contributor Author

That all sounds good. I think it is ok for rocker and docker to have different interpretations of interactive. I tested my use case and found running non-interactive, detach, sleep infinity achieves my goal of keeping a container up and running in the back. When I re-attach and run ps -ef, I get

UID          PID    PPID  C STIME TTY          TIME CMD
yuqi           1       0  0 17:47 ?        00:00:00 sleep infinity
...

Thank you for your time and consideration! I have merged your changes to the branch.

Copy link
Collaborator

@tfoote tfoote left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great, I'm glad it's working for you now. I'll bring this in as is for now. But I'll open a feature request for extending the interactivity to potentially detached processes.

@tfoote tfoote merged commit ade9803 into osrf:main Feb 19, 2025
4 checks passed
@YuqiHuai YuqiHuai deleted the features/detach-plugin branch February 19, 2025 07:41
@YuqiHuai
Copy link
Contributor Author

Thanks again for your time and consideration! I learned a lot about rocker and docker from our conversation.

tfoote added a commit that referenced this pull request Aug 8, 2025
The comment is correct but this looks like it was changed in #320 by accident.
tfoote added a commit that referenced this pull request Aug 11, 2025
* Restore interactive as the default behavior

The comment is correct but this looks like it was changed in #320 by accident.

Co-authored-by: Scott K Logan <logans@cottsay.net>

---------

Co-authored-by: Scott K Logan <logans@cottsay.net>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants