I've got a problem with environment variables in docker.
When I run command:
$ docker run ubuntu /bin/bash -c "echo $HOME"
I've got response:
/Users/bylek
But when I run:
$ docker run -it ubuntu /bin/bash
and then:
root#5e079c47affa:/# echo $HOME
I've got:
/root
Second response is correct. Why first command return $HOME value from my host?
echo $HOME is being evaluated on your host because you haven't got the syntax of the switch to bash correct. It's Linux so you need single quotes.
Try replacing your double quotes with single quotes.
eg. This is what I get:
bash-3.2$ docker run ubuntu /bin/bash -c 'echo $HOME'
/root
Related
I can't understand some thing, namely as we know we can pass to docker run argument -e SOME_VAR=13.
Then each process launched (for example using docker exec ping localhost -c $SOME_VAR=13) can see this variable.
How does it work ? After all, enviroment are about bash, we don't launched bash. I can't understand it. Can you explain me how -e does work without shell ?
For example, let's look at following example:
[user#user~]$ sudo docker run -d -e XYZ=123 ubuntu sleep 10000
2543e7235fa9
[user#user~]$ sudo docker exec -it 2543e7235fa9 echo test
test
[user#user~]$ sudo docker exec -it 2543e7235fa9 echo $XYZ
<empty row>
Why did I get <empty row> instead of 123 ?
The problem is that your $XYZ is getting interpolated in the host shell environment, not your container.
$ export XYZ=456
$ docker run -d -e XYZ=123 ubuntu sleep 10000
$ docker exec -it $(docker ps -ql) echo $XYZ
$ 456
$ docker exec -it $(docker ps -ql) sh -c 'echo $XYZ'
$ 123
You have to quote it so it's passed through as a string literal to the container. Then it works fine.
The environment is not specific to shells. Even ordinary processes have environments. They work the same for both shells and ordinary processes. This is because shells are ordinary processes.
When you do SOMEVAR=13 someBinary you define an environment variable called SOMEVAR for the new process, someBinary. You do this with -e in docker because you ask another process to start your process, the docker daemon.
Folks,
I'm following the Docker tutorial here: https://docs.docker.com/get-started/part4/#configure-a-docker-machine-shell-to-the-swarm-manager and coming up against resistance when running this particular command:
eval $(docker-machine env myvm1)
I'm actually running (as above but with addition of sudo).
eval $(sudo docker-machine env myvm1)
I get no output from the command line to tell me anything has been done and when I run:
sudo docker-machine ls
I see that myvm1 does not have an active state as expected. I do know that this step isn't necessary but I'd like to understand why the command is not working and try to fix it.
I am running docker 17.09.0-ce
On Ubuntu 16.04 LTS
zsh shell (have tried switching to bash)
This is just on my local machine by the way, not a server.
Any help would be much appreciated.
There's less to go wrong if you run the eval on the far side of sudo:
sudo sh -c 'eval "$(docker-machine env myvm1)"; docker-machine ls'
Otherwise, the environment variables set by evaling the output of docker-machine env aren't necessarily (barring some very specific /etc/sudoers configuration) propagated through to the future docker-machine invocation.
If you wanted to automate this with a shell function, that can be done:
# docker-env sudo; usage: desudo vm-name command-to-run
desudo() {
local cmd1 cmd2
printf -v cmd1 'eval "$(docker-machine env %q)"' "$1"; shift
printf -v cmd2 '%q ' "$#"
sudo bash -c "${cmd1} && exec ${cmd2}"
}
...used as:
desudo vm1 docker-machine ls
You should run eval $(docker-machine env myvm1).
In fact, you don't have to add sudo.
But you may doesn't have permission to run docker without sudo, here is how to solve this issue on Linux.
Following the steps in this article "Post-installation steps for Linux"
Create the docker group. sudo groupadd docker
Add your user to the docker group. sudo usermod -aG docker $USER
Log out and log back in so that your group membership is re-evaluated.
Verify that you can run docker commands without sudo.docker run hello-world.
If you see the following error:
WARNING: Error loading config file: /home/user/.docker/config.json -
stat /home/user/.docker/config.json: permission denied
Fix it with:
$ sudo chown "$USER":"$USER" /home/"$USER"/.docker -R
$ sudo chmod g+rwx "/home/$USER/.docker" -R
I too was having the exact same problem as posted and have spent the better part of the morning googling for an answer. I went back through the documentation and realised that I completely omitted the post-installation steps for Linux.
https://docs.docker.com/install/linux/linux-postinstall/
I followed the instructions laid out in the section labelled Manage Docker as a non-root user and eval $(sudo docker-machine env myvm1) and the subsequent docker-machine ls worked as expected. In addition... it eliminates the need to prefix all your docker commands withsudo.
I should have RTFM I guess?
I'm actually running (as above but with addition of sudo).
eval $(sudo docker-machine env myvm1)
I get no output from the command line to tell me anything has been done and when I run:
sudo docker-machine ls
I see that myvm1 does not have an active state as expected.
run this command it will work
sudo sh -c 'eval "$(docker-machine env myvm1)"; docker-machine ls'
thank you for reading my post.
Problem:
# docker ps
CONTAINER ID IMAGE COMMAND
35c8b832403a ubuntu1604:1 "sh -c /bin/sh"
# docker exec -i -t 35c8b832403a type type
rpc error: code = 2 desc = oci runtime error: exec failed: container_linux.go:262: starting container process caused "exec: \"type\": executable file not found in $PATH"
# Dockerfile
FROM ubuntu:16.04
ENV PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
RUN apt-get update && apt-get -y upgrade
ENTRYPOINT ["sh", "-c"]
CMD ["/bin/bash"]
Description:
My objective is to get "type" shell builtin been execute in a way of writing docker exec as below
docker exec -i -t 35c8b832403a type type (FAILED)
NOT
docker exec -i -t 35c8b832403a sh -c "type type" (PASSED)
I have googling around, do some modification in the container (change /etc/profile, /etc/environment, bashrc) but failed.
From the docker documentation itself, it has state that:
COMMAND will run in the default directory of the container. It the
underlying image has a custom directory specified with the WORKDIR
directive in its Dockerfile, this will be used instead.
COMMAND should be an executable, a chained or a quoted command will
not work. Example: docker exec -ti my_container "echo a && echo
b" will not work, but docker exec -ti my_container sh -c "echo a &&
echo b" will.
But seem it IS POSSIBLE when I able to get the right output FROM DOCKER FEDORA (Dockerfile: FROM fedora:25)
# docker ps
CONTAINER ID IMAGE COMMAND
2a17b2338518 fedora25:1 "sh -c /bin/sh"
# docker exec -i -t 2a17b2338518 type type
type is a shell builtin
Question:
Is there any way to enable this on Ubuntu docker? Image/Container tweaks? Vagrantfile Configuration? Please help.
Others:
Using docker run, I able to get the right output because of the "ENTRYPOINT" in the Dockerfile. However the image need to be save instead of export.
Just in case, to be able to execute type as you expect, it would need to be part of the path. Being a shell builtin wouldn't help because as you said, you don't want to execute /bin/bash -c 'type type'
If you want to have type executed as a builtin shell command, this means you need to execute a shell /bin/bash or /bin/sh and then execute 'type type' on it, making it /bin/bash -c 'type type'
After all, as #Henry said, docker exec is a the full command that will be executed and there is no place for CMD or ENTRYPOINT on it.
CMD and ENTRYPOINT are meaningless if you run docker exec. The remaining arguments are taken as the command and executed inside the already existing container.
Maybe you wanted to use docker run?
I'm trying to do two commands in docker exec. Concretely, I have to run a command inside a specific directory.
I tried this, butit didn't work:
docker exec [id] -c 'cd /var/www/project && composer install'
Parameter -c is not detected.
I also tried this:
docker exec [id] cd /var/www/project && composer install
But the command composer install is executed after the docker exec command.
How can I do it?
In your first example, you are giving the -c flag to docker exec. That's an easy answer: docker exec does not have a -c flag.
In your second example, your shell is parsing this into two commands before Docker even sees it. It is equivalent to this:
if docker exec [id] cd /var/www/project
then
composer install
fi
First, the docker exec is run, and if it exits 0 (success), composer install will try to run locally, outside of Docker.
What you need to do is pass both commands in as a single argument to docker exec using a string. Then they will not be interpreted by a shell until already inside the container.
docker exec [id] "cd /var/www/project && composer install"
However, as you noted in the comments, this also does not work. That's because cd is a shell builtin, and doesn't exist on its own. Trying to execute it as the initial command will fail. So the next step is to hand this off to a shell to execute.
docker exec [id] "bash -c 'cd /var/www/project && composer install'"
And finally, at this point the && has moved into an inner set of quote marks, so we don't really need the quotes around the bash command... you can drop them if you prefer.
docker exec [id] bash -c 'cd /var/www/project && composer install'
Everything after the container id is the command to run, so in the first example -c isn't an option to exec, but a command docker tries to run and fails since that command doesn't exist.
Most likely you found this syntax from a docker run command where the entrypoint was set to /bin/sh. However, exec bypasses the entrypoint, so you need to include the full command to run. As others have pointed out, that command includes a shell like bash or in the below example, sh:
docker exec [id] /bin/sh -c 'cd /var/www/project && composer install'
The other answers are fine if you want to run 2 arbitrary commands. But if the first command is simply cd, then you should use the -w option to set the working directory instead.
docker exec -w {dir} {container} {commands}
So in your example:
docker exec -w /var/www/project {container} composer install
as Nehal J Wani said in his commentary, the correct syntax is the following:
docker exec [id] /bin/bash -c 'cd /var/www/project && composer install'
many thanks!
I would like to add my example here because it is a bit more complex then the ones thate were shown above. This example also illustrates on how to find a container id that should be used in the docker exec command.
I needed to execute a composite docker exec command against docker container over ssh.
I managed to achieve this in 2 steps:
-definition of the variable that contains a command expored as an environment variable
-ssh command that runs it
environment varialbe definition:
export COMMAND="bash -c 'php bin/console --version && composer --version'"
ssh command that runs on a remote system:
ssh -t -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -i keyfile.pem ec2-user#111.222.111.222 'docker exec docker ps|grep php|grep api|grep -v cron|awk '"'"'{print $1}'"'"' '$COMMAND
As you can see I left the command out of the single quotes to pass its actual value to the SSH process
The output of the command execution is:
Warning: Permanently added '111.222.111.222' (ECDSA) to the list of known hosts.
Cannot load Xdebug - it was already loaded
Symfony 4.3.5 (env: dev, debug: true)
Cannot load Xdebug - it was already loaded
Composer version 1.9.1 2019-11-01 17:20:17
Connection to 111.222.111.222 closed.
If you wish to execute this command in a single line you can use a bit modified version of my first example:
COMMAND="bash -c 'php bin/console --version && composer --version'" ssh -t -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -i keyfile.pem ec2-user#111.222.111.222 'docker exec `docker ps|grep php|grep api|grep -v cron|awk '"'"'{print $1}'"'"'` '$COMMAND
I use the command docker run --rm -it govim bash -l to run Docker images, but it does not display color output.
If I source ~/.bash_profile or run bash -l again, output will then correctly be output with color.
Bash Prompt Image
My bash_profile and bash_prompt files.
The OP SolomonT reports that docker run with env do work:
docker run --rm -it -e "TERM=xterm-256color" govim bash -l
And Fernando Correia adds in the comments:
To get both color support and make tmux work, I combined both examples:
docker exec -it my-container env TERM=xterm-256color script -q -c "/bin/bash" /dev/null
As chepner commented (earlier answer), .bash_profile is sourced (itis an interactive shell), since bash_prompt is called by .bash_profile.
But docker issue 9299 illustrates that TERM doesn't seem to be set right away, forcing the users to open another bash with:
docker exec -ti test env TERM=xterm-256color bash -l
You have similar color issues with issue 8755.
To illustrate/reproduce the problem:
docker exec -ti $CONTAINER_NAME tty
not a tty
The current workaround is :
docker exec -ti `your_container_id` script -q -c "/bin/bash" /dev/null
Both are supposing you have a running container first, which might not be convenient here.
Based on VonC's answer I adding the following to my Dockerfile (which allows me to run the container without typing the environment variables on the command line every time):
ENV TERM xterm-256color
#... more stuff
CMD ["bash", "-l"]
And sure enough it works with:
docker run -it my-image:tag
For tmux to work with color, in my ~/.tmux.conf I need:
set -g default-terminal "screen-256color"
and for UTF-8 support in tmux, in my ~/.bashrc:
alias tmux='tmux -u'
My Dockerfile:
FROM fedora:26
ENV TERM xterm-256color
RUN dnf upgrade -y && \
dnf install golang tmux git vim -y && \
mkdir -p /app/go/{bin,pkg,src} && \
echo 'export GOPATH=/app/go' >> $HOME/.bashrc && \
echo 'export PATH=$PATH:$GOPATH/bin' >> $HOME/.bashrc && \
mkdir -p ~/.vim/autoload ~/.vim/bundle && \
curl -LSso ~/.vim/autoload/pathogen.vim \
https://tpo.pe/pathogen.vim && \
git clone https://github.com/farazdagi/vim-go-ide.git \
~/.vim_go_runtime && \
bash ~/.vim_go_runtime/bin/install && \
echo "alias govim='vim -u ~/.vimrc.go'" >> ~/.bashrc && \
echo "alias tmux='tmux -u'" >> ~/.bashrc && \
echo 'set -g default-terminal "screen-256color"' >> ~/.tmux.conf
CMD ["bash", "-l"]
The Dockerfile builds an image based off Fedora 26, updates it, installs a few packages (Git, Vim, golang and tmux), installs the pathogen plugin for Vim, then it installs a Git repository from here vim-go-ide and finally does a few tweaks to a few configuration files to get color and UTF-8 working fine. You just need to add persistent storage, probably mounted under /app/go.
If you have an image with all the development tools already installed, just make a Dockerfile with ENV statement and add the commands to modify the configuration files in a RUN statement without the installation commands and use your base image in the FROM statement. I prefer this solution because I'm lazy and (besides the initial setup) it saves typing when you want to run the image.
Using Vim and plugins within tmux
Adding -t is working for me:
docker exec -t vendor/bin/phpunit
Adding to VonC's answer, I made this Bash function:
drun() { # start container with the specified entrypoint and colour terminal
if [[ $# -lt 2 ]]; then
echo "drun needs 2+ arguments: image entrypoint" >&2
return
fi
docker run -ti -e "TERM=xterm-256color" "$#"
}
I think this is something that you'd have to implement manually. My container has Python, so here's how I print in color using a single line:
Example Docker file:
FROM django:python3
RUN python -c "print('\033[90m HELLO_WORLD \033[0m')"
RUN python -c "print('\033[91m HELLO_WORLD \033[0m')"
RUN python -c "print('\033[92m HELLO_WORLD \033[0m')"
RUN python -c "print('\033[93m HELLO_WORLD \033[0m')"
RUN python -c "print('\033[94m HELLO_WORLD \033[0m')"
RUN python -c "print('\033[95m HELLO_WORLD \033[0m')"
RUN python -c "print('\033[96m HELLO_WORLD \033[0m')"
RUN python -c "print('\033[97m HELLO_WORLD \033[0m')"
RUN python -c "print('\033[98m HELLO_WORLD \033[0m')"
Standard terminal:
You need to add the following line to your Dockerfile:
RUN echo PS1="'"'\[\e]0;\u#\h: \w\a\]${debian_chroot:+($debian_chroot)}\ \033[01;32m\]\u#\h\[\033[00m\]:\[\033[01;34m\]\w\[\033[00m\]\$ '"'" >> /app/.bashrc
Change the /app/.bashrc to where your .bashrc file is in the docker.
If you want ls command to have colors too add this line:
RUN echo alias ls="'"'ls --color=auto'"'" >> /app/.bashrc