BR-ANAC-DOV-MOD-1 study materials
BR-ANAC-DOV-MOD-1 study resources

BR-ANAC-DOV-MOD-1 common mistakes

BR-ANAC-DOV-MOD-1 · Understand the traps and how to avoid them.

Mistake 1

Running `docker run` with a container port published as `-p 8080:80` but then testing the container's own loopback (`curl localhost:80` inside the container) instead of the host-mapped port, and concluding the mapping failed.

Candidates conflate the container's internal listening port with the host-published port and forget that the left side of -p HOST:CONTAINER is where the client connects; they also miss that the app may bind to 127.0.0.1 inside the container, which is unreachable from outside even with a correct mapping.

What to do instead

Read the mapping right-to-left: traffic to host port 8080 is forwarded to container port 80. Test from the host with curl localhost:8080, verify the process listens on 0.0.0.0 inside the container (ss -ltn or netstat), and confirm with docker port <container> which host bindings exist.

Mistake 2

Creating a user-defined bridge network but then connecting containers by container name while the containers were attached to the default bridge, so name-based DNS resolution fails and the candidate blames Docker DNS.

The default bridge network does not provide automatic DNS resolution by container name; only user-defined networks do. Candidates start containers without --network and expect the same behaviour they read about for custom networks.

What to do instead

Create the network once (docker network create appnet), start every service with --network appnet (or the compose networks: key), and verify membership with docker network inspect appnet. Then resolve by service/container name or by the network alias.

Mistake 3

Building an image with a Dockerfile whose `COPY . .` precedes `RUN npm install` (or pip install), so every source change invalidates the dependency layer and rebuilds take minutes; the candidate then reports the build as 'slow' rather than fixing layer order.

Candidates write Dockerfiles top-to-bottom in the order they think about the app, not in order of change frequency, and do not understand that each instruction creates a cached layer keyed on its inputs.

What to do instead

Order instructions from least to most frequently changing: base image, system packages, copy only the dependency manifest (COPY package.json package-lock.json ./), install dependencies, then copy the remaining source. Add a .dockerignore so unrelated files do not bust the cache.

Mistake 4

Treating `docker compose down` and `docker compose down -v` as equivalent, then losing named-volume data (or, conversely, expecting data to persist after `-v` and reporting a storage bug).

Candidates memorize down as 'stop everything' without checking which resources it removes; named volumes are preserved by default, and only -v/--volumes deletes them.

What to do instead

Remember: down removes containers and networks but keeps named volumes; down -v also removes volumes declared in the compose file (and anonymous volumes). Before any destructive command, run docker volume ls and docker compose config --volumes to see what is at stake.

Mistake 5

Mounting a host path with `-v /data:/app/data` on a host where `/data` does not exist, then finding an empty directory owned by root inside the container and assuming the image is broken.

Docker creates a missing host directory automatically as root when using a bind mount, which silently masks the image's baked-in content and produces permission errors for a non-root container user.

What to do instead

Create the host directory first with correct ownership, prefer --mount type=bind,source=...,target=... which fails loudly if the source is missing, and set the container user's UID/GID (or use --user $(id -u):$(id -g)) so writes succeed. Use a named volume when host-path semantics are not actually needed.

Mistake 6

Pushing to a registry and hitting `denied: requested access to the resource is denied`, then retrying the same push instead of checking the tag's repository prefix and login state.

The image tag does not match the target repository (for example a local name pushed to a private registry without the registry-host:port/namespace/name:tag prefix), or the session is not authenticated to that registry, or the user lacks push permission.

What to do instead

Tag explicitly for the destination (docker tag app:latest registry.example.com/team/app:1.0), authenticate with docker login registry.example.com, confirm with docker info which registry credentials apply, and push the fully qualified tag. For insecure local registries, configure the daemon's insecure-registries list rather than fighting auth.

Mistake 7

Deploying a Swarm service with `docker service create` and then looking for the containers with `docker ps` on the manager, concluding the service failed because nothing appears.

Swarm tasks run as containers on whichever nodes the scheduler picks; on a multi-node cluster the manager may host none of them, and docker ps only shows local containers.

What to do instead

Use docker service ls for desired vs running replicas, docker service ps <service> for per-task state and node placement, and docker ps on the specific node. Check docker service logs and docker node ls for scheduling constraints.

Mistake 8

Assuming a `HEALTHCHECK` in the Dockerfile makes `docker run` restart or block on an unhealthy container, then reporting that health checks 'do not work'.

Docker only records health status; it does not act on it. Restart or replacement behaviour requires an orchestrator (Swarm, Compose with depends_on: condition: service_healthy, or restart policies), and --restart policies do not consider health.

What to do instead

Verify with docker inspect --format '{{.State.Health.Status}}'. Use depends_on with condition: service_healthy in Compose for startup ordering, and rely on the orchestrator (Swarm update/rollback, --health-cmd at service level) to replace unhealthy tasks. Do not expect docker run to gate on health.

Mistake 9

Baking secrets into an image via `ENV` or `ARG` and believing deleting them in a later layer removes them, then failing a security question about image inspection.

Every layer is retained in the image history, so ENV API_KEY=... and build args are visible in docker history and image metadata even if a later RUN unset runs. Candidates confuse runtime environment with build-time secrecy.

What to do instead

Never pass secrets as ENV/ARG for real credentials. Use BuildKit secret mounts (RUN --mount=type=secret,id=token ...), runtime injection (environment from a secret store, --env-file outside the image), or orchestrator secrets. Audit with docker history --no-trunc and an image scanner.

Mistake 10

Running containers as root by default and bind-mounting the Docker socket into a container to 'make it work', without recognizing that socket access equals host root.

The default user in most base images is root, and mounting /var/run/docker.sock gives the container full control of the daemon; candidates take the quickest path to a working demo and miss the privilege escalation.

What to do instead

Add a non-root USER in the Dockerfile (create the user and chown app files), drop capabilities (--cap-drop ALL, add back only what is needed), avoid --privileged, and never mount the Docker socket into untrusted workloads; use a scoped API proxy or rootless Docker instead. Verify with docker run --rm image id.