Introduction to container based development - Part 3/4 - Volumes
Tags: docker
Published: 2020-03-26 19:50:47

This is the third part of our container based development series

This post is based on the container development [article]( https://github.com/drFabio/containerDevelopment/blob/master/article.pdf) created by me.

On the previous articles we did a program that count from 0 to 19 but could not do anything besides that. A program that can not persist is not so useful so let's modify our program a little so it will count the current file content and then count to that value +20. For that we need to create a [volume](https://docs.docker.com/storage/volumes/) on the container, this will make  a specific folder on the container persist when mounted. All the files for this step are on the projects repository on the [secondContainer branch](https://github.com/drFabio/containerDevelopment/tree/secondContainer).

First we need to add a proper volume on our docker file.

**Dockefile**

```Dockerfile
FROM node:13-alpine3.10
RUN mkdir -p /app/ourApp/data
COPY ./nodeCounter.js  /app/ourApp/
WORKDIR  /app/ourApp/
VOLUME /app/ourApp/data/
CMD node ./nodeCounter.js
```

Then we need to make sure our program don't stop at 20 but stops at start + 20

**nodeCounter.js**

```javascript
const fs = require('fs')
const path = require('path')

const counterFile = path.resolve(__dirname, './data/counter.txt')

const COUNTER_LIMIT = 20
const INTERVAL = 1000
let counterData = 0
if (fs.existsSync(counterFile)) {
  const fileData = fs.readFileSync(counterFile)
  counterData = parseInt(fileData, 10)
}

const stopCounter = counterData + COUNTER_LIMIT

const recursiveCounter = () => {
  if (counterData === stopCounter) {
    process.exit(0)
  }
  console.log(counterData)
  counterData++
  fs.writeFileSync(counterFile, counterData)
  setTimeout(recursiveCounter, INTERVAL)
}

recursiveCounter()
```

Then we need to build our image with the same name and a new tag.

```shell
docker build -t container_dev:second  .
```

We should see an output with the text:

"Successfully tagged container_dev:second"

But out work is not over we need to actually create a volume on our computer (the host) so our container can read and write persistent data.

```shell
docker volume create our-named-volume
```
But where physically our volume is? For that we can inspect the volume and check it's exact path.

```shell
docker volume inspect our-named-volume
```
That would give all the volume data like the one below, the mountpoint is where docker created our volume.

```text
[
    {
        "CreatedAt": "2020-03-20T10:44:48+01:00",
        "Driver": "local",
        "Labels": {},
        "Mountpoint": "/var/lib/docker/volumes/our-named-volume/_data",
        "Name": "our-named-volume",
        "Options": {},
        "Scope": "local"
    }
]
```

Now to run our app with one new argument , -v to link the volume

```shell
docker run -v our-named-volume:/app/ourApp container_dev:second
```

Run it twice and you will notice we start where we stopped. If you open 2 shells and do it a little bit after the first one start you should see they are sharing and modifying the same file (There is a race condition here but we don't mind for now).

We have a way to persist state, actually we even have a way to share the same set of files between multiple containers!

I would like to call attention about the importance of mounting, if we run without the "-v" command we will have the same behavior as the first time, our state would not persist.

So let's see what we learned

 - For a volume to be accessible in the container we need to create it at some location inside the container.
 - We need to link a volume with the -v when running the docker run argument.
 -  Multiple containers can have access to the same volume.

Next part: Containers and installing PHP alongside node in 16 lines of code!