<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title></title>
    <description>At the intersection of full-stack cloud technologies, devops, security, and infrastructure as code</description>
    <link>https://www.lonimbus.com//</link>
    <atom:link href="https://www.lonimbus.com//feed.xml" rel="self" type="application/rss+xml"/>
    <pubDate>Wed, 03 Jan 2018 19:06:56 +0000</pubDate>
    <lastBuildDate>Wed, 03 Jan 2018 19:06:56 +0000</lastBuildDate>
    <generator>Jekyll v3.5.1</generator>
    
      <item>
        <title>Speaking at KubeCon 2017 - Part 4 - The Talk</title>
        <description>&lt;p&gt;My final corrections and preparation, how it went, and future thoughts as I wrap up this four post series of my experience leading up to and speaking at KubeCon 2017.&lt;/p&gt;

&lt;h5 id=&quot;post-series-navigation&quot;&gt;Post Series Navigation:&lt;/h5&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;/speaking-at-kubecon-2017-part-1-the-cfp-submission&quot;&gt;Part 1 - The CFP Submission&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;/speaking-at-kubecon-2017-part-2-research&quot;&gt;Part 2 - Research&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;/speaking-at-kubecon-2017-part-3-first-run&quot;&gt;Part 3 - First Draft&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;/speaking-at-kubecon-2017-part-4&quot;&gt;Part 4 - The Talk&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=vTgQLzeBfRU&quot;&gt;The Recorded Talk&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://goo.gl/TNRxtd&quot;&gt;The Final Slides&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;more-visuals-needed&quot;&gt;More Visuals Needed!&lt;/h2&gt;

&lt;p&gt;While I felt like my &lt;a href=&quot;http://goo.gl/p42Shd&quot;&gt;dry-run slide deck&lt;/a&gt; was visually appealing in color scheme, used varying font styles for emphasis, and had decent clip-art style photos, it lacked a visual foundation.  I needed to convey a picture of a Kubernetes cluster that was simple enough to understand by the audience yet had enough detail to encompass all the attacks/hardening steps.&lt;/p&gt;

&lt;p&gt;I spent well over 20 hrs coming up with the visual of &lt;a href=&quot;http://goo.gl/TNRxtd/#22&quot;&gt;Slide 22&lt;/a&gt; using &lt;a href=&quot;https://cloudcraft.co&quot;&gt;Cloudcraft&lt;/a&gt;.  I was happy that I now had a visual anchor of the playing field that I could leverage when explaining each attack type.&lt;/p&gt;

&lt;h2 id=&quot;preparation&quot;&gt;Preparation&lt;/h2&gt;

&lt;p&gt;I knew that I needed to spend less time on the setup, less time doing the demos, and more time explaining how to harden things.  And shave about 20 mins off my run time.&lt;/p&gt;

&lt;p&gt;As I practiced, I found ways to set up each slide with fewer words.  I consolidated several slides and threw out a handful altogether.  I even went so far as to hand edit the asciinema JSON such that the typing delays more closely matched my prepared words.  So when I clicked “start” on the demo, what I said was concisely summarizing the text going across the screen and calling the audience’s attention to the exact spot I wanted them to see as it appeared.&lt;/p&gt;

&lt;p&gt;I practiced maybe a dozen times before arriving in Austin.  And I probably doubled that number while I was there in my hotel room before falling asleep each night.  I suppose it helped me burn off the nervous energy since I was speaking after lunch on the last day.&lt;/p&gt;

&lt;h2 id=&quot;the-day-of&quot;&gt;The Day Of&lt;/h2&gt;

&lt;p&gt;I went to the keynotes in the morning, but I was so nervous, I skipped the two morning sessions.  My talk was at 2pm, the first after lunch, so I grabbed a sandwich and went to an empty side of the conference to practice out loud.  The problem with this approach, you see, is that your voice is a perishable commodity.  Having recently gotten over a cough and having spoken out loud all week to myself in practicing, a bit of a hoarseness was creeping in.&lt;/p&gt;

&lt;p&gt;The 10 mins waiting for the talk to start were when I was most nervous.  Is my battery still good?  Is the screen still displaying or did it sleep?  Is my slide advancer still working?  My microphone level good?&lt;/p&gt;

&lt;p&gt;The moment I started speaking, I knew it was going to be just fine.  Yes, I had a bit of that cough pop up, but the room was attentive and I got a lot of head nods.  I thought I set up the demos decently, executed them well, and gotten their attention on the right moments.  What threw me off, though, was the lack of questions.  I think to some degree, most folks were a combination of conference-fatiguted and still somewhat firehosed with the info.  I had a few really good conversations and congratulatory remarks from folks in the hallway afterward. Finally, I felt relief.  I remember saying to myself, “Ok, THAT’s done”.&lt;/p&gt;

&lt;h2 id=&quot;parting-thoughts&quot;&gt;Parting Thoughts&lt;/h2&gt;

&lt;p&gt;I appreciate all the help I’ve received from my family, close friends, and the Kuberentes community members (see the last slide on my deck) for the patience, support, and guidance in helping me complete this journey.  And thank you to the CNCF/KubeCon Committee members for giving me the opportunity to present.&lt;/p&gt;

&lt;p&gt;This blog series is a diary of sorts to help me remember all the hard work, why I did it, and to allow myself to feel proud about the past 5 months.  I hope that chronicling it all might help would-be presenters see my end-to-end process, see the final result, and have a better perspective of the overall experience.  Of course, not every talk requires or should be as technically dense or try to cover so much ground.  I firmly believe that everyone has something of value to offer the community if they look hard enough into their work or ask the right questions of themselves.  If not, be patient and keep asking.  It’ll come.&lt;/p&gt;

&lt;h5 id=&quot;post-series-navigation-1&quot;&gt;Post Series Navigation:&lt;/h5&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;/speaking-at-kubecon-2017-part-1-the-cfp-submission&quot;&gt;Part 1 - The CFP Submission&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;/speaking-at-kubecon-2017-part-2-research&quot;&gt;Part 2 - Research&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;/speaking-at-kubecon-2017-part-3-first-run&quot;&gt;Part 3 - First Draft&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;/speaking-at-kubecon-2017-part-4&quot;&gt;Part 4 - The Talk&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=vTgQLzeBfRU&quot;&gt;The Recorded Talk&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://goo.gl/TNRxtd&quot;&gt;The Final Slides&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</description>
        <pubDate>Wed, 03 Jan 2018 13:57:07 +0000</pubDate>
        <link>https://www.lonimbus.com//speaking-at-kubecon-2017-part-4</link>
        <guid isPermaLink="true">https://www.lonimbus.com//speaking-at-kubecon-2017-part-4</guid>
        
        
        <category>kubernetes</category>
        
        <category>kubecon</category>
        
        <category>speaking</category>
        
      </item>
    
      <item>
        <title>Speaking at KubeCon 2017 - Part 3 - First Run</title>
        <description>&lt;p&gt;The opportunity to present a “dry run” of this talk was the most important lesson learned of the level of preparation required to really pull off a solid performance at KubeCon.&lt;/p&gt;

&lt;h5 id=&quot;post-series-navigation&quot;&gt;Post Series Navigation:&lt;/h5&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;/speaking-at-kubecon-2017-part-1-the-cfp-submission&quot;&gt;Part 1 - The CFP Submission&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;/speaking-at-kubecon-2017-part-2-research&quot;&gt;Part 2 - Research&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;/speaking-at-kubecon-2017-part-3-first-run&quot;&gt;Part 3 - First Run&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;/speaking-at-kubecon-2017-part-4&quot;&gt;Part 4 - The Talk&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=vTgQLzeBfRU&quot;&gt;The Recorded Talk&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://goo.gl/TNRxtd&quot;&gt;The Final Slides&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;the-dry-run&quot;&gt;The Dry Run&lt;/h2&gt;

&lt;p&gt;About the time I submitted my CFP, a the &lt;a href=&quot;https://www.meetup.com/NOVA-Kubernetes&quot;&gt;NOVA Kubernetes Meetup&lt;/a&gt; was just getting started and had its first meetup.  I offered and was gratiously accepted to speak at the next meetup in October.  I know myself enough to know that I work best with a deadline, so setting one would sharpen the focus.&lt;/p&gt;

&lt;p&gt;I practiced a few times, and every iteration was better than the last, but also became longer.  I became so driven to &lt;em&gt;prove&lt;/em&gt; my attacks worked and were really simple that I added lots of asciinema demos.  I figured I could chop it down a bit later.&lt;/p&gt;

&lt;p&gt;Going into the talk, I was looking for a couple things.&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Did I establish myself with enough credibility?&lt;/li&gt;
  &lt;li&gt;Did the demos present well?&lt;/li&gt;
  &lt;li&gt;Did I cover everything?&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Here’s the original version of the talk given at the meetup: &lt;a href=&quot;http://goo.gl/p42Shd&quot;&gt;http://goo.gl/p42Shd&lt;/a&gt;&lt;/p&gt;

&lt;h2 id=&quot;initial-reception&quot;&gt;Initial Reception&lt;/h2&gt;

&lt;p&gt;During the talk, I quickly realized that despite the majority of the audience having used Kubernetes, I was only getting about 3 or 4 folks nodding their heads throughout each walkthrough.  And when I glanced down at my watch, I realized that I was cracking 45 mins and I didn’t even get to the hardening bits yet.&lt;/p&gt;

&lt;p&gt;I had overshot the audience, firehosed them with information that was far too dense, and went way over the time.  The audience clapped and a few thanked me personally for the talk, but I knew I swung big and missed.&lt;/p&gt;

&lt;p&gt;The slides were shared via Twitter, and I received a warm response from some folks, but a comment from one person made me realize that I had inadvertently made it seem like I was picking on a specific project.  While I thought I was just using it as an example that covered the most use cases, it was received very differently.  I responded to that person and vowed to be more careful about impartiality.&lt;/p&gt;

&lt;p&gt;So, about those goals:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Did I establish myself with enough credibility? - Yep, but just being the speaker.  I didn’t need to do anything more than that.&lt;/li&gt;
  &lt;li&gt;Did the demos present well? - Practically speaking, yes.  They worked.  I just had too many of them and went way too quickly.&lt;/li&gt;
  &lt;li&gt;Did I cover everything? - Yes, at the expense of overwhelming the audience and going way long on time.&lt;/li&gt;
&lt;/ol&gt;

&lt;h5 id=&quot;post-series-navigation-1&quot;&gt;Post Series Navigation:&lt;/h5&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;/speaking-at-kubecon-2017-part-1-the-cfp-submission&quot;&gt;Part 1 - The CFP Submission&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;/speaking-at-kubecon-2017-part-2-research&quot;&gt;Part 2 - Research&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;/speaking-at-kubecon-2017-part-3-first-run&quot;&gt;Part 3 - First Run&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;/speaking-at-kubecon-2017-part-4&quot;&gt;Part 4 - The Talk&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=vTgQLzeBfRU&quot;&gt;The Recorded Talk&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://goo.gl/TNRxtd&quot;&gt;The Final Slides&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</description>
        <pubDate>Wed, 03 Jan 2018 13:56:07 +0000</pubDate>
        <link>https://www.lonimbus.com//speaking-at-kubecon-2017-part-3-first-run</link>
        <guid isPermaLink="true">https://www.lonimbus.com//speaking-at-kubecon-2017-part-3-first-run</guid>
        
        
        <category>kubernetes</category>
        
        <category>kubecon</category>
        
        <category>speaking</category>
        
      </item>
    
      <item>
        <title>Speaking at KubeCon 2017 - Part 2 - Research</title>
        <description>&lt;p&gt;Having performed a good portion of the research and validation prior to being accepted as a form of passing the time, I’ll admit I let the scope creep a bit too far.&lt;/p&gt;

&lt;h5 id=&quot;post-series-navigation&quot;&gt;Post Series Navigation:&lt;/h5&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;/speaking-at-kubecon-2017-part-1-the-cfp-submission&quot;&gt;Part 1 - The CFP Submission&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;/speaking-at-kubecon-2017-part-2-research&quot;&gt;Part 2 - Research&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;/speaking-at-kubecon-2017-part-3-first-run&quot;&gt;Part 3 - First Run&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;/speaking-at-kubecon-2017-part-4&quot;&gt;Part 4 - The Talk&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=vTgQLzeBfRU&quot;&gt;The Recorded Talk&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://goo.gl/TNRxtd&quot;&gt;The Final Slides&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;how-i-approached-the-problem&quot;&gt;How I Approached the Problem&lt;/h2&gt;

&lt;p&gt;My search for a Kubernetes installer or managed service that shared my desired set of default security capabilities and settings hardened out-of-the-box took much longer than I had anticipated.  It was a very time consuming journey, but that arduous process fraught with tedium brought the perspective and expertise over time that I needed to feel confident during the talk.&lt;/p&gt;

&lt;p&gt;After manually discovering, installing, configuring, testing/prodding, and destroying a dozen or so tools/services, I was able to come up with a set of possible attacks stemming from configuration issues that were common to most of them.&lt;/p&gt;

&lt;p&gt;It was then that I realized that many of the installers had released updates in that short window of time, forever locking those findings to those versions.&lt;/p&gt;

&lt;p&gt;I needed a tool to help me solve the problem of being able to easily acquire and install newer versions of an installer’s release while also being able to go back and re-assess an older release several months later reliably.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://github.com/bgeesaman/kubeatf&quot;&gt;KubeATF&lt;/a&gt; was hacked together late at night using the tools I knew best: bash and Ansible.  It attempts to be a simple CRUD interface for spinning up, validating, and destroying clusters with repeatable results.  While it may not be useful outside this context, I think it was worth sharing in the interest of being completely transparent about my assessment approach in case anyone disagreed with it.&lt;/p&gt;

&lt;h2 id=&quot;reaching-out-to-the-community&quot;&gt;Reaching Out to the Community&lt;/h2&gt;

&lt;p&gt;When I reached out directly to the folks at &lt;a href=&quot;https://heptio.com&quot;&gt;Heptio&lt;/a&gt;, &lt;a href=&quot;https://github.com/kubernetes/kops&quot;&gt;kops&lt;/a&gt;, and &lt;a href=&quot;https://github.com/kubernetes-incubator/kube-aws&quot;&gt;kube-aws&lt;/a&gt;, I got very positive responses to what I was highlighting.  Instead of ignoring, downplaying, or outright dismissing me, I was asked to help them ensure they accurately captured the issues.  This provided all the validation I needed to know that this work was not only useful – it was openly welcomed.&lt;/p&gt;

&lt;p&gt;Disclosing to a couple of the bigger named providers was much more formal and drawn out, but it certainly wasn’t a negative experience.  Thankfully, all of my issues identified were already on their radar and on track for resolution.&lt;/p&gt;

&lt;h2 id=&quot;scope-creep&quot;&gt;Scope Creep&lt;/h2&gt;

&lt;p&gt;The months between acceptance and actually presenting were longer than I expected, so I became somewhat of a connoisseur of installers.  It was a pretty standard process to take one and make it work inside &lt;code&gt;kubeatf&lt;/code&gt;, so I could assess them against my criteria from start to finish in under 3 hrs.  In hindsight, I went overboard a bit, but it did make for a more comprehensive looking results graph.&lt;/p&gt;

&lt;p&gt;I also spent some time making a plugin for &lt;a href=&quot;https://github.com/heptio/sonobuoy&quot;&gt;Heptio’s Sonobuoy&lt;/a&gt; tool called &lt;a href=&quot;https://github.com/bgeesaman/sonobuoy-plugin-bulkhead&quot;&gt;bulkhead&lt;/a&gt; in the attempt to perform some level of assessment against the CIS Kubernetes Benchmark by dropping in Aqua Security’s &lt;a href=&quot;https://github.com/aquasecurity/kube-bench&quot;&gt;kube-bench&lt;/a&gt; tool.  This really could have been an entire talk topic itself, so I released it in its initial format with plans on working on it again in the future.&lt;/p&gt;

&lt;h5 id=&quot;post-series-navigation-1&quot;&gt;Post Series Navigation:&lt;/h5&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;/speaking-at-kubecon-2017-part-1-the-cfp-submission&quot;&gt;Part 1 - The CFP Submission&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;/speaking-at-kubecon-2017-part-2-research&quot;&gt;Part 2 - Research&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;/speaking-at-kubecon-2017-part-3-first-run&quot;&gt;Part 3 - First Run&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;/speaking-at-kubecon-2017-part-4&quot;&gt;Part 4 - The Talk&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=vTgQLzeBfRU&quot;&gt;The Recorded Talk&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://goo.gl/TNRxtd&quot;&gt;The Final Slides&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</description>
        <pubDate>Wed, 03 Jan 2018 13:55:07 +0000</pubDate>
        <link>https://www.lonimbus.com//speaking-at-kubecon-2017-part-2-research</link>
        <guid isPermaLink="true">https://www.lonimbus.com//speaking-at-kubecon-2017-part-2-research</guid>
        
        
        <category>kubernetes</category>
        
        <category>kubecon</category>
        
        <category>speaking</category>
        
      </item>
    
      <item>
        <title>Speaking at KubeCon 2017 - Part 1 - The CFP Submission</title>
        <description>&lt;p&gt;In this four part blog series on my journey to speaking at KubeCon 2017, I want to share the knowledge that I have learned in the hopes that it encourages others in the community to muster the courage and confidence to bring their own unique experiences to light.&lt;/p&gt;

&lt;h5 id=&quot;post-series-navigation&quot;&gt;Post Series Navigation:&lt;/h5&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;/speaking-at-kubecon-2017-part-1-the-cfp-submission&quot;&gt;Part 1 - The CFP Submission&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;/speaking-at-kubecon-2017-part-2-research&quot;&gt;Part 2 - Research&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;/speaking-at-kubecon-2017-part-3-first-run&quot;&gt;Part 3 - First Run&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;/speaking-at-kubecon-2017-part-4&quot;&gt;Part 4 - The Talk&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=vTgQLzeBfRU&quot;&gt;The Recorded Talk&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://goo.gl/TNRxtd&quot;&gt;The Final Slides&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;the-desire-to-speak&quot;&gt;The Desire to Speak&lt;/h2&gt;

&lt;p&gt;I’ve been in the InfoSec space for some time, and I’ve attended a decent range of conferences as an attendee or vendor in all of them.  In some cases, I’ve given presentations to decent sized audiences as a Sales Engineer, but it wasn’t a topic of passion.  The preparation process and execution was excellent practice, though, and it definitely removed my fear of public speaking.&lt;/p&gt;

&lt;p&gt;So, it seems I was always prepared &lt;em&gt;mechanically&lt;/em&gt; to do it.  I just needed the right mix of topic, expertise, and timing.  I knew I could execute on it if I just found the right “thing” to speak about.&lt;/p&gt;

&lt;h2 id=&quot;choosing-the-topic&quot;&gt;Choosing the Topic&lt;/h2&gt;

&lt;p&gt;When the project at work I was working on hit a major milestone, I had a chance to think about what we accomplished leveraging Kubernetes.  I reflected on the fact that in the middle of our project, KubeCon 2016 videos were released.  I distinctly remember saying to myself, “Wow, what a treasure trove!” and I immediately linked several videos to colleagues with a &lt;em&gt;must watch&lt;/em&gt; tag.  In the back of my mind, I sort of had this notion that I owed the community something in return.&lt;/p&gt;

&lt;p&gt;That reflection led to thinking about a deep dive technical overview of what we built, how we built it, and what we learned as something to potentially submit.  Everybody loves deep dives, right?  All the hype gets peeled back, and the harsh realities and trade-offs of production come to light.  What better way to give back to the system administrators and implementors?&lt;/p&gt;

&lt;p&gt;While I was listing some of the challenges that we had to solve or work around, I realized that most of them were related to hardening our Kubernetes cluster for our use case.  The defaults were pretty wide open, and we spent a lot of time “closing the door and locking it” so to speak.&lt;/p&gt;

&lt;p&gt;As I made some notes for each item on the list of security hardening steps we took, I decided to look at some of the other projects in the community that installed Kubernetes to see if they already had these covered.  As in, “maybe the installer we picked just had these as the defaults” and we needed to use another installer next time around.  I began a quest of sorts to find “the one” Kubernetes installation or managed service that embodied and enforced the “internally secure components and isolated workload” opinions that I shared.  However, after looking at about 9 or 10, the pattern had emerged.&lt;/p&gt;

&lt;p&gt;The community had to know what I saw.  I felt morally and ethically compelled to share this information, because I’d wager a good percentage of production clusters in the wild were essentially one small vulnerability from cluster takeover or cloud account compromise.&lt;/p&gt;

&lt;p&gt;I set out to contact every single project and/or service I looked at to let them know what I was finding, and in that process, I met an uncharacteristically welcoming and friendly community.  Every single one of them responded to my writeups.  Every single one thanked me.  Most kept in touch over the months leading up to KubeCon.  To say that it was a positive culture difference from the InfoSec world would be an understatement.&lt;/p&gt;

&lt;h2 id=&quot;writing-the-cfp-submission&quot;&gt;Writing the CFP Submission&lt;/h2&gt;

&lt;p&gt;I suppose I was fortunate that I had this knowledge before writing the CFP submission.  It certainly made it easier to write.  But CFP submissions aren’t judged solely on technical merit.  Having never written one before, I decided that mimicking the tone and delivery of prior successful abstract and bios was my best bet.&lt;/p&gt;

&lt;p&gt;So, I hit up the CNCF Youtube page, sorted by “most popular”, and pulled the abstracts and bios of about two dozen of the best technical videos and tried to find a few that sounded like something I’d write, but better.  After surgically creating my franken-bio-stract, I had a decent start.&lt;/p&gt;

&lt;p&gt;Looking at the CFP submission form, though, there was an extra field to the effect of “How would your talk benefit the community?”.  I’ll admit, this fantastic question threw me for a loop.  “Yeah, how would I maximize this talk and the supporting data in terms of the contribution to others?” I remember saying to a good friend.&lt;/p&gt;

&lt;h2 id=&quot;peer-review&quot;&gt;Peer Review&lt;/h2&gt;

&lt;p&gt;It’s my firm belief that the 4 conversations I had prior to submitting were what shaped it into something worthy of selection.  Answering for questions like “who is your audience, and why would they care?” and “what are you doing to fix these issues?” made me realize my talk was missing a key goal: “What can I show the audience that is better today than 4 months ago when I found and disclosed these issues?”&lt;/p&gt;

&lt;p&gt;Once I asked the right question of myself, I had the right answer to the community benefit section.  My goals became:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Demonstrate what is feasible and possible in terms of potential attack vectors&lt;/li&gt;
  &lt;li&gt;Disclose those issues to the community in a responsible way early&lt;/li&gt;
  &lt;li&gt;Determine the best methods of prevention for each attack&lt;/li&gt;
  &lt;li&gt;Work really hard to have fixes already in place or clear guidance on how to prevent them before the talk&lt;/li&gt;
  &lt;li&gt;Present the issues with those fixes to the public/audience in clear and objective manner&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=vTgQLzeBfRU&quot;&gt;Hacking and Hardening Kubernetes Clusters by Example&lt;/a&gt; wasn’t the greatest title, but it got to the point of the talk decently enough.  After writing and re-writing it about 6 times, I finally submitted it once I was convinced “I simply can’t make it any better without making it worse”.&lt;/p&gt;

&lt;h2 id=&quot;the-waiting-game&quot;&gt;The Waiting Game&lt;/h2&gt;

&lt;p&gt;And then, the wait.  Submissions were due on August 21st, but the overwhelming number of submissions led to a form of DoS attack on the committee that made the selection take a few weeks longer than anticipated.&lt;/p&gt;

&lt;p&gt;The only way to take my mind off of the waiting was to decide that I was going to do the talk regardless of acceptance to KubeCon, so just set out to do the work as if I was.&lt;/p&gt;

&lt;p&gt;When the acceptance email came, I was awash with relief.  I had spent a lot of personal time and racked up some decent cloud bills doing the legwork, and I was happy to know the plan was coming together.  The next day, though, I was overcome with deep, deep feelings of Imposter Syndrome.  I felt this sudden weight of pressure to live up to some imaginary bar of the excellence of all previous KubeCon talks, the desire not to let the committee regret their choice because so many good folks had theirs rejected, and the thought that maybe I wasn’t “expert” enough to deliver this topic properly.&lt;/p&gt;

&lt;p&gt;While I can’t say I completely overcame those feelings, sharing that I had them with several members of the community helped me achieve some perspective.  I’ll admit they were the constant driver to keep going and to produce the best possible body of work I could on the topic.&lt;/p&gt;

&lt;h5 id=&quot;post-series-navigation-1&quot;&gt;Post Series Navigation:&lt;/h5&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;/speaking-at-kubecon-2017-part-1-the-cfp-submission&quot;&gt;Part 1 - The CFP Submission&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;/speaking-at-kubecon-2017-part-2-research&quot;&gt;Part 2 - Research&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;/speaking-at-kubecon-2017-part-3-first-run&quot;&gt;Part 3 - First Run&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;/speaking-at-kubecon-2017-part-4&quot;&gt;Part 4 - The Talk&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=vTgQLzeBfRU&quot;&gt;The Recorded Talk&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://goo.gl/TNRxtd&quot;&gt;The Final Slides&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</description>
        <pubDate>Wed, 03 Jan 2018 13:54:07 +0000</pubDate>
        <link>https://www.lonimbus.com//speaking-at-kubecon-2017-part-1-the-cfp-submission</link>
        <guid isPermaLink="true">https://www.lonimbus.com//speaking-at-kubecon-2017-part-1-the-cfp-submission</guid>
        
        
        <category>kubernetes</category>
        
        <category>kubecon</category>
        
        <category>speaking</category>
        
      </item>
    
      <item>
        <title>Installing Kubernetes on Baremetal via CoreOS Tectonic with Grub Booting</title>
        <description>&lt;p&gt;At work, we use &lt;a href=&quot;https://github.com/kubernetes-incubator/kube-aws&quot;&gt;kube-aws&lt;/a&gt; to deploy our &lt;a href=&quot;https://kubernetes.io&quot;&gt;Kubernetes&lt;/a&gt; clusters running on top of &lt;a href=&quot;https://coreos.com/os/docs/latest&quot;&gt;Container Linux&lt;/a&gt; inside of AWS.  I wanted to be able try new things with Kubernetes in my personal lab without having to rack up huge AWS bills, so that means figuring out a good way to deploy Kubernetes to baremetal in the least painful way.  I wanted to try &lt;a href=&quot;https://coreos.com/tectonic/&quot;&gt;Tectonic&lt;/a&gt; because it offers a simplified graphical installer, and that means I also need to install &lt;a href=&quot;https://coreos.com/matchbox/docs/latest&quot;&gt;Matchbox&lt;/a&gt; to support the baremetal provisioning aspects.&lt;/p&gt;

&lt;p&gt;After reading through the entire &lt;a href=&quot;https://coreos.com/tectonic/docs/latest/install/bare-metal/index.html&quot;&gt;Tectonic Installation Guide&lt;/a&gt;, I realized that it doesn’t cover some of the underlying OS provisioning components as they vary per environment.  Since I don’t have that infrastructure as I’m starting from scratch, I had to get that going before continuing the installation.  Here’s my summary of steps taken (including a custom dnsmasq container) to round out a full working guide.&lt;/p&gt;

&lt;h2 id=&quot;architecture-overview&quot;&gt;Architecture Overview&lt;/h2&gt;
&lt;p&gt;My personal lab is a mixture of PCs, 1U servers, and Mac hardware.  So, for this lab, I’m going to pick one of each to ensure the entire process would work on all my hardware.&lt;/p&gt;

&lt;p&gt;As per the &lt;a href=&quot;https://coreos.com/tectonic/docs/latest/install/bare-metal/index.html&quot;&gt;installation guide&lt;/a&gt;, Tectonic needs three systems at a minimum.  Here are my systems per role:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Deployment/Provisioning system
    &lt;ul&gt;
      &lt;li&gt;&lt;code&gt;deploy.lab&lt;/code&gt; -   &lt;code&gt;172.22.10.2/24&lt;/code&gt;&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Kubernetes Controller
    &lt;ul&gt;
      &lt;li&gt;&lt;code&gt;mp.lab&lt;/code&gt; -&lt;code&gt;172.22.10.50/24&lt;/code&gt;&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Kubernetes Worker
    &lt;ul&gt;
      &lt;li&gt;&lt;code&gt;smpc.lab&lt;/code&gt; -&lt;code&gt;172.22.10.54/24&lt;/code&gt;&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;h5 id=&quot;network-diagram&quot;&gt;Network Diagram&lt;/h5&gt;
&lt;p&gt;The simplistic network environment is as follows:
&lt;img src=&quot;/assets/images/arch1.png&quot; alt=&quot;3d architecture&quot; class=&quot;img-responsive&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;detailed-pxenetboot-to-coreos-installation-flow&quot;&gt;Detailed PXE/Netboot to CoreOS Installation Flow&lt;/h2&gt;
&lt;p&gt;The following describes the complete baremetal provisioning process from DHCP request to CoreOS installation.  Configuring the provisioning system to support this workflow is described in the subsequent section.&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Using IPMI or a keyboard during booting, tell the system to “boot from network”.  This will cause the NIC to perform a DHCP request and look for TFTP related settings to boot from.  In my case, it was &lt;code&gt;F12&lt;/code&gt; for my server and holding &lt;code&gt;n&lt;/code&gt; during the boot chime for the Mac.&lt;/li&gt;
  &lt;li&gt;The DHCP server responds with an IP and subnet along with information pointing to the TFTP server and a filename of what to download/run from that TFTP server.&lt;/li&gt;
  &lt;li&gt;The system attempts to connect to the TFTP server and download/run that initial file.  In the case of &lt;code&gt;grub2&lt;/code&gt;, that initial boot file runs and then also tries to contact the same TFTP server looking for a grub boot configuration.&lt;/li&gt;
  &lt;li&gt;If a grub boot configuration file is found, it follows that configuration.  In the case of &lt;code&gt;matchbox&lt;/code&gt;, it should be a pointing to its web port and passing the NIC’s MAC address:&lt;/li&gt;
&lt;/ol&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;lineno&quot;&gt; 1 &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;set&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;default&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;0&amp;quot;&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 2 &lt;/span&gt;insmod video_bochs
&lt;span class=&quot;lineno&quot;&gt; 3 &lt;/span&gt;insmod video_cirrus
&lt;span class=&quot;lineno&quot;&gt; 4 &lt;/span&gt;insmod all_video
&lt;span class=&quot;lineno&quot;&gt; 5 &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;set&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;gfxpayload&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;keep
&lt;span class=&quot;lineno&quot;&gt; 6 &lt;/span&gt;insmod gzio
&lt;span class=&quot;lineno&quot;&gt; 7 &lt;/span&gt;insmod part_gpt
&lt;span class=&quot;lineno&quot;&gt; 8 &lt;/span&gt;insmod ext2
&lt;span class=&quot;lineno&quot;&gt; 9 &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;set&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;timeout&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;10&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;10 &lt;/span&gt;menuentry &lt;span class=&quot;s1&quot;&gt;&amp;#39;CoreOS Install&amp;#39;&lt;/span&gt; --class os &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;11 &lt;/span&gt;     insmod net
&lt;span class=&quot;lineno&quot;&gt;12 &lt;/span&gt;     insmod http
&lt;span class=&quot;lineno&quot;&gt;13 &lt;/span&gt;     &lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;Loading Linux ...&amp;#39;&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;14 &lt;/span&gt;     &lt;span class=&quot;nb&quot;&gt;set&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;root&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;http,deploy.lab:8080
&lt;span class=&quot;lineno&quot;&gt;15 &lt;/span&gt;     configfile /grub?mac&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$net_default_mac&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;16 &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;ol start=&quot;5&quot;&gt;
  &lt;li&gt;Since the initial grub configuration does nothing but load an HTTP module and defer to a web address for the rest of the &lt;code&gt;grub&lt;/code&gt; configuration, it provides a convenient way to grab a system-specific boot configuration without having to change your TFTP provided configuration file.  In this case, &lt;code&gt;Matchbox&lt;/code&gt; answers to web requests at the &lt;code&gt;/grub?mac=XX:XX:XX:XX:XX:XX&lt;/code&gt; URL with a tailored boot configuration, like so:&lt;/li&gt;
&lt;/ol&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-console&quot; data-lang=&quot;console&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;[admin@deploy ~]$&lt;/span&gt; curl http://deploy.lab:8080/grub?mac&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;00&lt;/span&gt;:23:32:2f:40:3c
&lt;span class=&quot;go&quot;&gt;default=0&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;fallback=1&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;timeout=1&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;menuentry &amp;quot;CoreOS (EFI)&amp;quot; {&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;  echo &amp;quot;Loading kernel&amp;quot;&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;  linuxefi &amp;quot;/assets/coreos/1409.5.0/coreos_production_pxe.vmlinuz&amp;quot; coreos.config.url=http://deploy.lab:8080/ignition?mac=$net_efinet0_dhcp_mac coreos.first_boot=yes console=tty0 console=ttyS0&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;  echo &amp;quot;Loading initrd&amp;quot;&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;  initrdefi  &amp;quot;/assets/coreos/1409.5.0/coreos_production_pxe_image.cpio.gz&amp;quot;&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;menuentry &amp;quot;CoreOS (BIOS)&amp;quot; {&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;  echo &amp;quot;Loading kernel&amp;quot;&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;  linux &amp;quot;/assets/coreos/1409.5.0/coreos_production_pxe.vmlinuz&amp;quot; coreos.config.url=http://deploy.lab:8080/ignition?mac=$net_efinet0_dhcp_mac coreos.first_boot=yes console=tty0 console=ttyS0&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;  echo &amp;quot;Loading initrd&amp;quot;&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;  initrd  &amp;quot;/assets/coreos/1409.5.0/coreos_production_pxe_image.cpio.gz&amp;quot;&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;ol start=&quot;6&quot;&gt;
  &lt;li&gt;Now that grub knows what to boot, where to get it, and extra kernel parameters for the ignition configuration for what to install inside the OS and how, the system can begin and complete the installation.  Here is the ignition configuration that the CoreOS kernel pulls from the &lt;code&gt;coreos.config.url&lt;/code&gt; URL which basically says to install CoreOS Container Linux and reboot:&lt;/li&gt;
&lt;/ol&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-console&quot; data-lang=&quot;console&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;[admin@deploy ~]$&lt;/span&gt; curl http://deploy.lab:8080/ignition?mac&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;00&lt;/span&gt;:23:32:2f:40:3c
&lt;span class=&quot;go&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;  &amp;quot;ignition&amp;quot;: {&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;    &amp;quot;version&amp;quot;: &amp;quot;2.0.0&amp;quot;,&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;    &amp;quot;config&amp;quot;: {&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;    }&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;  },&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;  &amp;quot;storage&amp;quot;: {&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;    &amp;quot;files&amp;quot;: [&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;      {&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;        &amp;quot;filesystem&amp;quot;: &amp;quot;root&amp;quot;,&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;        &amp;quot;path&amp;quot;: &amp;quot;\/opt\/installer&amp;quot;,&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;        &amp;quot;contents&amp;quot;: {&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;          &amp;quot;source&amp;quot;: &amp;quot;data:,%23!%2Fbin%2Fbash%20-ex%0Acurl%20%22http%3A%2F%2Fdeploy.lab%3A8080%2Fignition%3Fmac%3D00%3A23%3A32%3A2f%3A40%3A3c%26os%3Dinstalled%22%20-o%20ignition.json%0Acoreos-install%20-d%20%2Fdev%2Fsda%20-C%20stable%20-V%201409.5.0%20-i%20ignition.json%20-b%20http%3A%2F%2Fdeploy.lab%3A8080%2Fassets%2Fcoreos%0Audevadm%20settle%0Asystemctl%20reboot%0A&amp;quot;,&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;          &amp;quot;verification&amp;quot;: {  &lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;          }&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;        },&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;        &amp;quot;mode&amp;quot;: 320,&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;        &amp;quot;user&amp;quot;: {&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;        },&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;        &amp;quot;group&amp;quot;: {&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;          &lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;        }&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;      }&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;    ]&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;  },&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;  &amp;quot;systemd&amp;quot;: {&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;    &amp;quot;units&amp;quot;: [&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;      {&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;        &amp;quot;name&amp;quot;: &amp;quot;installer.service&amp;quot;,&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;        &amp;quot;enable&amp;quot;: true,&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;        &amp;quot;contents&amp;quot;: &amp;quot;[Unit]\nRequires=network-online.target\nAfter=network-online.target\n[Service]\nType=simple\nExecStart=\/opt\/installer\n[Install]\nWantedBy=multi-user.target\n&amp;quot;&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;      }&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;    ]&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;  },&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;  &amp;quot;networkd&amp;quot;: {&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;  },&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;  &amp;quot;passwd&amp;quot;: {&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;    &amp;quot;users&amp;quot;: [&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;      {&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;        &amp;quot;name&amp;quot;: &amp;quot;debug&amp;quot;,&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;        &amp;quot;sshAuthorizedKeys&amp;quot;: [&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;          &amp;quot;ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAAAgQCugz\/eu\/a6U5ZXtYVp9ufCghVSP0Lux\/nP6BgbranKE6r3h3xgqo8yR2LUG9VwH6Vo+BtGgToeww+jbgr3oq9g8\/mQmNvQEefvWyzhYxrpv6q36fdYS0KhQxA6vnpOZZ1M9cZ1q6iPaUryxDUFU3HULDKM4g\/6XBzqBJZ2illyuw==&amp;quot;&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;        ],&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;        &amp;quot;create&amp;quot;: {&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;          &amp;quot;groups&amp;quot;: [&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;            &amp;quot;sudo&amp;quot;,&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;            &amp;quot;docker&amp;quot;&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;          ]&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;        }&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;      }&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;    ]&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;  }&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;ul&gt;
  &lt;li&gt;Here are the URL-decoded contents of &lt;code&gt;/opt/installer&lt;/code&gt; from inside the ignition configuration above.  Notice how it uses the &lt;code&gt;os=installed&lt;/code&gt; parameter to pull a “normal” boot configuration specific to this machine for future booting after being installed to disk &lt;code&gt;/dev/sda&lt;/code&gt;:&lt;/li&gt;
&lt;/ul&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;lineno&quot;&gt;1 &lt;/span&gt;&lt;span class=&quot;ch&quot;&gt;#!/bin/bash -ex&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;2 &lt;/span&gt;curl &lt;span class=&quot;s2&quot;&gt;&amp;quot;http://deploy.lab:8080/ignition?mac=00:23:32:2f:40:3c&amp;amp;os=installed&amp;quot;&lt;/span&gt; -o ignition.json
&lt;span class=&quot;lineno&quot;&gt;3 &lt;/span&gt;coreos-install -d /dev/sda -C stable -V &lt;span class=&quot;m&quot;&gt;1409&lt;/span&gt;.5.0 -i ignition.json -b http://deploy.lab:8080/assets/coreos
&lt;span class=&quot;lineno&quot;&gt;4 &lt;/span&gt;udevadm settle
&lt;span class=&quot;lineno&quot;&gt;5 &lt;/span&gt;systemctl reboot&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;ul&gt;
  &lt;li&gt;Also, if you notice the name of the user available via SSH during that first boot/installation is &lt;code&gt;debug&lt;/code&gt; and uses the same SSH key as what will be available after the installation completes and is rebooted for the permanent user &lt;code&gt;core&lt;/code&gt;.  This is really handy if you are troubleshooting why the installation is failing or want to watch that process as it goes.  Note that it’s really only available for a few minutes on quick systems since the installation completes so quickly.&lt;/li&gt;
&lt;/ul&gt;

&lt;ol start=&quot;7&quot;&gt;
  &lt;li&gt;At this point, CoreOS/Container Linux has been installed to &lt;code&gt;/dev/sda&lt;/code&gt;, a user named &lt;code&gt;core&lt;/code&gt; with an SSH key set, and has an ignition configuration that configured its systemd units.  This is where Matchbox/Ignition stop and normal SSH-based administration can take over.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2 id=&quot;provisioning-infrastructure-configuration&quot;&gt;Provisioning Infrastructure Configuration&lt;/h2&gt;
&lt;p&gt;There are several components that run on the &lt;code&gt;deploy.lab&lt;/code&gt; system that all need to work in concert for the above process to be successful:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Matchbox - The &lt;a href=&quot;https://quay.io/coreos/matchbox&quot;&gt;CoreOS provided container&lt;/a&gt; that handles the web serving of grub, CoreOS, and Igntition templates provided by the Tectonic installer.&lt;/li&gt;
  &lt;li&gt;DHCP, DNS, TFTP, Grub Network Boot Images and Configuration - This is handled by a &lt;a href=&quot;https://github.com/bgeesaman/maas&quot;&gt;custom container&lt;/a&gt; built using &lt;code&gt;dnsmasq&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;h4 id=&quot;setting-up-deploylab&quot;&gt;Setting up &lt;code&gt;deploy.lab&lt;/code&gt;&lt;/h4&gt;
&lt;p&gt;I hand installed &lt;a href=&quot;https://www.centos.org&quot;&gt;Centos 7.3&lt;/a&gt; with the minimal install and ensured that it had a recent version of &lt;a href=&quot;https://www.docker.com&quot;&gt;Docker&lt;/a&gt; with SSH key authentication as the &lt;code&gt;admin&lt;/code&gt; user in the &lt;code&gt;docker&lt;/code&gt; group:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-console&quot; data-lang=&quot;console&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;go&quot;&gt;~$ ssh deploy&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;[admin@deploy ~]$&lt;/span&gt; groups 
&lt;span class=&quot;go&quot;&gt;admin wheel docker&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;[admin@deploy ~]$&lt;/span&gt; id
&lt;span class=&quot;go&quot;&gt;uid=1000(admin) gid=1000(admin) groups=1000(admin),10(wheel),993(docker)&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;[admin@deploy ~]$&lt;/span&gt; docker version
&lt;span class=&quot;go&quot;&gt;Client:&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt; Version:      17.05.0-ce&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt; API version:  1.29&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt; Go version:   go1.7.5&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt; Git commit:   89658be&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt; Built:        Thu May  4 22:06:25 2017&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt; OS/Arch:      linux/amd64&lt;/span&gt;

&lt;span class=&quot;go&quot;&gt;Server:&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt; Version:      17.05.0-ce&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt; API version:  1.29 (minimum version 1.12)&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt; Go version:   go1.7.5&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt; Git commit:   89658be&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt; Built:        Thu May  4 22:06:25 2017&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt; OS/Arch:      linux/amd64&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt; Experimental: false&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;h4 id=&quot;installing-and-configuring-the-matchbox-container-on-deploylab&quot;&gt;Installing and Configuring the Matchbox Container on &lt;code&gt;deploy.lab&lt;/code&gt;&lt;/h4&gt;
&lt;p&gt;The &lt;a href=&quot;https://coreos.com/matchbox/docs/latest/deployment.html#docker&quot;&gt;matchbox documentation&lt;/a&gt; for running via &lt;code&gt;docker&lt;/code&gt; is a bit misleading as it actually requires several things to be completed before actually running the container.&lt;/p&gt;

&lt;p&gt;First, create the &lt;code&gt;matchbox&lt;/code&gt; user and create/own the &lt;code&gt;/var/lib/matchbox&lt;/code&gt; directory where it will keep all the assets and profiles.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-console&quot; data-lang=&quot;console&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;[admin@deploy ~]$&lt;/span&gt; sudo useradd -U matchbox
&lt;span class=&quot;gp&quot;&gt;[admin@deploy ~]$&lt;/span&gt; sudo mkdir -p /var/lib/matchbox/assets
&lt;span class=&quot;gp&quot;&gt;[admin@deploy ~]$&lt;/span&gt; sudo chown -R matchbox:matchbox /var/lib/matchbox&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Download the &lt;code&gt;matchbox&lt;/code&gt; package, verify its signature, and untar it:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-console&quot; data-lang=&quot;console&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;[admin@deploy ~]$&lt;/span&gt; wget https://github.com/coreos/matchbox/releases/download/v0.6.1/matchbox-v0.6.1-linux-amd64.tar.gz
&lt;span class=&quot;gp&quot;&gt;[admin@deploy ~]$&lt;/span&gt; wget https://github.com/coreos/matchbox/releases/download/v0.6.1/matchbox-v0.6.1-linux-amd64.tar.gz.asc
&lt;span class=&quot;gp&quot;&gt;[admin@deploy ~]$&lt;/span&gt; gpg --keyserver pgp.mit.edu --recv-key 18AD5014C99EF7E3BA5F6CE950BDD3E0FC8A365E
&lt;span class=&quot;gp&quot;&gt;[admin@deploy ~]$&lt;/span&gt; gpg --verify matchbox-v0.6.1-linux-amd64.tar.gz.asc matchbox-v0.6.1-linux-amd64.tar.gz

&lt;span class=&quot;gp&quot;&gt;[admin@deploy ~]$&lt;/span&gt; tar xzvf matchbox-v0.6.1-linux-amd64.tar.gz
&lt;span class=&quot;gp&quot;&gt;[admin@deploy ~]$&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;cd&lt;/span&gt; matchbox-v0.6.1-linux-amd64&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Run a script to grab the version(s) of CoreOS/Container Linux to the current directory and then copy them to the assets directory to be available via &lt;code&gt;matchbox&lt;/code&gt; on port &lt;code&gt;8080&lt;/code&gt;:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-console&quot; data-lang=&quot;console&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;[admin@deploy ~]$&lt;/span&gt; ./scripts/get-coreos stable &lt;span class=&quot;m&quot;&gt;1409&lt;/span&gt;.5.0 .
&lt;span class=&quot;gp&quot;&gt;[admin@deploy ~]$&lt;/span&gt; sudo cp -r coreos /var/lib/matchbox/assets&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Drop out of the &lt;code&gt;matchbox&lt;/code&gt; installation directory and run it via &lt;code&gt;docker&lt;/code&gt;:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-console&quot; data-lang=&quot;console&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;[admin@deploy ~]$&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;cd&lt;/span&gt; ~
&lt;span class=&quot;gp&quot;&gt;[admin@deploy ~]$&lt;/span&gt; docker run --net&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;host --rm &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
    -v /var/lib/matchbox:/var/lib/matchbox:Z &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
    -v /etc/matchbox:/etc/matchbox:Z,ro &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
    quay.io/coreos/matchbox:latest -address&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;.0.0.0:8080 &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
    -rpc-address&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;.0.0.0:8081 -log-level&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;debug&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Finally, verify that &lt;code&gt;matchbox&lt;/code&gt; is running and able to serve up your downloaded CoreOS image(s).  If you see this, you should be good to go:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-console&quot; data-lang=&quot;console&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;[admin@deploy ~]$&lt;/span&gt; curl http://deploy.lab:8080/assets/coreos/1409.5.0/
&lt;span class=&quot;go&quot;&gt;&amp;lt;pre&amp;gt;&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;&amp;lt;a href=&amp;quot;CoreOS_Image_Signing_Key.asc&amp;quot;&amp;gt;CoreOS_Image_Signing_Key.asc&amp;lt;/a&amp;gt;&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;&amp;lt;a href=&amp;quot;coreos_production_image.bin.bz2&amp;quot;&amp;gt;coreos_production_image.bin.bz2&amp;lt;/a&amp;gt;&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;&amp;lt;a href=&amp;quot;coreos_production_image.bin.bz2.sig&amp;quot;&amp;gt;coreos_production_image.bin.bz2.sig&amp;lt;/a&amp;gt;&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;&amp;lt;a href=&amp;quot;coreos_production_pxe.vmlinuz&amp;quot;&amp;gt;coreos_production_pxe.vmlinuz&amp;lt;/a&amp;gt;&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;&amp;lt;a href=&amp;quot;coreos_production_pxe.vmlinuz.sig&amp;quot;&amp;gt;coreos_production_pxe.vmlinuz.sig&amp;lt;/a&amp;gt;&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;&amp;lt;a href=&amp;quot;coreos_production_pxe_image.cpio.gz&amp;quot;&amp;gt;coreos_production_pxe_image.cpio.gz&amp;lt;/a&amp;gt;&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;&amp;lt;a href=&amp;quot;coreos_production_pxe_image.cpio.gz.sig&amp;quot;&amp;gt;coreos_production_pxe_image.cpio.gz.sig&amp;lt;/a&amp;gt;&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;&amp;lt;/pre&amp;gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;h4 id=&quot;installing-and-configuring-the-dnsmasq-dns-dhcp-tftp-grub-container-on-deploylab&quot;&gt;Installing and Configuring the DNSMasq (DNS, DHCP, TFTP, Grub) Container on &lt;code&gt;deploy.lab&lt;/code&gt;&lt;/h4&gt;

&lt;p&gt;It’s easiest to grab a copy of the repo and build your own docker image locally.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-console&quot; data-lang=&quot;console&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;[admin@deploy ~]$&lt;/span&gt; git clone https://github.com/bgeesaman/maas
&lt;span class=&quot;gp&quot;&gt;[admin@deploy ~]$&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;cd&lt;/span&gt; maas&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Edit the files in &lt;code&gt;files&lt;/code&gt; directory as needed.  Most changes are IP addresses, MAC addresses, and hostnames for your environment:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-console&quot; data-lang=&quot;console&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;[admin@deploy maas]$&lt;/span&gt; vi files/dnsmasq.conf
&lt;span class=&quot;gp&quot;&gt;[admin@deploy maas]$&lt;/span&gt; vi files/grub/*&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Finally, build and run the image:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-console&quot; data-lang=&quot;console&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;[admin@deploy maas]$&lt;/span&gt; ./buildandrun.sh&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;h4 id=&quot;running-the-tectonic-installer&quot;&gt;Running the Tectonic Installer&lt;/h4&gt;
&lt;p&gt;With the above in place and a free license from CoreOS for Tectonic, you can now follow the &lt;a href=&quot;https://coreos.com/tectonic/docs/latest/install/bare-metal/index.html&quot;&gt;Tectonic Baremetal with Graphical Installer guide&lt;/a&gt; having satisfied the pre-requisites–with one exception.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;Grub-specific Gotcha&lt;/p&gt;

    &lt;p&gt;The Tectonic installer will run you through several steps of supplying configuration and will arrive at a point where it instructs you to “power on your systems” that are to be baremetal booted from the network, but it won’t work out-of-the-box.  The details are in &lt;a href=&quot;https://github.com/coreos/tectonic-installer/issues/1317&quot;&gt;this github issue&lt;/a&gt; for what is happening to prevent &lt;code&gt;grub&lt;/code&gt; from working by default.  The good news is that there is a simple workaround.  On the &lt;code&gt;deploy.lab&lt;/code&gt; system, this is the default profile that the Tectonic GUI installer places into your &lt;code&gt;/var/lib/matchbox/profiles&lt;/code&gt; folder:&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-console&quot; data-lang=&quot;console&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;[admin@deploy ~]$&lt;/span&gt; cat /var/lib/matchbox/profiles/coreos-install.json 
&lt;span class=&quot;go&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;	&amp;quot;id&amp;quot;: &amp;quot;coreos-install&amp;quot;,&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;	&amp;quot;ignition_id&amp;quot;: &amp;quot;coreos-install.yaml.tmpl&amp;quot;,&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;	&amp;quot;boot&amp;quot;: {&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;		&amp;quot;kernel&amp;quot;: &amp;quot;/assets/coreos/1409.5.0/coreos_production_pxe.vmlinuz&amp;quot;,&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;		&amp;quot;initrd&amp;quot;: [&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;			&amp;quot;/assets/coreos/1409.5.0/coreos_production_pxe_image.cpio.gz&amp;quot;&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;		],&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;		&amp;quot;args&amp;quot;: [&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;			&amp;quot;coreos.config.url=http://deploy.lab:8080/ignition?uuid=${uuid}\u0026mac=${mac:hexhyp}&amp;quot;,&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;			&amp;quot;coreos.first_boot=yes&amp;quot;,&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;			&amp;quot;console=tty0&amp;quot;,&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;			&amp;quot;console=ttyS0&amp;quot;&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;		]&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;	}&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Notice the &lt;code&gt;args&lt;/code&gt; section.  When the system is booting from the network and pulls the &lt;code&gt;/grub?mac=XX:XX:XX:XX:XX:XX&lt;/code&gt; configuration, this &lt;code&gt;args&lt;/code&gt; list is directly dropped into the kernel line.  However, the &lt;code&gt;uuid&lt;/code&gt; and &lt;code&gt;mac:hexhyp&lt;/code&gt; variables are &lt;code&gt;ipxe&lt;/code&gt; boot environment specific.  For &lt;code&gt;grub2&lt;/code&gt;, it actually varies slightly.  To fix this, we need to make some customizations to the &lt;code&gt;matchbox&lt;/code&gt; &lt;code&gt;groups&lt;/code&gt; configuration files.  I chose to make one for each system based on the &lt;code&gt;mac&lt;/code&gt; address selector.  Notice that I now reference the &lt;code&gt;coreos-install-mp&lt;/code&gt; or &lt;code&gt;coreos-install-smpc&lt;/code&gt; profiles:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-console&quot; data-lang=&quot;console&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;[admin@deploy ~]$&lt;/span&gt; cat /var/lib/matchbox/groups/coreos-install-mp.json 
&lt;span class=&quot;go&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;	&amp;quot;id&amp;quot;: &amp;quot;coreos-install-mp&amp;quot;,&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;	&amp;quot;profile&amp;quot;: &amp;quot;coreos-install-mp&amp;quot;,&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;	&amp;quot;selector&amp;quot;: {&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;		&amp;quot;mac&amp;quot;: &amp;quot;00:23:32:2f:40:3c&amp;quot;&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;	},&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;	&amp;quot;metadata&amp;quot;: {&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;		&amp;quot;baseurl&amp;quot;: &amp;quot;http://deploy.lab:8080/assets/coreos&amp;quot;,&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;		&amp;quot;coreos_channel&amp;quot;: &amp;quot;stable&amp;quot;,&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;		&amp;quot;coreos_version&amp;quot;: &amp;quot;1409.5.0&amp;quot;,&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;		&amp;quot;ignition_endpoint&amp;quot;: &amp;quot;http://deploy.lab:8080/ignition&amp;quot;,&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;		&amp;quot;ssh_authorized_key&amp;quot;: &amp;quot;ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAAAgQCugz/eu/a6U5ZXtYVp9ufCghVSP0Lux/nP6BgbranKE6r3h3xgqo8yR2LUG9VwH6Vo+BtGgToeww+jbgr3oq9g8/mQmNvQEefvWyzhYxrpv6q36fdYS0KhQxA6vnpOZZ1M9cZ1q6iPaUryxDUFU3HULDKM4g/6XBzqBJZ2illyuw==&amp;quot;&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;	}&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;[admin@deploy ~]$&lt;/span&gt; cat /var/lib/matchbox/groups/coreos-install-smpc.json 
&lt;span class=&quot;go&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;	&amp;quot;id&amp;quot;: &amp;quot;coreos-install-smpc&amp;quot;,&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;	&amp;quot;profile&amp;quot;: &amp;quot;coreos-install-smpc&amp;quot;,&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;	&amp;quot;selector&amp;quot;: {&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;		&amp;quot;mac&amp;quot;: &amp;quot;00:30:48:fb:e2:44&amp;quot;&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;	},&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;	&amp;quot;metadata&amp;quot;: {&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;		&amp;quot;baseurl&amp;quot;: &amp;quot;http://deploy.lab:8080/assets/coreos&amp;quot;,&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;		&amp;quot;coreos_channel&amp;quot;: &amp;quot;stable&amp;quot;,&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;		&amp;quot;coreos_version&amp;quot;: &amp;quot;1409.5.0&amp;quot;,&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;		&amp;quot;ignition_endpoint&amp;quot;: &amp;quot;http://deploy.lab:8080/ignition&amp;quot;,&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;		&amp;quot;ssh_authorized_key&amp;quot;: &amp;quot;ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAAAgQCugz/eu/a6U5ZXtYVp9ufCghVSP0Lux/nP6BgbranKE6r3h3xgqo8yR2LUG9VwH6Vo+BtGgToeww+jbgr3oq9g8/mQmNvQEefvWyzhYxrpv6q36fdYS0KhQxA6vnpOZZ1M9cZ1q6iPaUryxDUFU3HULDKM4g/6XBzqBJZ2illyuw==&amp;quot;&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;	}&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;We also need to make those renamed profiles.  Notice the variable &lt;code&gt;$net_efinet0_dhcp_mac&lt;/code&gt; for UEFI/Mac hardware and the &lt;code&gt;$net_default_mac&lt;/code&gt; variable for BIOS booting hardware.  Also notice that I made another unique ignition template to install to &lt;code&gt;/dev/sdb&lt;/code&gt; instead of &lt;code&gt;/dev/sda&lt;/code&gt; for the &lt;code&gt;smpc.lab&lt;/code&gt; system:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;admin@deploy ~&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;$ cat /var/lib/matchbox/profiles/coreos-install-mp.json 
&lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;s2&quot;&gt;&amp;quot;id&amp;quot;&lt;/span&gt;: &lt;span class=&quot;s2&quot;&gt;&amp;quot;coreos-install&amp;quot;&lt;/span&gt;,
	&lt;span class=&quot;s2&quot;&gt;&amp;quot;ignition_id&amp;quot;&lt;/span&gt;: &lt;span class=&quot;s2&quot;&gt;&amp;quot;coreos-install.yaml.tmpl&amp;quot;&lt;/span&gt;,
	&lt;span class=&quot;s2&quot;&gt;&amp;quot;boot&amp;quot;&lt;/span&gt;: &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;s2&quot;&gt;&amp;quot;kernel&amp;quot;&lt;/span&gt;: &lt;span class=&quot;s2&quot;&gt;&amp;quot;/assets/coreos/1409.5.0/coreos_production_pxe.vmlinuz&amp;quot;&lt;/span&gt;,
		&lt;span class=&quot;s2&quot;&gt;&amp;quot;initrd&amp;quot;&lt;/span&gt;: &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;
			&lt;span class=&quot;s2&quot;&gt;&amp;quot;/assets/coreos/1409.5.0/coreos_production_pxe_image.cpio.gz&amp;quot;&lt;/span&gt;
		&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;,
		&lt;span class=&quot;s2&quot;&gt;&amp;quot;args&amp;quot;&lt;/span&gt;: &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;
			&lt;span class=&quot;s2&quot;&gt;&amp;quot;coreos.config.url=http://deploy.lab:8080/ignition?mac=&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$net_efinet0_dhcp_mac&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;&lt;/span&gt;,
			&lt;span class=&quot;s2&quot;&gt;&amp;quot;coreos.first_boot=yes&amp;quot;&lt;/span&gt;,
			&lt;span class=&quot;s2&quot;&gt;&amp;quot;console=tty0&amp;quot;&lt;/span&gt;,
			&lt;span class=&quot;s2&quot;&gt;&amp;quot;console=ttyS0&amp;quot;&lt;/span&gt;
		&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;
	&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;admin@deploy ~&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;$ cat /var/lib/matchbox/profiles/coreos-install-smpc.json 
&lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;s2&quot;&gt;&amp;quot;id&amp;quot;&lt;/span&gt;: &lt;span class=&quot;s2&quot;&gt;&amp;quot;coreos-install&amp;quot;&lt;/span&gt;,
	&lt;span class=&quot;s2&quot;&gt;&amp;quot;ignition_id&amp;quot;&lt;/span&gt;: &lt;span class=&quot;s2&quot;&gt;&amp;quot;coreos-install-sdb.yaml.tmpl&amp;quot;&lt;/span&gt;,
	&lt;span class=&quot;s2&quot;&gt;&amp;quot;boot&amp;quot;&lt;/span&gt;: &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;s2&quot;&gt;&amp;quot;kernel&amp;quot;&lt;/span&gt;: &lt;span class=&quot;s2&quot;&gt;&amp;quot;/assets/coreos/1409.5.0/coreos_production_pxe.vmlinuz&amp;quot;&lt;/span&gt;,
		&lt;span class=&quot;s2&quot;&gt;&amp;quot;initrd&amp;quot;&lt;/span&gt;: &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;
			&lt;span class=&quot;s2&quot;&gt;&amp;quot;/assets/coreos/1409.5.0/coreos_production_pxe_image.cpio.gz&amp;quot;&lt;/span&gt;
		&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;,
		&lt;span class=&quot;s2&quot;&gt;&amp;quot;args&amp;quot;&lt;/span&gt;: &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;
			&lt;span class=&quot;s2&quot;&gt;&amp;quot;coreos.config.url=http://deploy.lab:8080/ignition?mac=&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$net_default_mac&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;&lt;/span&gt;,
			&lt;span class=&quot;s2&quot;&gt;&amp;quot;coreos.first_boot=yes&amp;quot;&lt;/span&gt;,
			&lt;span class=&quot;s2&quot;&gt;&amp;quot;console=tty0&amp;quot;&lt;/span&gt;,
			&lt;span class=&quot;s2&quot;&gt;&amp;quot;console=ttyS0&amp;quot;&lt;/span&gt;
		&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;
	&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Once the above changes have been made, you should be able to successfully PXE/Netboot the systems and continue on with the final portion of the Tectonic installer.  If you run into issues, double-check your formatting of the profiles and groups as well as hitting the &lt;code&gt;/grub&lt;/code&gt; and &lt;code&gt;/ignition&lt;/code&gt; endpoints with the proper parameters to see what configurations are being provided to your systems.&lt;/p&gt;

&lt;p&gt;Congratulations!  You should now be able to hit the web UI of the Tectonic Console, use &lt;code&gt;kubectl&lt;/code&gt;, and &lt;code&gt;ssh&lt;/code&gt; into the systems using the &lt;code&gt;core&lt;/code&gt; user and the SSH key you supplied.  I hope this helps you understand what’s going on behind a fairly sophisticated and easily customizable baremetal Container Linux and Kubernetes installation system.&lt;/p&gt;
</description>
        <pubDate>Wed, 02 Aug 2017 08:54:07 +0000</pubDate>
        <link>https://www.lonimbus.com//coreos-matchbox-baremetal-grub2</link>
        <guid isPermaLink="true">https://www.lonimbus.com//coreos-matchbox-baremetal-grub2</guid>
        
        
        <category>kubernetes</category>
        
        <category>coreos</category>
        
        <category>matchbox</category>
        
        <category>dnsmasq</category>
        
        <category>baremetal</category>
        
      </item>
    
      <item>
        <title>CaaS Part 1 - Kubernetes on Centos 7.x Bare Metal</title>
        <description>&lt;p&gt;I’ve found these talks really helpful in understanding what Kubernetes does and how it works from an architectural level:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=WwBdNXt6wO4&quot;&gt;A Technical Overview of Kubernetes&lt;/a&gt; - by Brendan Burns, formerly of Google.&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=DGlQgNmobuc&quot;&gt;Kubernetes: Changing the Way That we Think and Talk About Computing&lt;/a&gt; - by Brian Dorsey at Google.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4 id=&quot;hello-world-with-kubernetes&quot;&gt;“Hello World” with Kubernetes&lt;/h4&gt;

&lt;p&gt;I’d highly recommend starting your first cluster in Google Container Engine (which is Kubernetes under the hood) by following this guide &lt;a href=&quot;https://cloud.google.com/container-engine/docs/quickstart&quot;&gt;Quickstart for Kubernetes on GCE&lt;/a&gt; and then moving on to deploying a sample app such as &lt;a href=&quot;https://cloud.google.com/container-engine/docs/tutorials/guestbook&quot;&gt;a simple PHP/Redis guestbook&lt;/a&gt; to get a feel for how to use and interact with Kubernetes at an introductory level.  New accounts currently get $300 in credits, so this shouldn’t cost you anything for a good while.&lt;/p&gt;

&lt;h2 id=&quot;deploying-with-kubespray&quot;&gt;Deploying with Kubespray&lt;/h2&gt;

&lt;p&gt;So now that we know what Kubernetes does and a few things about how apps and services get deployed, exposed, and scaled in Kubernetes, it’s time to build our own cluster.  For that task, I’m choosing the &lt;a href=&quot;https://docs.kubespray.io/&quot;&gt;Kubespray&lt;/a&gt; project.  It follows a similar pattern to that of the Kolla project: clone a repo, edit your inventory and some vars in a file, then say “go”.  Out pops a working cluster.&lt;/p&gt;

&lt;h4 id=&quot;requirements&quot;&gt;Requirements&lt;/h4&gt;

&lt;p&gt;What’s needed:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Some spare hardware on the same subnet (e.g. 172.22.10.x/24)&lt;/li&gt;
  &lt;li&gt;All systems running a recent Linux and Docker (e.g. Centos 7.x updated and Docker 1.12.3)&lt;/li&gt;
  &lt;li&gt;Kubespray cloned to a deployment host&lt;/li&gt;
  &lt;li&gt;Internet Access on all nodes&lt;/li&gt;
  &lt;li&gt;Firewall disabled on all nodes&lt;/li&gt;
  &lt;li&gt;SSH Key on a sudo-enabled account on all nodes&lt;/li&gt;
  &lt;li&gt;Ansible 2.x and python-netaddr installed on the deploy system&lt;/li&gt;
  &lt;li&gt;Centos 7 specific: TTY support for sudo in &lt;code&gt;/etc/sudoers&lt;/code&gt; on all nodes&lt;/li&gt;
&lt;/ul&gt;

&lt;h4 id=&quot;deploy-system&quot;&gt;Deploy System&lt;/h4&gt;

&lt;p&gt;On my OSX system, I did the following:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;code&gt;git clone https://github.com/kubernetes-incubator/kargo&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;&lt;code&gt;cd kargo&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;&lt;code&gt;pip install -r requirements.txt&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;&lt;code&gt;cp inventory/inventory.example inventory/hosts&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;Edited &lt;code&gt;inventory/hosts&lt;/code&gt; to be:&lt;/li&gt;
&lt;/ul&gt;

&lt;pre&gt;&lt;code&gt;[nodes]
mm1 ansible_ssh_host=172.22.10.51 ip=172.22.10.51 ansible_user=admin
mm2 ansible_ssh_host=172.22.10.52 ip=172.22.10.52 ansible_user=admin
mm3 ansible_ssh_host=172.22.10.53 ip=172.22.10.53 ansible_user=admin
smpc ansible_ssh_host=172.22.10.54 ip=172.22.10.54 ansible_user=admin
sm1 ansible_ssh_host=172.22.10.55 ip=172.22.10.55 ansible_user=admin
sm2 ansible_ssh_host=172.22.10.56 ip=172.22.10.56 ansible_user=admin
d1 ansible_ssh_host=172.22.10.57 ip=172.22.10.57 ansible_user=admin
d2 ansible_ssh_host=172.22.10.58 ip=172.22.10.58 ansible_user=admin

[kube-master]
mm1
mm2

[etcd]
mm1
mm2
mm3

[kube-node]
mm1
mm2
mm3
smpc
sm1
sm2
d1
d2

[k8s-cluster:children]
kube-node
kube-master
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;I decided to make all my nodes available for scheduling as “minions”, have two “masters” on &lt;code&gt;mm1&lt;/code&gt; and &lt;code&gt;mm2&lt;/code&gt;, and have three &lt;code&gt;etcd&lt;/code&gt; nodes on all three mac minis.  Added up, this provides over 80 vCPUs and 300+GB of RAM all running on top of local SSDs.&lt;/p&gt;

&lt;h4 id=&quot;node-preparation&quot;&gt;Node Preparation&lt;/h4&gt;
&lt;p&gt;On each of the nodes, I ensured that&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;Defaults    !requiretty
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;was in my &lt;code&gt;/etc/sudoers&lt;/code&gt; file.&lt;/p&gt;

&lt;p&gt;I then ran:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;systemctl stop firewalld
systemctl disable firewalld
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;to disable the firewall for now.&lt;/p&gt;

&lt;h4 id=&quot;kubespray&quot;&gt;Kubespray&lt;/h4&gt;

&lt;p&gt;Finally, on the deployment host, I ran:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;$ ansible-playbook -i inventory/hosts -b --become-user=root cluster.yml
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;About 15-20 mins later, I had a working Kubernetes v1.4.3 cluster on all my nodes.  To verify, I SSHed into &lt;code&gt;mm1&lt;/code&gt; using &lt;code&gt;ssh admin@172.22.10.51&lt;/code&gt;and ran:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$ kubectl get nodes
NAME      STATUS    AGE
d1        Ready     1d
d2        Ready     1d
mm1       Ready     1d
mm2       Ready     1d
mm3       Ready     1d
sm1       Ready     1d
sm2       Ready     1d
smpc      Ready     1d
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;and&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$ kubectl cluster-info 
Kubernetes master is running at http://localhost:8080
dnsmasq is running at http://localhost:8080/api/v1/proxy/namespaces/kube-system/services/dnsmasq

To further debug and diagnose cluster problems, use 'kubectl cluster-info dump'.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;and&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$ kubectl get componentstatuses
NAME                 STATUS    MESSAGE              ERROR
controller-manager   Healthy   ok                   
scheduler            Healthy   ok                   
etcd-0               Healthy   {&quot;health&quot;: &quot;true&quot;}   
etcd-1               Healthy   {&quot;health&quot;: &quot;true&quot;}   
etcd-2               Healthy   {&quot;health&quot;: &quot;true&quot;}
&lt;/code&gt;&lt;/pre&gt;

&lt;h4 id=&quot;next-steps&quot;&gt;Next Steps&lt;/h4&gt;

&lt;p&gt;At this point, I now have a working Kubernetes cluster with a 3-node etcd cluster (fully TLS enabled), 2 master nodes, and 8 total worker/minion nodes with almost zero additional configuration.  This should hopefully set myself up for following the &lt;a href=&quot;http://docs.openstack.org/developer/kolla-kubernetes/multi-node.html&quot;&gt;Multi-Node Kolla-Kubernetes&lt;/a&gt; guide for getting Kolla/Openstack going on a cluster.  That, however, is for another day.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/2016/07/25/neverending-uphill-journey.html&quot;&gt;Back to Index&lt;/a&gt;&lt;/p&gt;
</description>
        <pubDate>Tue, 15 Nov 2016 00:00:00 +0000</pubDate>
        <link>https://www.lonimbus.com//2016/11/15/caas-1.html</link>
        <guid isPermaLink="true">https://www.lonimbus.com//2016/11/15/caas-1.html</guid>
        
        
      </item>
    
      <item>
        <title>MaaS Part 4 - A Revised Approach</title>
        <description>&lt;p&gt;In &lt;a href=&quot;/2016/07/26/maas-3.html&quot;&gt;part 3&lt;/a&gt;, I identified several weaknesses to my approach to this project as shown in &lt;a href=&quot;/2016/07/26/maas-1.html&quot;&gt;part 1&lt;/a&gt; and &lt;a href=&quot;/2016/07/26/maas-2.html&quot;&gt;part 2&lt;/a&gt;.  To summarize:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Lack of central inventory of systems and asset attributes&lt;/li&gt;
  &lt;li&gt;Hardcoded paths and configuration files/settings in Docker containers&lt;/li&gt;
  &lt;li&gt;Hardcoded DHCP Leases&lt;/li&gt;
  &lt;li&gt;Individually crafted Kickstart configuration files&lt;/li&gt;
  &lt;li&gt;SELinux is disabled on &lt;code&gt;deploy&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;One version of one operating system supported&lt;/li&gt;
  &lt;li&gt;Logging from the containers&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;However, I kept finding things to add to that list as I looked back on it:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;
    &lt;h5 id=&quot;it-wasnt-very-dry&quot;&gt;It wasn’t very “DRY”&lt;/h5&gt;
    &lt;p&gt;The containers shared a lot of similarities in terms of starting base image and what I was doing.  I repeated a bunch of shared code between the containers.  Yuck.  Seemed better that these could be running as a single container and save some overhead.  That violates the light vs heavy containers rule, but my scaling needs are limited right now.  I’m valuing simplicity and speed of development above the complexity and possibility to scale.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;h5 id=&quot;there-was-no-testing-of-the-container-contents&quot;&gt;There was no testing of the container contents&lt;/h5&gt;
    &lt;p&gt;Everything I was doing was manually tested.  Hacker Dockerfile, run build, exec into it, validate by hand, rinse, repeat.  It just felt &lt;em&gt;hacky&lt;/em&gt;.  Also, using purpose-built containers like php5.6-apache meant having to go in and break up the entrypoint/cmd.  I had several issues overriding those and adding in my own bits successfully.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;h5 id=&quot;inspecting-the-containers-as-i-built-it-was-tedious&quot;&gt;Inspecting the containers as I built it was tedious&lt;/h5&gt;
    &lt;p&gt;See point 2 above.  It was incredibly hard to know if what I was doing was achieving the desired result.  The build process happens and you get an image.  Hopefully you didn’t make a mistake and it now no longer runs.  I did that quite a bit.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;h5 id=&quot;i-was-building-on-my-deploy-system-directly&quot;&gt;I was building on my deploy system directly&lt;/h5&gt;
    &lt;p&gt;There was again a problem keeping track of what’s working and what’s not.  I had to frequently clear the system of images and start the build over to validate the process.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;h2 id=&quot;revised-approach-with-ansible-container&quot;&gt;Revised Approach with Ansible-Container&lt;/h2&gt;

&lt;p&gt;I started a new repo called &lt;a href=&quot;https://github.com/bgeesaman/netpxemirror-ac&quot;&gt;https://github.com/bgeesaman/netpxemirror-ac&lt;/a&gt; and implemented a simple helper shell script, &lt;code&gt;orc&lt;/code&gt; to help me with using &lt;a href=&quot;https://docs.ansible.com/ansible-container&quot;&gt;Ansible-Container&lt;/a&gt;.  I edited the &lt;code&gt;ansible/container.yml&lt;/code&gt; and the &lt;code&gt;ansible/main.yml&lt;/code&gt; to create a single container called &lt;code&gt;maas&lt;/code&gt; from the &lt;code&gt;phusion/baseimage&lt;/code&gt;:&lt;/p&gt;

&lt;h4 id=&quot;containeryml&quot;&gt;container.yml&lt;/h4&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-yaml&quot; data-lang=&quot;yaml&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;lineno&quot;&gt; 1 &lt;/span&gt;&lt;span class=&quot;l l-Scalar l-Scalar-Plain&quot;&gt;version&lt;/span&gt;&lt;span class=&quot;p p-Indicator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;quot;1&amp;quot;&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 2 &lt;/span&gt;&lt;span class=&quot;l l-Scalar l-Scalar-Plain&quot;&gt;services&lt;/span&gt;&lt;span class=&quot;p p-Indicator&quot;&gt;:&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 3 &lt;/span&gt;  &lt;span class=&quot;l l-Scalar l-Scalar-Plain&quot;&gt;maas&lt;/span&gt;&lt;span class=&quot;p p-Indicator&quot;&gt;:&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 4 &lt;/span&gt;    &lt;span class=&quot;l l-Scalar l-Scalar-Plain&quot;&gt;image&lt;/span&gt;&lt;span class=&quot;p p-Indicator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;l l-Scalar l-Scalar-Plain&quot;&gt;phusion/baseimage:latest&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 5 &lt;/span&gt;    &lt;span class=&quot;l l-Scalar l-Scalar-Plain&quot;&gt;command&lt;/span&gt;&lt;span class=&quot;p p-Indicator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p p-Indicator&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;#39;/sbin/my_init&amp;#39;&lt;/span&gt;&lt;span class=&quot;p p-Indicator&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 6 &lt;/span&gt;    &lt;span class=&quot;l l-Scalar l-Scalar-Plain&quot;&gt;ports&lt;/span&gt;&lt;span class=&quot;p p-Indicator&quot;&gt;:&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 7 &lt;/span&gt;      &lt;span class=&quot;p p-Indicator&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;quot;80:80&amp;quot;&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 8 &lt;/span&gt;      &lt;span class=&quot;p p-Indicator&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;quot;67:67/udp&amp;quot;&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 9 &lt;/span&gt;      &lt;span class=&quot;p p-Indicator&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;quot;69:69/udp&amp;quot;&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;10 &lt;/span&gt;    &lt;span class=&quot;l l-Scalar l-Scalar-Plain&quot;&gt;environment&lt;/span&gt;&lt;span class=&quot;p p-Indicator&quot;&gt;:&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;11 &lt;/span&gt;      &lt;span class=&quot;l l-Scalar l-Scalar-Plain&quot;&gt;TERM&lt;/span&gt;&lt;span class=&quot;p p-Indicator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;l l-Scalar l-Scalar-Plain&quot;&gt;vt100&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;12 &lt;/span&gt;&lt;span class=&quot;l l-Scalar l-Scalar-Plain&quot;&gt;registries&lt;/span&gt;&lt;span class=&quot;p p-Indicator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p p-Indicator&quot;&gt;{}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;In the &lt;code&gt;main.yml&lt;/code&gt;, I found it necessary to keep the &lt;code&gt;hosts: all&lt;/code&gt; section intact from the example and just edit the per-“host” steps.  The name &lt;code&gt;maas&lt;/code&gt; from &lt;code&gt;container.yml&lt;/code&gt; becomes the “host” in &lt;code&gt;main.yml&lt;/code&gt;.  Taking a page from previous work with &lt;a href=&quot;https://packer.io&quot;&gt;packer&lt;/a&gt; and Ansible before, I separated things into a role called &lt;code&gt;maas&lt;/code&gt;.  Note that the name has no relation to the “host”, but it needs to exist under the &lt;code&gt;ansible&lt;/code&gt; directory in a &lt;code&gt;roles&lt;/code&gt; folder.&lt;/p&gt;

&lt;h4 id=&quot;mainyml&quot;&gt;main.yml&lt;/h4&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-yaml&quot; data-lang=&quot;yaml&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;lineno&quot;&gt;1 &lt;/span&gt;&lt;span class=&quot;p p-Indicator&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;l l-Scalar l-Scalar-Plain&quot;&gt;hosts&lt;/span&gt;&lt;span class=&quot;p p-Indicator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;l l-Scalar l-Scalar-Plain&quot;&gt;all&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;2 &lt;/span&gt;  &lt;span class=&quot;l l-Scalar l-Scalar-Plain&quot;&gt;gather_facts&lt;/span&gt;&lt;span class=&quot;p p-Indicator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;l l-Scalar l-Scalar-Plain&quot;&gt;false&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;3 &lt;/span&gt;  &lt;span class=&quot;l l-Scalar l-Scalar-Plain&quot;&gt;tasks&lt;/span&gt;&lt;span class=&quot;p p-Indicator&quot;&gt;:&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;4 &lt;/span&gt;    &lt;span class=&quot;p p-Indicator&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;l l-Scalar l-Scalar-Plain&quot;&gt;raw&lt;/span&gt;&lt;span class=&quot;p p-Indicator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;l l-Scalar l-Scalar-Plain&quot;&gt;which python || apt-get update&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;5 &lt;/span&gt;    &lt;span class=&quot;p p-Indicator&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;l l-Scalar l-Scalar-Plain&quot;&gt;raw&lt;/span&gt;&lt;span class=&quot;p p-Indicator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;l l-Scalar l-Scalar-Plain&quot;&gt;(which python &amp;amp;&amp;amp; which aptitude) || apt-get install -y python python-apt aptitude&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;6 &lt;/span&gt;&lt;span class=&quot;p p-Indicator&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;l l-Scalar l-Scalar-Plain&quot;&gt;hosts&lt;/span&gt;&lt;span class=&quot;p p-Indicator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;l l-Scalar l-Scalar-Plain&quot;&gt;maas&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;7 &lt;/span&gt;  &lt;span class=&quot;l l-Scalar l-Scalar-Plain&quot;&gt;tasks&lt;/span&gt;&lt;span class=&quot;p p-Indicator&quot;&gt;:&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;8 &lt;/span&gt;  &lt;span class=&quot;l l-Scalar l-Scalar-Plain&quot;&gt;roles&lt;/span&gt;&lt;span class=&quot;p p-Indicator&quot;&gt;:&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;9 &lt;/span&gt;    &lt;span class=&quot;p p-Indicator&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;p p-Indicator&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;role&lt;/span&gt;&lt;span class=&quot;p p-Indicator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;quot;maas&amp;quot;&lt;/span&gt; &lt;span class=&quot;p p-Indicator&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;I performed an &lt;code&gt;ansible-galaxy init&lt;/code&gt; inside the &lt;code&gt;ansible/roles/maas&lt;/code&gt; directory and began editing my &lt;code&gt;tasks/main.yml&lt;/code&gt; and my &lt;code&gt;vars/main.yml&lt;/code&gt;.&lt;/p&gt;

&lt;h3 id=&quot;stepping-through-the-role&quot;&gt;Stepping Through the Role&lt;/h3&gt;

&lt;p&gt;When ansible uses a role, it uses the variables, files, templates, and plays contained in that role when running the &lt;code&gt;tasks/main.yml&lt;/code&gt; play.  This gives a nice structure to hold the files needed to build this container.&lt;/p&gt;

&lt;h5 id=&quot;caveat&quot;&gt;CAVEAT&lt;/h5&gt;
&lt;p&gt;I have to comment out the &lt;code&gt;service isc-dhcp-server start&lt;/code&gt; entry in &lt;code&gt;/etc/my_init.d/30_dhcp&lt;/code&gt; on my workstation in order to run/test locally.  This is because the subnets in the dhcpd configuration file don’t match any local interfaces.  Also, this container will give out leases to systems talking on the same subnet as my workstation when running/testing.  This might not be what you want.&lt;/p&gt;

&lt;h4 id=&quot;tasksmainyml&quot;&gt;tasks/main.yml&lt;/h4&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-yaml&quot; data-lang=&quot;yaml&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;lineno&quot;&gt; 1 &lt;/span&gt;&lt;span class=&quot;nn&quot;&gt;---&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 2 &lt;/span&gt;&lt;span class=&quot;p p-Indicator&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;l l-Scalar l-Scalar-Plain&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p p-Indicator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;l l-Scalar l-Scalar-Plain&quot;&gt;Update Apt&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 3 &lt;/span&gt;  &lt;span class=&quot;l l-Scalar l-Scalar-Plain&quot;&gt;apt&lt;/span&gt;&lt;span class=&quot;p p-Indicator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;l l-Scalar l-Scalar-Plain&quot;&gt;upgrade=yes&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 4 &lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 5 &lt;/span&gt;&lt;span class=&quot;p p-Indicator&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;l l-Scalar l-Scalar-Plain&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p p-Indicator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;l l-Scalar l-Scalar-Plain&quot;&gt;Install packages into container&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 6 &lt;/span&gt;  &lt;span class=&quot;l l-Scalar l-Scalar-Plain&quot;&gt;apt&lt;/span&gt;&lt;span class=&quot;p p-Indicator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;l l-Scalar l-Scalar-Plain&quot;&gt;name=&amp;quot;&amp;quot; state=installed&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 7 &lt;/span&gt;  &lt;span class=&quot;l l-Scalar l-Scalar-Plain&quot;&gt;with_items&lt;/span&gt;&lt;span class=&quot;p p-Indicator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;quot;&amp;quot;&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 8 &lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 9 &lt;/span&gt;&lt;span class=&quot;p p-Indicator&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;l l-Scalar l-Scalar-Plain&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p p-Indicator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;l l-Scalar l-Scalar-Plain&quot;&gt;Configure Web Mirror&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;10 &lt;/span&gt;  &lt;span class=&quot;l l-Scalar l-Scalar-Plain&quot;&gt;include&lt;/span&gt;&lt;span class=&quot;p p-Indicator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;quot;tasks/mirror.yml&amp;quot;&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;11 &lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;12 &lt;/span&gt;&lt;span class=&quot;p p-Indicator&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;l l-Scalar l-Scalar-Plain&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p p-Indicator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;l l-Scalar l-Scalar-Plain&quot;&gt;Configure Mirror Sync&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;13 &lt;/span&gt;  &lt;span class=&quot;l l-Scalar l-Scalar-Plain&quot;&gt;include&lt;/span&gt;&lt;span class=&quot;p p-Indicator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;quot;tasks/sync.yml&amp;quot;&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;14 &lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;15 &lt;/span&gt;&lt;span class=&quot;p p-Indicator&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;l l-Scalar l-Scalar-Plain&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p p-Indicator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;l l-Scalar l-Scalar-Plain&quot;&gt;Configure TFTP&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;16 &lt;/span&gt;  &lt;span class=&quot;l l-Scalar l-Scalar-Plain&quot;&gt;include&lt;/span&gt;&lt;span class=&quot;p p-Indicator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;quot;tasks/tftp.yml&amp;quot;&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;17 &lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;18 &lt;/span&gt;&lt;span class=&quot;p p-Indicator&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;l l-Scalar l-Scalar-Plain&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p p-Indicator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;l l-Scalar l-Scalar-Plain&quot;&gt;Configure DHCP&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;19 &lt;/span&gt;  &lt;span class=&quot;l l-Scalar l-Scalar-Plain&quot;&gt;include&lt;/span&gt;&lt;span class=&quot;p p-Indicator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;quot;tasks/dhcp.yml&amp;quot;&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;20 &lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;21 &lt;/span&gt;&lt;span class=&quot;p p-Indicator&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;l l-Scalar l-Scalar-Plain&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p p-Indicator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;l l-Scalar l-Scalar-Plain&quot;&gt;Add final script on init&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;22 &lt;/span&gt;  &lt;span class=&quot;l l-Scalar l-Scalar-Plain&quot;&gt;template&lt;/span&gt;&lt;span class=&quot;p p-Indicator&quot;&gt;:&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;23 &lt;/span&gt;    &lt;span class=&quot;l l-Scalar l-Scalar-Plain&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;p p-Indicator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;l l-Scalar l-Scalar-Plain&quot;&gt;start.sh.j2&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;24 &lt;/span&gt;    &lt;span class=&quot;l l-Scalar l-Scalar-Plain&quot;&gt;dest&lt;/span&gt;&lt;span class=&quot;p p-Indicator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;l l-Scalar l-Scalar-Plain&quot;&gt;/etc/my_init.d/99_start&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;25 &lt;/span&gt;    &lt;span class=&quot;l l-Scalar l-Scalar-Plain&quot;&gt;owner&lt;/span&gt;&lt;span class=&quot;p p-Indicator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;l l-Scalar l-Scalar-Plain&quot;&gt;root&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;26 &lt;/span&gt;    &lt;span class=&quot;l l-Scalar l-Scalar-Plain&quot;&gt;group&lt;/span&gt;&lt;span class=&quot;p p-Indicator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;l l-Scalar l-Scalar-Plain&quot;&gt;root&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;27 &lt;/span&gt;    &lt;span class=&quot;l l-Scalar l-Scalar-Plain&quot;&gt;mode&lt;/span&gt;&lt;span class=&quot;p p-Indicator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;l l-Scalar l-Scalar-Plain&quot;&gt;0744&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Because this is a Debian based image, updating apt is a common first step.  Next, it installs some packages listed in &lt;code&gt;vars/main.yml&lt;/code&gt;.  Then, it walks through separate plays for installing the yum mirror pieces, the syncing pieces, the TFTP server, and the DHCP server.  Finally, I drop in the last “init” script with some basic shell stuff that looks a lot like what I was doing in my entry scripts in my Dockerfiles.&lt;/p&gt;

&lt;h3 id=&quot;easing-the-buildtest-process&quot;&gt;Easing the Build/Test Process&lt;/h3&gt;

&lt;p&gt;I wrote a really quick shell script in the root of the repo called &lt;code&gt;orc&lt;/code&gt; which is very rough right now and specific to my needs.  However, it means I can do a &lt;code&gt;./orc build&lt;/code&gt; followed by an &lt;code&gt;./orc test&lt;/code&gt; followed by a &lt;code&gt;./orc deploy&lt;/code&gt; as needed.  Here’s what actions &lt;code&gt;orc&lt;/code&gt; provides at a glance:&lt;/p&gt;

&lt;h5 id=&quot;orc-build&quot;&gt;orc build&lt;/h5&gt;
&lt;p&gt;Runs &lt;code&gt;ansible-container build&lt;/code&gt;&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-console&quot; data-lang=&quot;console&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; ./orc build
&lt;span class=&quot;go&quot;&gt;No DOCKER_HOST environment variable found. Assuming UNIX socket at /var/run/docker.sock&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;Starting Docker Compose engine to build your images...&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;Attaching to ansible_ansible-container_1&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;Cleaning up Ansible Container builder...&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;Attaching to ansible_ansible-container_1, ansible_maas_1&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;ansible-container_1  | &lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;ansible-container_1  | PLAY [all] *********************************************************************&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;ansible-container_1  | &lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;ansible-container_1  | TASK [raw] *********************************************************************&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;ansible-container_1  | ok: [maas]&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;ansible-container_1  | &lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;ansible-container_1  | TASK [raw] *********************************************************************&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;ansible-container_1  | ok: [maas]&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;ansible-container_1  | &lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;ansible-container_1  | PLAY [maas] ********************************************************************&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;ansible-container_1  | &lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;ansible-container_1  | TASK [setup] *******************************************************************&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;ansible-container_1  | ok: [maas]&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;ansible-container_1  | &lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;ansible-container_1  | TASK [maas : Update Apt] *******************************************************&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;ansible-container_1  | ok: [maas]&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;ansible-container_1  | &lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;ansible-container_1  | TASK [maas : Install packages into container] **********************************&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;ansible-container_1  | ok: [maas] =&amp;gt; (item=[u&amp;#39;ca-certificates&amp;#39;, u&amp;#39;wget&amp;#39;, u&amp;#39;net-tools&amp;#39;])&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;ansible-container_1  | &lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;ansible-container_1  | TASK [maas : Configure Web Mirror] *********************************************&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;ansible-container_1  | included: /ansible-container/ansible/roles/maas/tasks/mirror.yml for maas&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;ansible-container_1  | &lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;ansible-container_1  | TASK [maas : Install Apache2] **************************************************&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;ansible-container_1  | ok: [maas]&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;ansible-container_1  | &lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;ansible-container_1  | TASK [maas : Install php7] *****************************************************&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;ansible-container_1  | ok: [maas]&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;ansible-container_1  | &lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;ansible-container_1  | TASK [maas : Enable mod_rewrite] ***********************************************&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;ansible-container_1  | ok: [maas]&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;ansible-container_1  | &lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;ansible-container_1  | TASK [maas : Configure Apache2] ************************************************&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;ansible-container_1  | ok: [maas]&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;ansible-container_1  | &lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;ansible-container_1  | TASK [maas : Enable Apache2 at start] ******************************************&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;ansible-container_1  | ok: [maas]&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;ansible-container_1  | &lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;ansible-container_1  | TASK [maas : Configure Mirror Sync] ********************************************&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;ansible-container_1  | included: /ansible-container/ansible/roles/maas/tasks/sync.yml for maas&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;ansible-container_1  | &lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;ansible-container_1  | TASK [maas : Install repo packages] ********************************************&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;ansible-container_1  | ok: [maas] =&amp;gt; (item=[u&amp;#39;createrepo&amp;#39;, u&amp;#39;rsync&amp;#39;])&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;ansible-container_1  | &lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;ansible-container_1  | TASK [maas : Copy Mirror Crontab] **********************************************&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;ansible-container_1  | ok: [maas]&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;ansible-container_1  | &lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;ansible-container_1  | TASK [maas : Copy Mirror Sync Script] ******************************************&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;ansible-container_1  | ok: [maas]&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;ansible-container_1  | &lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;ansible-container_1  | TASK [maas : Configure TFTP] ***************************************************&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;ansible-container_1  | included: /ansible-container/ansible/roles/maas/tasks/tftp.yml for maas&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;ansible-container_1  | &lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;ansible-container_1  | TASK [maas : Install TFTP] *****************************************************&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;ansible-container_1  | ok: [maas]&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;ansible-container_1  | &lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;ansible-container_1  | TASK [maas : Configure TFTPd] **************************************************&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;ansible-container_1  | ok: [maas]&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;ansible-container_1  | &lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;ansible-container_1  | TASK [maas : Enable TFTPd at start] ********************************************&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;ansible-container_1  | ok: [maas]&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;ansible-container_1  | &lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;ansible-container_1  | TASK [maas : Template grub.cfg and ks.php files into place] ********************&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;ansible-container_1  | ok: [maas] =&amp;gt; (item={u&amp;#39;src&amp;#39;: u&amp;#39;grub.cfg-net.j2&amp;#39;, u&amp;#39;dst&amp;#39;: u&amp;#39;/root/grub.cfg-net&amp;#39;})&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;ansible-container_1  | ok: [maas] =&amp;gt; (item={u&amp;#39;src&amp;#39;: u&amp;#39;grub.cfg-i386-pc.j2&amp;#39;, u&amp;#39;dst&amp;#39;: u&amp;#39;/root/grub.cfg-i386-pc&amp;#39;})&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;ansible-container_1  | ok: [maas] =&amp;gt; (item={u&amp;#39;src&amp;#39;: u&amp;#39;grub.cfg-x86_64-efi.j2&amp;#39;, u&amp;#39;dst&amp;#39;: u&amp;#39;/root/grub.cfg-x86_64-efi&amp;#39;})&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;ansible-container_1  | ok: [maas] =&amp;gt; (item={u&amp;#39;src&amp;#39;: u&amp;#39;ks.php.j2&amp;#39;, u&amp;#39;dst&amp;#39;: u&amp;#39;/root/ks.php&amp;#39;})&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;ansible-container_1  | &lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;ansible-container_1  | TASK [maas : Make kickstart directory] *****************************************&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;ansible-container_1  | ok: [maas]&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;ansible-container_1  | &lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;ansible-container_1  | TASK [maas : Generate kickstarts] **********************************************&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;ansible-container_1  | changed: [maas] =&amp;gt; (item={u&amp;#39;name&amp;#39;: u&amp;#39;mp&amp;#39;, u&amp;#39;mgmtip&amp;#39;: u&amp;#39;172.22.10.50&amp;#39;, u&amp;#39;ram&amp;#39;: u&amp;#39;24&amp;#39;, u&amp;#39;mgmtif&amp;#39;: u&amp;#39;enp7s0f0&amp;#39;, u&amp;#39;platform&amp;#39;: u&amp;#39;mac&amp;#39;, u&amp;#39;mgmtmac&amp;#39;: u&amp;#39;00:23:32:2f:40:3c&amp;#39;, u&amp;#39;cores&amp;#39;: u&amp;#39;8&amp;#39;, u&amp;#39;disk&amp;#39;: u&amp;#39;240&amp;#39;, u&amp;#39;arch&amp;#39;: u&amp;#39;x86_64&amp;#39;, u&amp;#39;mbr&amp;#39;: u&amp;#39;sda&amp;#39;})&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;ansible-container_1  | changed: [maas] =&amp;gt; (item={u&amp;#39;name&amp;#39;: u&amp;#39;mm1&amp;#39;, u&amp;#39;mgmtip&amp;#39;: u&amp;#39;172.22.10.51&amp;#39;, u&amp;#39;ram&amp;#39;: u&amp;#39;16&amp;#39;, u&amp;#39;mgmtif&amp;#39;: u&amp;#39;enp1s0f0&amp;#39;, u&amp;#39;platform&amp;#39;: u&amp;#39;mac&amp;#39;, u&amp;#39;mgmtmac&amp;#39;: u&amp;#39;a8:20:66:34:ff:e9&amp;#39;, u&amp;#39;cores&amp;#39;: u&amp;#39;4&amp;#39;, u&amp;#39;disk&amp;#39;: u&amp;#39;250&amp;#39;, u&amp;#39;arch&amp;#39;: u&amp;#39;x86_64&amp;#39;, u&amp;#39;mbr&amp;#39;: u&amp;#39;sdb&amp;#39;})&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;ansible-container_1  | changed: [maas] =&amp;gt; (item={u&amp;#39;name&amp;#39;: u&amp;#39;mm2&amp;#39;, u&amp;#39;mgmtip&amp;#39;: u&amp;#39;172.22.10.52&amp;#39;, u&amp;#39;ram&amp;#39;: u&amp;#39;16&amp;#39;, u&amp;#39;mgmtif&amp;#39;: u&amp;#39;enp1s0f0&amp;#39;, u&amp;#39;platform&amp;#39;: u&amp;#39;mac&amp;#39;, u&amp;#39;mgmtmac&amp;#39;: u&amp;#39;a8:20:66:4a:ce:46&amp;#39;, u&amp;#39;cores&amp;#39;: u&amp;#39;4&amp;#39;, u&amp;#39;disk&amp;#39;: u&amp;#39;250&amp;#39;, u&amp;#39;arch&amp;#39;: u&amp;#39;x86_64&amp;#39;, u&amp;#39;mbr&amp;#39;: u&amp;#39;sda&amp;#39;})&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;ansible-container_1  | changed: [maas] =&amp;gt; (item={u&amp;#39;name&amp;#39;: u&amp;#39;mm3&amp;#39;, u&amp;#39;mgmtip&amp;#39;: u&amp;#39;172.22.10.53&amp;#39;, u&amp;#39;ram&amp;#39;: u&amp;#39;16&amp;#39;, u&amp;#39;mgmtif&amp;#39;: u&amp;#39;enp1s0f0&amp;#39;, u&amp;#39;platform&amp;#39;: u&amp;#39;mac&amp;#39;, u&amp;#39;mgmtmac&amp;#39;: u&amp;#39;a8:20:66:4a:d9:da&amp;#39;, u&amp;#39;cores&amp;#39;: u&amp;#39;4&amp;#39;, u&amp;#39;disk&amp;#39;: u&amp;#39;250&amp;#39;, u&amp;#39;arch&amp;#39;: u&amp;#39;x86_64&amp;#39;, u&amp;#39;mbr&amp;#39;: u&amp;#39;sda&amp;#39;})&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;ansible-container_1  | changed: [maas] =&amp;gt; (item={u&amp;#39;name&amp;#39;: u&amp;#39;smpc&amp;#39;, u&amp;#39;mgmtip&amp;#39;: u&amp;#39;172.22.10.54&amp;#39;, u&amp;#39;ram&amp;#39;: u&amp;#39;12&amp;#39;, u&amp;#39;mgmtif&amp;#39;: u&amp;#39;enp6s0&amp;#39;, u&amp;#39;platform&amp;#39;: u&amp;#39;pc&amp;#39;, u&amp;#39;mgmtmac&amp;#39;: u&amp;#39;00:30:48:fb:e2:44&amp;#39;, u&amp;#39;cores&amp;#39;: u&amp;#39;4&amp;#39;, u&amp;#39;disk&amp;#39;: u&amp;#39;240&amp;#39;, u&amp;#39;arch&amp;#39;: u&amp;#39;x86_64&amp;#39;, u&amp;#39;mbr&amp;#39;: u&amp;#39;sda&amp;#39;})&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;ansible-container_1  | changed: [maas] =&amp;gt; (item={u&amp;#39;name&amp;#39;: u&amp;#39;sm1&amp;#39;, u&amp;#39;mgmtip&amp;#39;: u&amp;#39;172.22.10.55&amp;#39;, u&amp;#39;ram&amp;#39;: u&amp;#39;96&amp;#39;, u&amp;#39;mgmtif&amp;#39;: u&amp;#39;enp11s0&amp;#39;, u&amp;#39;platform&amp;#39;: u&amp;#39;pc&amp;#39;, u&amp;#39;mgmtmac&amp;#39;: u&amp;#39;00:25:90:96:c4:9a&amp;#39;, u&amp;#39;cores&amp;#39;: u&amp;#39;16&amp;#39;, u&amp;#39;disk&amp;#39;: u&amp;#39;512&amp;#39;, u&amp;#39;arch&amp;#39;: u&amp;#39;x86_64&amp;#39;, u&amp;#39;mbr&amp;#39;: u&amp;#39;sda&amp;#39;})&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;ansible-container_1  | changed: [maas] =&amp;gt; (item={u&amp;#39;name&amp;#39;: u&amp;#39;sm2&amp;#39;, u&amp;#39;mgmtip&amp;#39;: u&amp;#39;172.22.10.56&amp;#39;, u&amp;#39;ram&amp;#39;: u&amp;#39;96&amp;#39;, u&amp;#39;mgmtif&amp;#39;: u&amp;#39;enp11s0&amp;#39;, u&amp;#39;platform&amp;#39;: u&amp;#39;pc&amp;#39;, u&amp;#39;mgmtmac&amp;#39;: u&amp;#39;00:25:90:96:c6:5a&amp;#39;, u&amp;#39;cores&amp;#39;: u&amp;#39;16&amp;#39;, u&amp;#39;disk&amp;#39;: u&amp;#39;512&amp;#39;, u&amp;#39;arch&amp;#39;: u&amp;#39;x86_64&amp;#39;, u&amp;#39;mbr&amp;#39;: u&amp;#39;sda&amp;#39;})&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;ansible-container_1  | changed: [maas] =&amp;gt; (item={u&amp;#39;name&amp;#39;: u&amp;#39;d1&amp;#39;, u&amp;#39;mgmtip&amp;#39;: u&amp;#39;172.22.10.57&amp;#39;, u&amp;#39;ram&amp;#39;: u&amp;#39;32&amp;#39;, u&amp;#39;mgmtif&amp;#39;: u&amp;#39;em1&amp;#39;, u&amp;#39;platform&amp;#39;: u&amp;#39;pc&amp;#39;, u&amp;#39;mgmtmac&amp;#39;: u&amp;#39;bc:30:5b:e5:73:b7&amp;#39;, u&amp;#39;cores&amp;#39;: u&amp;#39;4&amp;#39;, u&amp;#39;disk&amp;#39;: u&amp;#39;240&amp;#39;, u&amp;#39;arch&amp;#39;: u&amp;#39;x86_64&amp;#39;, u&amp;#39;mbr&amp;#39;: u&amp;#39;sda&amp;#39;})&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;ansible-container_1  | changed: [maas] =&amp;gt; (item={u&amp;#39;name&amp;#39;: u&amp;#39;d2&amp;#39;, u&amp;#39;mgmtip&amp;#39;: u&amp;#39;172.22.10.58&amp;#39;, u&amp;#39;ram&amp;#39;: u&amp;#39;32&amp;#39;, u&amp;#39;mgmtif&amp;#39;: u&amp;#39;em1&amp;#39;, u&amp;#39;platform&amp;#39;: u&amp;#39;pc&amp;#39;, u&amp;#39;mgmtmac&amp;#39;: u&amp;#39;bc:30:5b:e5:75:28&amp;#39;, u&amp;#39;cores&amp;#39;: u&amp;#39;4&amp;#39;, u&amp;#39;disk&amp;#39;: u&amp;#39;240&amp;#39;, u&amp;#39;arch&amp;#39;: u&amp;#39;x86_64&amp;#39;, u&amp;#39;mbr&amp;#39;: u&amp;#39;sda&amp;#39;})&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;ansible-container_1  | &lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;ansible-container_1  | TASK [maas : Configure DHCP] ***************************************************&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;ansible-container_1  | included: /ansible-container/ansible/roles/maas/tasks/dhcp.yml for maas&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;ansible-container_1  | &lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;ansible-container_1  | TASK [maas : Install repo packages] ********************************************&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;ansible-container_1  | ok: [maas] =&amp;gt; (item=[u&amp;#39;isc-dhcp-server&amp;#39;, u&amp;#39;grub-common&amp;#39;, u&amp;#39;grub2-common&amp;#39;, u&amp;#39;grub-imageboot&amp;#39;, u&amp;#39;grub-pc-bin&amp;#39;, u&amp;#39;grub-efi&amp;#39;])&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;ansible-container_1  | &lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;ansible-container_1  | TASK [maas : Configure DHCPD] **************************************************&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;ansible-container_1  | ok: [maas]&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;ansible-container_1  | &lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;ansible-container_1  | TASK [maas : Enable DHCP server] ***********************************************&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;ansible-container_1  | ok: [maas]&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;ansible-container_1  | &lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;ansible-container_1  | TASK [maas : Add final script on init] *****************************************&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;ansible-container_1  | ok: [maas]&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;ansible-container_1  | &lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;ansible-container_1  | PLAY RECAP *********************************************************************&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;ansible-container_1  | maas                       : ok=27   changed=1    unreachable=0    failed=0   &lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;ansible-container_1  | &lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;ansible_ansible-container_1 exited with code 0&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;Aborting on container exit...&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;Stopping ansible_maas_1 ... done&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;Exporting built containers as images...&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;Committing image...&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;Exported netpxemirror-ac-maas with image ID sha256:516ae0de22da34d87a9726dca0a6d92b9602b9df3c757b4bc7e71c9fc1e6ec60&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;Cleaning up maas build container...&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;Cleaning up Ansible Container builder...&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;h5 id=&quot;orc-buildclean&quot;&gt;orc buildclean&lt;/h5&gt;
&lt;p&gt;Runs &lt;code&gt;ansible-container build --from-scratch&lt;/code&gt; to rebuild from a clean starting point.  Useful if large changes to packages and scripts are made in the role.&lt;/p&gt;

&lt;h5 id=&quot;orc-run&quot;&gt;orc run&lt;/h5&gt;
&lt;p&gt;Runs &lt;code&gt;ansible-container run&lt;/code&gt; locally.  This variation has a while loop for the init script instead of your “production” init script.  In my case, it takes the place of &lt;code&gt;/sbin/my_init&lt;/code&gt; from the &lt;code&gt;phusion/baseimage&lt;/code&gt;.&lt;/p&gt;

&lt;h5 id=&quot;orc-test&quot;&gt;orc test&lt;/h5&gt;
&lt;p&gt;Finds the id of the running container, runs the &lt;code&gt;chef/inspec&lt;/code&gt; docker container and attaches to it to run the test suite.  Thanks to the Chef folks for making &lt;code&gt;inspec&lt;/code&gt; so easy to use/install.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-console&quot; data-lang=&quot;console&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; docker pull chef/inspec
&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;did&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;$(&lt;/span&gt;docker ps -q --filter&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;name=ansible_maas_1&amp;#39;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; docker run -it --rm -v &lt;span class=&quot;k&quot;&gt;$(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;pwd&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;)&lt;/span&gt;:/share -v /var/run/docker.sock:/var/run/docker.sock chef/inspec &lt;span class=&quot;nb&quot;&gt;exec&lt;/span&gt; spec/test.rb -t docker://&lt;span class=&quot;nv&quot;&gt;$did&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; No DOCKER_HOST environment variable found. Assuming UNIX socket at /var/run/docker.sock
&lt;span class=&quot;go&quot;&gt;Attaching to ansible_ansible-container_1&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;Cleaning up Ansible Container builder...&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;Attaching to ansible_maas_1&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;maas_1               | *** Running /etc/my_init.d/00_regen_ssh_host_keys.sh...&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;maas_1               | *** Running /etc/my_init.d/10_apache2...&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;maas_1               |  * Starting Apache httpd web server apache2&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;maas_1               | AH00558: apache2: Could not reliably determine the server&amp;#39;s fully qualified domain name, using 172.17.0.2. Set the &amp;#39;ServerName&amp;#39; directive globally to suppress this message&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;maas_1               |  * &lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;maas_1               | *** Running /etc/my_init.d/20_tftpd...&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;maas_1               |  * Starting HPA&amp;#39;s tftpd in.tftpd&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;maas_1               |    ...done.&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;maas_1               | *** Running /etc/my_init.d/30_dhcp...&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;maas_1               | *** Running /etc/my_init.d/99_start...&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;maas_1               | Netboot directory for i386-pc created. Configure your DHCP server to point to /nbi/boot/grub/i386-pc/core.0&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;maas_1               | Netboot directory for x86_64-efi created. Configure your DHCP server to point to /nbi/boot/grub/x86_64-efi/core.efi&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;maas_1               | *** Running /etc/rc.local...&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;maas_1               | *** Booting runit daemon...&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;maas_1               | *** Runit started as PID 75&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;maas_1               | Jul 28 19:34:32 4ca404c631e7 syslog-ng[80]: syslog-ng starting up; version=&amp;#39;3.5.6&amp;#39;&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;maas_1               | Jul 28 19:39:01 4ca404c631e7 CRON[137]: (root) CMD (  [ -x /usr/lib/php/sessionclean ] &amp;amp;&amp;amp; /usr/lib/php/sessionclean)&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;maas_1               | Jul 28 20:09:01 4ca404c631e7 CRON[1264]: (root) CMD (  [ -x /usr/lib/php/sessionclean ] &amp;amp;&amp;amp; /usr/lib/php/sessionclean)&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;maas_1               | Jul 28 20:17:01 4ca404c631e7 CRON[1306]: (root) CMD (   cd / &amp;amp;&amp;amp; run-parts --report /etc/cron.hourly)&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;maas_1               | Jul 28 20:39:01 4ca404c631e7 CRON[1309]: (root) CMD (  [ -x /usr/lib/php/sessionclean ] &amp;amp;&amp;amp; /usr/lib/php/sessionclean)&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;...................&lt;/span&gt;

&lt;span class=&quot;go&quot;&gt;Finished in 3.65 seconds (files took 2.16 seconds to load)&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;19 examples, 0 failures&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;h4 id=&quot;orc-deploy&quot;&gt;orc deploy&lt;/h4&gt;
&lt;p&gt;A bit of custom stuff to send over the latest image to my &lt;code&gt;deploy&lt;/code&gt; system in docker-compose format and starts it there.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-console&quot; data-lang=&quot;console&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; ./orc deploy
&lt;span class=&quot;go&quot;&gt;* Deploying...&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt; - Syncing the latest&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt; 521MiB 0:00:43 [12.1MiB/s] [                                                    &amp;lt;=&amp;gt;                                   ]&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt; - Copying compose file&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt; - Restarting compose app&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;Stopping admin_maas_1 ... done&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;Removing admin_maas_1 ... done&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;* Done.&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;h3 id=&quot;whats-better&quot;&gt;What’s Better?&lt;/h3&gt;

&lt;p&gt;Well, this approach pretty much provides the same functionality as before, but it’s much easier to adjust/tweak and maintain.  Here’s where things stand after moving to this method:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Lack of central inventory of systems and asset attributes
    &lt;ul&gt;
      &lt;li&gt;All of that data is now stored in the &lt;code&gt;maas&lt;/code&gt; roles’ &lt;code&gt;vars/main.yml&lt;/code&gt; in a format that Ansible can parse/loop through&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Hardcoded paths and configuration files/settings in Docker containers
    &lt;ul&gt;
      &lt;li&gt;All of the key variables and path names have been separated into variables–again stored in the &lt;code&gt;maas&lt;/code&gt; roles’ &lt;code&gt;vars/main.yml&lt;/code&gt;.  Now, changing names of files/directories is a trivial exercises as needs change.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Hardcoded DHCP Leases
    &lt;ul&gt;
      &lt;li&gt;These are generated during the templating run by Jinja2 filters in the &lt;code&gt;dhcpd.conf.j2&lt;/code&gt; template stored in the &lt;code&gt;maas&lt;/code&gt; &lt;code&gt;templates&lt;/code&gt; folder and called by the &lt;code&gt;dhcp.yml&lt;/code&gt; task/play.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Individually crafted Kickstart configuration files
    &lt;ul&gt;
      &lt;li&gt;Using the variable storage method in the roles’ &lt;code&gt;vars/main.yml&lt;/code&gt;, the &lt;code&gt;ks.cfg.j2&lt;/code&gt; template is used to generate all the per-host kickstart files.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;SELinux is disabled on &lt;code&gt;deploy&lt;/code&gt;
    &lt;ul&gt;
      &lt;li&gt;Not yet addressed, but it should be a simpler debugging exercise now that it’s a single docker container running on &lt;code&gt;deploy&lt;/code&gt;.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;One version of one operating system supported
    &lt;ul&gt;
      &lt;li&gt;Not yet addressed, but it’s easier to add support now that all configuration files are templated with Ansible/Jinja2.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Logging from the containers
    &lt;ul&gt;
      &lt;li&gt;The &lt;code&gt;phusion/baseimage&lt;/code&gt; runs a syslog daemon out of the box, but it currently is not sent anywhere.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;It wasn’t very “DRY”
    &lt;ul&gt;
      &lt;li&gt;Instead of three separate containers from 2 different &lt;code&gt;FROM&lt;/code&gt; base images, it’s now a single debian-based container running 3 key services.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;There was no testing of the container contents
    &lt;ul&gt;
      &lt;li&gt;Adding inspec testing means I can now confidently add test coverage and perform testing during the build process in a few seconds instead of manually validating functionality.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Inspecting the containers as I built it was tedious
    &lt;ul&gt;
      &lt;li&gt;The additional insight gained by using debugging features in Ansible and the logging as the play is being run means I can more quickly diagnose where something went wrong.  Ansible does a decent job of capturing the error message when things go sideways, and it spits it out immediately.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;I was building on my deploy system directly
    &lt;ul&gt;
      &lt;li&gt;Using a bit of docker and ssh glued together with some &lt;code&gt;docker-compose&lt;/code&gt;, I have the build and test processes running on my workstation and the final container running on the &lt;code&gt;deploy&lt;/code&gt; system.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href=&quot;/2016/07/25/neverending-uphill-journey.html&quot;&gt;Back to Index&lt;/a&gt;&lt;/p&gt;

</description>
        <pubDate>Thu, 28 Jul 2016 00:00:00 +0000</pubDate>
        <link>https://www.lonimbus.com//2016/07/28/maas-4.html</link>
        <guid isPermaLink="true">https://www.lonimbus.com//2016/07/28/maas-4.html</guid>
        
        
      </item>
    
      <item>
        <title>MaaS Part 3 - Remaining Issues</title>
        <description>&lt;p&gt;In &lt;a href=&quot;/2016/07/26/maas-1.html&quot;&gt;part 1&lt;/a&gt; and &lt;a href=&quot;/2016/07/26/maas-2.html&quot;&gt;part 2&lt;/a&gt;, I’ve got the basis for a simple network-based hardware provisioning system.  However, it has some issues that I’d like to list here to drive future improvement efforts.&lt;/p&gt;

&lt;p&gt;Update: &lt;a href=&quot;/2016/07/28/maas-4.html&quot;&gt;part 4&lt;/a&gt; addresses several of these issues plus some new ones using &lt;a href=&quot;https://www.ansible.com/ansible-container&quot;&gt;Ansible-Container&lt;/a&gt;, some shell scripting, and &lt;a href=&quot;https://www.chef.io/inspec/&quot;&gt;Inspec&lt;/a&gt;.&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;
    &lt;h5 id=&quot;lack-of-central-inventory-of-systems-and-asset-attributes&quot;&gt;Lack of central inventory of systems and asset attributes&lt;/h5&gt;
    &lt;p&gt;There is no central place that defines an asset and its attributes like hostname, mac address, system type, CPU, RAM, Disks, etc.  As &lt;a href=&quot;https://www.ansible.com/&quot;&gt;Ansible&lt;/a&gt; is typically my go-to tool of choice for lightweight orchestration and configuration management, it seems logical to define these in an inventory file and vars file.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;h5 id=&quot;hardcoded-paths-and-configuration-filessettings-in-docker-containers&quot;&gt;Hardcoded paths and configuration files/settings in Docker containers&lt;/h5&gt;
    &lt;p&gt;While Docker containers help make what’s needed explicit in terms of configuration settings, it’s difficult to avoid embedding paths that change per deployment.  What if I don’t like my TFTP root as &lt;code&gt;/nbi&lt;/code&gt;?  Right now, it’d be very painful to change that path and re-test everything.  I’m curious to see if &lt;a href=&quot;https://www.ansible.com/ansible-container&quot;&gt;Ansible-Container&lt;/a&gt; helps take the sting out of making templated configuration files inside Docker containers.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;h5 id=&quot;hardcoded-dhcp-leases&quot;&gt;Hardcoded DHCP Leases&lt;/h5&gt;
    &lt;p&gt;Because I have a fixed set of hardware, this is a one-time effort.  However, it fails to scale at any size beyond where it is now.  These static reservations should be generated from the asset system or leases be dynamic and have the IP updates tied into DNS directly.  A quick looping Ansible playbook to generate these from the inventory/vars files could do the trick.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;h5 id=&quot;individually-crafted-kickstart-configuration-files&quot;&gt;Individually crafted Kickstart configuration files&lt;/h5&gt;
    &lt;p&gt;While 95% of each kickstart file is identical, templates with a couple variables from the asset system generating the final kickstart files would be better.  Another quick looping Ansible playbook to generate these from the inventory/vars files would solve this.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;h5 id=&quot;selinux-is-disabled-on-deploy&quot;&gt;SELinux is disabled on &lt;code&gt;deploy&lt;/code&gt;&lt;/h5&gt;
    &lt;p&gt;This was a matter of avoiding very difficult to debug issues during rapid iteration.  It’s not “production ready” unless it has an SELinux policy that aligns with the needs of the app, and this one just needs some time and elbow grease.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;h5 id=&quot;one-version-of-one-operating-system-supported&quot;&gt;One version of one operating system supported&lt;/h5&gt;
    &lt;p&gt;I’m standardizing on Centos 7.x here, but an eventuality will be to support newer releases as time goes on.  Assuming all the other issues are handled better with Ansible roles/playbooks, this problem most likely becomes much easier, too.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;h5 id=&quot;logging-from-the-containers&quot;&gt;Logging from the containers&lt;/h5&gt;
    &lt;p&gt;I want to know what’s happening in terms of DHCP giving out leases, TFTP files downloaded, Kickstart configs downloaded, and general errors when they happen.  This will require more investigation into best practices.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href=&quot;/2016/07/25/neverending-uphill-journey.html&quot;&gt;Back to Index&lt;/a&gt;&lt;/p&gt;

</description>
        <pubDate>Tue, 26 Jul 2016 00:00:00 +0000</pubDate>
        <link>https://www.lonimbus.com//2016/07/26/maas-3.html</link>
        <guid isPermaLink="true">https://www.lonimbus.com//2016/07/26/maas-3.html</guid>
        
        
      </item>
    
      <item>
        <title>MaaS Part 2 - Centos 7.x and Kickstart</title>
        <description>&lt;p&gt;In &lt;a href=&quot;/2016/07/26/maas-1.html&quot;&gt;part 1&lt;/a&gt;, I walked through the initial network booting process to be able to start the Centos 7.x installation process.  In this part, part 2, I’ll continue on to explain the Centos 7.x specific portions of things as well as break down the kickstart configuration file.&lt;/p&gt;

&lt;h3 id=&quot;centos-7-specifics&quot;&gt;Centos 7 Specifics&lt;/h3&gt;
&lt;p&gt;In the &lt;code&gt;grub.cfg&lt;/code&gt; file, the following kernel line:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;  linux (tftp)/vmlinuz noipv6 inst.repo=http://deploy/repos/centos/7/os/x86_64/ inst.ks=http://deploy/ks.cfg inst.ks.sendmac
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;has three RedHat/Centos specific items under the &lt;code&gt;inst&lt;/code&gt; prefix.  &lt;a href=&quot;https://rhinstaller.github.io/anaconda/boot-options.html&quot;&gt;Full reference&lt;/a&gt;&lt;/p&gt;

&lt;h5 id=&quot;instrepo&quot;&gt;inst.repo&lt;/h5&gt;
&lt;p&gt;This option tells the installer (anaconda) where it can find its installation repository.  In this case, the web root of our &lt;code&gt;centos7mirror&lt;/code&gt; container.&lt;/p&gt;

&lt;h5 id=&quot;instks&quot;&gt;inst.ks&lt;/h5&gt;
&lt;p&gt;This option tells anaconda where it can find the optional kickstart configuration file.  Again in this case, the web root of our &lt;code&gt;centos7mirror&lt;/code&gt; container.&lt;/p&gt;

&lt;h5 id=&quot;instkssendmac&quot;&gt;inst.ks.sendmac&lt;/h5&gt;
&lt;p&gt;This option tells anaconda to send the NIC name and mac address of the interface used to request the kickstart inside as special HTTP header named &lt;code&gt;X-RHN-Provisioning-MAC-0&lt;/code&gt;.  e.g.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;X-RHN-Provisioning-MAC-0: eth0 01:23:45:67:89:ab
&lt;/code&gt;&lt;/pre&gt;

&lt;h3 id=&quot;custom-kickstart-handler&quot;&gt;Custom Kickstart Handler&lt;/h3&gt;
&lt;p&gt;So, in our &lt;code&gt;/var/www/html/ks.php&lt;/code&gt; file, we parse the MAC header and serve up our custom kickstart file if it’s valid and exists as a configuration file.  Remember, we use mod_rewrite rules to make any requests for &lt;code&gt;ks.cfg&lt;/code&gt; be served by &lt;code&gt;/var/www/html/ks.php&lt;/code&gt;:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-php&quot; data-lang=&quot;php&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;lineno&quot;&gt; 1 &lt;/span&gt;&lt;span class=&quot;cp&quot;&gt;&amp;lt;?php&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 2 &lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;# kickstart needs text/plain or it fails&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 3 &lt;/span&gt;  &lt;span class=&quot;nb&quot;&gt;header&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;Content-Type: text/plain&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 4 &lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 5 &lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;# Cfg file path&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 6 &lt;/span&gt;  &lt;span class=&quot;nv&quot;&gt;$cfgpath&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;./cfg&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 7 &lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 8 &lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;# Did we get the inst.ks.sendmac header&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 9 &lt;/span&gt;  &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;isset&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$_SERVER&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;HTTP_X_RHN_PROVISIONING_MAC_0&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]))&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;10 &lt;/span&gt;    &lt;span class=&quot;c1&quot;&gt;# Parse the header&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;11 &lt;/span&gt;    &lt;span class=&quot;nv&quot;&gt;$macstring&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$_SERVER&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;HTTP_X_RHN_PROVISIONING_MAC_0&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;];&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;12 &lt;/span&gt;    &lt;span class=&quot;nv&quot;&gt;$macarray&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;explode&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot; &amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$macstring&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;13 &lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;14 &lt;/span&gt;    &lt;span class=&quot;c1&quot;&gt;# Did the header contain a mac address?&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;15 &lt;/span&gt;    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;isset&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$macarray&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]))&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;16 &lt;/span&gt;      &lt;span class=&quot;nv&quot;&gt;$mac&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$macarray&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;];&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;17 &lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;18 &lt;/span&gt;      &lt;span class=&quot;c1&quot;&gt;# Valid mac format?&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;19 &lt;/span&gt;      &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;preg_match&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;/([a-fA-F0-9]{2}:?){6}/&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$mac&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;20 &lt;/span&gt;        &lt;span class=&quot;k&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;Invalid Request&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;21 &lt;/span&gt;        &lt;span class=&quot;k&quot;&gt;exit&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;22 &lt;/span&gt;      &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;23 &lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;24 &lt;/span&gt;      &lt;span class=&quot;c1&quot;&gt;# Send its config if one exists&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;25 &lt;/span&gt;      &lt;span class=&quot;nv&quot;&gt;$configfile&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;$cfgpath&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;$mac&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;.cfg&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;26 &lt;/span&gt;      &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;file_exists&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$configfile&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;27 &lt;/span&gt;        &lt;span class=&quot;nb&quot;&gt;readfile&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$configfile&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;28 &lt;/span&gt;      &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;29 &lt;/span&gt;        &lt;span class=&quot;k&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;Invalid Request&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;30 &lt;/span&gt;      &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;31 &lt;/span&gt;    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;32 &lt;/span&gt;  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;33 &lt;/span&gt;    &lt;span class=&quot;k&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;Invalid Request&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;34 &lt;/span&gt;    &lt;span class=&quot;k&quot;&gt;exit&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;35 &lt;/span&gt;  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;36 &lt;/span&gt;&lt;span class=&quot;cp&quot;&gt;?&amp;gt;&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;And here is what’s in &lt;code&gt;/var/www/html/cfg&lt;/code&gt;:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-console&quot; data-lang=&quot;console&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;[admin@deploy cfg]$&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;pwd&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;/var/www/html/cfg&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;[admin@deploy cfg]$&lt;/span&gt; ls -al
&lt;span class=&quot;go&quot;&gt;total 40&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;drwxr-xr-x 2 root root 4096 Jul 25 15:04 .&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;drwxr-xr-x 4 root root   58 Jul 26 01:00 ..&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;-rw-r--r-- 1 root root 1814 Jul 25 15:04 00:23:32:2f:40:3c.cfg&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;-rw-r--r-- 1 root root 1819 Jul 25 15:04 00:25:90:96:c4:9a.cfg&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;-rw-r--r-- 1 root root 1819 Jul 25 15:04 00:25:90:96:c6:5a.cfg&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;-rw-r--r-- 1 root root 1808 Jul 25 15:04 00:30:48:fb:e2:44.cfg&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;-rw-r--r-- 1 root root 1811 Jul 25 15:04 a8:20:66:34:ff:e9.cfg&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;-rw-r--r-- 1 root root 1811 Jul 25 15:04 a8:20:66:4a:ce:46.cfg&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;-rw-r--r-- 1 root root 1811 Jul 25 15:04 a8:20:66:4a:d9:da.cfg&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;-rw-r--r-- 1 root root 1810 Jul 25 15:04 bc:30:5b:e5:73:b7.cfg&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;-rw-r--r-- 1 root root 1810 Jul 25 15:04 bc:30:5b:e5:75:28.cfg&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;h3 id=&quot;custom-kickstart-file&quot;&gt;Custom Kickstart File&lt;/h3&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;lineno&quot;&gt; 1 &lt;/span&gt;&lt;span class=&quot;c1&quot;&gt;#version=DEVEL&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 2 &lt;/span&gt;&lt;span class=&quot;c1&quot;&gt;# System authorization information&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 3 &lt;/span&gt;auth --enableshadow --passalgo&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;sha512
&lt;span class=&quot;lineno&quot;&gt; 4 &lt;/span&gt;&lt;span class=&quot;c1&quot;&gt;# Use CDROM installation media&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 5 &lt;/span&gt;url --url http://deploy/repos/centos/7/os/x86_64/
&lt;span class=&quot;lineno&quot;&gt; 6 &lt;/span&gt;&lt;span class=&quot;c1&quot;&gt;# Use graphical install&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 7 &lt;/span&gt;&lt;span class=&quot;c1&quot;&gt;#graphical&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 8 &lt;/span&gt;text
&lt;span class=&quot;lineno&quot;&gt; 9 &lt;/span&gt;&lt;span class=&quot;c1&quot;&gt;# Run the Setup Agent on first boot&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;10 &lt;/span&gt;firstboot --enable
&lt;span class=&quot;lineno&quot;&gt;11 &lt;/span&gt;ignoredisk --only-use&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;sdb
&lt;span class=&quot;lineno&quot;&gt;12 &lt;/span&gt;&lt;span class=&quot;c1&quot;&gt;# Keyboard layouts&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;13 &lt;/span&gt;keyboard --vckeymap&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;us --xlayouts&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;us&amp;#39;&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;14 &lt;/span&gt;&lt;span class=&quot;c1&quot;&gt;# System language&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;15 &lt;/span&gt;lang en_US.UTF-8
&lt;span class=&quot;lineno&quot;&gt;16 &lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;17 &lt;/span&gt;&lt;span class=&quot;c1&quot;&gt;# Network information&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;18 &lt;/span&gt;network  --bootproto&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;dhcp --device&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;enp2s0 --noipv6 --activate
&lt;span class=&quot;lineno&quot;&gt;19 &lt;/span&gt;network  --hostname&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;mm1
&lt;span class=&quot;lineno&quot;&gt;20 &lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;21 &lt;/span&gt;&lt;span class=&quot;c1&quot;&gt;# During Install&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;22 &lt;/span&gt;sshpw --user&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;root s3cr3t
&lt;span class=&quot;lineno&quot;&gt;23 &lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;24 &lt;/span&gt;&lt;span class=&quot;c1&quot;&gt;# Root password&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;25 &lt;/span&gt;rootpw --iscrypted &lt;span class=&quot;nv&quot;&gt;$6$SANKK2GLJES9hSp9$PgaXUwpz2S4mRwg6kUQo&lt;/span&gt;.E3IyArxeA.MdIc77e1kkPRDD3BI8d3mxrwmoD.8BbZ2613XJoZNgWX0fwCsu1tih.
&lt;span class=&quot;lineno&quot;&gt;26 &lt;/span&gt;&lt;span class=&quot;c1&quot;&gt;# System timezone&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;27 &lt;/span&gt;timezone America/New_York --isUtc
&lt;span class=&quot;lineno&quot;&gt;28 &lt;/span&gt;user --groups&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;wheel --name&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;admin --password&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$6$0&lt;/span&gt;YFXS7zQLIQ99FCh&lt;span class=&quot;nv&quot;&gt;$gqxId0ypSP16GCwiOfOcGUZK9AASxatDVF4g8PtTy5HDaZ5jXeIo9NeOU4ttK1KWjsI&lt;/span&gt;/6D6TVMfOh37XCMSG2/ --iscrypted --gecos&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;admin&amp;quot;&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;29 &lt;/span&gt;&lt;span class=&quot;c1&quot;&gt;# System bootloader configuration&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;30 &lt;/span&gt;bootloader --append&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot; crashkernel=auto&amp;quot;&lt;/span&gt; --location&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;mbr --boot-drive&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;sdb
&lt;span class=&quot;lineno&quot;&gt;31 &lt;/span&gt;autopart --type&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;lvm
&lt;span class=&quot;lineno&quot;&gt;32 &lt;/span&gt;&lt;span class=&quot;c1&quot;&gt;# Partition clearing information&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;33 &lt;/span&gt;clearpart --all --initlabel --drives&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;sda,sdb
&lt;span class=&quot;lineno&quot;&gt;34 &lt;/span&gt;&lt;span class=&quot;c1&quot;&gt;# Reboot after install finishes&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;35 &lt;/span&gt;reboot
&lt;span class=&quot;lineno&quot;&gt;36 &lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;37 &lt;/span&gt;%packages
&lt;span class=&quot;lineno&quot;&gt;38 &lt;/span&gt;@^minimal
&lt;span class=&quot;lineno&quot;&gt;39 &lt;/span&gt;@core
&lt;span class=&quot;lineno&quot;&gt;40 &lt;/span&gt;kexec-tools
&lt;span class=&quot;lineno&quot;&gt;41 &lt;/span&gt;net-tools
&lt;span class=&quot;lineno&quot;&gt;42 &lt;/span&gt;tcpdump
&lt;span class=&quot;lineno&quot;&gt;43 &lt;/span&gt;wget
&lt;span class=&quot;lineno&quot;&gt;44 &lt;/span&gt;nc
&lt;span class=&quot;lineno&quot;&gt;45 &lt;/span&gt;%end
&lt;span class=&quot;lineno&quot;&gt;46 &lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;47 &lt;/span&gt;%addon com_redhat_kdump --enable --reserve-mb&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;auto&amp;#39;&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;48 &lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;49 &lt;/span&gt;%end
&lt;span class=&quot;lineno&quot;&gt;50 &lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;51 &lt;/span&gt;%post --log&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;/root/postinstall.log
&lt;span class=&quot;lineno&quot;&gt;52 &lt;/span&gt;&lt;span class=&quot;c1&quot;&gt;# SSH UseDNS no&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;53 &lt;/span&gt;sed -ri &lt;span class=&quot;s1&quot;&gt;&amp;#39;s/#UseDNS yes/UseDNS no/&amp;#39;&lt;/span&gt;g /etc/ssh/sshd_config
&lt;span class=&quot;lineno&quot;&gt;54 &lt;/span&gt;&lt;span class=&quot;c1&quot;&gt;# SSH Key&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;55 &lt;/span&gt;mkdir -p /home/admin/.ssh
&lt;span class=&quot;lineno&quot;&gt;56 &lt;/span&gt;chmod &lt;span class=&quot;m&quot;&gt;700&lt;/span&gt; /home/admin/.ssh
&lt;span class=&quot;lineno&quot;&gt;57 &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAAAgQCugz/eu/a6U5ZXtYVp9ufCghVSP0Lux/nP6BgbranKE6r3h3xgqo8yR2LUG9VwH6Vo+BtGgToeww+jbgr3oq9g8/mQmNvQEefvWyzhYxrpv6q36fdYS0KhQxA6vnpOZZ1M9cZ1q6iPaUryxDUFU3HULDKM4g/6XBzqBJZ2illyuw==&amp;quot;&lt;/span&gt; &amp;gt; /home/admin/.ssh/authorized_keys
&lt;span class=&quot;lineno&quot;&gt;58 &lt;/span&gt;chmod &lt;span class=&quot;m&quot;&gt;600&lt;/span&gt; /home/admin/.ssh/authorized_keys
&lt;span class=&quot;lineno&quot;&gt;59 &lt;/span&gt;chown -R admin:admin /home/admin/.ssh
&lt;span class=&quot;lineno&quot;&gt;60 &lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;61 &lt;/span&gt;yum -y update
&lt;span class=&quot;lineno&quot;&gt;62 &lt;/span&gt; 
&lt;span class=&quot;lineno&quot;&gt;63 &lt;/span&gt;%end&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;A couple key notes:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;The file was created by first performing a manual installation.  This ends up as &lt;code&gt;/root/anaconda-ks.cfg&lt;/code&gt; after installation completes.  I then added a couple packages and then the contents of the &lt;code&gt;post&lt;/code&gt; section.&lt;/li&gt;
  &lt;li&gt;All partitions are cleared and the default partitioning scheme is used&lt;/li&gt;
  &lt;li&gt;A default account of &lt;code&gt;admin&lt;/code&gt; is made&lt;/li&gt;
  &lt;li&gt;A public SSH key for &lt;code&gt;admin&lt;/code&gt; is added to enable access once booted&lt;/li&gt;
  &lt;li&gt;&lt;code&gt;UseDNS no&lt;/code&gt; is changed to speed up SSH access by removing reverse DNS lookups on connection.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href=&quot;/2016/07/25/neverending-uphill-journey.html&quot;&gt;Back to Index&lt;/a&gt;&lt;/p&gt;

</description>
        <pubDate>Tue, 26 Jul 2016 00:00:00 +0000</pubDate>
        <link>https://www.lonimbus.com//2016/07/26/maas-2.html</link>
        <guid isPermaLink="true">https://www.lonimbus.com//2016/07/26/maas-2.html</guid>
        
        
      </item>
    
      <item>
        <title>MaaS Part 1 - Netboot Macs and PXEBooting PCs from Linux</title>
        <description>&lt;p&gt;When building a “Metal as a Service” (MAAS) layer, the idea is to make it very easy to go from “box to rack to ready” for a large number of servers.  To make this easier and to reduce complexity at this layer, most organizations purchase one or more sets of similar servers from a single manufacturer.  Depending on the level of service, they may have the manufacturer/vendor prepare the systems a certain way before they show up at the door.  A technician can just unbox them, inventory the asset, slide them into the rack, cable it up, and be done with their part.&lt;/p&gt;

&lt;p&gt;The goal is that the provisioning system picks up from the power-on event from that point on.  It gets a base operating system followed by some configuration management to put it into a production state.  When that system is no longer being used in that production state, it goes through a similar re-provisioning process to become useful again for another application.&lt;/p&gt;

&lt;p&gt;Naturally, this can get out of hand without proper tooling once you go past, say, 10 servers.  I’ve been doing a fair bit of reading about this, and &lt;a href=&quot;http://rebar.digital&quot;&gt;Digital Rebar&lt;/a&gt; looks like the best of breed for the power and customization aspects.  It’s the latest from the folks that developed Crowbar.&lt;/p&gt;

&lt;p&gt;So why am I not going to use Digital Rebar?&lt;/p&gt;

&lt;p&gt;Well, two reasons.  I know that learning comes best from experiencing the pain firsthand.  So instead of just dropping in a very impressive toolset that does 500 things more than I need, I wanted to get familiar with the handful of things I do need in a focused way.  I could spend a few days installing and configuring Digital Rebar and learning the way it solves the problem while relearning all that forgotten PXEBoot knowledge from 10 years ago, or I could choose to do one thing at a time and truly understand the simplest use case.&lt;/p&gt;

&lt;p&gt;Secondly, I have a mix of systems, and I don’t believe my use case is baked into Digital Rebar.  Namely, Mac Netboot support alongside PC PXEboot support.  Until I got it working, I didn’t even know if it was possible.  As far as I can google, it’s not been documented anywhere public.  Maybe these posts will spark a discussion of working that support into a tool like Digital Rebar, but I’m not sure of the popularity of it.  I mean, most folks want to Netboot OSX on a Mac or at least dual boot with Linux, not just Linux alone.&lt;/p&gt;

&lt;h2 id=&quot;the-problem&quot;&gt;The Problem&lt;/h2&gt;

&lt;p&gt;So, how do I get Macs and PC servers to go from bare metal to a common base Centos 7.x latest state with a known IP configuration, hostname, and SSH access booting just Linux?&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;&lt;a href=&quot;#deploy-host&quot;&gt;Create a deploy host.&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#supporting-services&quot;&gt;Install and configure a DHCP server, a TFTP server, and a Webserver&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#custom-configuration&quot;&gt;Custom configuration&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#walking-through-the-process&quot;&gt;Walking Through the Process&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h3 id=&quot;deploy-host&quot;&gt;Deploy Host&lt;/h3&gt;

&lt;p&gt;I am using a low-power Celeron system as my base Centos 7.x system from which to develop, test, and provide netboot and pxeboot support.  I had downloaded the minimal ISO from &lt;a href=&quot;http://isoredirect.centos.org/centos/7/isos/x86_64/CentOS-7-x86_64-Minimal-1511.iso&quot;&gt;here&lt;/a&gt;, ran dd to &lt;a href=&quot;http://osxdaily.com/2015/06/05/copy-iso-to-usb-drive-mac-os-x-command/&quot;&gt;write it directly to a USB&lt;/a&gt;, and did a manual installation of the base packages.&lt;/p&gt;

&lt;p&gt;Finally, I gave it a static IP of &lt;code&gt;172.22.10.2/24&lt;/code&gt; on the management network, added a DNS entry for the hostname called &lt;code&gt;deploy&lt;/code&gt; on my pfsense system (&lt;code&gt;172.22.10.1&lt;/code&gt;), and generated a &lt;a href=&quot;https://help.github.com/articles/generating-a-new-ssh-key-and-adding-it-to-the-ssh-agent/&quot;&gt;new SSH keypair&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Now, from my workstation, I can SSH into the &lt;code&gt;deploy&lt;/code&gt; system on the management network that my servers have their primary NIC attached, build, and run the &lt;a href=&quot;https://github.com/bgeesaman/netpxemirror&quot;&gt;containers&lt;/a&gt;.&lt;/p&gt;

&lt;h3 id=&quot;supporting-services&quot;&gt;Supporting Services&lt;/h3&gt;

&lt;p&gt;I’ll admit I spent over a week getting Netboot to work from a Linux DHCP server trying several angles.  I tried very hard to use ipxe in several ways, but never got very far. Oddly enough, I spent only 2 hrs adding PXEBoot support to that same DHCP/TFTP setup for the PCs.&lt;/p&gt;

&lt;p&gt;I owe all I learned about this process from:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://bennettp123.com/2012/05/05/booting-imac-12,1-from-isc-dhcp&quot;&gt;https://bennettp123.com/2012/05/05/booting-imac-12,1-from-isc-dhcp&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://bitbucket.org/bruienne/bsdpy&quot;&gt;https://bitbucket.org/bruienne/bsdpy&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://themacwrangler.wordpress.com/2015/04/24/creating-a-netboot-server-with-centos-7-and-bsdpy/&quot;&gt;https://themacwrangler.wordpress.com/2015/04/24/creating-a-netboot-server-with-centos-7-and-bsdpy/&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Thank you to those above who paved the way.  I will take a smidge of credit for tying this all together in terms of grub2 booting over the network and figuring out the EFI stuff, but the heavy lifting and the DHCP Netboot trickery they did was pretty impressive.&lt;/p&gt;

&lt;h5 id=&quot;basic-pxenetboot-process&quot;&gt;Basic PXE/NetBoot Process&lt;/h5&gt;

&lt;p&gt;My hope is that understanding the boot process along with reading the comments in the handful of configuration files in the Docker containers will make things clear for anyone else attempting this.&lt;/p&gt;

&lt;p&gt;Here’s the basic, high level process of PXE/Netbooting.&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;System is booted from a NIC that supports PXEbooting.  This typically means changing the boot order to have the NIC first, hitting a key to network boot just this time, or configuring a BMC or ILOM card to boot the system from the network.&lt;/li&gt;
  &lt;li&gt;The system acquires an IP address via DHCP/Bootp.  A properly configured DHCP server will respond with an IP, subnet, gateway, and file to boot from.&lt;/li&gt;
  &lt;li&gt;Optionally, the system also asks for a pointer to a file to boot from over the network.&lt;/li&gt;
  &lt;li&gt;If supplied by the DHCP server, the system uses the &lt;code&gt;next-server&lt;/code&gt; and &lt;code&gt;filename&lt;/code&gt; results to TFTP download/run that bootable file.
  &lt;img src=&quot;/assets/images/grub-efi-tftp.png&quot; alt=&quot;grub efi tftp&quot; class=&quot;img-responsive&quot; /&gt;&lt;/li&gt;
  &lt;li&gt;From there, the bootable file controls the remainder of the boot process (install an OS, run an OS from memory, etc).  Often, this means hosting via a web server or FTP server the configuration for installation and even a repository of all the installation packages for the OS.
  &lt;img src=&quot;/assets/images/initial-kickstart.png&quot; alt=&quot;initial&quot; class=&quot;img-responsive&quot; /&gt;
  &lt;img src=&quot;/assets/images/final-kickstart.png&quot; alt=&quot;final&quot; class=&quot;img-responsive&quot; /&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h5 id=&quot;back-to-configuring-all-this-stuff&quot;&gt;Back to Configuring all this stuff&lt;/h5&gt;

&lt;p&gt;I originally got this working with the version of isc-dhcp-server, tftpd, and httpd from the Centos7.x repos installed natively on &lt;code&gt;deploy&lt;/code&gt;, but all the working and non-working config files, log files, and such were cluttering things up.  It was very difficult to iterate knowing what files were being used or not.&lt;/p&gt;

&lt;p&gt;So, of course, I decided to address that by &lt;a href=&quot;https://github.com/bgeesaman/netpxemirror&quot;&gt;dockerizing those services&lt;/a&gt;, wiping the deploy system, and redeploying the same services from pure docker containers.  By recreating all my work and encapsulating it properly into Docker containers, I have a way to share my work that folks may be able to understand.&lt;/p&gt;

&lt;p&gt;This also means my &lt;code&gt;deploy&lt;/code&gt; system really only needs to run Docker and the knowledge to build and run the containers from scratch can come from a git repo.&lt;/p&gt;

&lt;p&gt;On the &lt;code&gt;deploy&lt;/code&gt; system, it’s installation was pretty straightforward.  I followed the &lt;a href=&quot;https://docs.docker.com/engine/installation/linux/centos/&quot;&gt;Centos 7.x guide&lt;/a&gt; for getting Docker up and running at boot.  I use an account named &lt;code&gt;admin&lt;/code&gt; with sudo privileges on my &lt;code&gt;deploy&lt;/code&gt; host, so I added &lt;code&gt;admin&lt;/code&gt; to the &lt;code&gt;docker&lt;/code&gt; group to avoid having to type &lt;code&gt;sudo&lt;/code&gt; on every docker command.&lt;/p&gt;

&lt;h5 id=&quot;what-needs-to-be-dockerized&quot;&gt;What needs to be dockerized:&lt;/h5&gt;

&lt;ul&gt;
  &lt;li&gt;DHCP - isc-dhcp-server - Provide IPs and pointers to TFTP boot files&lt;/li&gt;
  &lt;li&gt;TFTP - tftpd-hpa - Provide bootable grub2 images and grub.cfg files&lt;/li&gt;
  &lt;li&gt;Web - apache2 - Provide Kickstart configuration files and a local Centos 7.x mirror&lt;/li&gt;
  &lt;li&gt;Rsync - createrepo and rsync - Run on cron to keep the mirror updated each night&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Right away, we know that this can get messy really quickly.  Custom DHCP configs, TFTP roots, Web roots and configurations, and of course, the 28GB of stuff in the Centos 7.x Repo in that web root.  Thankfully, the process of Dockerizing forces things to be explicitly handled properly.&lt;/p&gt;

&lt;p&gt;Here is that repository with those services broken up into three separate containers: &lt;a href=&quot;https://github.com/bgeesaman/netpxemirror&quot;&gt;https://github.com/bgeesaman/netpxemirror&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;On my &lt;code&gt;deploy&lt;/code&gt; system, after installing Docker, I ran:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$ cd ~
$ git clone https://github.com/bgeesaman/netpxemirror.git
Cloning into 'netpxemirror'...
remote: Counting objects: 50, done.
remote: Compressing objects: 100% (34/34), done.
remote: Total 50 (delta 11), reused 47 (delta 11), pack-reused 0
Unpacking objects: 100% (50/50), done.
$ cd netpxemirror
### Configure the services to your environment ###
$ ./build.sh
$ ./run.sh
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This built and ran &lt;code&gt;netpxeboot&lt;/code&gt;, &lt;code&gt;centos7mirror&lt;/code&gt;, and &lt;code&gt;mirrorsync&lt;/code&gt;.&lt;/p&gt;

&lt;h2 id=&quot;warning&quot;&gt;WARNING&lt;/h2&gt;
&lt;p&gt;Running the &lt;code&gt;mirrorsync&lt;/code&gt; container for the first time will immediately begin rsyncing 28GB of data into &lt;code&gt;/var/www/html/repos&lt;/code&gt;!  I did this so that I could restore the state of a working &lt;code&gt;deploy&lt;/code&gt; system from scratch assuming there was no local repo already.  Edit the &lt;code&gt;mirrorsync/files/start.sh&lt;/code&gt; to prevent this behavior before running &lt;code&gt;build.sh&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Assuming the configuration is correct, a &lt;code&gt;docker ps&lt;/code&gt; shows:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$ docker ps
CONTAINER ID        IMAGE               COMMAND                CREATED             STATUS              PORTS                NAMES
9bcdd7f44d38        netpxeboot          &quot;/root/start.sh&quot;       14 hours ago        Up 14 hours                              netpxeboot
6a1c28fdfc7a        mirrorsync          &quot;/root/start.sh&quot;       15 hours ago        Up 15 hours                              mirrorsync
eebd43890189        centos7mirror       &quot;apache2-foreground&quot;   23 hours ago        Up 23 hours         0.0.0.0:80-&amp;gt;80/tcp   centos7mirror
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Keen observers will notice that TCP port 80 is forwarded to the &lt;code&gt;centos7mirror&lt;/code&gt; container running apache2, but UDP/67 and UDP/69 are not for &lt;code&gt;netpxeboot&lt;/code&gt;.  That’s because the &lt;code&gt;netpxeboot&lt;/code&gt; container is started with &lt;code&gt;--net=host&lt;/code&gt; in the &lt;code&gt;docker run&lt;/code&gt; command so that it can bind to the host’s network stack and see broadcasts from the systems asking for IP addresses.&lt;/p&gt;

&lt;h3 id=&quot;containers-at-a-glance&quot;&gt;Containers at a Glance&lt;/h3&gt;

&lt;h5 id=&quot;centos7mirror&quot;&gt;centos7mirror&lt;/h5&gt;
&lt;p&gt;Based on the &lt;a href=&quot;https://github.com/docker-library/php/blob/f016f5dc420e7d360f7381eb014ac6697e247e11/5.6/apache/Dockerfile&quot;&gt;php:5.6-apache&lt;/a&gt; container, I add a custom &lt;code&gt;docker-php.conf&lt;/code&gt; to apache and enable &lt;code&gt;mod_rewrite&lt;/code&gt;.  This makes this a PHP 5.6 webserver with the ability to serve up dynamic content based on the request data and to make the URLs cleaner.&lt;/p&gt;

&lt;h5 id=&quot;mirrorsync&quot;&gt;mirrorsync&lt;/h5&gt;
&lt;p&gt;Based on &lt;a href=&quot;https://hub.docker.com/r/phusion/baseimage&quot;&gt;phusion/baseimage&lt;/a&gt;, this Ubuntu based system provides a simple cron based functionality to keep the Yum repository in sync with the Centos 7.x mirror of my choice.&lt;/p&gt;

&lt;h5 id=&quot;netpxeboot&quot;&gt;netpxeboot&lt;/h5&gt;
&lt;p&gt;Also based on &lt;a href=&quot;https://hub.docker.com/r/phusion/baseimage&quot;&gt;phusion/baseimage&lt;/a&gt;, this Ubuntu based system provides the isc-dhcp-server, tftpd-hpa server, and the configuration files for grub booting over TFTP.  A PHP script for serving custom kickstart files out of the webroot in &lt;code&gt;centos7mirror&lt;/code&gt; based on mac address is also here.&lt;/p&gt;

&lt;h3 id=&quot;custom-configuration&quot;&gt;Custom Configuration&lt;/h3&gt;
&lt;p&gt;Now, there’s probably a 100% chance that the containers didn’t work for you if you simply git cloned them and tried building them.  So, I’ll point you to each of the places that you’ll want to edit for your needs.  Namely, the IP addresses, paths, and URLs for things.  I’ll start with the local mirror and mirror syncing process.&lt;/p&gt;

&lt;h5 id=&quot;centos7mirror-1&quot;&gt;centos7mirror&lt;/h5&gt;
&lt;p&gt;Realistically, there is very little to configure here with the exception of the web root and the name of the file you want associated with serving kickstart configurations.  I chose &lt;code&gt;/var/www/html&lt;/code&gt; since it’s the default for the web root.  Also, the &lt;code&gt;ks.cfg&lt;/code&gt; mod_rewrite rule actually calls the &lt;code&gt;/var/www/html/ks.php&lt;/code&gt; file for knowing what kickstart to serve up.  &lt;code&gt;ks.php&lt;/code&gt; is put into place by &lt;code&gt;netpxeboot&lt;/code&gt; on its first run.&lt;/p&gt;

&lt;h5 id=&quot;mirrorsync-1&quot;&gt;mirrorsync&lt;/h5&gt;
&lt;p&gt;If you edited the web root path, you’ll need to search/replace it in all the files in the &lt;code&gt;files&lt;/code&gt; directory.  Mostly, though, you’ll want to edit the &lt;code&gt;cron.sh&lt;/code&gt; file to pull from another repo and &lt;code&gt;crontab&lt;/code&gt; to adjust the schedule of when the sync happens.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;11 1 * * * root /root/cron.sh &amp;gt;&amp;gt; /var/log/cron.log 2&amp;gt;&amp;amp;1
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Means it runs on the eleventh minute of the first hour of every day.  I tend to use slighty “off” times to avoid contention with other folks who run their jobs on the hour exactly.&lt;/p&gt;

&lt;h5 id=&quot;netpxeboot-1&quot;&gt;netpxeboot&lt;/h5&gt;
&lt;p&gt;The files &lt;code&gt;ADD&lt;/code&gt;ed  in the Dockerfile into this container are the primary points of configuration, but I’ll warn you that making one incorrect change here can easily break things.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;ks.php&lt;/code&gt; serves up kickstart files in &lt;code&gt;/var/www/html/cfg/ma:ca:dd:re:ss.cfg&lt;/code&gt; based on the mac address sent in the header as configured from the &lt;code&gt;grub.cfg&lt;/code&gt; option called &lt;code&gt;inst.ks.sendmac&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;tftpd-hpa&lt;/code&gt; specifies mostly the base path of the TFTP files.  In my case, &lt;code&gt;/nbi&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;dhcpd.conf&lt;/code&gt; is where the PXE/Netbooting magic happens.  Reserved IPs, lease times and ranges, paths, and more go here.  If you don’t have PCs, remove the &lt;code&gt;pc&lt;/code&gt; class block.  If you don’t have Macs, remove the entire &lt;code&gt;netboot&lt;/code&gt; class block.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;lineno&quot;&gt;  1 &lt;/span&gt;&lt;span class=&quot;c1&quot;&gt;# dhcpd.conf&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;  2 &lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;  3 &lt;/span&gt;option domain-name &lt;span class=&quot;s2&quot;&gt;&amp;quot;example.org&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;  4 &lt;/span&gt;option domain-name-servers ns1.example.org, ns2.example.org&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;  5 &lt;/span&gt;default-lease-time &lt;span class=&quot;m&quot;&gt;3600&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;  6 &lt;/span&gt;max-lease-time &lt;span class=&quot;m&quot;&gt;7200&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;  7 &lt;/span&gt;ddns-update-style none&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;  8 &lt;/span&gt;ddns-updates off&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;  9 &lt;/span&gt;ignore client-updates&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 10 &lt;/span&gt;allow booting&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 11 &lt;/span&gt;allow bootp&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 12 &lt;/span&gt;authoritative&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 13 &lt;/span&gt;log-facility local7&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 14 &lt;/span&gt;boot-unknown-clients on&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 15 &lt;/span&gt;ping-check off&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 16 &lt;/span&gt;allow-unknown-clients&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 17 &lt;/span&gt;allow-known-clients&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 18 &lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 19 &lt;/span&gt;subnet &lt;span class=&quot;m&quot;&gt;172&lt;/span&gt;.22.10.0 netmask &lt;span class=&quot;m&quot;&gt;255&lt;/span&gt;.255.255.0 &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 20 &lt;/span&gt;  range &lt;span class=&quot;m&quot;&gt;172&lt;/span&gt;.22.10.5 &lt;span class=&quot;m&quot;&gt;172&lt;/span&gt;.22.10.30&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 21 &lt;/span&gt;  range dynamic-bootp &lt;span class=&quot;m&quot;&gt;172&lt;/span&gt;.22.10.31 &lt;span class=&quot;m&quot;&gt;172&lt;/span&gt;.22.10.49&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 22 &lt;/span&gt;  allow booting&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 23 &lt;/span&gt;  allow bootp&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 24 &lt;/span&gt;  option domain-name-servers &lt;span class=&quot;m&quot;&gt;172&lt;/span&gt;.22.10.1&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; 
&lt;span class=&quot;lineno&quot;&gt; 25 &lt;/span&gt;  option domain-name &lt;span class=&quot;s2&quot;&gt;&amp;quot;lonimbus.com&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 26 &lt;/span&gt;  option routers &lt;span class=&quot;m&quot;&gt;172&lt;/span&gt;.22.10.1&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 27 &lt;/span&gt;  option broadcast-address &lt;span class=&quot;m&quot;&gt;172&lt;/span&gt;.22.10.255&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 28 &lt;/span&gt;  default-lease-time &lt;span class=&quot;m&quot;&gt;6000&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 29 &lt;/span&gt;  max-lease-time &lt;span class=&quot;m&quot;&gt;7200&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 30 &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 31 &lt;/span&gt;host mp &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 32 &lt;/span&gt;  hardware ethernet &lt;span class=&quot;m&quot;&gt;00&lt;/span&gt;:23:32:2f:40:3c&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 33 &lt;/span&gt;  fixed-address &lt;span class=&quot;m&quot;&gt;172&lt;/span&gt;.22.10.50&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 34 &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 35 &lt;/span&gt;host mm1 &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 36 &lt;/span&gt;  hardware ethernet a8:20:66:34:ff:e9&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 37 &lt;/span&gt;  fixed-address &lt;span class=&quot;m&quot;&gt;172&lt;/span&gt;.22.10.51&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 38 &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 39 &lt;/span&gt;host mm2 &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 40 &lt;/span&gt;  hardware ethernet a8:20:66:4a:ce:46&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 41 &lt;/span&gt;  fixed-address &lt;span class=&quot;m&quot;&gt;172&lt;/span&gt;.22.10.52&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 42 &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 43 &lt;/span&gt;host mm3 &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 44 &lt;/span&gt;  hardware ethernet a8:20:66:4a:d9:da&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 45 &lt;/span&gt;  fixed-address &lt;span class=&quot;m&quot;&gt;172&lt;/span&gt;.22.10.53&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 46 &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 47 &lt;/span&gt;host smpc &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 48 &lt;/span&gt;  hardware ethernet &lt;span class=&quot;m&quot;&gt;00&lt;/span&gt;:30:48:fb:e2:44&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 49 &lt;/span&gt;  fixed-address &lt;span class=&quot;m&quot;&gt;172&lt;/span&gt;.22.10.54&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 50 &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 51 &lt;/span&gt;host sm1 &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 52 &lt;/span&gt;  hardware ethernet &lt;span class=&quot;m&quot;&gt;00&lt;/span&gt;:25:90:96:c4:9a&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 53 &lt;/span&gt;  fixed-address &lt;span class=&quot;m&quot;&gt;172&lt;/span&gt;.22.10.55&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 54 &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 55 &lt;/span&gt;host sm2 &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 56 &lt;/span&gt;  hardware ethernet &lt;span class=&quot;m&quot;&gt;00&lt;/span&gt;:25:90:96:c6:5a&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 57 &lt;/span&gt;  fixed-address &lt;span class=&quot;m&quot;&gt;172&lt;/span&gt;.22.10.56&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 58 &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 59 &lt;/span&gt;host d1 &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 60 &lt;/span&gt;  hardware ethernet bc:30:5b:e5:73:b7&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 61 &lt;/span&gt;  fixed-address &lt;span class=&quot;m&quot;&gt;172&lt;/span&gt;.22.10.57&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 62 &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 63 &lt;/span&gt;host d2 &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 64 &lt;/span&gt;  hardware ethernet bc:30:5b:e5:75:28&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 65 &lt;/span&gt;  fixed-address &lt;span class=&quot;m&quot;&gt;172&lt;/span&gt;.22.10.58&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 66 &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 67 &lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 68 &lt;/span&gt;class &lt;span class=&quot;s2&quot;&gt;&amp;quot;pc&amp;quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 69 &lt;/span&gt;  match &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; substring&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;option vendor-class-identifier, &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;m&quot;&gt;20&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;PXEClient:Arch:00000&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 70 &lt;/span&gt;    filename &lt;span class=&quot;s2&quot;&gt;&amp;quot;boot/grub/i386-pc/core.0&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 71 &lt;/span&gt;    next-server &lt;span class=&quot;m&quot;&gt;172&lt;/span&gt;.22.10.2&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 72 &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 73 &lt;/span&gt;class &lt;span class=&quot;s2&quot;&gt;&amp;quot;netboot&amp;quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 74 &lt;/span&gt;    match &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; substring &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;option vendor-class-identifier, &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;m&quot;&gt;9&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;AAPLBSDPC&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 75 &lt;/span&gt;    option dhcp-parameter-request-list &lt;span class=&quot;m&quot;&gt;1&lt;/span&gt;,3,17,43,60&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 76 &lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 77 &lt;/span&gt;    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;option dhcp-message-type &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 78 &lt;/span&gt;        option vendor-class-identifier &lt;span class=&quot;s2&quot;&gt;&amp;quot;AAPLBSDPC&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 79 &lt;/span&gt;        option vendor-encapsulated-options
&lt;span class=&quot;lineno&quot;&gt; 80 &lt;/span&gt;            &lt;span class=&quot;m&quot;&gt;08&lt;/span&gt;:04:81:00:00:89&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;    &lt;span class=&quot;c1&quot;&gt;# bsdp option 8 (length 04) -- selected image id;&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 81 &lt;/span&gt;    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt; elsif &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;option dhcp-message-type &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;8&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 82 &lt;/span&gt;        option vendor-class-identifier &lt;span class=&quot;s2&quot;&gt;&amp;quot;AAPLBSDPC&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 83 &lt;/span&gt;        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;substring&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;option vendor-encapsulated-options, &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;m&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;01&lt;/span&gt;:01:01&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 84 &lt;/span&gt;            log&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;debug, &lt;span class=&quot;s2&quot;&gt;&amp;quot;bsdp_msgtype_list&amp;quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 85 &lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 86 &lt;/span&gt;            &lt;span class=&quot;c1&quot;&gt;# bsdp image list message:&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 87 &lt;/span&gt;            &lt;span class=&quot;c1&quot;&gt;# one image, plus one default image (both are the same)&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 88 &lt;/span&gt;            option vendor-encapsulated-options 
&lt;span class=&quot;lineno&quot;&gt; 89 &lt;/span&gt;                &lt;span class=&quot;m&quot;&gt;01&lt;/span&gt;:01:01:                              &lt;span class=&quot;c1&quot;&gt;# bsdp_msgtype_list&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 90 &lt;/span&gt;                &lt;span class=&quot;m&quot;&gt;04&lt;/span&gt;:02:                                 &lt;span class=&quot;c1&quot;&gt;# bsdp option code 4 (length 02) server priority&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 91 &lt;/span&gt;                    &lt;span class=&quot;m&quot;&gt;80&lt;/span&gt;:00:                             &lt;span class=&quot;c1&quot;&gt;#  Priority (32768)&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 92 &lt;/span&gt;                &lt;span class=&quot;m&quot;&gt;07&lt;/span&gt;:04:                                 &lt;span class=&quot;c1&quot;&gt;# bsdp option code 7 (length 04) default image id&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 93 &lt;/span&gt;                    &lt;span class=&quot;m&quot;&gt;81&lt;/span&gt;:00:00:89:                       &lt;span class=&quot;c1&quot;&gt;#  Image ID (137)&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 94 &lt;/span&gt;                &lt;span class=&quot;m&quot;&gt;09&lt;/span&gt;:0e:                                 &lt;span class=&quot;c1&quot;&gt;# bsdp option code 9 (length 0e) image list&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 95 &lt;/span&gt;                    &lt;span class=&quot;m&quot;&gt;81&lt;/span&gt;:00:00:89:                       &lt;span class=&quot;c1&quot;&gt;#  Image ID (137)&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 96 &lt;/span&gt;                        &lt;span class=&quot;m&quot;&gt;09&lt;/span&gt;:54:68:65:2d:49:6d:61:67:65&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;#   Name (length 09) &amp;#39;The-Image&amp;#39;&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 97 &lt;/span&gt;        &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 98 &lt;/span&gt;            log&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;debug, &lt;span class=&quot;s2&quot;&gt;&amp;quot;bspd_msgtype_select&amp;quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 99 &lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;100 &lt;/span&gt;            &lt;span class=&quot;c1&quot;&gt;# details about the selected image&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;101 &lt;/span&gt;            option vendor-encapsulated-options
&lt;span class=&quot;lineno&quot;&gt;102 &lt;/span&gt;                &lt;span class=&quot;m&quot;&gt;01&lt;/span&gt;:01:02:                       &lt;span class=&quot;c1&quot;&gt;# bsdp_msgtype_select &lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;103 &lt;/span&gt;                &lt;span class=&quot;m&quot;&gt;08&lt;/span&gt;:04:                          &lt;span class=&quot;c1&quot;&gt;# bsdptag_selected_boot_image&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;104 &lt;/span&gt;                    &lt;span class=&quot;m&quot;&gt;81&lt;/span&gt;:00:00:89:                &lt;span class=&quot;c1&quot;&gt;#  Image ID (137)&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;105 &lt;/span&gt;                &lt;span class=&quot;m&quot;&gt;82&lt;/span&gt;:09:                          &lt;span class=&quot;c1&quot;&gt;# Machine Name (length 09)&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;106 &lt;/span&gt;                    &lt;span class=&quot;m&quot;&gt;54&lt;/span&gt;:68:65:2d:49:6d:61:67:65&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;#  &amp;#39;The-Image&amp;#39;&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;107 &lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;108 &lt;/span&gt;            &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;substring&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;option vendor-class-identifier, &lt;span class=&quot;m&quot;&gt;10&lt;/span&gt;, &lt;span class=&quot;m&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;i386&amp;quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;109 &lt;/span&gt;                filename &lt;span class=&quot;s2&quot;&gt;&amp;quot;mactel64.efi&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;110 &lt;/span&gt;                next-server &lt;span class=&quot;m&quot;&gt;172&lt;/span&gt;.22.10.2&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;111 &lt;/span&gt;            &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;112 &lt;/span&gt;        &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;113 &lt;/span&gt;    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;114 &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;&lt;code&gt;grub.cfg-net&lt;/code&gt; gets baked into the &lt;code&gt;mactel64.efi&lt;/code&gt; file served up for macs&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;lineno&quot;&gt; 1 &lt;/span&gt;insmod efi_gop
&lt;span class=&quot;lineno&quot;&gt; 2 &lt;/span&gt;insmod efi_uga
&lt;span class=&quot;lineno&quot;&gt; 3 &lt;/span&gt;insmod video_bochs
&lt;span class=&quot;lineno&quot;&gt; 4 &lt;/span&gt;insmod video_cirrus
&lt;span class=&quot;lineno&quot;&gt; 5 &lt;/span&gt;insmod all_video
&lt;span class=&quot;lineno&quot;&gt; 6 &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;set&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;gfxpayload&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;keep
&lt;span class=&quot;lineno&quot;&gt; 7 &lt;/span&gt;insmod gzio
&lt;span class=&quot;lineno&quot;&gt; 8 &lt;/span&gt;insmod part_gpt
&lt;span class=&quot;lineno&quot;&gt; 9 &lt;/span&gt;insmod ext2
&lt;span class=&quot;lineno&quot;&gt;10 &lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;11 &lt;/span&gt;insmod net
&lt;span class=&quot;lineno&quot;&gt;12 &lt;/span&gt;insmod efinet
&lt;span class=&quot;lineno&quot;&gt;13 &lt;/span&gt;insmod tftp
&lt;span class=&quot;lineno&quot;&gt;14 &lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;15 &lt;/span&gt;net_bootp efinet0
&lt;span class=&quot;lineno&quot;&gt;16 &lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;17 &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;set&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;net_default_server&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;172&lt;/span&gt;.22.10.2
&lt;span class=&quot;lineno&quot;&gt;18 &lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;19 &lt;/span&gt;configfile &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;tftp&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;/boot/grub/x86_64-efi/grub.cfg-01-&lt;span class=&quot;nv&quot;&gt;$net_efinet0_mac&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;&lt;code&gt;grub.cfg-*&lt;/code&gt; gets pulled via TFTP depending on architecture by the grub2 image first pulled via DHCP.  Notice the URLs, IPs, and paths to &lt;code&gt;ks.cfg&lt;/code&gt; here.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;lineno&quot;&gt; 1 &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;set&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;default&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;0&amp;quot;&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 2 &lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 3 &lt;/span&gt;insmod video_bochs
&lt;span class=&quot;lineno&quot;&gt; 4 &lt;/span&gt;insmod video_cirrus
&lt;span class=&quot;lineno&quot;&gt; 5 &lt;/span&gt;insmod all_video
&lt;span class=&quot;lineno&quot;&gt; 6 &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;set&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;gfxpayload&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;keep
&lt;span class=&quot;lineno&quot;&gt; 7 &lt;/span&gt;insmod gzio
&lt;span class=&quot;lineno&quot;&gt; 8 &lt;/span&gt;insmod part_gpt
&lt;span class=&quot;lineno&quot;&gt; 9 &lt;/span&gt;insmod ext2
&lt;span class=&quot;lineno&quot;&gt;10 &lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;11 &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;set&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;timeout&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;10&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;12 &lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;13 &lt;/span&gt;menuentry &lt;span class=&quot;s1&quot;&gt;&amp;#39;Unattended Centos 7 Install&amp;#39;&lt;/span&gt; --class os &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;14 &lt;/span&gt;     insmod net
&lt;span class=&quot;lineno&quot;&gt;15 &lt;/span&gt;     insmod tftp
&lt;span class=&quot;lineno&quot;&gt;16 &lt;/span&gt;     &lt;span class=&quot;c1&quot;&gt;# TFTP server&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;17 &lt;/span&gt;     &lt;span class=&quot;nb&quot;&gt;set&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;net_default_server&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;172&lt;/span&gt;.22.10.2
&lt;span class=&quot;lineno&quot;&gt;18 &lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;19 &lt;/span&gt;     &lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;Network status: &amp;#39;&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;20 &lt;/span&gt;     net_ls_cards
&lt;span class=&quot;lineno&quot;&gt;21 &lt;/span&gt;     net_ls_addr
&lt;span class=&quot;lineno&quot;&gt;22 &lt;/span&gt;     net_ls_routes
&lt;span class=&quot;lineno&quot;&gt;23 &lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;24 &lt;/span&gt;     &lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;Loading Linux ...&amp;#39;&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;25 &lt;/span&gt;     &lt;span class=&quot;c1&quot;&gt;#linux (tftp)/vmlinuz noipv6 inst.repo=http://centos.aol.com/7/os/x86_64/ inst.ks=http://172.22.10.2/ks.cfg inst.ks.sendmac&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;26 &lt;/span&gt;     linux &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;tftp&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;/vmlinuz noipv6 inst.repo&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;http://deploy/repos/centos/7/os/x86_64/ inst.ks&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;http://deploy/ks.cfg inst.ks.sendmac
&lt;span class=&quot;lineno&quot;&gt;27 &lt;/span&gt;     &lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;Loading initial ramdisk ...&amp;#39;&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;28 &lt;/span&gt;     initrd &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;tftp&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;/initrd.img
&lt;span class=&quot;lineno&quot;&gt;29 &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;&lt;code&gt;start.sh&lt;/code&gt; the entry point of the container.  Lots of one-time setup steps here necessary for successful operation.  Change paths/URLs carefully here.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;lineno&quot;&gt; 1 &lt;/span&gt;&lt;span class=&quot;ch&quot;&gt;#!/bin/bash&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 2 &lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 3 &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;set&lt;/span&gt; -euo pipefail
&lt;span class=&quot;lineno&quot;&gt; 4 &lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 5 &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;TFTPPATH&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;/nbi&amp;quot;&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 6 &lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 7 &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt; ! -d /var/www/html/cfg &lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;then&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 8 &lt;/span&gt;  mkdir -p /var/www/html/cfg
&lt;span class=&quot;lineno&quot;&gt; 9 &lt;/span&gt;  cp -R /root/cfg/* /var/www/html/cfg/
&lt;span class=&quot;lineno&quot;&gt;10 &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;fi&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;11 &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt; ! -f /var/www/html/index.html &lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;then&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;12 &lt;/span&gt;  cp /root/index.html /var/www/html/index.html
&lt;span class=&quot;lineno&quot;&gt;13 &lt;/span&gt;  chmod &lt;span class=&quot;m&quot;&gt;644&lt;/span&gt; /var/www/html/index.html
&lt;span class=&quot;lineno&quot;&gt;14 &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;fi&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;15 &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt; ! -f /var/www/html/ks.php &lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;then&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;16 &lt;/span&gt;  cp /root/ks.php /var/www/html/ks.php
&lt;span class=&quot;lineno&quot;&gt;17 &lt;/span&gt;  chmod &lt;span class=&quot;m&quot;&gt;644&lt;/span&gt; /var/www/html/ks.php
&lt;span class=&quot;lineno&quot;&gt;18 &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;fi&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;19 &lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;20 &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt; ! -f &lt;span class=&quot;nv&quot;&gt;$TFTPPATH&lt;/span&gt;/grub.cfg-net &lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;then&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;21 &lt;/span&gt;  cp /root/grub.cfg-net &lt;span class=&quot;nv&quot;&gt;$TFTPPATH&lt;/span&gt;/grub.cfg-net
&lt;span class=&quot;lineno&quot;&gt;22 &lt;/span&gt;  chmod &lt;span class=&quot;m&quot;&gt;644&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$TFTPPATH&lt;/span&gt;/grub.cfg-net
&lt;span class=&quot;lineno&quot;&gt;23 &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;fi&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;24 &lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;25 &lt;/span&gt;&lt;span class=&quot;c1&quot;&gt;# Generate mactel boot efi&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;26 &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt; ! -f &lt;span class=&quot;nv&quot;&gt;$TFTPPATH&lt;/span&gt;/mactel64.efi &lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;then&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;27 &lt;/span&gt;  grub-mkimage -d /usr/lib/grub/x86_64-efi/ -O x86_64-efi -o &lt;span class=&quot;nv&quot;&gt;$TFTPPATH&lt;/span&gt;/mactel64.efi -p &lt;span class=&quot;s1&quot;&gt;&amp;#39;(tftp)/boot/grub&amp;#39;&lt;/span&gt; -c &lt;span class=&quot;nv&quot;&gt;$TFTPPATH&lt;/span&gt;/grub.cfg-net normal configfile net efinet tftp efi_gop efi_uga all_video gzio part_gpt ext2 &lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; linuxefi
&lt;span class=&quot;lineno&quot;&gt;28 &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;fi&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;29 &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt; ! -d &lt;span class=&quot;nv&quot;&gt;$TFTPPATH&lt;/span&gt;/boot/grub &lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;then&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;30 &lt;/span&gt;  grub-mknetdir --net-directory&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$TFTPPATH&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;31 &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;fi&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;32 &lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;33 &lt;/span&gt;cp /root/grub.cfg-i386-pc &lt;span class=&quot;nv&quot;&gt;$TFTPPATH&lt;/span&gt;/boot/grub/i386-pc/grub.cfg
&lt;span class=&quot;lineno&quot;&gt;34 &lt;/span&gt;cp /root/grub.cfg-i386-pc &lt;span class=&quot;nv&quot;&gt;$TFTPPATH&lt;/span&gt;/boot/grub/grub.cfg
&lt;span class=&quot;lineno&quot;&gt;35 &lt;/span&gt;cp /root/grub.cfg-x86_64-efi &lt;span class=&quot;nv&quot;&gt;$TFTPPATH&lt;/span&gt;/boot/grub/x86_64-efi/grub.cfg
&lt;span class=&quot;lineno&quot;&gt;36 &lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;37 &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt; ! -f &lt;span class=&quot;nv&quot;&gt;$TFTPPATH&lt;/span&gt;/initrd.img &lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;then&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;38 &lt;/span&gt;  wget --quiet -O &lt;span class=&quot;nv&quot;&gt;$TFTPPATH&lt;/span&gt;/initrd.img http://centos.aol.com/7/os/x86_64/isolinux/initrd.img
&lt;span class=&quot;lineno&quot;&gt;39 &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;fi&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;40 &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt; ! -f &lt;span class=&quot;nv&quot;&gt;$TFTPPATH&lt;/span&gt;/vmlinuz &lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;then&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;41 &lt;/span&gt;  wget --quiet -O &lt;span class=&quot;nv&quot;&gt;$TFTPPATH&lt;/span&gt;/vmlinuz http://centos.aol.com/7/os/x86_64/isolinux/vmlinuz
&lt;span class=&quot;lineno&quot;&gt;42 &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;fi&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;43 &lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;44 &lt;/span&gt;&lt;span class=&quot;c1&quot;&gt;# Start dhcp and tftpd&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;45 &lt;/span&gt;/etc/init.d/isc-dhcp-server start
&lt;span class=&quot;lineno&quot;&gt;46 &lt;/span&gt;/etc/init.d/tftpd-hpa start
&lt;span class=&quot;lineno&quot;&gt;47 &lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;48 &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;Tailing logs...&amp;quot;&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;49 &lt;/span&gt;tail -f /var/log/syslog&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;h3 id=&quot;walking-through-the-process&quot;&gt;Walking Through the Process&lt;/h3&gt;

&lt;h5 id=&quot;step-1&quot;&gt;Step 1:&lt;/h5&gt;

&lt;p&gt;Boot the system from the network.  My Dells and SuperMicros use &lt;code&gt;f12&lt;/code&gt; and the Macs have you hold &lt;code&gt;n&lt;/code&gt; right at and slightly after the boot chime.  Helps to have a keyboard and mouse on these systems as you iterate.&lt;/p&gt;

&lt;h5 id=&quot;step-2&quot;&gt;Step 2:&lt;/h5&gt;

&lt;p&gt;On the &lt;code&gt;deploy&lt;/code&gt; system, you can run: &lt;code&gt;tcpdump -ni eth0 not port 22&lt;/code&gt; to watch the process unfold.  This is my primary method of debugging along with watching the screen as it boots.  You’ll see the system request an address via DHCP.  If your DHCP server is configured and listening correctly, you’ll see it respond with a DHCP reply.  On your PC system, you should see something indicating it got an IP.  Macs just show the blinking globe by default unless you enable verbose booting.&lt;/p&gt;

&lt;h5 id=&quot;step-3&quot;&gt;Step 3:&lt;/h5&gt;

&lt;p&gt;Very shortly after the DHCP lease is acquired, you’ll see a TFTP RRQ for the &lt;code&gt;boot/grub/i386-pc/core.0&lt;/code&gt; or &lt;code&gt;mactel64.efi&lt;/code&gt; binary.  Both of them should initialize grub on the system to a point that it can look for its proper &lt;code&gt;grub.cfg&lt;/code&gt; file on that same TFTP server.  In that tcpdump output, you’ll see the file grabs over UDP/69 and the paths/names requested.  You can narrow things down to only what’s being pulled via TFTP by running &lt;code&gt;tcpdump -ni eth0 port 69&lt;/code&gt; if you are having pathing or file name issues.&lt;/p&gt;

&lt;h5 id=&quot;step-4&quot;&gt;Step 4:&lt;/h5&gt;

&lt;p&gt;After it grabs the second &lt;code&gt;grub.cfg&lt;/code&gt; via TFTP, it follows the instructions contained in it.  In our case, it’s to load the &lt;code&gt;vmlinuz&lt;/code&gt; and &lt;code&gt;initrd.img&lt;/code&gt; from TFTP (again) and to boot from them with some additional options.&lt;/p&gt;

&lt;h5 id=&quot;step-5&quot;&gt;Step 5:&lt;/h5&gt;

&lt;p&gt;&lt;code&gt;inst.repo&lt;/code&gt; and &lt;code&gt;inst.ks&lt;/code&gt; are the custom boot options used here to specify where to get the base installation packages and the installation configuration files, respectively.  Both are served via apache out of the &lt;code&gt;centos7mirror&lt;/code&gt; container.&lt;/p&gt;

&lt;h5 id=&quot;step-6&quot;&gt;Step 6:&lt;/h5&gt;

&lt;p&gt;From this point, it’s a normal &lt;a href=&quot;/2016/07/26/maas-2.html&quot;&gt;Kickstart and Centos 7.x installation process&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/2016/07/25/neverending-uphill-journey.html&quot;&gt;Back to Index&lt;/a&gt;&lt;/p&gt;

</description>
        <pubDate>Tue, 26 Jul 2016 00:00:00 +0000</pubDate>
        <link>https://www.lonimbus.com//2016/07/26/maas-1.html</link>
        <guid isPermaLink="true">https://www.lonimbus.com//2016/07/26/maas-1.html</guid>
        
        
      </item>
    
  </channel>
</rss>
