Sunday, June 11, 2017

Docker -Introducing Volume containers

Introducing volumes:

A host or containers directory tree is created by a set of mount points that describe how to piece  together one or more file systems.

Volume: A volume  is a mount point on the containers directory tree where a portion of the host directory tree has been mounted .
With out volumes,containers users are limited to working with the union  file system that provides image mounts.
Although the union file system works for building and sharing images,its less than ideal for working with persistent or shared data.volumes fill those use cases and  play a critical role in containerized system design.
Volume provide container independent data management:
A volume is a tool for segmenting and sharing data that has a scope or life cycle that independent of a single container.
That makes volumes an important part of any containerized system design that shares or writes files.
Examples of data that differ in scope or access from a container include the following:
Database software versus database data
Web application versus log data
Data processing application versus input and output data
Webserver versus static content.
Products versus support tools.
Volumes enable separation of concerns and create modularity for architectural components.
That modularity helps you understand,build,support and reuse parts of larger systems more easily.
Think about in this way :images are appropriate for packaging and distributing relatively static files like programs.
Volumes hold dynamic data or specializations.this distinction makes images reusable and data simple to share.
This separation of relatively static or dynamic files space allows application or image authors to implement advanced patterns such as polymorphic and composable tools.
Polymorphic tool:It maintains a consistent  interface but might have several implementations that do different things.
Consider an application such as general application server:
Apache Tomcat ,for example is an application that provides an HTTP interface on a network and dispatches any requests it receives to pluggable programs.
Tomcat has polymorphic behavior.Using volumes,you can inject behavior into containers with out modifying an image.
Alternatively,consider a database program like Mongodb or MySQL.The value of a database is defined by the data it contains .
A database program always presents the  same interface but takes on a wholly different value depending on that can be injected with a volume .
A more fundamentally,
Volumes enable the separation of application and host concerns
At some point image will be loaded onto a host and a container created from it.Docker knows little about the  host where its running and can only make assertions about what files should be available to the container.
That means Docker alone has no way to take advantage of host-specific facilities like mounted networks storage or mixed spinning and solid state drives.
But a user with knowledge of the host can use volumes to map directories  in a container to appropriate storage on that host.
Volume containers:
Get started ,By creating a single container that defines a volume.This is called a volume container.
Docker run –d \
--volume  /var/lib/Cassandra/data  \
--name cass-shared  \
alpine echo data container .
(specify volume mount point  inside the container ).
The volume containers will immediately stop.That is appropriate for the purpose of this example.dont remove it yet.
EXTRAS:
Your going to use the volume it created when you create a new container running Cassandra.
Docker run –d \
   --volumes –from cass-shared \
   --name cass1 \
Cassandra : 2.2
(Inherit volume definitions).
After docker pulls the Cassandra:2.2 image from dockerhub:
It creates a new container and copies the volume definitions from the volume container.
After that,both containers have a volume mounted at /var/lib/Cassandra/data that points to the same location on the host directory tree.
Next start a container from the Cassandra:2.2 image,but run Cassandra client tool and connect to your running server:

Volume types
There are two types of volumes
Every volume is a mount point on the container directory tree to a location on to the host directory tree,but the types differ in where that location is on the host.
The first type of volume is a bind mount.Bind mount volumes use  any user-specified directory or file on the host operating system.
The second type is a managed volume.Managed voulmes use locations  that are created by docker  daemon in space controlled by the daemon called docker managed space.

BIND MOUNT VOLUMES:
A Bind mount volume is a volume that points to a user-specified location on the host file system.It is very useful  when the host provides some file or directory that needs to be mounted into the container directory tree at a specific point.
Bind mount volumes are useful if you want to share data with other processes running outside a container,such as components of the host system itself.They also work if you want to share data that lives
For example,
suppose your working on a document or web pages on your local computer and want to share your work with your friend .
One way to do so would be to use docker to launch a web server and server content that you have copied into webserver image.Although that would work and might even be a best practice for production environments,its cumbersome to rebuild the image everytime you want to share an updated version of the document.
Instead,you could use docker to launch the web server and bind mount the location of your document into the new container at the web server document root.you can try this for yourself.
Create a new directory in your home directory called example-docs .
Now create a file named index.html in that directory .Add a nice message for your friend to the file.
The following  command will start an Apache HTTP server where your directory is bind mounted to the servers document root.
 docker run –d  --name bmweb \
-v   ~/example-docs :/usr /local/apache/htdocs \
-p 80:80 \
httpd:latest

(with this container running,you should be able to point your browser at the ipaddress where your docker engine is running and see the file you created.)
In this example you used the  -v option and a location map to create the bind mount volume .
The map is delimited with a colon(as is common with linux-style command line tools)
The map key (the path before the colon)is the absolute path of a location on the host file system and the value (the path of the colon)is the location where it should be mounted inside the container.you must specific location with absolute paths.
This example touches on an important attribute or feature voulmes,when you mount a volume on a container file system,it replaces the content that the images provides at that location.
In the above following example,the httpd:latest image provides some default HTML content at /usr/local/apache2/htdocs/ ,but when you mounted a volume at that location,the content provided by the image was overridden by the content on the host.This behavior is the basis for the polymorphic container pattern.

If  we want to make sure that the apache HTTP webserver cannot change the contents of this volume.Even the most trusted software can contain vulnerabilities and its best minimize the impact of an attack  on your website,Docker provides a mechanism to mount volumes as read-only.

You can do this by appending :ro to the volume map specification,you should change the run command to something like the following:
Docker rm   -vf bmweb
Docker run –name bmweb_ro  \
--volume   ~/example-docs :/usr/local/apache2/htdocs/:ro   \
-p 80:80 \
httpd:latest

By mounting the Docker read-only,you can prevent any processor inside the container to modifying the content of the volume.
Example:Quick-test:
Docker run –rm \
-v  ~/example-docs:/testspace:ro  \
alpine \
/bin/sh –c ‘echo test   >  /testspace/test’
Note:
If you specify  a host directory that doesn’t exist,Docker will create it for you.It’s better to have more control over the ownership and permission set on a directory.
Bind mount volumes aren’t limited to directories:
You can use bind mount volumes to mount individual files.This provides flexibility to create or link resources at a level that avoids conflicts with other resources.
For Example:
Consider when you want to mount a specific file into a directory that contains otherfiles.concretely,suppose you only wanted to serve a  single additional file alongside the web content that shipped with some image.
If you use a bind mount of a whole directory over that location the other files will be lost .By using a specific file as a volume,you can override or inject individual files.
IMPORTANT THING TO NOTE IN THIS CASE IS THAT THE FILE MUST EXIST ON THE HOST  BEFORE YOU CREATE  THE CONTAINER.OTHERWISE,DOCKER WILL ASSUME THAT YOU WANTED TO USE A DIRECTORY ,CREATE IT ON THE HOST AND MOUNT IT AT THE DESIRED LOCATION.(EVEN IF THAT LOCATION IS OCCUPIED BY A FILE).
Few problems with the Bind mount volumes:
If a container description depends on content at a specific location on the host file system,then that description isn’t portable to hosts where the content is unavailable or available in some other locations.
Create an opportunity for conflict with other containers,It would be bad idea to start multiple instances of Cassandra that all use the same host locations as a volume.In that case,each of the instances  would compete  for the same set of files  with out other tools such as file locks,that would likely result in corruption of the database.
Bind mount volumes are appropriate tools for workstation or machines with specialized concerns.It’s better to avoid  these kinds  of specific bindings in generalized platforms or hardware pools.you can take advantage of volumes in a host-agnostic and portable way with Docker managed volumes.
Docker-managed volumes:
Managed volumes are different from bind mount volumes because the Docker Daemon creates manages volumes in  a portion of the host’s file system that’s owned by Docker,using managed volumes is a method of decoupling volumes from specialized locations on the file-system.
Managed volumes are created when you use the –v option (or --volume) on docker run but only specify the mount point in container directory tree.

Example of Cassandra:
The container named cass-shared specified a volume at /var/lib/Cassandra/data:

Docker run –d \
-v  /var/lib/Cassandra/data \
--name cass-shared \
alpine echo data container
(specific volume mount point inside container).

Steps to use Inspect command:
When you created this container,the docker daemon created directories to store the contents of the three volumes somewhere in a part of the host file system that it controls.To find out exactly where this folder is ,you can use Docker inspect command filtered for volume keys.
Note:
The important thing to take away from this output is that docker created each of the volumes in a directory controlled by the docker daemon on the host.
Docker inspect  -f  “{{json .volumes}}” cass-shared

The output look like this:
{“/var/lib/Cassandra/data”:”/mnt/sda1/var/lib/docker/

The inspect subcommand will output a list of container mount points and the corresponding path on the host directory tree

The volume key points to a value that is itself a map.In this map each key is a mount point in the container, and the value is the location of the directory on the host file system
Docker managed volumes may seem difficult to work with if your manually building or linking tools together on your desktop,but in larger systems where specific locality  of the data is less important,managed volumes are a much more effective way to organize your data.
Sharing access to data is a key features of voulmes.if you have decoupled volumes from known locations on the file system,you need to know how to share volumes between containers with out exposing the exact location of managed containers.
SHARING VOLUMES:
Suppose you have a web server running inside a container that logs all the requests it receives to /logs/access.If you want to move those logs off your web server into storage that’s more permanent,you might do that with a script inside another container.Sharing volumes between containers is where their value become more obvious.Just as there are  two types of volumes,there are two ways to share volumes between containers.

Host-dependent sharing:
Two or more containers are said to use host-dependent sharing when each has a bind mount volume for a single known location on the host file system.This is the most obvious way to share some disk  space between containers.
Mkdir     ~/web-logs-example
(set up a known location)
docker run –name plath  -d \
-v  ~/web-logs-exaple:/data  \
dockerinaction/ch4_writer_a
(Bind mount the location into a log-writing container)
docker run   --rm  \
-v   ~/web-logs-example:/reader-data  \
alpine:latest   \
head  /reader-data/logA
(Bind mount the same location into a container for reading)
cat  ~/web-logs-example/logA
(view the logs from the host)
docker stop plath
(stop the writer).

EXTRAS
In this example you created two containers:one named plath that writes lines to a file and  an other that views the top part of the file.These containers share a common bind mount volume.Outside any container you can see the changes by listing the contents of the directory you created or viewing the new file.
Explore ways that containers might be linked together in this way.
Managed volume life cycle:
Managed volumes have lifecycles that are independent of any container,but as of this writing you can only reference them by the containers that use them.

Volume ownership
Managed volumes are second class entities.you have no way to share or delete a  specific managed volume because you have no way to identify a managed volume.Managed voulmes are only created  when you omit a  bind mount source and they are only identifiable by the containers that use them.
The highest fidelity way to identify volumes is to define a single container for each   manage volumes you consume.More  importantly,doing so helps you delete specific volumes.unless you resort to examining volume mapping on a container and manually cleaning up the docker managed space,removing volumes requires a referencing container and that makes it important to understand which  containers own each managed volume.
Cleaning up volumes:
Cleaning up managed volumes is a manual task.This default functionality prevents accidental destruction of potentially valuable data.Docker can’t delete bind mount volumes because the source exists outside the docker scope.Doing so could result in all manner of conflicts,instability and  unintentional data loss.
Docker can delete managed volumes when deleting containers.Running the docker rm command with the –v option will attempt to delete any managed volumes referenced by the  target container.Any managed volumes that are referenced by other containers will be skipped,but the internal counters will be decremented.this can lead to the problematic scenario.

Note:The  user created an orphan volume by deleting the two owners of that volume without instructing Docker remove the volumes attached to those containers.
If you delete every container that references a managed volume but fail to use the –v flag,you will make  that volume an orphan.Removing orphaned volumes requires messy manual steps but depending on the size of the volumes it may be worth the effort.Alternatively there are orphan volume cleanup scripts that you might consider using.You should carefully check those before running them.You will need to run those scripts as privileged user and if they contain malware,you could be handing over full control of your system.

Note:It’s better to avoid  the situation by getting into habit of using the –v option and using the volume container pattern.

We can remove all stopped containers and their volumes with the following command:

docker rm  -v $(docker   ps  -aq)

Advanced container patterns with volumes:

Volumes are a used to accomplish a wide range of file system customization and container interactions.
Volume containers are important for keeping a handle on data even in cases where a single container  should have exclusive access to some data.These handles make it possible to easily backup,restore and migrate data.
Examples:
Suppose you wanted to update your database software (use a new image).
If your database container writes its state to a volume and that volume was defined by a volume container ,the migration would be as simple as shutting down the original database container and starting the new one with the volume container as a volume source.

Note:
Using a container name prefix  such as vc_ would be a great hint for humans or scripts not to use the –v option when deleting a container.

Data-packed volume containers:
Volume containers are in a unique positions to seed volumes with data.The data-packed volume containers extension formalizes that notion.
It describes how images can be used to distribute static resources like configuration or code for use in containers created with other images.
(Data is packed and distributed in an image that also defines a volume)

A data-packed volume container is built from an image that copies static content from its image to volume it defines,so these containers can be used to distribute  critical architecture information like configuration,key material and code.You can build these by hand if you have an image that has the data you would like to make available by running and defining the volume and running a cp command at container-creation time.
Example:
docker run  --name dpvc \
-v /config \
dockerinaction/ch4_packed /bin/bash –c  ‘cp /packed/ *  /config/’
(copy content to the volume)

docker run  --rm  --volumes-from dpvc \
alpine:latest ls  /config
(list shared material)

docker run  --rm  --volumes-from dpvc \
alpine:latest   cat /config/packedData
(view shared material)
The commands in this code share files distributed by a single image.
Using data-packed volume containers to inject material into  a new container is the basis for the polymorphic container pattern.
Polymorphic container pattern:
A polymorphic tool is one that you interact with in  a consistent way but might have several implementations that do different things.Using volumes,you can inject different behavior into containers without modifying an image.
A polymorphic container is one that provides some functionality that’s easily substituted using volumes .
For Example:you have an image that contains the binaries for Node.JS and by default executes a command that runs the Node.JS program located at app/app.JS .
You can change the behavior of the containers  created from this image by injecting your own app.js implementation using a volume mounted at /app/app.js .It might make more sense to layer that new functionality in a new image .But there are some cases when this is the best solution.The first during development when you might not want to build a new image each time you iterate.The second is during operational events.

Example:
Consider a situation where an operational issue has occurred.In oreder to triage the issue,you might need tools available in an image that you had not anticipated when the  image  was built.But if you mount  a volume where you make additional tools available.
You can use docker exec command to run additional processes in a container :

Docker run  --name tools dockerinaction/ch4_tools
(create data-packed volume container with tools)
docker run  --rm \
--volumes from tools  \
alpine:latest  \
ls /operations/*
(list shared tools)
docker run  -d  --name  important_application \
--volume-from-tools \
dockerinaction/ch4_ia
(start another container with shared tools)
docker exec important_application  /operations/tools/someTool
(Use shared tool in running conatiners)
docker  rm –vf  important_application
(shutdown the applications)
docker rm –v  tools
(cleanup the tools)

We can inject files into  otherwise static containers to change all types of behavior.Most commonly,you will use polymorphic containers to inject application configuration.consider a multi-state deployment pipeline where an application’s configuration would change depending on where you deploy it.
You might use  data_packed volume containers to contribute environment-specific configuration at each stage. And then your application would look for its configuration at some known location.

Example:
docker run  --name devconfig \
-v /config  \
dockerinaction/ch4_packed_config:latest \
/bin/sh  -c ‘cp /development/* /config/’

docker run –name  prodconfig \
-v /config  \
dockerinaction /ch4_packed_config:latest \
/bin/sh –c  ‘cp /production/* /config/’



docker run –name  devApp \
--volume-from devconfig  \
dockerinaction/ch4_polyapp

docker run –name prodApp \
--volume-from prodconfig \
dockerinaction/ch4_polyapp

In the above following example ,you start the same application twicw but with a different configuration file injected.Using this pattern  you can build a simple version-controlled configuration distribution system.

Note:
Volumes allow containers to share files with the host or other containers.

No comments:

Post a Comment