Ask Your Question
0

Sourcing of containerized ROS via docker-py

asked 2018-08-03 07:39:37 -0500

thinwybk gravatar image

updated 2018-08-03 11:38:03 -0500

I want to run a docker container wrapping ROS indigo using docker-py without running a command.

>>> import docker
>>> docker_client = docker.DockerClient(base_url='unix://var/run/docker.sock')
>>> container = docker_client.containers.run(image="osrf/ros:indigo-desktop-trusty", detach=True, tty=True)

According to docker container ls the container is running. /ros_entrypoint.sh as COMMAND made me think the entry point script is executed when the container is run.

CONTAINER ID        IMAGE                            COMMAND                  CREATED             STATUS              PORTS               NAMES
69b97aa978f1        osrf/ros:indigo-desktop-trusty   "/ros_entrypoint.s..."   2 minutes ago       Up 2 minutes                            festive_lichterman

However when I call a ros command line tool in the container

>>> logs = container.exec_run(cmd='rosparam list')
>>> print(logs)

I get this error

ExecResult(exit_code=126, output='rpc error: code = 2 desc = oci runtime error: exec failed: container_linux.go:247: starting container process caused "exec: \\"rosparam\\": executable file not found in $PATH"\n\r\n')

with possible root cause that (a) the entry point script is not executed when the container is run or (b) that exec_run() is executed in another shell which has entry point script not executed.

Does someone have an idea about how to reliably source the env when executing subsequent commands in docker containers using docker-py?

EDIT:

The behavior described above corresponds to the following docker command line observation. If one executes subsequent commands they are executed in separate bash session which lack sourcing of the environment. (rosversion does not depend on sourced environment and is executable.)

kromer@rc-019:~/ws_gitlab$ docker run --name roscli --rm -i -t -d osrf/ros:indigo-desktop-full bash
ecd86cd4df75ff316738364fac64cd5afa43d7799e014b3e399dc1a58a2e1a66
kromer@rc-019:~/ws_gitlab$ docker container ls
CONTAINER ID        IMAGE                          COMMAND                  CREATED             STATUS              PORTS               NAMES
ecd86cd4df75        osrf/ros:indigo-desktop-full   "/ros_entrypoint.s..."   3 seconds ago       Up 1 second                             roscli
kromer@rc-019:~/ws_gitlab$ docker exec roscli rosparam
rpc error: code = 2 desc = oci runtime error: exec failed: container_linux.go:247: starting container process caused "exec: \"rosparam\": executable file not found in $PATH"

If one attaches to the containers initial bash session the environment is sourced and e.g. rosparam gives expected output:

kromer@rc-019:~/ws_gitlab$ docker run --name roscli --rm -i -t -d osrf/ros:indigo-desktop-full bash
f6ab686c8477a14be65b1d16b66bf95fc94c92891c04551c94b8dad5662cd469
kromer@rc-019:~/ws_gitlab$ docker attach roscli
root@f6ab686c8477:/# rosparam
rosparam is a command-line tool for getting, setting, and deleting parameters from the ROS Parameter Server.

Commands:
    rosparam set    set parameter
    rosparam get    get parameter
    rosparam load   load parameters from file
    rosparam dump   dump parameters to file
    rosparam delete delete parameter
    rosparam list   list parameter names

root@f6ab686c8477:/# exit
exit
kromer@rc-019:~/ws_gitlab$ docker container ls
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
edit retag flag offensive close merge delete

Comments

rosversion does not seem to depend on sourcing: It can be called as subsequent command with logs = container.exec_run(cmd='rosversion') which gives a reasonable output ExecResult(exit_code=64, output='Usage: rosversion <package/stack> or rosversion -d\n').

thinwybk gravatar imagethinwybk ( 2018-08-03 10:06:24 -0500 )edit

2 Answers

Sort by ยป oldest newest most voted
0

answered 2018-08-06 04:44:43 -0500

thinwybk gravatar image

The probably most easy solution is to put the the call of /ros_entrypoint.sh in front of the actual command. (This works because ros_entrypoint.sh calls the argument passed...)

>>> import docker
>>> docker_client = docker.DockerClient(base_url='unix://var/run/docker.sock')
>>> container = docker_client.containers.run(image="osrf/ros:indigo-desktop-trusty", detach=True, tty=True)
>>> logs = container.exec_run(cmd='/ros_entrypoint.sh rosparam list')
>>> print(logs)
ExecResult(exit_code=1, output='ERROR: Unable to communicate with master!\n')
edit flag offensive delete link more
0

answered 2018-08-09 08:28:10 -0500

airhorns gravatar image

The entrypoint listed in a Dockerfile is skipped unless the command is passed as an array of strings instead of one string (with spaces and whatnot). This is a bit of a weird behavior with docker that isn't obvious, but, you have to give it your command in such a way that it knows it can run it after the entrypoint and not in a subshell. See the CMD documentation here: https://docs.docker.com/engine/refere... . The same applies to the command: data in a docker-compoose file, and it looks like docker-py supports passing a python list instead of a string as well: https://docker-py.readthedocs.io/en/s... .

So, if you changed your code to:

>>> logs = container.exec_run(cmd=['rosparam', 'list'])
>>> print(logs)

I think you'd have your entrypoint executed.

edit flag offensive delete link more

Comments

No, the entry point is not executed. Even with list syntax you get ExecResult(exit_code=126, output='rpc error: code = 2 desc = oci runtime error: exec failed: container_linux.go:247: starting container process caused "exec: \\"rosparam\\": executable file not found in $PATH"\n\r\n').

thinwybk gravatar imagethinwybk ( 2018-08-10 05:22:40 -0500 )edit

Dang. Is your ENTRYPOINT set in the Dockerfile with the array-of-strings style format? See the note at the bottom of this reference: https://medium.freecodecamp.org/docke...

airhorns gravatar imageairhorns ( 2018-08-10 14:08:33 -0500 )edit

The entry point of the ROS indigo docker image (Dockerfile) uses list syntax as well.

thinwybk gravatar imagethinwybk ( 2018-08-12 13:09:03 -0500 )edit

Upon rereading your question I can clarify, my answer is wrong, oops! Docker never executes your entrypoint for commands invoked via exec. It's only used in the execution of the CMD at the init of the container. Are you using exec for running many commands in the same container though?

airhorns gravatar imageairhorns ( 2018-08-13 15:57:44 -0500 )edit

I use run() to run a single "blocking" command in a container. Several exec_run() are called in sequence to run "non blocking" commands in a single (obviously: different) container.

thinwybk gravatar imagethinwybk ( 2018-08-18 10:11:35 -0500 )edit

Your Answer

Please start posting anonymously - your entry will be published after you log in or create a new account.

Add Answer

Question Tools

2 followers

Stats

Asked: 2018-08-03 07:39:37 -0500

Seen: 154 times

Last updated: Aug 09 '18