DEV Community

Cover image for Day 7: Docker Volumes
Jonas Scholz
Jonas Scholz Subscriber

Posted on • Originally published at adventofdocker.com

Day 7: Docker Volumes

This is a crosspost from adventofdocker.com

Yesterday we learned that containers are ephemeral - any changes made inside a container are lost when it stops. But what if you need to persist data? That's where volumes come in!

Let's modify our HTTP server to save some data:

package main import ( "fmt" "net/http" "os" "time" ) func main() { http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { // Record new visit timestamp := time.Now().Format(time.RFC3339) + "\n" os.MkdirAll("data", 0755) f, _ := os.OpenFile("data/visits.txt", os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644) f.WriteString(timestamp) f.Close() // Read and display all visits data, err := os.ReadFile("data/visits.txt") if err != nil { fmt.Fprintf(w, "Error reading visits!") return } fmt.Fprintf(w, "New visit recorded at %s\n\nAll visits:\n%s", timestamp, string(data)) }) fmt.Println("Listening on port 8080") http.ListenAndServe(":8080", nil) } 
Enter fullscreen mode Exit fullscreen mode

Our Dockerfile stays the same:

FROM golang COPY . . RUN go build -o main main.go EXPOSE 8080 CMD ["./main"] 
Enter fullscreen mode Exit fullscreen mode

Let's build and run it:

$ docker build -t hello-world-go . $ docker run -p 8080:8080 hello-world-go 
Enter fullscreen mode Exit fullscreen mode

When you visit localhost:8080, each visit gets recorded and displayed. However, if you stop and restart the container, all your visits are gone! This is because containers are ephemeral - any changes made inside them are lost when they stop.

Solving with Docker Volumes

We can fix this by using volumes. First, create a named volume:

$ docker volume create mydata 
Enter fullscreen mode Exit fullscreen mode

Now run the container with the volume mounted:

$ docker run -p 8080:8080 -v mydata:/data hello-world-go 
Enter fullscreen mode Exit fullscreen mode

The -v mydata:/data flag mounts our volume named mydata to the /data directory inside the container. Try it out:

  1. Visit localhost:8080 a few times - you'll see the list grow with each visit
  2. Stop the container with docker stop <container_id>
  3. Start a new container with the same volume:
$ docker run -p 8080:8080 -v mydata:/data hello-world-go 
Enter fullscreen mode Exit fullscreen mode

Your visits are still there! The data persists even when containers are stopped or removed.

Managing Volumes

List all volumes:

$ docker volume ls DRIVER VOLUME NAME local mydata 
Enter fullscreen mode Exit fullscreen mode

Inspect a volume:

$ docker volume inspect mydata [ { "CreatedAt": "2024-12-07T...", "Driver": "local", "Labels": {}, "Mountpoint": "/var/lib/docker/volumes/mydata/_data", "Name": "mydata", "Options": {}, "Scope": "local" } ] 
Enter fullscreen mode Exit fullscreen mode

Remove a volume:

$ docker volume rm mydata 
Enter fullscreen mode Exit fullscreen mode

You can also use anonymous volumes by omitting the volume name:

$ docker run -v /data hello-world-go 
Enter fullscreen mode Exit fullscreen mode

Docker will create a random volume name for you. These are harder to manage but useful for temporary data.

Bind Mounts

Instead of using a Docker-managed volume, you can mount a directory from your host directly:

$ docker run -v $(pwd)/data:/data hello-world-go 
Enter fullscreen mode Exit fullscreen mode

This mounts the ./data directory from your current location into the container. Great for development, I recommend reading more about bind mounts here.

That's it for today! Tomorrow we'll have our first quiz to test what you've learned this week. Make sure you're comfortable with:

  • Basic Docker commands
  • Building images
  • Running containers
  • Port mapping
  • Layers
  • Volumes

Until then, happy coding! 🐳🎄

Jonas

Top comments (1)

Collapse
 
kawasthi2889 profile image
Kaustubh • Edited

Hey man! Nice tutorial. Just a suggestion, don't use relative path "data/visits.txt", instead use "/data/visits. I dont know why this is happening. my default workdir is /go but data directory is created in root (/), and yet the volume is not able to read it like it is inside that go directory.
I actually struggled for an hour on this. I made the path absolute and it worked.
To test this i made my WORKDIR / and my RUN go build -o main go/main.go when the paths are relative in main.go and it worked.