You have an image — now you need to run it. In this article we will walk through the docker run command, the flags you use every day, and what happens to a container after it starts: how to view logs, step inside, and stop it cleanly.
What happens on start
When you type docker run, Docker creates a container from the image — an isolated process with its own file system, network, and environment variables — and starts it.
Short formula: an image is the recipe, a container is the cooked dish.
The simplest run:
docker run eclipse-temurin:21-jre java -version
Docker pulls the image (if it is not present locally), creates a container, runs the command, and exits. The container stops as soon as the process inside it finishes.
Core docker run flags
Most real-world runs use several flags together. Let's go through each one.
-p: port mapping
A container lives in an isolated network — you cannot reach it from the outside until you explicitly open a port.
docker run -p 8080:8080 my-spring-app
# ^ ^
# host:container
The left side is the port on your machine (the host), the right side is the port inside the container. You can use different numbers:
docker run -p 9090:8080 my-spring-app # the app listens on 8080, reachable from outside on 9090
-e: environment variables
This is the main way to pass configuration into a container — database passwords, URLs of external services, Spring Boot profiles. Each variable is a separate -e flag:
docker run \
-e SPRING_PROFILES_ACTIVE=prod \
-e DB_URL=jdbc:postgresql://db:5432/myapp \
-e DB_PASSWORD=secret \
my-spring-app
Inside Spring Boot these variables are automatically picked up as application properties (through Environment).
-d: detached mode
By default docker run keeps the terminal busy — the output goes straight to the console. The -d (detached) flag runs the container in the background and returns control immediately:
docker run -d -p 8080:8080 my-spring-app
Docker prints the container id and that's it. You view logs separately — more on that below.
--name: container name
By default Docker makes up names like elegant_hopper — not very convenient. Set your own:
docker run -d --name my-app -p 8080:8080 my-spring-app
Now you can refer to the container by name in every command: docker logs my-app, docker stop my-app.
--rm: auto-remove
If you need the container only once (to run a test, execute a script), the --rm flag removes it automatically when it stops:
docker run --rm my-spring-app java -jar app.jar --check-config
Without --rm, stopped containers pile up and take up space.
Everything together — a typical run
docker run -d \
--name my-app \
--rm \
-p 8080:8080 \
-e SPRING_PROFILES_ACTIVE=prod \
-e DB_URL=jdbc:postgresql://db:5432/myapp \
my-spring-app:1.0
Passing configuration through environment variables
In the container world, configuration is not stored inside the image — it comes from outside at run time. This is an idea from the 12-factor app methodology: the same image is deployed across different environments (development, testing, production) with different variables.
For Spring Boot it looks like this: in application.yml you write ${DB_URL}, and you pass the actual value through -e DB_URL=... when you start the container. No secret ever ends up in the image.
If there are many variables, it is convenient to move them into a file:
# .env
SPRING_PROFILES_ACTIVE=prod
DB_URL=jdbc:postgresql://db:5432/myapp
DB_PASSWORD=secret
docker run -d --env-file .env -p 8080:8080 my-spring-app
Just don't commit a .env with real passwords into the repository.
The container lifecycle
After it starts, a container moves through several states.
Commands for managing it:
docker ps # list of running containers
docker ps -a # all of them, including stopped
docker stop my-app # graceful stop (SIGTERM, then SIGKILL after 10s)
docker start my-app # start a stopped container
docker rm my-app # remove a stopped container
docker rm -f my-app # stop and remove at once
docker stop sends the process a SIGTERM signal — the application can catch it and shut down cleanly (close database connections, wait for current requests). After 10 seconds Docker forcibly kills the process with SIGKILL.
Logs: docker logs
Everything the application writes to stdout and stderr is collected by Docker automatically.
docker logs my-app # print all accumulated logs
docker logs -f my-app # follow the logs in real time (like tail -f)
docker logs --tail 100 my-app # the last 100 lines
Spring Boot writes to stdout by default — you don't need to configure anything extra. If the application writes to a file inside the container, docker logs will not see that file.
Step inside: docker exec
Sometimes you need to see what is happening inside a running container — check the file system, environment variables, network connections.
docker exec -it my-app sh # start a shell inside the container
docker exec -it my-app bash # if bash is present in the image
The -it flags mean: -i — forward keyboard input, -t — attach a pseudo-terminal. Together they give you an interactive session.
Inside you can check the variables:
env | grep SPRING
Or look at which processes are running:
ps aux
docker exec does not restart the application — the command runs alongside the already-running process.
Healthcheck: verifying it works
Docker can periodically check whether a container is alive — not just that the process is running, but that the application actually responds. This is a healthcheck.
The easiest way is to define it in the Dockerfile:
HEALTHCHECK --interval=30s --timeout=5s --retries=3 \
CMD wget -qO- http://localhost:8080/actuator/health || exit 1
After it starts, the container spends some time in the starting state — Docker waits for the healthcheck to pass for the first time. Then it moves to healthy or unhealthy.
To view the status:
docker inspect --format='{{.State.Health.Status}}' my-app
In an isolated docker run, a healthcheck only affects the status — the container is not restarted automatically. Automatic restart is already a job for Docker Compose or an orchestrator.
In short
docker runcreates a container from an image and starts it; when the process finishes, the container stops.-p host:container— port mapping; without it you cannot connect to the container from the outside.-e KEY=VALUE— pass an environment variable; this is the main way to configure things following the 12-factor principle.-d— detached mode;--name— a convenient name;--rm— remove the container after it stops.docker logs -f— follow the logs in real time;docker exec -it ... sh— an interactive session inside.docker stopsendsSIGTERM, giving the application 10 seconds to shut down cleanly.- A healthcheck verifies that the application is not just running but actually responding.
What to read next
- What Docker is and why you need it — if you haven't read it yet: images, layers, isolation from scratch.
- Volumes and data — how to keep data across container restarts.
- Networking in Docker — how containers talk to each other and to the outside world.