A closer look at commands and args in Docker containers
Tags: devops, docker, containers
Published: 2021-06-22 12:12:33

---
title: A closer look at commands and args in Docker containers
published: true
date: 2021-06-22 12:12:00 UTC
tags: devops, docker, containers
cover_image: https://sahansera.dev/static/afd2b98ee600abec38ffd661a5bbfc0b/dcbba/closer-look-at-docker-commands-args.webp
canonical_url: https://sahansera.dev/closer-look-at-docker-commands-args/
---

Today we will be looking at how we can make use of commands and args in Docker to run our own processes when we spin up containers. This could be useful if you want to run one-off tasks without having to create your own images.

Let’s imagine that we want run a bash command. What’s the easiest way to do this? Just by spinning up a container using a lightweight image like busybox, ubuntu, debian? For instance, let’s say we use Debian as our base image.

```bash
docker run debian echo hello
```

We will get back “hello”, which is expected. What would happen if we check if the container is running?

![closer-look-at-docker-commands-args-1.png](https://sahansera.dev/static/f95d3de0aaad7b5732e819a67d288262/5a190/closer-look-at-docker-commands-args-1.png "closer-look-at-docker-commands-args-1.png")

The container has stopped running. Containers are not meant to host an operating system compared to a VM. When you run a basic container like Debian or Ubuntu, it will exit once you perform a `docker run debian`

However, in cases like Nginx, or Redis they will keep running unless you shut it down or it crashes for some reason. How does this happen?

### Under the hood

Let’s have a look at their `Dockerfile`s. Note that these are oversimplified versions of these files (except for Debian).

![closer-look-at-docker-commands-args-2.jpg](https://sahansera.dev/static/a58c3692b8f52023dda40fc11ff10a99/4b190/closer-look-at-docker-commands-args-2.jpg "closer-look-at-docker-commands-args-2.jpg")

Each of these files defines a `CMD` instruction at the bottom which tells them to run some command. In the case of Debian, it issues just `bash` which is just a shell, not a process. If you already spotted, both `Redis` and `nginx` Dockerfiles have definitions to spin up their processes - the Redis server and Nginx web server, respectively.

### The `CMD` instruction

You would be wondering how would one go about customising which commands to run when you spin up a container. One way to specify commands when you start a container is by issuing the name of the executable when we run the container. For example,

```bash
docker run debian echo hello-world
```

If you check the container status, you will see that your container has stopped. Can we make this permanent? Yes, that’s why we need to have a Dockerfile to specify what’s our desired state when the container runs.

Say we use the `CMD` instruction in our Dockerfile, there are 3 ways to specify this according to [Docker docs](https://docs.docker.com/engine/reference/builder/#cmd).

- `CMD ["executable","param1","param2"]` (_exec_ form, this is the preferred form)
- `CMD ["param1","param2"]` (as _default parameters to ENTRYPOINT_)
- `CMD command param1 param2` (_shell_ form)

> 💡 There can only be one CMD instruction in a Dockerfile. If you list more than one CMD then only the last CMD will take effect.

[Test1.Dockerfile](https://github.com/sahansera/DockerCommandsAndArgs/blob/main/Test1.Dockerfile)

```bash
FROM debian
CMD ["printf", "Hello from Test1"]
```

How can we dynamically define what gets printed? One caveat here is that if we are to pass in command line args it _will not get appended_ to the existing CMD instruction we have set. Docker will try to execute as a command and our CMD instruction will get replaced. Let’s give this a test.

If you run `docker run test1 hello`, it will result in a “starting container process caused: exec: “hello”: executable file not found in $PATH: unknown.” error.

![closer-look-at-docker-commands-args-3.png](https://sahansera.dev/static/53ecb5794a150e415c6de7f322750391/5a190/closer-look-at-docker-commands-args-3.png "closer-look-at-docker-commands-args-3.png")

We can still pass in a command like so: `docker run test1 printf hello` but that beats the purpose of having a Dockerfile in the first place.

### The `ENTRYPOINT` instruction

How can we specify something to run always so that we only need to specify its arguments. Let’s create another file called Test2.Dockerfile.

[Test2.Dockerfile](https://github.com/sahansera/DockerCommandsAndArgs/blob/main/Test2.Dockerfile)

```bash
FROM debian
ENTRYPOINT ["printf", "Hello from %s\n"]
CMD ["Test2"]
```

The `ENTRYPOINT` instruction says Docker that whatever we have specified there, must be run when the container starts. In other words, if we are to pass in arguments, they will get _appended_ to what we have specified there as the ENTRYPOINT.

```bash
docker build -t test -f Test2.Dockerfile .
```

If we run this now, we get the following.

![closer-look-at-docker-commands-args-4.png](https://sahansera.dev/static/dbb90d816be54985423774870e4ba81f/5a190/closer-look-at-docker-commands-args-4.png "closer-look-at-docker-commands-args-4.png")

Cool! If we pass in a parameter now, it gets picked up and _replaces_ the `CMD` instruction we had at line no. 3; but it will still show the output as we have defined in our ENTRYPOINT. This makes sense since there can be only one CMD instruction per container.

![closer-look-at-docker-commands-args-5.png](https://sahansera.dev/static/f0d79600acb0ae4c0db45455f0332fe7/5a190/closer-look-at-docker-commands-args-5.png "closer-look-at-docker-commands-args-5.png")

You would be thinking what’s the purpose of having CMD if it gets replaced? It’s really handy when you want to specify a default value.

What would happen if we specify multiple arguments?

![closer-look-at-docker-commands-args-6.png](https://sahansera.dev/static/83ffc7d92c4cf7e05b3c11f080e299a2/5a190/closer-look-at-docker-commands-args-6.png "closer-look-at-docker-commands-args-6.png")

What happend here? Let me know in the comments below what are your thoughts on this 😊

### Conclusion

In this article we looked at passing in commands and args to container when we spin them up. In the next article, we will compare this to a Kubernetes Pod definition and figure out how we can do the same.

### References

[https://docs.docker.com/engine/reference/builder/](https://docs.docker.com/engine/reference/builder/)