Here’s a table detailing the differences between the EXPOSE and PUBLISH commands in Docker:

FeatureEXPOSEPUBLISH
DefinitionEXPOSE is a Dockerfile instruction used to specify which ports an application inside a Docker container listens on.PUBLISH (often used with the -p flag in Docker CLI commands) maps a container’s port to a host’s port, making it accessible from the host.
ScopeDockerfile instruction. It doesn’t actually publish the port but documents which ports are intended to be exposed.CLI command option during container runtime, actively binds container ports to host ports.
Syntax ExampleEXPOSE 80/tcpdocker run -p 80:80/tcp myimage
Effect on NetworkingIt has no effect on accessibility from the host, serves as documentation and a hint for networking between containers.Makes the container’s port accessible from the host, directly affecting network accessibility.
Used DuringBuild-time in Dockerfile, affects the image metadata.Run-time, affects the running container.
Default BehaviorDoes not make ports accessible from the host, but can be used by linked containers.Explicitly maps and makes container ports accessible on the host machine.
VisibilityPorts exposed are visible and can be inspected using the docker inspect command.Published ports are active and visible both in Docker inspection and from the host network.
FlexibilityStatic, as it’s embedded into the image during the build and cannot be changed unless the image is rebuilt.Flexible, can be set differently each time a container is run, without changing the Docker image.

How to Use “EXPOSE” or “–expose” in Docker

The EXPOSE in the Dockerfile and the --expose in the docker run command work similarly and are used to inform what ports the containerized application listens on. This can be used for inter-container communication. To use the EXPOSE or --expose command in Docker, go through the following steps.

Step 1: Create HTML File

First, you’ll need to create a simple HTML program for demonstration. For instance, we have created an index.html file in nano editor to create an HTML program. You can also use our code for practice:

To create a file, execute the following command:

sudo nano index.html

Now, paste the following snippet into the file. To save the file, hit “CTRL+S” and exit the editor through “CTRL+X”:

<!DOCTYPE html>
<html>
<head>
	<title>Sample Application</title>
	<style>
		body {
			background-color: #D2B48C;
		}
		.container {
			text-align: center;
			padding: 50px;
		}
		p {
			color:#800000;
			font-weight: bold;
		}
	</style>
</head>
<body>
	<div class="container">
		<h1>Welcome to Hands-On.Cloud</h1>
	</div>
</body>
</html>

Step 2: Generate Dockerfile

Create another file in the nano editor named Dockerfile and the given snippet into the file:

FROM nginx:latest
COPY index.html /usr/share/nginx/html/index.html
EXPOSE 80
ENTRYPOINT ["nginx", "-g", "daemon off;"]

In the above snipped, the EXPOSE command is used to expose the container for inter-container communication, but it cannot be accessible outside the Docker on the host machine:

FROM nginx:latest
COPY index.html /usr/share/nginx/html/index.html
EXPOSE 80
ENTRYPOINT ["nginx", "-g", "daemon off;"]

Step 3: Make a Docker Image

Generate the container blueprint (image) from the Dockerfile instructions. For this purpose, utilize the given command:

docker build -t html-image .

In the above command, the -t option will utilized to set the image name, and “.” is used to read the Dockerfile context from the current working directory:

docker build -t html-image .

Step 4: Fire Up Container

Now, fire up the container through the docker run command:

docker run --name demo-cont html-image

In the given command, --name is utilized to set the name of the container:

docker run --name demo-cont html-image

Step 5: List Down the Container

For confirmation, list the Docker containers:

docker ps -a

Here, you can see the demo-cont is accessible on port 80, specified by the EXPOSE command. However, this will expose service from inside the container but cannot be accessible on the host machine:

docker ps -a

Step 6: Access Containerized Application

Now, access the container shell to access the containerized service from inside the container. For this purpose, execute the docker exec -it <container-name> sh command:

docker exec -it demo-cont sh

After that, execute the curl http://localhost:80 command inside the container shell to check if the application is executing or not:

docker exec -it demo-cont sh

The above output shows that we have effectively exposed the application inside the container.

In this case, if the user directly tries to access the containerized service outside the container by directly browsing the http://localhost:80 through the curl command, they will get the error “Failed to connect to localhost port 80” as shown below:

http://localhost:80

The above error occurs because the EXPOSE or --expose command will expose the containerized service inside the container only. This service cannot be accessible from outside the Docker environment on a host system.

Use “–expose” Option

Alternatively, the user can expose the containerized service for inter-container communication through the --expose option of the docker run command:

docker run --name demo-cont --expose 80 html-image
docker run --name demo-cont --expose 80 html-image

That is how users can expose the containerized service only for containers inside the Docker.

How to Use “-p” or “–publish” in Docker

In order to access the containerized service outside the container on the Host machine, the user can forward the container port on the host system through the --publish or -p option of the docker run command.

For this purpose, go through the mentioned steps.

Step 1: Execute Container

Run the container through the docker run -p <host-port>:<container-port> -- name <container-name> <image-name> command:

docker run -p 80:80 --name demo-cont1 html-image

The above command will expose the container port “80” on the host system on port “80”:

docker run -p 80:80 --name demo-cont1 html-image

Step 2: View Containers

List down the containers for verification:

docker ps -a

The below output shows that we have effectively mapped the container port on the host system:

docker ps -a

Step 3: Access the Application on the Host System

Now, access the containerized service from outside the container shell directly from the system through the curl command:

curl http://localhost:80

In this case, we did not get any error and successfully accessed the containerized service on the host machine:

curl http://localhost:80

Users can access the containerized service or application from the browser by navigating to http://localhost:80 URL:

http://localhost:80

We have demonstrated the key difference between --expose and --publish in Docker.

Conclusion

The key difference between “–expose” and “–publish” in Docker is that “expose” or “EXPOSE” are utilized to expose the containerized service inside the container. It will be accessible to containers running in Docker but cannot be accessed from outside the Docker on the host machine. In contrast, the “-p” or “–publish” command will be used for port mapping and publishing the container port on the host. This means, containerized service can be accessible outside the container on the host machine. This write-up has covered practical examples to understand the key difference between “–expose” and “–publish” in Docker.