Run Stateless Docker Containers

Mark Shust
InstructorMark Shust

Share this video with your friends

Send Tweet
Published 4 years ago
Updated 3 years ago

Docker containers should be designed to be stateless, meaning that they can survive system reboots and container terminations gracefully, and without the loss of data. Designing with stateless containers in mind will also help your app grow and make future horizontal scaling trivial.

In this lesson, we will review an app that saves uploaded files to the filesystem. Then we will learn how to setup a persistent volume for the uploaded files so they can survive Docker container halts, restarts, stops and respawns.

[00:00] Docker containers should be designed to stateless, meaning that they can survive system reboots and container terminations gracefully, and without the loss of data. Designing with stateless containers in mind will also help your app grow and making future horizontal scaling tasks trivial.

[00:16] Let's review our setup. Here, we have a small Express app that uploads files to the local file system. Note that the base route serves up an HTML form with file inputs, and the upload route handles moving or uploaded file into a folder on the file system named uploads.

[00:33] The Docker file for this app is simple. We are simply setting up our current working directory, copying over assets, making an uploads directory, running Yarn to install prerequisites, exposing port 8080, and then starting our web server.

[00:52] We are using Docker compose to run our containers. For our main app service, we will simply build our app from the local directory's Docker file, and also bind port 8080 from the app to the host. We will start our app up with docker-compose up. Let's test out the file upload functionality by uploading an image of our cat friend.

[01:21] We can see that Herman is successfully uploaded to the uploads folder, but we have a small problem here. Let's stop our app, remove our containers, and start our app back up. Then let's refresh our browser window.

[01:37] Herman did in fact die when our container died. This presents two problems, one being that we will lose all our uploaded content if a container is killed off, the other being that no one likes dead kitties. This shows that Docker's file system is ephemeral, and that we need to design systems that can persist container terminations.

[01:57] Our entire fleet of containers should be able to kill off at any given moment and redeploy at any time without losing any data. The easiest way to fix this problem is to set up a persistent volume. Persistent volumes map a host directory into a container directory so that even when containers die, the volume does not.

[02:17] The directory will remap back to the host when the new containers are deployed. Setting up volumes is really easy with compose. Let's open up our docker-compose YAML file, then add a volumes property. Under this property, we will simply choose any arbitrary name for our persistent volume.

[02:37] Let's name this App Data. Make sure to suffix the name with a colon. Next, let's go into our app servers and add a volumes property. Since there can be many volumes set up, we prefix our volumes entries with a dash.

[02:52] Then we specify the name of the volume we want to use, in this case, App Data. Let's precede that with a colon, and then specify a folder to be persistent, in this case, /serv/uploads. When the container starts, this volume path will be mounted from our volume into the container at this directory.

[03:13] This is enough to persist data between container deletions and respawns. Let's remove our current app containers to ensure we are running from a clean state, then start our app again with compose. We will reupload our cat friend Herman and follow the link to ensure he is uploaded.

[03:35] Now, let's stop our app, and then completely kill off our containers and Herman again with docker-compose rm-f. At this point in time, Herman is officially a Schrödinger's cat, because he is currently both dead in our containers, but also alive and well within our boxed volume.

[03:54] Let's take him out of the box, and start our app back up with docker-compose up. If we refresh our browser, we can see that Herman is alive and well.

Harshesh
Harshesh
~ 4 years ago

A question: where does appdata: volume points to?

Mark Shust
Mark Shustinstructor
~ 4 years ago

The appdata: reference is basically pointing to a new scratch volume. It will store whatever you place on the volume, but outside of any container.

Harshesh
Harshesh
~ 4 years ago

..just clarifying, since the scratch location is not declared, it will consider the current location where we executed docker-compose command?

Mark Shust
Mark Shustinstructor
~ 4 years ago

No, this volume lives within docker as a docker volume. You can view all docker volumes with the docker volume ls command.

zarcode
zarcode
~ 4 years ago

I get this output:

$docker-compose up Building app Step 1/7 : FROM mhart/alpine-node ERROR: Service 'app' failed to build: Get https://registry-1.docker.io/v2/mhart/alpine-node/manifests/latest: unauthorized: incorrect username or password

Can I get some help?

Mark Shust
Mark Shustinstructor
~ 4 years ago

That's an odd one -- perhaps you can try again? Almost appears as though docekr.io or dockerhub experienced a server outage.

zarcode
zarcode
~ 4 years ago

You are right, thank you for help.

JP Erasmus
JP Erasmus
~ 4 years ago

Schrödinger's cat - very clever and funny!