{"id":236,"date":"2015-12-29T05:56:27","date_gmt":"2015-12-29T05:56:27","guid":{"rendered":"https:\/\/carson.fenimorefamily.com\/?p=236"},"modified":"2015-12-29T05:56:27","modified_gmt":"2015-12-29T05:56:27","slug":"containers-for-fun-and-profit","status":"publish","type":"post","link":"https:\/\/carson.fenimorefamily.com\/?p=236","title":{"rendered":"Containers for Fun and Profit"},"content":{"rendered":"<p>With all the whirl about containers I decided I could wait no longer to join the fray.  Here is a log of some of the things I learned.<\/p>\n<p><strong><a href=\"https:\/\/docs.docker.com\/linux\/step_one\/\">Basic test<\/a>, e.g. what the heck is this?<\/strong><\/p>\n<p>I spun up a cent7 vm several months back. Apparently my repos were a tad old and things didnt work until i did a yum update first, then reboot.  Then I could systemctl enable docker, systemctl start docker<\/p>\n<p>Note you MUST sudo in for docker commands to work<\/p>\n<p>Also note: cent7 has docker in it natively &#8211; no need to wget install it (unless you want to use some of the new features like the networking module)<\/p>\n<p>The following is your smoke test:<\/p>\n<p>[code]<br \/>\nsudo docker run hello-world<br \/>\n[\/code]<\/p>\n<p><strong><a href=\"https:\/\/docs.docker.com\/linux\/step_three\/\">Test 2: Expanded sample<\/a><\/strong><\/p>\n<p>This worked flawlessly\u2026<\/p>\n<p><strong><a href=\"https:\/\/docs.docker.com\/linux\/step_four\/\">Test 3: Interactive sample<\/a><\/strong><\/p>\n<p>Ditto, worked perfectly<\/p>\n<p><strong>Test 4: Do my own thing<\/strong><\/p>\n<p>I made a \u201clooper.py\u201d app with the following code:<\/p>\n<p>[code]<br \/>\n#!\/usr\/bin\/python<br \/>\nimport time<br \/>\nwhile True:<br \/>\n\tprint &quot;Hi! &quot;, time.time()<br \/>\n\ttime.sleep(1)<br \/>\n[\/code]<\/p>\n<p>I then made the following Dockerfile<\/p>\n<p>[code]<br \/>\nFROM docker.io\/centos:latest<br \/>\nRUN yum install python -y<br \/>\nCOPY looper.py \/<br \/>\nCMD \/looper.py<br \/>\n[\/code]<\/p>\n<p>And create the image with <\/p>\n<p>[code]<br \/>\n\tdocker build -t looper .<br \/>\n[\/code]<\/p>\n<p>When i ran the build one of the things I noticed is that python was already installed in the centos image.  I modified the Dockerfile by removing the RUN line, and one cool thing is that when i re-ran the build command, the python install layer was automatically removed, and everything else was basically a noop.  In other words docker appears to do a good job at being efficient.<\/p>\n<p>I then ran my looper:<\/p>\n<p>[code]<br \/>\n\tdocker run looper<br \/>\n[\/code]<\/p>\n<p>Nothing happened\u2026 So i thought\u2026and though\u2026 and eventually decided to try and attach.  Ubeknowest to me, by doing docker run i WAS attached, but nonetheless I learned a few things:<\/p>\n<ul>\n<li>To attach you need your container id<\/li>\n<li>To get your container id you run \u201cdocker ps\u201d<\/li>\n<\/ul>\n<p>Once I did a docker attach to my container id, i saw nothing, still.  I did a Ctrl-C and viola, my looper output appeared!  I suspected buffering, which turned out to be the case.  I modified looper as follows:<\/p>\n<p>[code]<br \/>\n#!\/usr\/bin\/python<br \/>\nimport time<br \/>\nimport sys<br \/>\nwhile True:<br \/>\n\tprint &quot;Hi! &quot;, time.time()<br \/>\n\tsys.stdout.flush()<br \/>\n\ttime.sleep(1)<br \/>\n[\/code]<\/p>\n<p>Then rebuilt, and re-ran, and it all worked.<\/p>\n<p>Note that this only runs the command in the foreground.  To run it in the background:<\/p>\n<p>[code]<br \/>\n\tdocker run -d looper<br \/>\n[\/code]<\/p>\n<p>You can then docker ps, find the cid, docker attach to it.   But\u2026 you cannot detach (without sending a SIGKILL)!  The docks say Ctrl-P + Ctrl+Q will detach, but this appears to only work if you use the following command when running it:<\/p>\n<p>[code]<br \/>\n\tdocker run -tdi looper<br \/>\n[\/code]<\/p>\n<p>Where <strong>t<\/strong> means create a tty, and <strong>i<\/strong> means \u201ckeep stdin open even if not attached\u201d.  This works well.<\/p>\n<p>Note that each time i make changes to looper, when i rebuild it takes at most 20 seconds.. if no changes, docker takes milliseconds\u2026<\/p>\n<p><strong>Test 5: layers<\/strong><\/p>\n<p>What if the container modifies a file?<\/p>\n<p>I modified looper.py to write to stdout and a file:<\/p>\n<p>[code]<br \/>\n#!\/usr\/bin\/python<br \/>\nimport time<br \/>\nimport sys<br \/>\nwhile True:<br \/>\n\tmsg = &quot;Hi! &quot; + str(time.time())<br \/>\n\tprint msg<br \/>\n\twith open(&#8216;myfile&#8217;,&#8217;a&#8217;) as f:<br \/>\n\t\tf.write(msg + &#8216;\\n&#8217;)<br \/>\n\tsys.stdout.flush()<br \/>\n\ttime.sleep(1)<br \/>\n[\/code]<\/p>\n<p>For fun i created a file named \u201cmyfile\u201d, then build the image, then ran the container. When it runs i can do a docker diff:<\/p>\n<p>[code]<br \/>\n# docker diff f04849645523<br \/>\nA \/myfile<br \/>\n[\/code]<\/p>\n<p>And to be clear, this means the file was added in the image. Docker wont let the app reach into my own version of \u201cmyfile\u201d.<\/p>\n<p>What if i want to see the file?  In older versions of docker, apparently you had a few options, such as running ssh, or making a snapshot, but now its easy:<\/p>\n<p>[code]<br \/>\n\tdocker exec -t -i &lt;cid&gt; \/bin\/bash<br \/>\n[\/code]<\/p>\n<p>You can then just cat the file, etc.  If you actually want to copy the files out,<br \/>\nyou can export the whole filesystem (docker export <cid>) as a tar, but this seems nuts. If you just want a single file, use docker cp:<\/p>\n<p>[code]<br \/>\ndocker cp &lt;cid&gt;:&lt;src&gt; &lt;dest&gt;<br \/>\n[\/code]<\/p>\n<p><strong>Test 6: CPU limit<\/strong><\/p>\n<p>You can do a couple things:<\/p>\n<p>1) Limit the share of cpu usage across multiple containers. This is done by specifying a relative weighting (with -c)<\/p>\n<p>2) Pin the process to certain cpus with \u2014cpuset-cpus=<cpuset><\/p>\n<p>I havent been able to find an equivalent to the simple \u201climit to N processors\u201d idea on virtual machines.  The weighting is fairly close.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>With all the whirl about containers I decided I could wait no longer to join the fray. Here is a log of some of the things I learned. Basic test, e.g. what the heck is this? I spun up a cent7 vm several months back. Apparently my repos were a tad old and things didnt [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[5],"tags":[],"class_list":["post-236","post","type-post","status-publish","format-standard","hentry","category-containers"],"_links":{"self":[{"href":"https:\/\/carson.fenimorefamily.com\/index.php?rest_route=\/wp\/v2\/posts\/236","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/carson.fenimorefamily.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/carson.fenimorefamily.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/carson.fenimorefamily.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/carson.fenimorefamily.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=236"}],"version-history":[{"count":0,"href":"https:\/\/carson.fenimorefamily.com\/index.php?rest_route=\/wp\/v2\/posts\/236\/revisions"}],"wp:attachment":[{"href":"https:\/\/carson.fenimorefamily.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=236"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/carson.fenimorefamily.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=236"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/carson.fenimorefamily.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=236"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}