Skip to content
This repository was archived by the owner on May 27, 2020. It is now read-only.

Improved detection of available shell in container (fixes #5)#15

Merged
jpetazzo merged 4 commits intojpetazzo:masterfrom
thaJeztah:5-use-container-shell
Jul 26, 2014
Merged

Improved detection of available shell in container (fixes #5)#15
jpetazzo merged 4 commits intojpetazzo:masterfrom
thaJeztah:5-use-container-shell

Conversation

@thaJeztah
Copy link
Copy Markdown

docker-enter tried to open the same shell inside the container as on
the host, which failed if the container did not have that shell.

Additionally, (environment) variables of the host were also present in
the nsenter session.

This change;

  1. Checks if a command was given as parameter
  2. If no command, check if ‘bash’ is present inside the container
  3. Otherwise use ‘sh’ as shell

As discussed here; https://github.com/jpetazzo/nsenter/issues/5

@thaJeztah thaJeztah changed the title Improved detection of available shell in container Improved detection of available shell in container (fixes #5) Jul 24, 2014
Comment thread docker-enter Outdated
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

I think we might have to use "$@" because without the quotes it will break down the parameters... Not sure, but we should double-check first :-)

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Yeah, I first had the whole "@NSENTER...... line in both branches, once with "$@" and once with $COMMAND, but that was not very DRY.

I will check if I adding the quotes here works properly and update my PR. Thanks!

docker-enter tried to open the same shell inside the container as on
the host, which failed if the container did not *have* that shell.

Additionally, (environment) variables of the host were also present in
the nsenter session.

This change;
1. Checks if a command was given as parameter
2. If no command, check if ‘bash’ is present inside the container
3. Otherwise use ‘sh’ as shell

As discussed here; https://github.com/jpetazzo/nsenter/issues/5
@thaJeztah
Copy link
Copy Markdown
Author

@jpetazzo Ok, added the quotes, seems to work correctly (fingers crossed :)).

BTW, I was reading one of your older blogposts (http://jpetazzo.github.io/2014/03/23/lxc-attach-nsinit-nsenter-docker-0-9/); any reason you decided to use nsenter, not nsinit?

@thaJeztah
Copy link
Copy Markdown
Author

@JessThrysoee Looks good. But if I understood your comment here https://github.com/jpetazzo/nsenter/issues/5#issuecomment-50095177 correctly, exec -cl should already clear the environment variables, so wouldn't env --ignore-environment be redundant?

@thaJeztah
Copy link
Copy Markdown
Author

@JessThrysoee was thinking along the line of; "$NSENTER" $OPTS sh -c "exec -cl [COMMAND]", so also use it to run sh ("$NSENTER" $OPTS sh -c "exec sh")

ototh, clearing the environment twice wouldn't hurt. LOL

Probably, the $HOME var should be somewhere added to OPTS

@JessThrysoee
Copy link
Copy Markdown

Yes I also didn't think clearing the environment twice mattered. The -c could probably be omitted and exec -l would be sufficient (I haven't testet that).

But, sh -c "exec -cl [COMMAND]" will not work, because the -cl opts are a bash ting.

@JessThrysoee
Copy link
Copy Markdown

$HOME should not be added to OPTS, at least not for the exec -cl case, the -l handles $HOME for us.

In fact the only reason to go with exec is so that argv0 will become -bash (note the leading dash) which will start bash as a login shell with $HOME set -- that's what this article tells us http://lists.gnu.org/archive/html/bug-bash/2014-01/msg00063.html

Because the bourne shell version of exec doesn't accept options, there is nothing gained by sh -c "exec sh", it will be the same as just calling sh directly (except for an extra unnecessary execve).

@thaJeztah
Copy link
Copy Markdown
Author

@JessThrysoee makes sense (you're a lot better than this than I am!).

Just did a quick search and apparently, /root should be present after all (I was assuming this could differ per-distro). If not, it's probably not a big issue.

The sh version will then be;

"$NSENTER" $OPTS HOME=/root sh 

Is it okay to use your suggestions in my PR? Or would you prefer to open your own PR? Feels like plagiarism 😺

@jpetazzo only thing I run into when using sh instead of bash is I get a "sh: 3: Cannot set tty process group (No such process)" if I exit the shell. Any thoughts? Could this be a Docker thing?

Added various improvements as suggested by @JessThrysoee

- Use 'type' instead of 'which'
- Added OPTS var to reduce duplicated code
- Use 'exec -cl bash' for a 'clean' bash shell
- Added HOME=/root for 'sh' shell
@JessThrysoee
Copy link
Copy Markdown

@thaJeztah No need for another PR :-)

The "Cannot set tty..." seems to be a /bin/dash warning (the /bin/sh on most linux systems).

The exec -l trick is still not quite enough. Even though PATH and HOME is set, they are not exported. So I have come up with a better solution which also makes the script simpler:

#!/bin/sh

NSENTER="$(dirname "$0")/nsenter"

if [ -z "$1" ]; then
    echo "usage: docker-enter <container id/name> <command to run default:bash>"
else
    PID=$(docker inspect --format {{.State.Pid}} "$1")
    if [ -z "$PID" ]; then
        exit 1
    fi
    shift

    OPTS="--target $PID --mount --uts --ipc --net --pid -- env --ignore-environment --"

    if [ -z "$1" ]; then
        "$NSENTER" $OPTS su - root
    else
        "$NSENTER" $OPTS "$@"
    fi
fi

su will use the default shell and make sure the environment is set up properly.

@thaJeztah
Copy link
Copy Markdown
Author

@JessThrysoee clever! Love it!

Maybe we should add some documentation inside the script to explain why su is used as it may confuse people.

I'll update the PR later and will think of documentation later

More awesomeness by @JessThrysoee

Now using su to;
- Automatically log in to the default shell of the container
- Set up the right environment variables (e.g. $PATH, $HOME)
- No longer requiring to *detect* the default shell
@thaJeztah
Copy link
Copy Markdown
Author

Updated the PR. Haven squashed yet, in case more improvements come 😄

@JessThrysoee
Copy link
Copy Markdown

Looks good, but I have just one more tweak :-)

I just read the su manpage and it says "clears all environment variables except for TERM". We really want to preserve TERM so here is yet another attempt:

#!/bin/sh

NSENTER=$(dirname "$0")/nsenter

if [ -z "$1" ]; then
    echo "usage: docker-enter <container id/name> <command to run default:bash>"
else
    PID=$(docker inspect --format "{{.State.Pid}}" "$1")
    if [ -z "$PID" ]; then
        exit 1
    fi
    shift

    OPTS="--target $PID --mount --uts --ipc --net --pid --"

    if [ -z "$1" ]; then
        # No command given.
        # Use su to clear all host environment variables except for TERM, 
        # initialize the environment variables HOME, SHELL, USER, LOGNAME, PATH,
        # and start a login shell.
        "$NSENTER" $OPTS su - root

    else
        # Use env to clear all host environment variables.
        "$NSENTER" $OPTS env --ignore-environment -- "$@"
    fi
fi

I also updated the comments with the information from the su manpage.

@thaJeztah
Copy link
Copy Markdown
Author

@JessThrysoee I'll update the PR when I'm back at my computer.

This has been very educational!

Only thing I'm not sure about is "what" to mention as default command here <command to run default:bash>; that description is inaccurate, but a full description will be difficult to provide, so maybe we should just leave that as a "known issue" 😉

@JessThrysoee
Copy link
Copy Markdown

How about?

echo "Usage: docker-enter CONTAINER [COMMAND [ARG]...]"
echo ""
echo "Enters the Docker CONTAINER and executes the specified COMMAND."
echo "If COMMAND is not specified, runs an interactive shell in CONTAINER.

The docker manpages just use CONTAINER for a container id or name.

@thaJeztah
Copy link
Copy Markdown
Author

@JessThrysoee guess something like that would work, was too focused on keeping it a single line (as it was now) but, that's nonsense. Guess it's getting late :)

Will update the PR in the morning, and clean up the commits if all things are ready.

Saw that quite a lot of work is in progress for implementing RunIn(), which will bring native nsinit/nsenter support to Docker

- Don’t clear TERM environment-variable when using su.
- Updated usage description
@thaJeztah
Copy link
Copy Markdown
Author

ping @jpetazzo

I think the new docker-enter has come quite a long way (the heavy lifting has been done by @JessThrysoee)

Do you want them rebased?

@jpetazzo
Copy link
Copy Markdown
Owner

Thanks! You're the best, all of you :-)

I'm happy to merge this. And sorry for the delay; I was at OSCON the whole week, and couldn't check GitHub notifications as much as I wanted!

jpetazzo pushed a commit that referenced this pull request Jul 26, 2014
Improved detection of available shell in container (fixes #5)
@jpetazzo jpetazzo merged commit ce21506 into jpetazzo:master Jul 26, 2014
@thaJeztah
Copy link
Copy Markdown
Author

@jpetazzo no problem at all, due to your delay we were able to come up with a better version!

....just in time before docker RunIn() is implemented LOL

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants