Lab 006: Port Mapping for a Containerized Application
Pre-requisites
Introduction
In this lab, we’ll run a container that serves a basic website written in Go. We’ll get to see how to map the container ports dynamically to ports on the local host. We’ll also get to specify which ports on the local host to bind our container ports to.
Create the Files
Here’s the code for our website.
webapp.go
```go
package main
import (
"fmt"
"net/http"
"os"
)
func hostHandler(w http.ResponseWriter, r *http.Request) {
name, err := os.Hostname()
if err != nil {
panic(err)
}
fmt.Fprintf(w, " HOSTNAME: %s
", name)
fmt.Fprintf(w, " ENVIRONMENT VARS:
")
fmt.Fprintf(w, "")
for _, evar := range os.Environ() {
fmt.Fprintf(w, "- %s
", evar)
}
fmt.Fprintf(w, "
")
}
func rootHandler(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, " Let's do this!
")
fmt.Fprintf(w, " Host info
")
}
func main() {
http.HandleFunc("/", rootHandler)
http.HandleFunc("/host/", hostHandler)
http.ListenAndServe(":8080",nil)
}
```
</details>
Let's compile and build the packages.
```bash
$ env GOARCH=386 GOOS=linux go build webapp.go
```
```bash
$ ll
total 6008
drwxrwxr-x 2 ubuntu ubuntu 4096 Jun 23 10:46 ./
drwxr-x--- 9 ubuntu ubuntu 4096 Jun 23 10:34 ../
-rwxrwxr-x 1 ubuntu ubuntu 6137719 Jun 23 10:46 webapp*
-rw-rw-r-- 1 ubuntu ubuntu 700 Jun 23 10:44 webapp.go
```
Now let's create the dockerfile.
```bash
FROM scratch
COPY webapp /
EXPOSE 8080
CMD ["/webapp"]
```
## Build the Image
```bash
$ docker build -t "webapp" .
```
```bash
$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
webapp latest 35cc7454ab2d 3 seconds ago 6.14MB
```
## Dynamically bind the port and Run the Container
Run the container in the background using the "-d" flag. To access the website, we should also map the local host's port to a port in the container.
Recall that in our dockerfile, our container exposes port 8080.
```bash
EXPOSE 8080
```
To dynamically map the container port to a port on the localhost, use the "-P" flag. In the example below, we see that the container port is binded to port 49153 on the localhost.
```bash
$ docker run -d -P webapp
```
```bash
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
ce03b2560913 webapp "/webapp" 5 seconds ago Up 4 seconds 0.0.0.0:49153->8080/tcp, :::49153->8080/tcp fervent_lichterman
```
Get the IP of your machine.
```bash
$ curl ipecho.net/plain; echo
```
Open your web browser and navigate to the IP, followed by the port.
## Map to a Specific Port and Run the Container
To specify the port on the localhost to which to bind the container port, use the "-p" flag.
```bash
$ docker run -d -p 3000:8080 webapp
```
```bash
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
e3e1018a9eaa webapp "/webapp" 7 seconds ago Up 6 seconds 0.0.0.0:3000->8080/tcp, :::3000->8080/tcp sad_jemison
ce03b2560913 webapp "/webapp" 6 minutes ago Up 6 minutes 0.0.0.0:49153->8080/tcp, :::49153->8080/tcp fervent_lichterman
```
Test it by running a cURL.
```bash
$ curl localhost:3000
Let's do this!
Host info
```
If we try to run another container and map to the same local host port, it will throw an error.
```bash
$ docker run -d -p 3000:8080 webapp
docker: Error response from daemon: driver failed programming external connectivity on endpoint kind_diffie
Bind for 0.0.0.0:3000 failed: port is already allocated.
```
## Cleanup
When you're done with the lab, you can stop all running containers by running the command below.
```bash
$ docker stop $(docker ps)
```
Once all containers have "Exited" status, remove them.
```bash
$ docker ps -a
```
```bash
$ docker container prune -f
```
Finally, remove all images.
```bash
$ docker image prune -af
```