The course is part of this learning path
In this lecture, you will learn how to use many of the commands in Docker to map your container to the proper port. You will be using a basic web application written in GO for this exercise.
You will review the port that the web application is going to use from the container.
We will build a new image and start the container with the Docker run command based off the image. We will look at how the application is running, and see if we can determine what is causing its issue.
You will get familiar with several Docker commands, which allows us to access bash while it is running. We will introduce you to bridge networks, and see how Docker continues to run the application inside the container.
Then, we will fetch the IP address and see where it points using the Docker inspect command. Lastly, we will walk through how to bind a container port to a host port, and see what happens when you try to bind two container ports to the same host port.
Welcome back. So far the code that we've run inside of containers has been writing some text to standard output. Now it's time to run something a bit more complex. So let's run a basic web application. Here's the web application we're going to run. It's an application written in Go, and it has two URL endpoints.
The first is the root URL, and then there's this other endpoint at slash host which will display the host name and some environment variables. I'm not going to go through all of this code. The important part to know is that this is a basic web app. It's going to run on port 8080 and serve up just a bit of markup.
I have the web application compiled into a binary named web app, and it's in the same directory as the Docker file. If I print off the Docker file to the terminal, you can see that it uses the scratch base image. It copies the web app binary into the container at the root directory, and then it exposes port 8080 from the container.
And we'll talk about this in a bit. And then it sets the default command to be the web app. So it's going to actually execute that binary. Okay, let's build this image, and then we can start up the container based on the image. Great, so the image built successfully. And we can see it here in the list of images.
Let's run this container with the docker run command. So notice it's just hanging here. This is expected, because the code is running inside of the container in an infinite loop. It's just running forever, serving up this website until we stop it. So the web application is running indefinitely and waiting for connections.
And while it's running, we're unable to interact with our bash prompt. Now really this is no different than if we ran this outside of Docker. It's not specific to Docker. However, we can solve this. Docker allows us to run the process in the background with the minus D flag. So for this flag, D stands for detach, as in Docker detaches from standard I/O and instead just prints the container ID, and then it's going to return us to our prompt.
So this allows us to run containers in the background. Let's try it out. Okay, there, notice the container ID is printed to the screen. And then we have access to our prompt again. So if I list off the containers, you can see based on the status here that that container is up and running. At this point, the container is running.
However, it's really not clear how we interact with this web app. By default, Docker containers run inside of their own network, called the bridge network. We're going to dive into that in the coming lesson on networking. So for now, the thing to know is that this web app is running inside of the container, and it's accessible via the container's IP address on port 8080.
It's possible to fetch the IP address using the docker inspect command and then passing in the container ID or name. Notice here, the IP address field, you can see that it's set with the container's IP. And if we curl this and we use port 8080, you can see that we get back some HTML. So this is the home page of the app.
Because each container has its own IP address, all of them can run on port 8080 inside of their own container, and then we can interact with them via their IP address. However, there is another way to interact with a web application inside of a container, and that would be to bind the port in the container to a port on the host.
Docker allows you to do this dynamically or explicitly. The Docker file specifies that the container exposes port 8080. By default, the expose instruction really doesn't do anything to the host. Docker lets you bind the container port to a host port with the publish or publish all flags. Publish all will dynamically map the exposed ports of the container to open ports on the host.
The minus capital P flag is the short form of publish all. So this is going to run the container in detached mode, which means it's gonna run in the background. It will also dynamically bind the exposed port 8080 to a port on the host. So we can use the docker ps command to see which port. In this case, the port is 32768.
So if we curl localhost on that port, we should get back some HTML. And we do. If I use the terminal-based browser Lynx, you can see that the site is up and running. It's usable, and everything works. So now if we start up another container, again using the publish all flag to dynamically map the ports, it's going to choose a different port automatically.
And notice the first container in the list here is 32769, and the second one is 32768. So it's going to map that for us automatically. Okay, let's stop these containers. And notice that the stop command allows you to pass in multiple container IDs. So now that they're stopped, let's prune them. And that's going to remove them both.
All right, perfect. So using publish all, you can dynamically map the ports that are exposed from the container to the host. Now, you can also use the publish flag, which will allow you to map specific ports. So in this case, we're going to use a lowercase P flag, which is the short form of publish, and it allows you to specify the port on the host that you want to use, and then a colon, and then the port on the container.
So what I wanna do is map port 3000 on the host to port 8080 inside of the container. And now if I list off the containers, you can see port 3000 maps to 8080. And if I curl localhost on port 3000, there we go, we get our HTML back. So since I've explicitly told Docker to use port 3000 on the host, if I run the same command, it's going to throw an error.
And there it is. When we did this dynamically, the ports were selected for us to ensure that there wasn't any conflict. If I run docker ps, you'll notice only the previous container is running. And if I run it again with the minus A flag, you can see that the other container tried to start and failed, so it's just left here in a created state.
So as expected, you can't bind two processes at the same time to the same port. So if you wanted to switch, you would have to stop the first container and then start the other. And there it is. Notice the first container is stopped and no longer using port 3000. And the new container is in a running state, and 3000 is bound to it.
Okay, let's summarize what we're covered so far in this lesson. Docker allows you to map ports from containers to the hosts running the containers. The mapping can be done dynamically with the publish all flag or explicitly with the publish flag. And by default, the expose instruction in the Docker file doesn't actually perform any port mapping.
It's up to you to determine how you want to publish the ports. All right, in the next lesson, we're going to be covering the Docker networking just a bit more in depth. So if you're ready to keep learning, then I'll see you in the next lesson.
About the Author
Ben Lambert is the Director of Engineering and was previously the lead author for DevOps and Microsoft Azure training content at Cloud Academy. His courses and learning paths covered Cloud Ecosystem technologies such as DC/OS, configuration management tools, and containers. As a software engineer, Ben’s experience includes building highly available web and mobile apps.
When he’s not building the first platform to run and measure enterprise transformation initiatives at Cloud Academy, he’s hiking, camping, or creating video games.