Docker has revolutionized software development and delivery by enabling containerized applications. But how do developers and sysadmins execute commands and inspect running containers?
In this hands-on guide, we‘ll deep dive into the various methods for running Linux commands within Docker containers. We‘ll also look at real-world examples, best practices, tips and tricks. Let‘s get started!
Why Container Commands Matter
Before we jump into the methods, it‘s important to understand why running commands in Docker containers is useful:
- Debugging – Executing
ps,ls,grephelps debug issues and inspect runtime environments. - Checking Versions – Verify installed software like MySQL, Nginx, Java versions by querying containers.
- One-time Setup – Run initialization commands during container startup like copying files or loading data.
- Process Management – Start long-running processes like Cron jobs and queue workers inside containers.
- Container Administration – commands like
df,free,iptableshelp manage and monitor containers. - Automation – Scripts can run commands in containers to control deployments and workflows.
According to Docker‘s 2022 survey, over 65% of organizations are running Docker in production. Common operations like debugging, process management, and automation require running Linux commands within the containers.
Getting an Interactive Shell Session
The most straightforward way to run commands is to start an interactive bash or sh shell inside the container. The two main methods are using docker run -it and docker exec -it.
docker run -it
Use the -it flags with docker run to start a new container and jump into its shell right away:
$ docker run -it ubuntu bash
root@d9b100f2f636:/#
This will fire up an Ubuntu container, start bash, and give you an interactive terminal. You can now run multiple commands like:
root@d9b100f2f636:/# pwd
/
root@d9b100f2f636:/# ls /etc
adduser.conf alternatives cron.daily environment kernel lsb-release network pm security ucf.conf
apm anacrontab cron.hourly exports kernel-img.conf lvm opt ppp services udev
bash.bashrc apache2 cron.monthly fstab ld.so.conf manpath.config passwd profile shells update-motd.d
...
Some other examples of using docker run -it:
- Start a CentOS container to yum install packages:
$ docker run -it centos yum install -y httpd
- Run Redis CLI client inside a new Redis container:
$ docker run -it redis redis-cli
- Open a Django shell in a Python container to query the database:
$ docker run -it my-django-image ./manage.py shell
So docker run -it allows spinning up containers and entering their shell in one command.
docker exec -it
If you already have containers running in the background, you can open an interactive shell in any of them with docker exec -it:
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
a871ad21ab12 nginx "nginx -g ‘daemon of..." About a minute ago Up About a minute 0.0.0.0:80->80/tcp, :::80->80/tcp focused_cori
$ docker exec -it a871ad21ab12 bash
root@a871ad21ab12:/#
This will start a bash session in the running Nginx container. You can now run multiple commands like checking nginx version, viewing config files, logs etc.
Some other examples:
- Open a
mysqlclient inside a MySQL container:
$ docker exec -it mydb mysql -uroot -p
- Tail Apache logs inside a container:
$ docker exec -it webapp tail -f /var/log/apache2/access.log
- Debug a Node.js app by starting a Node REPL:
$ docker exec -it node-app node
So docker exec -it allows entering a running container for troubleshooting or configuration.
Note: If the container uses
shinstead ofbash, substitute that in the command.
Pros and Cons
Interactive shells allow running multiple commands, inspecting logs, editing files. They provide unrestricted access to the container.
However, shells leave containers in a running state even after exiting. Repeated shells can accumulate many unused containers. Direct commands often work better.
Running One-off Commands
For running quick, one-time commands inside containers, use docker exec without -it:
$ docker exec webapp ps aux
$ docker exec db cat /var/log/mysql.log
$ docker exec redis redis-cli INFO
This executes the given command and prints its output without entering an interactive shell.
Some examples:
- Check running processes in a container:
$ docker exec webapp ps aux
- Get disk usage stats:
$ docker exec mongo df -h
- Find a text pattern in Nginx logs:
$ docker exec web grep "404" /var/log/nginx/error.log
- List Python packages installed in a container:
$ docker exec flask pip list
So docker exec allows running one-off commands and scripts without side effects. This is preferred over shells in many cases like CI/CD scripts, monitoring, and automation.
According to Docker‘s survey, over 40% of organizations are automating container deployments with CI/CD. Tools like Jenkins, GitHub Actions, Travis CI often run exec to interact with containers.
Pros and Cons
One-off exec allows quick commands without lingering effects. But you can only run a single command, not multiple like in shells.
Dockerfile RUN Instruction
Dockerfiles include a RUN instruction that executes commands during the image build process:
FROM ubuntu
RUN apt-get update
RUN apt-get install -y nginx
RUN nginx -v
The RUN commands run sequentially inside the container and commit the results into the image.
Some common examples:
- Install required packages:
RUN apt-get install -y python3 pip
- Execute complex shell commands:
RUN /bin/bash -c ‘source $HOME/.bashrc; echo $HOME‘
- Run configuration management tools like Ansible:
RUN ansible-playbook /playbook.yaml
So RUN allows baking commands into immutable container images. But RUN only runs during docker build, not in running containers.
Pros and Cons
RUN allows preparing images with packages, configs pre-baked. But it does not help manage production containers.
Comparison of Methods
Here is a quick comparison of the main methods for running Docker commands:
| Method | Interactive | Persistent | Use Case |
|---|---|---|---|
| docker run -it | Yes | No | Starting new containers |
| docker exec -it | Yes | No | Entering running containers |
| docker exec | No | No | One-off commands |
| Dockerfile RUN | No | Yes | Building images |
Best Practices
When running commands in Docker, keep these best practices in mind:
- Avoid SSH – Rather than SSHing into containers, use Docker exec.
- Immutable Images – Bake commands into images through Dockerfile RUN instead of changing running containers.
- Environments over Commands – Pass configurations through environments instead of interactive commands during start.
- Processes Belong in Services – Avoid running long-lived processes via containers‘ interactive shell. Define them in Docker Compose instead.
- Security – Don‘t blindly run commands from unverified sources. Restrict shell access.
Adhering to these best practices will keep your Docker environment clean and secure.
Real-World Debugging Examples
Here are some real-world examples of how container commands are useful based on my experience running Docker in production:
-
Slow Application – When a Ruby app slowed down, I checked CPU and memory inside the container with
docker execand discovered a memory leak. Restarting the container fixed it. -
Configuration Issues – A Node.js app broke after deploy. I used
docker execto inspect environment variables and logs, identifying a missing config value. -
Network Errors – When containers couldn‘t reach the network, I ran
ifconfiginside them to confirm missing IPs. Restarting the Docker daemon brought the network back up. -
Docker Hangs – Debugging a Docker hang, I used
docker execto check processes and logs inside the Docker daemon container itself, uncovering file descriptor limits needed tuning.
So container commands are invaluable for debugging production issues.
Integrating Commands into Deployments
Running container commands extends beyond interactive use. They are commonly used as part of automated application deployments.
For example, a CI/CD pipeline may:
- Build a Docker image with application code
- Run integration tests inside a container using
docker exec - Push image to registry if tests pass
- Pull image on production servers
- Run one-time
docker execfor setup like database migrations - Restart running containers to use new image
This allows deployments to automate and orchestrate containers using commands.
Tools like Kubernetes, Docker Swarm, Amazon ECS allow running commands on clusters of containers. Command-line integration is essential for DevOps.
Comparison with Virtual Machines
It‘s useful to contrast containers with traditional virtual machines (VMs):
- Containers are lightweight allowing commands to start instantly. VMs take longer to boot up.
- Containers are immutable and replaced across deployments. VMs are mutable leading to configuration drift.
- Docker guarantees availability of OS commands. VMs may have missing packages or dependencies.
- Containers have isolated environments per app. VMs share underlying host resources.
- Docker provides standard commands and arguments across all containers. VMs have custom configurations.
So while VMs provide full virtualization, containers are better suited for modern automation and microservices by design.
Alternative Container Runtimes
While Docker is the most popular, there are alternatives container runtimes:
- LXC – Low-level Linux container API. More difficult to use than Docker but very lightweight.
- runc – The container runtime embedded within Docker itself. Allows spawning containers without Docker.
- systemd-nspawn – Container runtime built into systemd. Integrated with Linux init system.
- rkt – Secure pod-native container engine from CoreOS. Focus on clusters and production.
However, all support similar commands for interacting with containers in principle. Docker strike the best balance of usability and production suitability for most use cases.
Supporting Windows and Mac Environments
Traditionally, Docker required a Linux environment to run containers natively. But newer versions include embedded Linux VMs to run containers on MacOS and Windows:
- Docker Desktop for Mac – MacOS app packing Docker Engine in a tiny Linux VM. Supports all native Docker capabilities.
- Docker Desktop for Windows – Windows app using the Linux Hyper-V VM. Similarly full-featured.
This allows developers on laptops to build and run containers with native performance. All CLI commands work uniformly across Linux, MacOS and Windows thanks to built-in virtualization.
Key Takeaways
We covered a lot of ground here. Let‘s recap the key takeaways:
- Interactive Shells – Great for exploring and debugging containers but leave containers running.
- One-off Commands – Ideal for automation, deployments, single operations.
- Dockerfile RUN – Allows baking commands into immutable container images.
- Best Practices – Favor environments, services, immutable images over container command hacks.
- Production Value – Commands are indispensable for monitoring, managing, and operating containers at scale.
- Standard Interfaces – Docker provides uniform CLI and APIs across environments.
Conclusion
I hope this guide gave you a comprehensive overview of running commands within Docker containers. We saw how critical they are for debugging and automating containers.
Here are some next steps to apply these concepts:
- Try out the various methods hands-on with some sample containers
- Incorporate useful commands into your Docker build and deployment workflows
- Follow the best practices around immutability and environments
- Check out the official Docker documentation for even more examples
Let me know if you have any other use cases for running commands with Docker! I‘m happy to discuss more Docker best practices.