Baeldung Pro – Ops – NPI EA (cat = Baeldung on Ops)
announcement - icon

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.

Partner – Orkes – NPI EA (cat=Kubernetes)
announcement - icon

Modern software architecture is often broken. Slow delivery leads to missed opportunities, innovation is stalled due to architectural complexities, and engineering resources are exceedingly expensive.

Orkes is the leading workflow orchestration platform built to enable teams to transform the way they develop, connect, and deploy applications, microservices, AI agents, and more.

With Orkes Conductor managed through Orkes Cloud, developers can focus on building mission critical applications without worrying about infrastructure maintenance to meet goals and, simply put, taking new products live faster and reducing total cost of ownership.

Try a 14-Day Free Trial of Orkes Conductor today.

1. Overview

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.

2. Use Docker for Interactive Mode and Command 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:

  • Debugging
  • Checking the state of the application
  • Making manual tweaks or inspecting the environment

Let’s see how we can run containers while executing scripts and accessing the container.

2.1. Run in Interactive Mode

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:

  • docker run: This is the basic command to run a container from a specified image. If we don’t specify a name (–n or ––name parameter), docker will create one for us.
  • -i (interactive): This option keeps the container’s standard input (STDIN) open, allowing us to interact with the running container even after executing a script.
  • -t (pseudo-TTY): Allocates a terminal interface necessary for interactive processes like a Bash shell. It lets us see the output and interact with the container like a terminal.

2.2. Create in Interactive Mode and Start

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

2.3. Command Execution and Bash

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:

  • python -c: This will execute a Python command.
  • exec bash: This command will open a Bash shell, allowing us to continue working interactively.

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:/#

4. Example of Interactive Mode and Script Execution

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.

4.1. Use Dockerfile

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

4.2. Use the Command Line

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"

4.3. Verify Inside the Container

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# 

5. Alternative Approaches

We can look at a few points for alternative approaches or refinement of what we have seen.

5.1. Interact When Container Exits After Script Execution

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.

5.2. Use ENTRYPOINT and CMD

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"]

6. Conclusion

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.