How to log all the processes running inside a Docker container? - docker

After having logged into the container using the command -
docker exec -it <container_name>
How do I check for all the processes running inside the container? Is "ps aux" the correct way to do it? Are there any better alternatives/approaches?

You can use dedicated command top to list process in docker container, regardless of the operating system in container.
docker top <container>

It is possible to show all the processes running inside a container without login to terminal by using the following command. Of course, it is just like how one can see by using ps -eaf, so just add it to docker exec.
bash $ sudo docker exec -it test1 ps -eaf
PID USER TIME COMMAND
1 root 0:00 sh
7 root 0:00 sh
60 root 0:00 /bin/sh
67 root 0:00 /bin/sh
84 root 0:00 ps -eaf
Like it was mentioned, if you are already inside of a container, then just use ps -eaf command to see the running processes.
By the way, it is recommended to have one user application / process per container.

Extending from the answer of #Slawomir
And With ps option, docker top [--help] CONTAINER [ps OPTIONS]
docker top <container_id> -eo pid,cmd

Related

Get stats for all processes in a container

I am interested in getting the cpu and mem info for each individual process in a container. I know docker stats gives me the info for the entire container and docker container top tells me the processes in a container. Is it possible to combine these two actions and get the stats for each process in a container?
One option would be to use the ps command inside the container. I looked into using htop, but I believe that's designed to be used interactively:
# start example ubuntu container
docker run -d --name ubuntu ubuntu:latest tail -f /dev/null
# execute ps aux inside container
docker exec -it ubuntu ps aux
Output:
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
root 1 0.0 0.0 2548 516 ? Ss 15:41 0:00 tail -f /dev/nu
root 7 0.0 0.1 5892 2924 pts/0 Rs+ 15:42 0:00 ps aux

Docker ssh, back to container showing unexpected results

I'm studying the Docker documentation, but I'm having a hard time understanding the concept of creating a container, ssh, and ssh back.
I created a container with
docker run -ti ubuntu /bin/bash
Then, it starts the container and I can run commands. docker ps gives me
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
0e37da213a37 ubuntu "/bin/bash" About a minute ago Up About a minute keen_sammet
The issue is after I exit the container I can't ssh back.
I tried docker attach that gives me Error: No such container and I tried docker exec -ti <container>/bin/bash that gives me the same message Error: No such container
How do I run and ssh back to the container?
When you exit the bash process, the container exits (in general, a container will exit when the foreground process exits). The error message you are seeing is accurately describing the situation (the container is no longer running).
If you want to be able to docker exec into a container, you will want to run some sort of persistent command. For example, if you were to run:
docker run -ti -d --name mycontainer ubuntu bash
This would start a "detached" container. That means you've started bash, but it's just hanging around doing nothing. You could use docker exec to start a new process in this container:
$ docker exec -it mycontainer ps -fe
UID PID PPID C STIME TTY TIME CMD
root 1 0 0 16:28 pts/0 00:00:00 bash
root 17 0 0 16:28 pts/1 00:00:00 ps -fe
Or:
$ docker exec -it mycontainer bash
There's really no reason to start bash as the main process in this case, since you're not interacting with it. You can just as easily run...
docker run -ti -d --name mycontainer ubuntu sleep inf
...and the behavior would be the same.
The most common use case for all of this is when your docker run command starts up some sort of persistent service (like a web server, or a database server, etc), and then you use docker exec to perform diagnostic or maintenance tasks.
The docker attach command will re-connect you with the primary console of a detached container. In other words, if we return to the initial example:
docker run -ti -d --name mycontainer ubuntu bash
You could connect to that bash process (instead of starting a new one) by running:
docker attach mycontainer
At this point, exit would cause the container to exit.
First, you don't ssh to a docker container (unless you have a sshd process in that container). But you can execute a command with docker exec -ti mycontainer bash -l
But you can exec a command only on running container. If the container exited already you must use another approach : create an image from the container and run a new one.
Here is an example. First I create a container and create a file within then I exit it.
$ docker run -ti debian:9-slim bash -l
root#09f889e80153:/# echo aaaaaaaaaa > /zzz
root#09f889e80153:/# cat /zzz
aaaaaaaaaa
root#09f889e80153:/# exit
logout
As you can see the container is exited (Exited (0) 24 seconds ago)
$ docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
09f889e80153 debian:9-slim "bash -l" 45 seconds ago Exited (0) 24 seconds ago thirsty_hodgkin
So I create a new image with docker commit
$ docker commit 09f889e80153 bla
sha256:6ceb88470326d2da4741099c144a11a00e7eb1f86310cfa745e8d3441ac9639e
So I can run a new container that contains previous container content.
$ docker run -ti bla bash -l
root#479a0af3d197:/# cat zzz
aaaaaaaaaa

docker exec. What if there is no shell process?

docker exec <container> <command>.
In the documentation it is written:
Run a command in a running container
But what does it mean exactly? What does it mean to execute a command in container. I can't imagine a situation that exec command is executed by a shell run in the container. But we cannot assume that every container has run shell or shell at whole.
The docker exec <container> <command> will run given command in the namespaces of the specified container. The docker exec creates new process and sets its namespaces to container's namespaces and after that executes command.
More on Linux namespaces can be found here:
Namespaces in operation
Namespaces of a process can be found using the following command:
sudo ls -l /proc/<PID>/ns
A container is an isolated environment for your process, with its own network environment, mounted filesystems, namespaced process list, etc. When you perform a docker run you create this namespace by running a command as pid 1. When you perform a docker exec you can run any command inside this same namespace. E.g.:
$ docker run --name test-exec -d busybox tail -f /dev/null
5e77cec13293e7146dac6858ed11be1e6a706ba973c419435303f4ec8c346e2d
$ docker exec test-exec ps -ef
PID USER TIME COMMAND
1 root 0:00 tail -f /dev/null
6 root 0:00 ps -ef
Note that in neither of the above commands did I even run a shell.

Stop a running Docker container by sending SIGTERM

I have a very very simple Go app listening on port 8080
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(200)
w.Header().Set("Content-Type", "text-plain")
w.Write([]byte("Hello World!"))
})
log.Fatal(http.ListenAndServe(":8080", http.DefaultServeMux))
I install it in a Docker container and start it like so:
FROM golang:alpine
ADD . /go/src/github.com/myuser/myapp
RUN go install github.com/myuser/myapp
ENTRYPOINT ["/go/bin/myapp"]
EXPOSE 8080
I then run the container using docker run:
docker run --publish 8080:8080 first-app
I expect that, like most programs, I can send a SIGTERM to the process running docker run and this will cause the container to stop running. I observe that sending SIGTERM has no effect, and instead I need to use a command like docker kill or docker stop.
Is this intended behavior? I've asked in the forums and on IRC and gotten no answer.
Any process run with docker must handle signals itself.
Alternatively use the --init flag to run the tini init as PID 1
The sh shell can become the PID 1 process depending on how you specify a command (CMD).
Detail
A SIGTERM is propagated by the docker run command to the Docker daemon by default but it will not take effect unless the signal is specifically handled in main process being run by Docker.
The first process you run in a container will have PID 1 in that containers context. This is treated as a special process by the linux kernel. It will not be sent a signal unless the process has a handler installed for that signal. It is also PID 1's job to forward signals onto other child processes.
docker run and other commands are API clients for the Remote API hosted by the docker daemon. The docker daemon runs as a seperate process and is the parent for the commands you run inside a container context. This means that there is no direct sending of signals between run and the daemon, in the standard unix manner.
The docker run and docker attach command have a --sig-proxy flag that defaults signal proxying to true. You can turn this off if you want.
docker exec does not proxy signals.
In a Dockerfile, be careful to use the "exec form" when specifying CMD and ENTRYPOINT defaults if you don't want sh to become the PID 1 process (Kevin Burke):
CMD [ "executable", "param1", "param2" ]
Signal Handling Go Example
Using the sample Go code here: https://gobyexample.com/signals
Run both a regular process that doesn't handle signals and the Go daemon that traps signals and put them in the background. I'm using sleep as it's easy and doesn't handle "daemon" signals.
$ docker run busybox sleep 6000 &
$ docker run gosignal &
With a ps tool that has a "tree" view, you can see the two distinct process trees. One for the docker run process under sshd. The other for the actual container processes, under docker daemon.
$ pstree -p
init(1)-+-VBoxService(1287)
|-docker(1356)---docker-containe(1369)-+-docker-containe(1511)---gitlab-ci-multi(1520)
| |-docker-containe(4069)---sleep(4078)
| `-docker-containe(4638)---main(4649)
`-sshd(1307)---sshd(1565)---sshd(1567)---sh(1568)-+-docker(4060)
|-docker(4632)
`-pstree(4671)
The details of docker hosts processes:
$ ps -ef | grep "docker r\|sleep\|main"
docker 4060 1568 0 02:57 pts/0 00:00:00 docker run busybox sleep 6000
root 4078 4069 0 02:58 ? 00:00:00 sleep 6000
docker 4632 1568 0 03:10 pts/0 00:00:00 docker run gosignal
root 4649 4638 0 03:10 ? 00:00:00 /main
Killing
I can't kill the docker run busybox sleep command:
$ kill 4060
$ ps -ef | grep 4060
docker 4060 1568 0 02:57 pts/0 00:00:00 docker run busybox sleep 6000
I can kill the docker run gosignal command that has the trap handler:
$ kill 4632
$
terminated
exiting
[2]+ Done docker run gosignal
Signals via docker exec
If I docker exec a new sleep process in the already running sleep container, I can send an ctrl-c and interrupt the docker exec itself, but that doesn't forward to the actual process:
$ docker exec 30b6652cfc04 sleep 600
^C
$ docker exec 30b6652cfc04 ps -ef
PID USER TIME COMMAND
1 root 0:00 sleep 6000 <- original
97 root 0:00 sleep 600 <- execed still running
102 root 0:00 ps -ef
So there are two factors at play here:
1) If you specify a string for an entrypoint, like this:
ENTRYPOINT /go/bin/myapp
Docker runs the script with /bin/sh -c 'command'. This intermediate script gets the SIGTERM, but doesn't send it to the running server app.
To avoid the intermediate layer, specify your entrypoint as an array of strings.
ENTRYPOINT ["/go/bin/myapp"]
2) I built the app I was trying to run with the following string:
docker build -t first-app .
This tagged the container with the name first-app. Unfortunately when I tried to rebuild/rerun the container I ran:
docker build .
Which didn't overwrite the tag, so my changes weren't being applied.
Once I did both of those things, I was able to kill the process with ctrl+c, and bring down the running container.
A very comprehensive description of this problem and the solutions can be found here:
https://vsupalov.com/docker-compose-stop-slow
In my case, my app expects to receive SIGTERM signal for graceful shutdown didn't receive it because the process started by a bash script which called from a dockerfile in this form: ENTRYPOINT ["/path/to/script.sh"]
so the script didn't propagate the SIGTERM to the app.
The solution was to use exec from the script run the command that starts the app:
e.g. exec java -jar ...

How do I run a command on an already existing Docker container?

I created a container with -d so it's not interactive.
docker run -d shykes/pybuilder bin/bash
I see that the container has exited:
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
d6c45e8cc5f0 shykes/pybuilder:latest "bin/bash" 41 minutes ago Exited (0) 2 seconds ago clever_bardeen
Now I would like to run occasional commands on the machine and exit. Just to get the response.
I tried to start the machine. I tried attaching. I thought I could call run with a container, but that does not seem to be allowed. Using start just seems to run and then exist quickly.
I'd like to get back into interactive mode after exiting.
I tried:
docker attach d6c45e8cc5f0
But I get:
2014/10/01 22:33:34 You cannot attach to a stopped container, start it first
But if I start it, it exits anyway. Catch 22. I can't win.
In October 2014 the Docker team introduced docker exec command: https://docs.docker.com/engine/reference/commandline/exec/
So now you can run any command in a running container just knowing its ID (or name):
docker exec -it <container_id_or_name> echo "Hello from container!"
Note that exec command works only on already running container. If the container is currently stopped, you need to first run it with the following command:
docker run -it -d shykes/pybuilder /bin/bash
The most important thing here is the -d option, which stands for detached. It means that the command you initially provided to the container (/bin/bash) will be run in the background and the container will not stop immediately.
Your container will exit as the command you gave it will end. Use the following options to keep it live:
-i Keep STDIN open even if not attached.
-t Allocate a pseudo-TTY.
So your new run command is:
docker run -it -d shykes/pybuilder bin/bash
If you would like to attach to an already running container:
docker exec -it CONTAINER_ID /bin/bash
In these examples /bin/bash is used as the command.
So I think the answer is simpler than many misleading answers above.
To start an existing container which is stopped
docker start <container-name/ID>
To stop a running container
docker stop <container-name/ID>
Then to login to the interactive shell of a container
docker exec -it <container-name/ID> bash
To start an existing container and attach to it in one command
docker start -ai <container-name/ID>
Beware, this will stop the container on exit. But in general, you need to start the container, attach and stop it after you are done.
To expand on katrmr's answer, if the container is stopped and can't be started due to an error, you'll need to commit it to an image. Then you can launch bash in the new image:
docker commit [CONTAINER_ID] temporary_image
docker run --entrypoint=bash -it temporary_image
Some of the answers here are misleading because they concern containers that are running, not stopped.
Sven Dowideit explained on the Docker forum that containers are bound to their process (and Docker can't change the process of a stopped container, seemingly due at least to its internal structure: https://github.com/docker/docker/issues/1437). So, basically the only option is to commit the container to an image and run it with a different command.
See https://forums.docker.com/t/run-command-in-stopped-container/343
(I believe the "ENTRYPOINT with arguments" approach wouldn't work either, since you still wouldn't be able to change the arguments to a stopped container.)
I had to use bash -c to run my command:
docker exec -it CONTAINER_ID bash -c "mysql_tzinfo_to_sql /usr/share/zoneinfo | mysql mysql"
Creating a container and sending commands to it, one by one:
docker create --name=my_new_container -it ubuntu
docker start my_new_container
// ps -a says 'Up X seconds'
docker exec my_new_container /path/to/my/command
// ps -a still says 'Up X+Y seconds'
docker exec my_new_container /path/to/another/command
If you are trying to run shell script, you need run it as bash.
docker exec -it containerid bash -c /path/to/your/script.sh
This is a combined answer I made up using the CDR LDN answer above and the answer I found here.
The following example starts an Arch Linux container from an image, and then installs git on that container using the pacman tool:
sudo docker run -it -d archlinux /bin/bash
sudo docker ps -l
sudo docker exec -it [container_ID] script /dev/null -c "pacman -S git --noconfirm"
That is all.
Pipe a command to docker exec bash stdin
Must remove the -t for it to work:
echo 'touch myfile' | docker exec -i CONTAINER_NAME bash
This can be more convenient that using CLI options sometimes.
Tested with:
docker run --name ub16 -it ubuntu:16.04 bash
then on another shell:
echo 'touch myfile' | docker exec -i ub16 bash
Then on first shell:
ls -l myfile
Tested on Docker 1.13.1, Ubuntu 16.04 host.
I would like to note that the top answer is a little misleading.
The issue with executing docker run is that a new container is created every time. However, there are cases where we would like to revisit old containers or not take up space with new containers.
(Given clever_bardeen is the name of the container created...)
In OP's case, make sure the docker image is first running by executing the following command:
docker start clever_bardeen
Then, execute the docker container using the following command:
docker exec -it clever_bardeen /bin/bash
I usually use this:
docker exec -it my-container-name bash
to continuously interact with a running container.
Assuming the image is using the default entrypoint /bin/sh -c, running /bin/bash will exit immediately in daemon mode (-d). If you want this container to run an interactive shell, use -it instead of -d. If you want to execute arbitrary commands in a container usually executing another process, you might want to try nsenter or nsinit. Have a look at https://blog.codecentric.de/en/2014/07/enter-docker-container/ for the details.
Unfortunately it is impossible to override ENTRYPOINT with arguments with docker run --entrypoint to achieve this goal.
Note: you can override the ENTRYPOINT setting using --entrypoint, but
this can only set the binary to exec (no sh -c will be used).
For Mac:
$ docker exec -it <container-name> sh
if you want to connect as root user:
$ docker exec -u 0 -it <container-name> sh
Simple answer: start and attach at the same time. In this case you are doing exactly what you asked for.
docker start <CONTAINER_ID/CONTAINER_NAME> && docker attach <CONTAINER_ID/CONTAINER_NAME>
make sure to change <CONTAINER_ID/CONTAINER_NAME>
I am running windows container and I need to look inside the docker container for files and folder created and copied.
In order to do that I used following docker entrypoint command to get the command prompt running inside the container or attach to the container.
ENTRYPOINT ["C:\\Windows\\System32\\cmd.exe", "-D", "FOREGROUND"]
That helped me both to the command prompt attach to container and to keep the container a live. :)
# docker exec -d container_id command
Ex:
# docker exec -d xcdefrdtt service jira stop
A quick way to resume and access the most recently exited container:
docker start -a -i `docker ps -q -l`
An easy solution that solved a similar problem for me:
docker run --interactive --tty <name_of_image>

Resources