Skip to content

Day 5 - Interacting with Containers

Published:ย atย 12:00 AM

Hey there! Congrats to making it to day 5. Today we will continue with our Go application from Day 4 and make it a bit more interesting. We will start by running a simple HTTP server and then see how we can interact with it!

As a quick reminder, yesterday we created a Dockerfile that looked like this:

FROM golang

COPY . .

RUN go build -o main main.go

CMD ["./main"]

And our main.go file looked like this:

package main

import "fmt"

func main() {
	fmt.Println("Hello, World!")
}

If you didnโ€™t create it yesterday, please create a new directory and add the files to it!

Printing hello world is of course a bit boring, so letโ€™s make our application a bit more interesting by adding a simple HTTP server.

To do this we will modify our main.go file to look like this:

package main

import (
	"fmt"
	"net/http"
)

func main() {
	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		fmt.Fprintln(w, "Hello World!") // this will be printed as a response when you request /
	})
	fmt.Println("Listening on port 8080")
	http.ListenAndServe(":8080", nil) // this will start the HTTP server (blocking operation) and listen on port 8080
}

Here we basically just create one route (/) that will print โ€œHello World!โ€ when someone visits the root path. The HTTP server will be listening on port 8080. If you feel adventurous, you can try to add some more routes, change the port or the message.

You can still use the same Dockerfile from yesterday and build the image just like we did yesterday.

$ docker build -t hello-world-go .

And then run it just like we did yesterday.

$ docker run hello-world-go

If you now open your browser and navigate to http://localhost:8080 you would expect to see โ€œHello, World!โ€ printed in your browser, right?

Well, not reallyโ€ฆ

Connection refused

This is because Docker containers are isolated from the host by default. This means that if you listen on a port in a container, it wonโ€™t be accessible from the host. You need to explicitly tell Docker that you want to expose a port. To do this, kill your running container (CTRL+C in your terminal) and modify your run command:

$ docker run -p 8080:8080 hello-world-go

This will expose port 8080 of the container to port 8080 on the host. Now if you navigate to http://localhost:8080 you should see โ€œHello, World!โ€ printed in your browser.

Hello, World!

Awesome! I think this is a great moment to play around with the ports a bit. Change the ports in your main.go file and see how it behaves.

Side note: If you see Dockerfiles that other people wrote, you will often see an EXPOSE instruction. The expose instruction actually doesnโ€™t expose the port to the host, it is basically just documentation to bridge the knowledge between the developer who wrote the Dockerfile and the people who will use it. You can read more about it here.

FROM golang

COPY . .

RUN go build -o main main.go

EXPOSE 8080

CMD ["./main"]

Interacting with running containers

I want to show you three helpful commands to interact with your containers. docker ps, docker stats, and docker exec!

During development it is not unusual that you have a bunch of containers running at the same time. You might have one for your API, one for your Frontend and one for your Database. What if you want to know what is currently running? That is what docker ps is for. docker ps lists the currently running containers:

$ docker ps
CONTAINER ID   IMAGE         COMMAND    CREATED         STATUS         PORTS                    NAMES
27a27b6343a7   http-server   "./main"   6 minutes ago   Up 6 minutes   0.0.0.0:8080->8080/tcp   funny_galois

Here you can see that we have one container running called funny_galois that is running the http-server image and listening on port 8080. Pretty useful, right? If the output is empty, itโ€™s probably because your container has already stopped. You can list all containers that have ever been run with the docker ps -a command.

Sometimes you want to know more about the resource usage of your containers. For this docker stats is your friend. docker stats will show you the resource usage of your containers:

$ docker stats
CONTAINER ID   NAME           CPU %     MEM USAGE / LIMIT     MEM %     NET I/O         BLOCK I/O   PIDS
27a27b6343a7   funny_galois   0.00%     4.914MiB / 7.661GiB   0.06%     4.59kB / 846B   0B / 0B     6

Here you can see that our funny_galois container has used 0.00% of the CPU and 4.914MiB of memory out of the limit of 7.661GiB (which is 0.06% of the memory). It has done 4.59kB of network I/O and 0B of block I/O and has 6 PIDs running. Super useful for debugging!

Now finally, I want to show you how to interact with a running container. What if you want to poke around in the container? Open a shell? Install some packages? Generally this isnโ€™t recommended (because containers should be ephemeral and stateless) but it can be useful for debugging. To do this we can use the docker exec command.

$ docker exec -it funny_galois bash

funny_galois is the name of our container, you can get the name of your container with docker ps from above. The -it flags are used to attach your terminal to the container so you can use it. The bash command will open a shell in the container. If you run this command you will see that you are dropped into the container, from here you can navigate around, install packages, poke around etc. For example, you might want to just check what is in your current directory with ls:

docker exec -ti funny_galois bash
root@27a27b6343a7:/go# ls
Dockerfile  bin  main  main.go  src

I recommend you to try this out and do some exploring in the container. Add files, install some packages. Have fun! Then stop your container and do it again, are the files still there? Why not?

Thatโ€™s the teaser for tomorrow, where we will take a step back and look at what exactly layers are, why containers are ephemeral and what that means for our workflow :)

Until then, happy hacking! ๐Ÿš€

Jonas


Previous Post
Day 4 - Building your first container
Next Post
Day 6 - Docker Image Layers
Sponsor logo

Sliplane

Deploy your Docker Apps straight from your Github repository in less than 2 minutes with sliplane.io

Learn More โ†’