[Docker] Storing Container Data In Docker Volumes

Storing data within a container image is one option for automating a container with data, but it requires a copy of the data to be in each container you run. For static files, this can be a waste of resources. Each file might not amount to more than a few megabytes, but once the containers are scaled up to handle a production load, that few megabytes can turn into gigabytes of waste. Instead, you can store one copy of the static files in a Docker volume for easy sharing between containers. In this lab, you will learn how Docker volumes interact with containers. You will do this by creating new volumes and attaching them to containers. You'll then clean up space left by anonymous volumes created automatically by the containers. Finally, you'll learn about backup strategies for your volumes.

 

 

### Check the setup

To start with, we have already fews images downloaded from DockerHub, and we currently don't have any volume

[cloud_user@ip-10-0-1-129 ~]$ docker images
REPOSITORY   TAG       IMAGE ID       CREATED       SIZE
httpd        2.4       6e794a483258   7 days ago    145MB
bash         latest    2552d69c6348   5 weeks ago   12.9MB
postgres     12.1      cf879a45faaa   2 years ago   394MB
[cloud_user@ip-10-0-1-129 ~]$ docker volume ls
DRIVER    VOLUME NAME

Anonymous volume

Run the postgres image:

docker run --name db1 -d postgres:12.1
docker run --name db1 -d postgres:12.1

Then let's check volume:

[cloud_user@ip-10-0-1-129 ~]$ docker volume ls
DRIVER    VOLUME NAME
local     45481ab743b77a1ce8bd3f480b50172e5f4d1c31ae51b565a0f371b11d14100d
local     affa07409189939e60eb3d520092fac428ac9cde54a63d5b4311b4f3694d9199

As we can see that, when postgres start, it needs some space to store the data, so it creates anymonus volume to do that.

Now, let's take a close look to the volume:

  • we want to inspect db1's volume
  • since the inspect response is large, we only interest in Mounts information: -f '{{ json .Mounts }}'
  • then we use python -m json.tool to pretty the json
[cloud_user@ip-10-0-1-129 ~]$ docker inspect db1 -f '{{ json .Mounts }}' | python -m json.tool
[
    {
        "Destination": "/var/lib/postgresql/data",
        "Driver": "local",
        "Mode": "",
        "Name": "affa07409189939e60eb3d520092fac428ac9cde54a63d5b4311b4f3694d9199",
        "Propagation": "",
        "RW": true,
        "Source": "/var/lib/docker/volumes/affa07409189939e60eb3d520092fac428ac9cde54a63d5b4311b4f3694d9199/_data",
        "Type": "volume"
    }
]

As you can see, the Name: affa07409189939e60eb3d520092fac428ac9cde54a63d5b4311b4f3694d9199 is the same as our volumes ouput.

--rm flag, clear the container after stop the container

Now let's run a third container with --rm flag

[cloud_user@ip-10-0-1-129 ~]$ docker run --name dbTmp --rm -d postgres:12.1
1956babce36e413f1402400cbe3201f3a88c5748c82cfa18654dccc1efffe6c9
[cloud_user@ip-10-0-1-129 ~]$ docker volume ls
DRIVER    VOLUME NAME
local     6f8c3d724bcd6c81738d6e2f64bfa65edcfc84170a10ae76ddd9c9ba7015b905
local     45481ab743b77a1ce8bd3f480b50172e5f4d1c31ae51b565a0f371b11d14100d
local     affa07409189939e60eb3d520092fac428ac9cde54a63d5b4311b4f3694d9199

Let's stop the containers

[cloud_user@ip-10-0-1-129 ~]$ docker stop db2 dbTmp
db2
dbTmp
[cloud_user@ip-10-0-1-129 ~]$ docker volume ls
DRIVER    VOLUME NAME
local     45481ab743b77a1ce8bd3f480b50172e5f4d1c31ae51b565a0f371b11d14100d
local     affa07409189939e60eb3d520092fac428ac9cde54a63d5b4311b4f3694d9199

As you can see, after stop db2, dbTmp, we still have two volume, one for db1, another is for db2.

The volume for dbTmp has been removed with container by --rm flag when container stopped.

Create Docker Volume

Let's create a docker volume to put our website code:

docker volume create webstie

[cloud_user@ip-10-0-1-129 ~]$ docker volume ls
DRIVER    VOLUME NAME
local     45481ab743b77a1ce8bd3f480b50172e5f4d1c31ae51b565a0f371b11d14100d
local     affa07409189939e60eb3d520092fac428ac9cde54a63d5b4311b4f3694d9199
local     website

Let's copy our website code from /home/cloud_user/widget-factory-inc/web/* to volume /var/lib/docker/volumes/website/_data/

sudo cp -r /home/cloud_user/widget-factory-inc/web/* /var/lib/docker/volumes/website/_data/

verify the files is there:

[cloud_user@ip-10-0-1-129 ~]$ sudo ls -l /var/lib/docker/volumes/website/_data/
total 16
drwxr-xr-x. 2 root root   76 Jan 25 14:23 img
-rw-r--r--. 1 root root 3059 Jan 25 14:23 index.html
-rw-r--r--. 1 root root 2910 Jan 25 14:23 quote.html
-rw-r--r--. 1 root root 2611 Jan 25 14:23 support.html
-rw-r--r--. 1 root root 2645 Jan 25 14:23 widgets.html

Serve the website using httpd

To server the website using httpd and mount website volume to it

docker run --name web1 -d -p 80:80 -v website:/usr/local/apache2/htdocs:ro httpd:2.4

We should be able to see the site.

Now, run with the --rm flag, see what's happen:

docker run --name webTmp -d --rm -v website:/usr/local/apache2/htdocs:ro httpd:2.4

[cloud_user@ip-10-0-1-129 ~]$ docker ps
CONTAINER ID   IMAGE           COMMAND                  CREATED          STATUS          PORTS                               NAMES
34ac79c977f2   httpd:2.4       "httpd-foreground"       2 seconds ago    Up 1 second     80/tcp                              webTmp
f2e2aa007625   httpd:2.4       "httpd-foreground"       2 minutes ago    Up 2 minutes    0.0.0.0:80->80/tcp, :::80->80/tcp   web1
f08726cd61cc   postgres:12.1   "docker-entrypoint.s…"   23 minutes ago   Up 23 minutes   5432/tcp                            db1

Let's stop the webTmp

[cloud_user@ip-10-0-1-129 ~]$ docker stop webTmp
webTmp
[cloud_user@ip-10-0-1-129 ~]$ docker ps
CONTAINER ID   IMAGE           COMMAND                  CREATED          STATUS          PORTS                               NAMES
f2e2aa007625   httpd:2.4       "httpd-foreground"       5 minutes ago    Up 5 minutes    0.0.0.0:80->80/tcp, :::80->80/tcp   web1
f08726cd61cc   postgres:12.1   "docker-entrypoint.s…"   26 minutes ago   Up 26 minutes   5432/tcp                            db1
[cloud_user@ip-10-0-1-129 ~]$ docker ps -a
CONTAINER ID   IMAGE           COMMAND                  CREATED          STATUS                      PORTS                               NAMES
f2e2aa007625   httpd:2.4       "httpd-foreground"       5 minutes ago    Up 5 minutes                0.0.0.0:80->80/tcp, :::80->80/tcp   web1
c00a4b92b0c8   postgres:12.1   "docker-entrypoint.s…"   25 minutes ago   Exited (0) 13 minutes ago                                       db2
f08726cd61cc   postgres:12.1   "docker-entrypoint.s…"   26 minutes ago   Up 26 minutes               5432/tcp                            db1

As we can see, webTmp has gone.

Check the volumes:

[cloud_user@ip-10-0-1-129 ~]$ docker volume ls
DRIVER    VOLUME NAME
local     45481ab743b77a1ce8bd3f480b50172e5f4d1c31ae51b565a0f371b11d14100d
local     affa07409189939e60eb3d520092fac428ac9cde54a63d5b4311b4f3694d9199
local     website

Then we want to prune the volumes:

[cloud_user@ip-10-0-1-129 ~]$ docker volume prune
WARNING! This will remove all local volumes not used by at least one container.
Are you sure you want to continue? [y/N] y
Total reclaimed space: 0B

Actually no volume has been removed! It is because even we stop db2, but the container is still there, so docker won't delete the volume which has link to a container

[cloud_user@ip-10-0-1-129 ~]$ docker ps -a
CONTAINER ID   IMAGE           COMMAND                  CREATED          STATUS                      PORTS                               NAMES
f2e2aa007625   httpd:2.4       "httpd-foreground"       8 minutes ago    Up 8 minutes                0.0.0.0:80->80/tcp, :::80->80/tcp   web1
c00a4b92b0c8   postgres:12.1   "docker-entrypoint.s…"   29 minutes ago   Exited (0) 17 minutes ago                                       db2
f08726cd61cc   postgres:12.1   "docker-entrypoint.s…"   30 minutes ago   Up 30 minutes               5432/tcp                            db1

Let's remove db2 container

[cloud_user@ip-10-0-1-129 ~]$ docker rm db2
db2
[cloud_user@ip-10-0-1-129 ~]$ docker ps -a
CONTAINER ID   IMAGE           COMMAND                  CREATED          STATUS          PORTS                               NAMES
f2e2aa007625   httpd:2.4       "httpd-foreground"       10 minutes ago   Up 10 minutes   0.0.0.0:80->80/tcp, :::80->80/tcp   web1
f08726cd61cc   postgres:12.1   "docker-entrypoint.s…"   31 minutes ago   Up 31 minutes   5432/tcp                            db1

Now db2 container has been deleted.

Let's remove the volme again:

[cloud_user@ip-10-0-1-129 ~]$ docker volume prune
WARNING! This will remove all local volumes not used by at least one container.
Are you sure you want to continue? [y/N] y
Deleted Volumes:
45481ab743b77a1ce8bd3f480b50172e5f4d1c31ae51b565a0f371b11d14100d

Total reclaimed space: 41.43MB

Deletion success!

Backup and restore data to a docker volume

Modify volume need sudo

[cloud_user@ip-10-0-1-129 ~]$ sudo su -
[sudo] password for cloud_user:
[root@ip-10-0-1-129 ~]#

First, let's where docker volume is:

[root@ip-10-0-1-129 ~]# docker volume inspect website
[
    {
        "CreatedAt": "2023-01-25T14:23:53-05:00",
        "Driver": "local",
        "Labels": {},
        "Mountpoint": "/var/lib/docker/volumes/website/_data",
        "Name": "website",
        "Options": {},
        "Scope": "local"
    }
]

Create a zip file of the voluem data

  • tar czf /tmp/website_$(date +%Y-%m-%d-%H%M).tgz create a zip under /tmp folder with date in name
  • -C /var/lib/docker/volumes/website/_data
  • -C /var/lib/docker/volumes/website/_data .: want to traget directory /var/lib/docker/volumes/website/_data and . we want to zip everythings in this folder

tar czf /tmp/website_$(date +%Y-%m-%d-%H%M).tgz -C /var/lib/docker/volumes/website/_data .

Let's see what have been generated:

[root@ip-10-0-1-129 ~]# ls -l /tmp/website_*.tgz
-rw-r--r--. 1 root root 11363 Jan 25 14:47 /tmp/website_2023-01-25-1447.tgz

Let's also see the files:

[root@ip-10-0-1-129 ~]# ls -l /tmp/website_*.tgz
-rw-r--r--. 1 root root 11363 Jan 25 14:47 /tmp/website_2023-01-25-1447.tgz
[root@ip-10-0-1-129 ~]# tar tf /tmp/website_2023-01-25-1447.tgz
./
./img/
./img/LargeWidget.png
./img/MediumWidget.png
./img/SmallWidget.png
./index.html
./quote.html
./support.html
./widgets.html

We have everthing backup! But one thing is not ideal is that, we don't want everytime to use root user to backup data.

exit

Create a backup with non root access

  • run a container with volumen website to container /website folder
  • create a volume with /tmp (where zip files live) to container /backup
  • zip everything under container's /website folder to /backup folder
docker run -it --rm -v website:/website -v /tmp:/backup bash tar czf /backup/website_$(date +%Y-%m-%d-%H-%M).tgz -C /website .

We should be able to see the zip files:

[cloud_user@ip-10-0-1-86 ~]$ ls -l /tmp
total 1212
-rw-r--r--. 1 root root 1212535 Jan 18  2022 aws-cfn-bootstrap-latest.amzn1.noarch.rpm
drwx------. 3 root root      17 Jan 26 02:30 systemd-private-65fe0c5b569d4f54bfac42ae4f2269c1-chronyd.service-xzrmML
-rw-r--r--. 1 root root   11364 Jan 26 02:52 website_2023-01-26-0252.tgz
-rw-r--r--. 1 root root   11351 Jan 26 02:55 website_2023-01-26-0255.tgz

Restore the files

To test our backup we need to use root access again: sudo su -

Go to the docker volume folder: cd /var/lib/docker/volumes/

Then cd into website volume folder: cd website/_data/

We want to remove everything: rm -rf *

Make sure everything has been deleted:

[root@ip-10-0-1-86 _data]# ls -l
total 0

Now we want to unzip the zip file /tmp/website_2023-01-26-0255.tgz into the current folder to restore the data

[root@ip-10-0-1-86 _data]# tar xf /tmp/website_2023-01-26-0255.tgz .
[root@ip-10-0-1-86 _data]# ls -l
total 16
drwxr-xr-x. 2 root root   76 Jan 26 02:46 img
-rw-r--r--. 1 root root 3059 Jan 26 02:46 index.html
-rw-r--r--. 1 root root 2910 Jan 26 02:46 quote.html
-rw-r--r--. 1 root root 2611 Jan 26 02:46 support.html
-rw-r--r--. 1 root root 2645 Jan 26 02:46 widgets.html

OK! now we got our data back

posted @ 2023-01-27 02:43  Zhentiw  阅读(40)  评论(0编辑  收藏  举报