Friday, July 15, 2022

Docker 101 - Manage Data

  


Before introducing how to manage data in Docker, let's use the mysql image to do some experiment to see if data is persist in container or not.



MySQL database



Let's follow the official document to run a mysql container.


Ex:
$ docker container run -d -e MYSQL_ROOT_PASSWORD=secret_pwd mysql

Result:
Unable to find image 'mysql:latest' locally
  latest: Pulling from library/mysql
  e54b73e95ef3: Pull complete
  327840d38cb2: Pull complete
  642077275f5f: Pull complete
  e077469d560d: Pull complete
  cbf214d981a6: Pull complete
  7d1cc1ea1b3d: Pull complete
  d48f3c15cb80: Pull complete
  94c3d7b2c9ae: Pull complete
  f6cfbf240ed7: Pull complete
  e12b159b2a12: Pull complete
  4e93c6fd777f: Pull complete
  Digest: sha256:152cf187a3efc56afb0b3877b4d21e231d1d6eb828ca92210...
  Status: Downloaded newer image for mysql:latest
  3577ab8e698b32d39259372dc6e189386846b60ff11075c1acd981d101ad8c8d

Ex: Check the container status
$ docker container ls -a

Result:
CONTAINER ID   IMAGE     COMMAND                  CREATED          
3577ab8e698b   mysql     "docker-entrypoint.s…"   18 seconds ago  

STATUS          PORTS                 NAMES
Up 17 seconds   3306/tcp, 33060/tcp   youthful_mahavira

Then our MySQL container is up.
Then we can use 'sh' to run mysql commands and  create a new database.

Ex:
$ docker container exec -it 3577 sh
  # mysql -u root -p
  Enter password: (secret_pwd)

  mysql> CREATE DATABASE demo;
  mysql> SHOW DATABASES;

Result:
 +--------------------+
 | Database           |
  +--------------------+
  | demo               |
  | information_schema |
  | mysql              |
  | performance_schema |
  | sys                |
  +--------------------+
  5 rows in set (0.00 sec)

The data will be kept if we stop and restart this running container because those data are saved in writable container layer.

Ex:
$ docker container stop 3577
  $ docker container start 3577
  $ docker container exec -it 3577 sh
  $ mysql -u root -p
  Enter password: (secret_pwd)

  mysql> SHOW DATABASES;

Result:
+--------------------+
  | Database           |
  +--------------------+
  | demo               |
  | information_schema |
  | mysql              |
  | performance_schema |
  | sys                |
  +--------------------+
  5 rows in set (0.00 sec)

But if this container is removed and got recreated, then all data are lost.

Ex:
$ docker container stop 3577
  $ docker container rm 3577
  $ docker container run -d -e MYSQL_ROOT_PASSWORD=secret_pwd mysql

Result:
317d15e11298d1f1afbf2c3050fc002fdfde559e873c3a5ea48050dc570f2ea1

Ex:
$ docker container exec -it 317d sh
$ mysql -u root -p
  Enter password: (secret_pwd)

  mysql> SHOW DATABASES;

Result:
+--------------------+
| Database           |
  +--------------------+
  | information_schema |
  | mysql              |
  | performance_schema |
  | sys                |
  +--------------------+
  4 rows in set (0.00 sec)


How to manage data in docker?



There are two ways to manage Data in Docker: Volumes and Bind Mounts.






Volumes



Volumes are stored in a part of the host filesystem which is managed by Docker (/var/lib/docker/volumes/ on Linux)
Non-Docker processes should not modify this part of the filesystem.
Volumes are the best way to persist data in Docker.

Let's specific mount when running MySQL container.

Ex:
$ docker container run -d  \
    --mount source=mysql-data,target=/var/lib/mysql \
        -e MYSQL_ROOT_PASSWORD=secret_pwd mysql

Result:
66f2a3d07cc7

We can use the following command to check the volumes.

Ex:
$ docker volume ls

Result:
DRIVER    VOLUME NAME
  local     mysql-data

We even can check it with more details.

Ex:
$ docker volume inspect mysql-data

Result:
[
    {
      "CreatedAt": "2022-07-15T11:18:58-07:00",
      "Driver": "local",
      "Labels": null,
      "Mountpoint": "/var/lib/docker/volumes/mysql-data/_data",
      "Name": "mysql-data",
      "Options": null,
      "Scope": "local"
    }
  ]

Let's create a new database under this MySQL container.

Ex:
$ docker container exec -it 66f2 sh
  # mysql -u root -p
  Enter password: (secret_pwd)

  mysql> CREATE DATABASE demo;
  mysql> SHOW DATABASES;

Result:
+--------------------+
| Database           |
+--------------------+
  | demo               |
  | information_schema |
  | mysql              |
  | performance_schema |
  | sys                |
  +--------------------+
  5 rows in set (0.00 sec)

Then let's stop and remove this container.
And create a new container and mount the data to the same volume 'mysql-data'.

Ex:
$ docker container stop 66f2
$ docker container rm 66f2
  $ docker container run -d  \
      --mount source=mysql-data,target=/var/lib/mysql \
      -e MYSQL_ROOT_PASSWORD=secret_pwd mysql

Result:
3d2360f62b86b3da6cc76360f285dc2745122e8df8d5bf0be457f30e5e459ce4

Then we can find 'demo' database in this new MySQL container.

Ex:
$ docker container exec -it 3d23 sh
$ mysql -u root -p
  Enter password: (secret_pwd)

  mysql> SHOW DATABASES;

Result:
+--------------------+
| Database           |
  +--------------------+
  | demo               |
  | information_schema |
  | mysql              |
  | performance_schema |
  | sys                |
  +--------------------+
  5 rows in set (0.00 sec)


Bind Mounts



Bind mounts may be stored anywhere on the host system.
Non-Docker processes on the Docker host or a Docker container can modify them at any time.

We can use the following example to see how to launch a static page to nginx container and keep changing it in our host filesystem.

Ex:
$ touch index.html
$ vim index.html


<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Bind Mounts Exp</title>
</head>
<body>
<h2>Hello World</h2>
</body>
  </html>


Then we can mount the current folder to nginx container with the following commands.

Ex: $(pwd) means the current folder
$ docker container run -it -d  \
-p 8080:80  \
--name web  \
--mount type=bind,source=$(pwd),target=/usr/share/nginx/html  \
nginx

Result:
2b5cac189c984c07f384020b2ca31f88782d3f0a309573a52ce74d48303dfa8f

Once this nginx container is up, then we can check the browser (localshot:8080), and the page will just simply show 'Hello World'




We can change the index.html directly in our host filesystem, and once we refresh the browser, then we can see the page got changed.

Ex:
$ vim index.html

<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Bind Mounts Exp</title>
</head>
<body>
<h2>Hello Docker</h2>
</body>
  </html>





Therefore, using bind mounts, we can make our development experience better.

No comments:

Post a Comment