Learn through the super-clean Baeldung Pro experience:
>> Membership and Baeldung Pro.
No ads, dark-mode and 6 months free of IntelliJ Idea Ultimate to start with.
Last updated: September 28, 2024
When we use Docker containers, sometimes we want to execute a command, such as running a script inside one, and then get access to the container for debugging or inspecting without manually running the script.
In this tutorial, we’ll see how to use Docker interactive mode after script execution.
Docker allows us to execute a command and maintain interactive shell access to the container in the same session. By combining the execution of a command with the interactive mode, we can run a container where a script executes automatically upon startup and then access the running container interactively. This usually happens for:
Let’s see how we can run containers while executing scripts and accessing the container.
If we want to allocate a terminal and keep the container alive for interactive access, we can use run with the -it option.
We can try this with Docker’s hello-world image:
$ docker run -it hello-world -n hello
Let’s break down the command:
We can also create an interactive container first and then start later. This is a smarter approach because we can attach several Bash sessions to a single container if we want to.
First, we create a container:
$ docker create -it hello-world --name hello
Then, second, we start it:
$ docker start hello
We have multiple options to run commands and interact with a Bash shell in the container, as we’ll also see in details later in an example. However, we can add a command while running the container with the sh -c option.
For example, if we want to run a simple Python print:
$ docker run -it python:3.9-slim sh -c "python -c 'print(\"Hello from Python\")' && exec bash"
Let’s break down the sh -c option. It uses && to chain multiple commands:
We’ll also see later how to apply this command in the Dockerfile.
Let’s look at the execution of the Docker command, where we can see the Python print and the prompt to the shell:
Hello from Python
root@1dbf38668053:/#
Let’s now see how to execute a script while running a container and access it to verify. We’ll use a Dockerfile or just the command line.
To demonstrate this, let’s create a Python script to run inside the container:
# script.py
# Add any changes here
# For example, creating a file in the container
with open("/app/output.txt", "w") as f:
f.write("This file was created by script.py inside the Docker container.\n")
The script.py file will create the output.txt file with some text.
Let’s see a Dockerfile example:
# Use a Python base image
FROM python:3.9-slim
# Set the working directory inside the container
WORKDIR /app
# Copy the Python script into the container
COPY script.py .
# Run the Python script and then drop into an interactive shell
CMD ["sh", "-c", "python script.py && exec bash"]
We can now build our image:
$ docker build -t python-interactive-mode .
Now, we can run our container:
$ docker run -it python-interactive-mode
As we have seen earlier, we can also lazily start our container:
docker create -it --name python-interactive-mode python-interactive-mode && \
docker start python-interactive-mode
Notably, in this case, we are not directly accessing the Bash shell. Therefore, we need to use the exec command:
$ docker exec -it python-interactive-mode bash
We can save time and just run Docker at the command line:
docker run -it \
-v "$(pwd)/script.py:/app/script.py" \
python:3.9-slim \
sh -c "python /app/script.py && exec bash"
Differently from what we have seen earlier, we are adding the volume to map the local file to the one we want to add to the container:
-v "$(pwd)/script.py:/app/script.py"
Whether we use a Dockerfile or the command line to run the container, we should see the prompt of the Bash shell. We can now check that our file exists and the content is correct:
root@beadfb9d2499:/app# cat output.txt
This file was created by script.py inside the Docker container.
root@beadfb9d2499:/app#
We can look at a few points for alternative approaches or refinement of what we have seen.
In our example, the python:3.9-slim Docker image will have no running process inside the container, which is different from using, for instance, a Node.js image. Therefore, once the script execution finishes and we exit the interactive shell, the container typically stops because it assumes its job is complete.
However, if we want to interact again with the container, once we exit, we can attach again a session to it:
$ docker start -ai python-interactive-mode
The -a (attach) option attaches to the container’s standard output (stdout) and standard error (stderr). With the -i option, we prompt again in the Bash shell.
Or, we can fix this issue by updating the CMD section in the Dockerfile:
# Execute the Python script and keep the container running
CMD ["sh", "-c", "python script.py && tail -f /dev/null"]
Using tail -f /dev/null is a lightweight way to keep the container running.
In the Dockerfile, we can combine ENTRYPOINT and CMD to ensure that a script always executes first and the interactive Bash session triggers afterward. This allows more flexible configurations to reuse our container with different scripts.
Likewise, let’s see how we can update the CMD section in the Dockerfile:
ENTRYPOINT ["python", "script.py"]
CMD ["bash"]
In this tutorial, we saw how to run a script inside a Docker container after its creation and access to a shell terminal. We created a Dockerfile or ran a Docker command at the command line. We also saw how to exit and re-enter the container while verifying the script execution.
As always, the complete source code of the article is available over on GitHub.