EXPOSE vs. Publish in Docker: A Deeper Dive
Tags: devops, docker, interview
Published: 2023-10-14 12:14:12

Recently, I interviewed for a DevOps position. To demonstrate my skills, I proudly presented the following Dockerfile for a server that was intended to run only on a single container:

```dockerfile
FROM nikolaik/python-nodejs:latest

WORKDIR /app

COPY . .

RUN pip install -r Requirements.txt
RUN npm install

EXPOSE 8000

CMD npm run start
```

Upon reviewing it, the interviewer pointed at the `EXPOSE 8000` line and asked whether it was best practice to specify the port exposure directly within the Dockerfile. I hesitated, thinking of potential security implications, and responded, "Wouldn't it be better to specify the port through an environment variable?" A raised eyebrow from the interviewer told me I'd stepped into a pitfall.

Upon returning home, my curiosity got the better of me, and I dived into some research. To my chagrin, I discovered that the `EXPOSE` directive in the Dockerfile isn't inherently a security concern, especially when running a single container. Before you find yourself in a similar scenario, let's delve deeper into this topic so you can navigate such questions with confidence.

## What does `EXPOSE` do?

The `EXPOSE` directive in a Dockerfile primarily serves as documentation, signaling to users which ports the containerized application is set to run on. Intriguingly, while `EXPOSE` will make the port available to other containers, it does not make that port accessible to the host machine or the external world.

For instance, with:

```dockerfile
EXPOSE 8000
```

The application inside the container runs on port 8000 and is accessible from other containers on the same machine, but not outside the Docker host.

## What about `Publish`?

The `--publish` or `-p` flag used with `docker run` is what truly opens up a port to external traffic. If you run a container without publishing a port, even if the Dockerfile contains an `EXPOSE` directive, the port won't be accessible from outside the Docker host.

For instance:

`docker run -p 8000:8000 your_image_name`

By doing this, you bind the container's port 8000 to the host machine's port 8000, thus facilitating external accessibility.

## Why the Confusion?

The blurring lines between `EXPOSE` and `Publish` arise from their interconnected yet distinct functionalities:

1. **Internal vs External**: `EXPOSE` makes a port accessible internally (i.e., between containers), while `Publish` ensures external access.
    
2. **Communication vs Action**: `EXPOSE` is a way to communicate which ports are intended for use, while `Publish` takes an actionable step to bind and open those ports.
    

### Security Implications:

While `EXPOSE` may seem benign as it doesn't directly expose ports to the outside world, caution is advised:

* `EXPOSE` alone won't open up your application to the world, but it makes it reachable by other containers.
    
* Control remains with the `-p` or `--publish` option. Exercise caution to open only the necessary ports and understand the ramifications.
    

As for my interview experience, it reminded me of the continual learning journey that the tech world offers. The correct response to the interviewer's query would have been: "The `EXPOSE` directive in the Dockerfile is more of a documentation or communication of intent. It does not open the port to the outside world. For a single container setup like this, it's okay. But we should always pair it with appropriate runtime flags like `-p` during `docker run` to control external accessibility."

Mistakes can be powerful teachers, and I'm grateful for the insight this one provided. Embrace the hiccups along the way – they're just stepping stones to mastery.