Running a Container

Running a Container

Bitnesia • Sep 8, 2026 92 •ID

After having a ready-to-use image, whether obtained via docker pull or built locally, the next step is running it into an active container. This chapter covers the docker run command thoroughly: from basic syntax, essential options such as ports, volumes, and environment variables, to the differences between running containers in background versus interactive mode. Developers needing to spin up a local database for daily development and Sysadmins or DevOps Engineers deploying services to production servers both rely on a solid understanding of docker run, as nearly all options covered here will be used repeatedly in subsequent chapters.

7.1 Docker Run Command

The docker run command is the most common way to create and start a new container from an image. Behind the scenes, this command combines two steps: Docker creates a new container from the specified image (equivalent to docker create), and then immediately starts it (equivalent to docker start). Its basic syntax is simple.

docker run [OPTIONS] IMAGE [COMMAND] [ARG...]

Try running your first container from the alpine image, a minimal Linux distribution frequently used for practice and testing due to its small size.

docker run alpine:3.20 echo "Halo dari container"

Docker displays the output Halo dari container and then the container immediately stops. This is normal behavior: as soon as the main process inside the container (in this example, the echo command) finishes executing, the container stops because there are no further active processes keeping it running. If the alpine:3.20 image is not yet available locally, Docker automatically pulls it from the registry before running the container, just like executing an implicit docker pull. Notice that the example above explicitly specifies the version tag 3.20 rather than defaulting to the latest tag, as discussed in the chapter on image naming and tagging.

Every running container receives a unique container ID and can be assigned a memorable name using the --name option. Without this option, Docker automatically assigns a random two-word name (such as happy_lovelace), which can be inconvenient when referencing it repeatedly in future commands.

docker run --name demo-alpine alpine:3.20 echo "Container dengan nama"

Container names must be unique on a single Docker host; attempting to create a new container using a name already assigned to another container (including stopped ones that have not been removed) will be rejected. Try re-running the exact same command.

docker run --name demo-alpine alpine:3.20 echo "Percobaan kedua"

Docker outputs the error docker: Error response from daemon: Conflict. The container name "/demo-alpine" is already in use by container "<container_id>". You have to remove (or rename) that container to be able to reuse that name. This message indicates that container names must be unique; remove the old container via docker rm or use a different name before trying again.

Check the list of all created containers, including stopped ones, using the -a option with docker ps.

docker ps -a
CONTAINER ID   IMAGE     COMMAND                  STATUS                     NAMES
3f9a1c2b4d5e   alpine:3.20   "echo 'Container de…"   Exited (0) 5 seconds ago  demo-alpine

Stopped containers like demo-alpine above do not automatically disappear; they remain stored on the host system along with their entire filesystem until manually removed. If a container is only needed for one-off tasks, such as executing a quick command for testing, the --rm option instructs Docker to remove the container immediately upon exiting to prevent stopped containers from accumulating.

docker run --rm alpine:3.20 echo "Container sekali pakai"

Run docker ps -a again after executing the command above; the container will not appear in the list because it has been automatically cleaned up. In practice, combining options with --rm is a standard practice for Sysadmins and DevOps Engineers when running containers for quick diagnostic or testing tasks to keep servers free of leftover stopped containers.

Clean up any remaining sample containers before proceeding to the next sub-chapter.

docker rm demo-alpine

7.2 Container Options

docker run accepts numerous options to configure how a container interacts with the external environment. The three most commonly used options in daily operations are port mapping, volume mounts, and environment variables.

7.2.1 Port Options with -p

The -p (or --publish) option maps a host port to a container port using the format HOST_PORT:CONTAINER_PORT. Pull and run the nginx image as a basic web server example.

docker run -d --name demo-nginx -p 8080:80 nginx:1.27

The command above maps port 8080 on the host machine to port 80 inside the container, which is the default port used by nginx. Access http://localhost:8080 via a browser or curl to verify that the web server is accessible from outside the container.

curl -I http://localhost:8080

An HTTP/1.1 200 OK response confirms that the port mapping is working correctly and nginx is responding normally.

A common mistake in this section is attempting to map to a host port that is already in use by another container. Try running a second container using the exact same host port.

docker run -d --name demo-nginx-2 -p 8080:80 nginx:1.27

Docker rejects the command with the error Error response from daemon: driver failed programming external connectivity on endpoint demo-nginx-2 (<endpoint_id>): Bind for 0.0.0.0:8080 failed: port is already allocated. A host port can only be mapped to one container at a time; to resolve this, use a different host port or stop the container currently occupying it. Even though it failed to start, the demo-nginx-2 container remains recorded on the host in a stopped state, so remember to remove it to avoid confusion with active containers.

docker rm demo-nginx-2

7.2.2 Volume Options with -v

The -v (or --volume) option mounts a host directory or a named volume into the container filesystem so that data written by the container persists after container removal. Comprehensive details regarding volume types and bind mounts are covered in a dedicated chapter; here the focus is on basic syntax when used with docker run.

docker run -d --name demo-nginx-vol -p 8081:80 -v nginx-data:/usr/share/nginx/html nginx:1.27

The command above creates (or reuses if it already exists) a named volume called nginx-data and mounts it to the /usr/share/nginx/html directory inside the container where nginx stores served HTML files.

Verify that the volume was created using docker volume ls.

docker volume ls
DRIVER    VOLUME NAME
local     nginx-data

The nginx-data volume remains intact even if the demo-nginx-vol container is deleted later, distinguishing it from standard container filesystems that disappear when the container is removed.

7.2.3 Environment Variable Options with -e

The -e (or --env) option injects environment variables into the container at runtime, which is useful for setting configurations without modifying or rebuilding the image. Try this with the mysql image, which requires specific environment variables to initialize.

docker run -d --name demo-mysql -e MYSQL_ROOT_PASSWORD=contoh_password_123 mysql:8.4

The MYSQL_ROOT_PASSWORD environment variable is processed by initialization scripts inside the mysql image during initial startup to set the root database password. Verify that the variable was assigned correctly using docker inspect.

docker inspect --format '{{.Config.Env}}' demo-mysql

The output displays all container environment variables, including MYSQL_ROOT_PASSWORD=contoh_password_123 injected via -e, along with default image environment variables like PATH.

When managing multiple environment variables, the --env-file option is more practical because it reads variables from a file containing KEY=VALUE pairs on each line instead of passing multiple -e flags. Create a mysql.env file containing the following line.

MYSQL_ROOT_PASSWORD=contoh_password_123
docker run -d --name demo-mysql-file --env-file ./mysql.env mysql:8.4

In production scenarios, avoid passing sensitive credentials directly on the command line via -e, as values can be captured in shell history or viewed via docker inspect by authorized host users. For production environments, consider dedicated secrets management mechanisms instead of plain environment variables.

Clean up all sample containers from this sub-chapter before continuing.

docker rm -f demo-nginx demo-nginx-vol demo-mysql demo-mysql-file
docker volume rm nginx-data

7.3 Detached vs Interactive Mode

Docker provides two main execution modes depending on application requirements: running in the background without locking the terminal, or running interactively with an active shell session.

7.3.1 Detached Mode with -d

The -d (or --detach) option runs the container in the background. The terminal returns to the prompt immediately after displaying the container ID, without waiting for the internal process to complete. This mode is the default choice for long-running services like web servers or databases designed to run continuously without direct user intervention.

docker run -d --name web-service nginx:1.27
7f8e9d0c1b2a3f4e5d6c7b8a9f0e1d2c3b4a5968...

The web-service container continues executing in the background while the terminal remains available for other commands. Check its status at any time using docker ps.

docker ps

7.3.2 Interactive Mode with -it

For different requirements, such as attaching directly to a container shell for inspection or debugging, interactive mode is required. Combining -i (--interactive, keeping STDIN open) and -t (--tty, allocating a pseudo-terminal) is typically written together as -it.

docker run -it --name demo-shell alpine:3.20 sh

The command above opens an active sh shell session inside the alpine container, and the terminal prompt changes to indicate execution inside the container. Run a few basic commands to test the session.

ls /
cat /etc/os-release
exit

The exit command terminates the shell session and stops the container simultaneously because the sh process was the sole primary process running inside the container. Without -t, the terminal can still pass input through STDIN, but output formatting and prompt rendering will be disrupted due to the missing pseudo-terminal; without -i, STDIN closes immediately, preventing input and causing the container to exit immediately upon startup.

In automated environments, Sysadmins and DevOps Engineers running docker run -it via scripts or CI/CD pipelines frequently encounter the error the input device is not a TTY. This occurs because -t requires an actual terminal connected to STDIN and STDOUT, which is absent in non-interactive CI runner environments. The solution is to omit -t (using only -i) for automated scripts, reserving -it specifically for manual terminal execution.

To access the shell of an already running container rather than starting a new one, use the docker exec command, which is detailed in the chapter on container interactions. Remove the sample containers from this sub-chapter.

docker rm -f web-service demo-shell

7.4 Port Mapping and Expose

Docker distinguishes between two concepts that are frequently confused: expose and publish. Understanding this distinction is essential for accurate container network configuration, particularly when exposing services outside the host machine.

The EXPOSE instruction in a Dockerfile serves purely as documentation between image builders and users, indicating which ports the application inside the container is designed to use. This instruction does not make the port accessible outside the container; it is merely metadata attached to the image. The --expose flag on docker run has a similar effect, recording exposed ports at runtime without publishing them to the host network interface.

docker run -d --name demo-expose --expose 9000 alpine:3.20 sleep 3600

Making a port accessible from outside the container requires publishing via the -p option discussed earlier. The -P (uppercase, --publish-all) option acts as a shortcut to publish all ports declared with EXPOSE in the Dockerfile or via --expose, mapping each to a random available port on the host.

docker run -d --name demo-nginx-random -P nginx:1.27

Check the randomly mapped ports using docker port.

docker port demo-nginx-random
80/tcp -> 0.0.0.0:32768
80/tcp -> [::]:32768

For precise and predictable port assignments required in production environments, explicitly mapping host ports with -p remains preferable to -P. The -p option can also bind ports exclusively to the host localhost rather than all network interfaces by prefixing an IP address.

docker run -d --name demo-nginx-local -p 127.0.0.1:8082:80 nginx:1.27

The container above is only accessible from the host machine itself via 127.0.0.1:8082 and not from external systems on the same network subnet. This pattern is useful for internal services that should not be directly exposed publicly, such as databases accessed exclusively by other containers over an internal Docker network.

By default, -p maps ports using the TCP protocol. To map UDP ports, explicitly append /udp to the container port specification.

docker run -d --name demo-udp -p 5353:53/udp alpine:3.20 sleep 3600

Engineers who confuse exposure and publishing often mistakenly assume that declaring EXPOSE 80 in a Dockerfile automatically makes the service externally accessible. Without applying -p during docker run, the port remains unreachable from external hosts. Always verify active port mappings using docker port <container_name> or checking the PORTS column in docker ps before verifying service connectivity.

docker ps --format "table {{.Names}}\t{{.Ports}}"

Clean up all sample containers used throughout this chapter.

docker rm -f demo-expose demo-nginx-random demo-nginx-local demo-udp
OptionFunction
--nameAssigns a custom name to the container
--rmAutomatically removes the container when it exits
-p HOST:CONTAINERPublishes container port(s) to specific host port(s)
-PPublishes all exposed ports to random host ports
--exposeExposes a port or range of ports without publishing
-vBinds a volume or bind mount to the container
-eSets environment variables in the container
-dRuns container in background (detached mode)
-itRuns container interactively with a pseudo-TTY attached