{"id":7926,"date":"2019-03-05T16:22:47","date_gmt":"2019-03-05T06:22:47","guid":{"rendered":"https:\/\/nsrd.info\/blog\/?p=7926"},"modified":"2019-03-05T16:22:55","modified_gmt":"2019-03-05T06:22:55","slug":"proof-of-concept-docker-with-boostfs","status":"publish","type":"post","link":"https:\/\/nsrd.info\/blog\/2019\/03\/05\/proof-of-concept-docker-with-boostfs\/","title":{"rendered":"Proof of Concept: Docker with BoostFS"},"content":{"rendered":"\n<p><b>Docker:<\/b> it&#8217;s where all the cool kids are playing these days (or so I&#8217;m told). It&#8217;s certainly got some good functionality and offers a lightweight approach to spinning up workloads compared to running a full virtual machine (VMware, Hyper-V, KVM or anything else, really, for that matter). <\/p>\n\n\n\n<p>I recently repurposed one of my servers at home as a dedicated development\/test server, giving me the opportunity to play around with Docker or anything else without occupying CPU cycles from my main VMware lab environment, and since I usually learn best by giving myself an actual task to perform, I thought, <i>can I get BoostFS running in a Docker container?<\/i><\/p>\n\n\n\n<p>My environment is:<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li>CentOS 7.6 Server as my Docker server<\/li><li>CentOS Docker Container<\/li><li>DDVE running DDOS 6.2.0.5<\/li><li>BoostFS 1.3<\/li><\/ul>\n\n\n\n<p>Initially I plowed right ahead and hit an obvious challenge: BoostFS uses the FUSE library, and within a Docker container, you can&#8217;t just load kernel modules. So, how does one get around this?<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"900\" height=\"900\" src=\"https:\/\/nsrd.info\/blog\/wp-content\/uploads\/2019\/03\/bigStock-Containers.jpg\" alt=\"Obligatory Shipping Container Photo Because I'm Writing About Containers\" class=\"wp-image-7928\" srcset=\"https:\/\/nsrd.info\/blog\/wp-content\/uploads\/2019\/03\/bigStock-Containers.jpg 900w, https:\/\/nsrd.info\/blog\/wp-content\/uploads\/2019\/03\/bigStock-Containers-150x150.jpg 150w, https:\/\/nsrd.info\/blog\/wp-content\/uploads\/2019\/03\/bigStock-Containers-300x300.jpg 300w, https:\/\/nsrd.info\/blog\/wp-content\/uploads\/2019\/03\/bigStock-Containers-768x768.jpg 768w, https:\/\/nsrd.info\/blog\/wp-content\/uploads\/2019\/03\/bigStock-Containers-144x144.jpg 144w, https:\/\/nsrd.info\/blog\/wp-content\/uploads\/2019\/03\/bigStock-Containers-200x200.jpg 200w\" sizes=\"auto, (max-width: 900px) 100vw, 900px\" \/><figcaption>Obligatory Shipping Container Photo Because I&#8217;m Writing About Containers<\/figcaption><\/figure>\n\n\n\n<p>The process for getting around this is the following:<\/p>\n\n\n\n<ol class=\"wp-block-list\"><li>Setup the Data Domain Mtree\/Storage Unit as you would for BoostFS. (Here&#8217;s an example where I&#8217;d set it up <strong><a rel=\"noreferrer noopener\" aria-label=\"previously (opens in a new tab)\" href=\"https:\/\/nsrd.info\/blog\/2018\/07\/30\/basics-getting-started-with-boostfs\/\" target=\"_blank\">previously<\/a><\/strong>.)<\/li><li>Add the fuse and fuse-libs package to your Docker server. (Make sure to activate it via a modprobe fuse, of course.)<\/li><li>Check out a CentOS docker image with permissions to access the FUSE device.<\/li><li>Deploy BoostFS within the Container<\/li><li>Setup the BoostFS configuration, and lockbox.<\/li><li>Mount the BoostFS storage unit from the DDVE to confirm it works.<\/li><li>Unmount the BoostFS storage unit.<\/li><li>Exit the Docker instance and save the image for easier access later.<\/li><\/ol>\n\n\n\n<p>Now, there&#8217;s some extra components to the above, but I&#8217;ll get to them as I go through. I&#8217;m going to assume if you wanted to read this, you&#8217;d be comfortable with items (1) and (2), so I&#8217;m jumping straight to item (3) for my walkthrough.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Getting a Docker Container Running<\/h2>\n\n\n\n<p>OK, first step is to get a Docker container running. Normally you&#8217;d d something like:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">$ <strong>docker run -it centos<\/strong><\/pre>\n\n\n\n<p>But in this case, we need to give our container a bit more access. Of course, I know this changes the security profile, but this is a proof of concept.<\/p>\n\n\n\n<p>So, the command we run instead is:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">pmdg@abydos <br> $ <strong>docker run -it --privileged --cap-add SYS_ADMIN --cap-add MKNOD --device \/dev\/fuse centos<\/strong><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Deploy BoostFS Within the Container<\/h2>\n\n\n\n<p>At this point you get a prompt inside your container, with the container ID as the hostname. The next step is to get the BoostFS package added to the container using the docker cp command. For me, that was:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">pmdg@abydos <br> $ <strong>docker cp DDBoostFS-1.3.0.0-607940.rhel.x86_64.rpm b6ad7a179778:\/tmp<\/strong><\/pre>\n\n\n\n<p>You&#8217;ll want to install the DDBoostFS Plugin now, but Docker will still want the FUSE base package and library installed as well, so I fall back on the old yum localinstall technique for that, viz.:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">root@b6ad7a179778 $ <strong>yum localinstall --nogpgcheck \/tmp\/DDBoostFS-1.3.0.0-607940.rhel.x86_64.rpm<\/strong> <br> Loaded plugins: fastestmirror, ovl<br> Examining \/tmp\/DDBoostFS-1.3.0.0-607940.rhel.x86_64.rpm: ddboostfs-1.3.0.0-607940.x86_64<br> Marking \/tmp\/DDBoostFS-1.3.0.0-607940.rhel.x86_64.rpm to be installed<br> Resolving Dependencies<br> --&gt; Running transaction check<br> ---&gt; Package ddboostfs.x86_64 0:1.3.0.0-607940 will be installed<br> --&gt; Processing Dependency: fuse &gt;= 2.8 for package: ddboostfs-1.3.0.0-607940.x86_64<br> Determining fastest mirrors<br><em>...snip...<\/em><br><br>Installed:<br>   ddboostfs.x86_64 0:1.3.0.0-607940                                             <br><br>Dependency Installed:<br>   fuse.x86_64 0:2.9.2-11.el7           fuse-libs.x86_64 0:2.9.2-11.el7          <br>   which.x86_64 0:2.20-7.el7           <br><br>Complete!<br> root@b6ad7a179778 $ <\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Setup BoostFS Configuration and Lockbox<\/h2>\n\n\n\n<p>Now we need to create a BoostFS configuration file. (I&#8217;ve also added BoostFS&#8217;s executable path, <strong>\/opt\/emc\/boostfs\/bin<\/strong>, to my PATH.)<\/p>\n\n\n\n<p>My container is going to write to a Data Domain called neutronium using a storage unit called BoostDocker, so the configuration file looks like the following:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">root@b6ad7a179778 $ <strong>cat \/opt\/emc\/boostfs\/etc\/boostfs.conf <\/strong><br>[global]<br> data-domain-system=neutronium.turbamentis.int<br> storage-unit=BoostDocker<br> lockbox-path=\/opt\/emc\/boostfs\/lockbox\/boostfs.lockbox<br> log-enabled=true<br> log-level=info<br> log-dir=\/opt\/emc\/boostfs\/log<br> log-file=output.log<br> log-maxsize=100<br> log-rotate-num=4<br><br>[\/container\/datadomain]<br> data-domain-system=neutronium.turbamentis.int<br> storage-unit=BoostDocker<br> security=lockbox<br> mtboost-enabled=true<br> mtboost-threads=16<br> max-connections=128<\/pre>\n\n\n\n<p>With the configuration file created, the next step is the lockbox:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">root@b6ad7a179778 $ <strong>boostfs lockbox set -u boost -d neutronium.turbamentis.int -s BoostDocker<\/strong><br> Enter storage unit user password: <br> Enter storage unit user password again to confirm: <br> Lockbox entry set<\/pre>\n\n\n\n<p>OK, now we&#8217;re getting closer.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Mount the BoostFS Storage Unit<\/h2>\n\n\n\n<p>With a lockbox and configuration file setup, we&#8217;re right to create the mount-point, and mount the BoostFS filesystem. First, creating the mount point:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">root@b6ad7a179778 $ <strong>mkdir -p \/container\/datadomain<\/strong><\/pre>\n\n\n\n<p>Now, to get access to a deduplicating mount-point:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">root@b6ad7a179778 $ <strong>boostfs mount \/container\/datadomain<\/strong><br><br> mount: Mounting neutronium.turbamentis.int:BoostDocker on \/container\/datadomain<\/pre>\n\n\n\n<p>We can see the mounted BoostFS filesystem via a &#8220;df&#8221; command:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">root@b6ad7a179778 $ <strong>df -h<\/strong><br> Filesystem                      Size  Used Avail Use% Mounted on<br> overlay                          50G  5.2G   45G  11% \/<br> tmpfs                            64M     0   64M   0% \/dev<br> tmpfs                           3.8G     0  3.8G   0% \/sys\/fs\/cgroup<br> \/dev\/mapper\/centos_abydos-root   50G  5.2G   45G  11% \/etc\/hosts<br> shm                              64M     0   64M   0% \/dev\/shm<br> boostfs                         354G   54G  300G  16% \/container\/datadomain<\/pre>\n\n\n\n<p>A quick test of writing data to the BoostFS filesystem:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">root@b6ad7a179778 $ <strong>du -hs \/usr\/share<\/strong><br> 37M    \/usr\/share<br> root@b6ad7a179778 $ <strong>tar cf \/container\/datadomain\/share.tar \/usr\/share<\/strong><br> tar: Removing leading <code>\/' from member names<\/code><br><code>tar: Removing leading<\/code>\/' from hard link targets<br> root@b6ad7a179778 $ <strong>ls -l \/container\/datadomain\/share.tar<br><\/strong> -rw-r--r-- 1 root root 34007040 Mar  5 04:44 \/container\/datadomain\/share.tar<\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Unmount the BoostFS Filesystem<\/h2>\n\n\n\n<p>To unmount the filesystem ahead of exiting the container, just execute:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">root@b6ad7a179778 $ <strong>boostfs unmount \/container\/datadomain<\/strong><br>root@b6ad7a179778 $ <strong>df -h<\/strong><br> Filesystem                      Size  Used Avail Use% Mounted on<br> overlay                          50G  5.2G   45G  11% \/<br> tmpfs                            64M     0   64M   0% \/dev<br> tmpfs                           3.8G     0  3.8G   0% \/sys\/fs\/cgroup<br> \/dev\/mapper\/centos_abydos-root   50G  5.2G   45G  11% \/etc\/hosts<br> shm                              64M     0   64M   0% \/dev\/shm<\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Exit the Docker Image, Save the Container Template<\/h2>\n\n\n\n<p>OK, now we&#8217;re ready to exit the Docker image and save the container template. For me, that worked as follows:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">root@b6ad7a179778 $ <strong>exit<\/strong><br> exit<br><br>pmdg@abydos<br>$ <strong>docker commit -m \"Added FUSE &amp; BoostFS\" -a \"Preston de Guise\" b6ad7a179778 centos\/boostfs<\/strong><br> sha256:96f67ea69027ae7d85904a0960f8266d4437ba4da60209f1a3c122bf000644ac<br><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Using the BoostFS Container<\/h2>\n\n\n\n<p>Obviously the point of creating a container template is to be able to make use of it. To do this, we have to:<\/p>\n\n\n\n<ol class=\"wp-block-list\"><li>Use docker to create a new container with the same settings as before.<\/li><li>Delete the lockbox information and recreate it. Why? The lockbox information is tied to the docker container we&#8217;d spun up for the creation of the template. But our new docker instance will get a different container ID \u2013&nbsp;a different hostname from the DD perspective, and we&#8217;ll need to start from scratch.<\/li><li>Mount the BoostFS storage unit.<\/li><\/ol>\n\n\n\n<p>So, here goes!<\/p>\n\n\n\n<p>First, getting the docker container running based on our new centos\/boostfs template:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">pmdg@abydos<br>$ <strong>docker run -it --privileged --cap-add SYS_ADMIN --cap-add MKNOD --device \/dev\/fuse centos\/boostfs<\/strong><br><\/pre>\n\n\n\n<p>Within the container, we delete and recreate the lockbox information:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">[root@8a2861cd001a \/]# <strong>rm \/opt\/emc\/boostfs\/lockbox\/*<\/strong><\/pre>\n\n\n\n<pre class=\"wp-block-preformatted\">[root@8a2861cd001a \/]# <strong>boostfs lockbox set -u boost -d neutronium.turbamentis.int -s BoostDocker<\/strong><br> Enter storage unit user password: <br> Enter storage unit user password again to confirm: <br> Lockbox entry set<\/pre>\n\n\n\n<p>Now, we can mount the BoostFS filesystem and access whatever we&#8217;d previously saved:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">[root@8a2861cd001a \/]# <strong>boostfs mount \/container\/datadomain<\/strong><br><br> mount: Mounting neutronium.turbamentis.int:BoostDocker on \/container\/datadomain<br> [root@8a2861cd001a \/]# <strong>ls -l \/container\/datadomain<\/strong><br> total 2076<br> -rw-r--r-- 1 root root 34007040 Mar  5 04:44 share.tar<\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Wrapping Up<\/h2>\n\n\n\n<p>I&#8217;m not pretending to know a lot about Docker with the above, but for me the next logical step in using Containers is to make sure when they <em>do<\/em> have state (and I know there&#8217;s a lot of arguments that they should, as much as possible, be stateless \u2013&nbsp;but there&#8217;s going to be arguments that there&#8217;s always exceptions), you can do a storage and network efficient operation to protect that state data. One way to do that without going through a full agent\/client configuration within something like Avamar or NetWorker (and dealing with obvious client hostname issues) is to use BoostFS instead, which is what I wanted to test out here.<\/p>\n\n\n\n<p><div>(There&#8217;s probably a whole raft of automation options in the above that I&#8217;ve not considered, but I&#8217;m still getting my head around docker.)<\/div><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Docker: it&#8217;s where all the cool kids are playing these days (or so I&#8217;m told). It&#8217;s certainly got some good&hellip;<\/p>\n","protected":false},"author":1,"featured_media":7928,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"jetpack_post_was_ever_published":false,"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_memberships_contains_paid_content":false,"footnotes":"","jetpack_publicize_message":"","jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":true,"jetpack_social_options":{"image_generator_settings":{"template":"highway","default_image_id":0,"font":"","enabled":false},"version":2}},"categories":[6,1181],"tags":[1460,1515,1514],"class_list":["post-7926","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-basics","category-data-domain-2","tag-boostfs","tag-container","tag-docker"],"aioseo_notices":[],"jetpack_publicize_connections":[],"jetpack_featured_media_url":"https:\/\/nsrd.info\/blog\/wp-content\/uploads\/2019\/03\/bigStock-Containers.jpg","jetpack_shortlink":"https:\/\/wp.me\/pKpIN-23Q","jetpack_sharing_enabled":true,"jetpack_likes_enabled":true,"_links":{"self":[{"href":"https:\/\/nsrd.info\/blog\/wp-json\/wp\/v2\/posts\/7926","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/nsrd.info\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/nsrd.info\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/nsrd.info\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/nsrd.info\/blog\/wp-json\/wp\/v2\/comments?post=7926"}],"version-history":[{"count":5,"href":"https:\/\/nsrd.info\/blog\/wp-json\/wp\/v2\/posts\/7926\/revisions"}],"predecessor-version":[{"id":7937,"href":"https:\/\/nsrd.info\/blog\/wp-json\/wp\/v2\/posts\/7926\/revisions\/7937"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/nsrd.info\/blog\/wp-json\/wp\/v2\/media\/7928"}],"wp:attachment":[{"href":"https:\/\/nsrd.info\/blog\/wp-json\/wp\/v2\/media?parent=7926"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/nsrd.info\/blog\/wp-json\/wp\/v2\/categories?post=7926"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/nsrd.info\/blog\/wp-json\/wp\/v2\/tags?post=7926"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}