<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <generator uri="https://gohugo.io/" version="0.169.0">Hugo</generator>
  <link href="https://www.codatory.page/feed.xml" rel="self" type="application/atom+xml"/>
  <link href="https://www.codatory.page/" rel="alternate" type="text/html"/>
  <updated>2026-11-12T20:42:32Z</updated>
  <id>https://www.codatory.page/feed.xml</id>
  <title type="html">Codatory&#39;s Scribbles</title>
  <subtitle>Notes on systems, RVs, and places along the way.</subtitle>
  <entry>
    <title type="html">Fix drm-kmod after upgrading FreeBSD to 14.2-RELEASE</title>
    <link href="https://www.codatory.page/2024/12/12/fix-drm-kmod-after-upgrading-freebsd-142-release.html" rel="alternate" type="text/html" title="Fix drm-kmod after upgrading FreeBSD to 14.2-RELEASE"/>
    <published>2024-12-12T00:00:00-05:00</published>
    <updated>2024-12-12T00:00:00-05:00</updated>
    <id>https://www.codatory.page/2024/12/12/fix-drm-kmod-after-upgrading-freebsd-142-release</id>
    <content type="html" xml:base="https://www.codatory.page/2024/12/12/fix-drm-kmod-after-upgrading-freebsd-142-release.html"><![CDATA[<p>Caution: this is probably not the best way to do this. I took a break from FreeBSD and am just getting back into it.</p>
<p>Do this from your &ldquo;broken&rdquo; install of 14.2. You may need to use an alternate console or SSH.</p>
<h2 id="prep-ports-and-os-sources">Prep Ports and OS Sources</h2>
<pre tabindex="0"><code>pkg install -y git portmaster

git clone --branch releng/14.2 https://github.com/freebsd/freebsd-src.git /usr/src

git clone --branch main https://github.com/freebsd/freebsd-ports.git /usr/ports
</code></pre><h2 id="rebuild-drm-kmod-and-drm-kmod-61">Rebuild drm-kmod and drm-kmod-61</h2>
<pre tabindex="0"><code>pkg remove drm-kmod drm-61-kmod drm-515-kmod drm-510-kmod

portmaster -f --packages-build -r drm-kmod drm-61-kmod
</code></pre><h2 id="reboot">Reboot</h2>
<p>Hope you work now!</p>
]]></content>
    <author><name>Codatory</name></author>
    <summary type="text">Caution: this is probably not the best way to do this. I took a break from FreeBSD and am just getting back into it.
Do this from your “broken” install of 14.2. You may need to use an alternate console or SSH.
Prep Ports and OS Sources pkg install -y git portmaster git clone --branch releng/14.2 https://github.com/freebsd/freebsd-src.git /usr/src git clone --branch main https://github.com/freebsd/freebsd-ports.git /usr/ports Rebuild drm-kmod and drm-kmod-61 pkg remove drm-kmod drm-61-kmod drm-515-kmod drm-510-kmod portmaster -f --packages-build -r drm-kmod drm-61-kmod Reboot Hope you work now!
</summary>
  </entry>
  <entry>
    <title type="html">Acadia National Park</title>
    <link href="https://www.codatory.page/2023/09/27/acadia-national-park.html" rel="alternate" type="text/html" title="Acadia National Park"/>
    <published>2023-09-27T01:00:00-04:00</published>
    <updated>2023-09-27T01:00:00-04:00</updated>
    <id>https://www.codatory.page/2023/09/27/acadia-national-park</id>
    <content type="html" xml:base="https://www.codatory.page/2023/09/27/acadia-national-park.html"><![CDATA[<p>Honestly, what can I say that hasn’t already been said about Acadia? It was absolutely gorgeous,
and picking just a few hikes to fit in the time I had was quite the challenge. If you have the
opportunity, definitely go visit!</p>
<p><picture class="post-image">
    <source type="image/webp"
      srcset="/assets/images/responsive/20230925_103324-480.webp 480w, /assets/images/responsive/20230925_103324-960.webp 960w"
      sizes="(max-width: 44rem) calc(100vw - 2rem), 42rem">
    <img src="/images/inline-images/20230925_103324_hu_2a2f164c352b842e.jpg" width="960" height="720"
      alt="Wooden sign for the Wild Gardens of Acadia" loading="eager" decoding="async">
  </picture>
<picture class="post-image">
    <source type="image/webp"
      srcset="/assets/images/responsive/20230925_114535-480.webp 480w, /assets/images/responsive/20230925_114535-900.webp 900w"
      sizes="auto, (max-width: 44rem) calc(100vw - 2rem), 42rem">
    <img src="/images/inline-images/20230925_114535_hu_ba3c62e186ff40b1.jpg" width="900" height="1200"
      alt="Path between evergreens with hills visible beyond" loading="lazy" decoding="async">
  </picture>
<picture class="post-image">
    <source type="image/webp"
      srcset="/assets/images/responsive/20230925_114628-480.webp 480w, /assets/images/responsive/20230925_114628-960.webp 960w"
      sizes="auto, (max-width: 44rem) calc(100vw - 2rem), 42rem">
    <img src="/images/inline-images/20230925_114628_hu_b1fe06e97f55b630.jpg" width="960" height="720"
      alt="Boulders along the shore of Jordan Pond beneath a wooded slope" loading="lazy" decoding="async">
  </picture>
<picture class="post-image">
    <source type="image/webp"
      srcset="/assets/images/responsive/20230925_114948-480.webp 480w, /assets/images/responsive/20230925_114948-960.webp 960w"
      sizes="auto, (max-width: 44rem) calc(100vw - 2rem), 42rem">
    <img src="/images/inline-images/20230925_114948_hu_f7a9de4272efe05f.jpg" width="960" height="720"
      alt="View down Jordan Pond from the rocky shallows" loading="lazy" decoding="async">
  </picture>
<picture class="post-image">
    <source type="image/webp"
      srcset="/assets/images/responsive/20230925_131701-480.webp 480w, /assets/images/responsive/20230925_131701-960.webp 960w"
      sizes="auto, (max-width: 44rem) calc(100vw - 2rem), 42rem">
    <img src="/images/inline-images/20230925_131701_hu_87357a6a8e1fc836.jpg" width="960" height="720"
      alt="View across Jordan Pond and forested hills from an exposed ledge" loading="lazy" decoding="async">
  </picture>
<picture class="post-image">
    <source type="image/webp"
      srcset="/assets/images/responsive/20230925_131713-480.webp 480w, /assets/images/responsive/20230925_131713-960.webp 960w"
      sizes="auto, (max-width: 44rem) calc(100vw - 2rem), 42rem">
    <img src="/images/inline-images/20230925_131713_hu_3b2c6548cf2825e.jpg" width="960" height="720"
      alt="Sloping granite ledge above Jordan Pond, framed by evergreens" loading="lazy" decoding="async">
  </picture>
<picture class="post-image">
    <source type="image/webp"
      srcset="/assets/images/responsive/20230925_132402-480.webp 480w, /assets/images/responsive/20230925_132402-960.webp 960w"
      sizes="auto, (max-width: 44rem) calc(100vw - 2rem), 42rem">
    <img src="/images/inline-images/20230925_132402_hu_175c1d4505c359fc.jpg" width="960" height="720"
      alt="Large rounded boulder perched on a bare granite ledge" loading="lazy" decoding="async">
  </picture>
<picture class="post-image">
    <source type="image/webp"
      srcset="/assets/images/responsive/20230925_151804-480.webp 480w, /assets/images/responsive/20230925_151804-960.webp 960w"
      sizes="auto, (max-width: 44rem) calc(100vw - 2rem), 42rem">
    <img src="/images/inline-images/20230925_151804_hu_b74fc3ca1d0ff108.jpg" width="960" height="720"
      alt="Jordan Pond seen between trees along the shore" loading="lazy" decoding="async">
  </picture>
<picture class="post-image">
    <source type="image/webp"
      srcset="/assets/images/responsive/20230926_153900-480.webp 480w, /assets/images/responsive/20230926_153900-960.webp 960w"
      sizes="auto, (max-width: 44rem) calc(100vw - 2rem), 42rem">
    <img src="/images/inline-images/20230926_153900_hu_2d701207ac5a5c66.jpg" width="960" height="720"
      alt="Rock-strewn trail through a stand of tall evergreens" loading="lazy" decoding="async">
  </picture>
<picture class="post-image">
    <source type="image/webp"
      srcset="/assets/images/responsive/20230926_154201-480.webp 480w, /assets/images/responsive/20230926_154201-960.webp 960w"
      sizes="auto, (max-width: 44rem) calc(100vw - 2rem), 42rem">
    <img src="/images/inline-images/20230926_154201_hu_ef5409d7bb809a15.jpg" width="960" height="720"
      alt="Blue Atlantic beside a rocky shore and a wooded headland" loading="lazy" decoding="async">
  </picture>
<picture class="post-image">
    <source type="image/webp"
      srcset="/assets/images/responsive/20230926_154242-480.webp 480w, /assets/images/responsive/20230926_154242-960.webp 960w"
      sizes="auto, (max-width: 44rem) calc(100vw - 2rem), 42rem">
    <img src="/images/inline-images/20230926_154242_hu_c07286589618401c.jpg" width="960" height="720"
      alt="Surf breaking against dark rocks along the coast" loading="lazy" decoding="async">
  </picture>
<picture class="post-image">
    <source type="image/webp"
      srcset="/assets/images/responsive/20230926_154250-480.webp 480w, /assets/images/responsive/20230926_154250-960.webp 960w"
      sizes="auto, (max-width: 44rem) calc(100vw - 2rem), 42rem">
    <img src="/images/inline-images/20230926_154250_hu_4f94a3d4a737e6eb.jpg" width="960" height="720"
      alt="Rocky shoreline curving toward a wooded point" loading="lazy" decoding="async">
  </picture></p>
]]></content>
    <author><name>Codatory</name></author>
    <summary type="text">Honestly, what can I say that hasn’t already been said about Acadia? It was absolutely gorgeous, and picking just a few hikes to fit in the time I had was quite the challenge. If you have the opportunity, definitely go visit!
</summary>
  </entry>
  <entry>
    <title type="html">Quechee Gorge</title>
    <link href="https://www.codatory.page/2023/09/19/quechee-gorge.html" rel="alternate" type="text/html" title="Quechee Gorge"/>
    <published>2023-09-19T01:00:00-04:00</published>
    <updated>2023-09-19T01:00:00-04:00</updated>
    <id>https://www.codatory.page/2023/09/19/quechee-gorge</id>
    <content type="html" xml:base="https://www.codatory.page/2023/09/19/quechee-gorge.html"><![CDATA[<p>If you google for things to do along I-91 in Vermont, one of the top things on the
list will inevitably be Quechee Gorge Trail. The state park made for a convenient
and affordable stop for the night, with direct access to the trail and easy access
to the shops nearby. Heads up though, the trail from the campground down is pretty
serious so if you aren’t a big hiker take the shortcut out to the road and join the
trail at the bridge where things are much easier.</p>
<p><picture class="post-image">
    <source type="image/webp"
      srcset="/assets/images/responsive/20230919_174703-480.webp 480w, /assets/images/responsive/20230919_174703-960.webp 960w"
      sizes="(max-width: 44rem) calc(100vw - 2rem), 42rem">
    <img src="/images/inline-images/20230919_174703_hu_bf6632bf5b95f1d8.jpg" width="960" height="1280"
      alt="River far below between steep wooded walls of Quechee Gorge" loading="eager" decoding="async">
  </picture>
<picture class="post-image">
    <source type="image/webp"
      srcset="/assets/images/responsive/20230919_175645-480.webp 480w, /assets/images/responsive/20230919_175645-960.webp 960w"
      sizes="auto, (max-width: 44rem) calc(100vw - 2rem), 42rem">
    <img src="/images/inline-images/20230919_175645_hu_8d9463df809c9756.jpg" width="960" height="1280"
      alt="Water spilling over a low dam above the gorge" loading="lazy" decoding="async">
  </picture>
<picture class="post-image">
    <source type="image/webp"
      srcset="/assets/images/responsive/20230919_181104-480.webp 480w, /assets/images/responsive/20230919_181104-960.webp 960w"
      sizes="auto, (max-width: 44rem) calc(100vw - 2rem), 42rem">
    <img src="/images/inline-images/20230919_181104_hu_2848866231475592.jpg" width="960" height="1280"
      alt="Leaf-covered trail descending through the woods" loading="lazy" decoding="async">
  </picture>
<picture class="post-image">
    <source type="image/webp"
      srcset="/assets/images/responsive/20230919_181546-480.webp 480w, /assets/images/responsive/20230919_181546-960.webp 960w"
      sizes="auto, (max-width: 44rem) calc(100vw - 2rem), 42rem">
    <img src="/images/inline-images/20230919_181546_hu_ac9b70b2cd9eb8c4.jpg" width="960" height="1280"
      alt="Whitewater running beside layered rock in the gorge" loading="lazy" decoding="async">
  </picture>
<picture class="post-image">
    <source type="image/webp"
      srcset="/assets/images/responsive/20230919_182155-480.webp 480w, /assets/images/responsive/20230919_182155-960.webp 960w"
      sizes="auto, (max-width: 44rem) calc(100vw - 2rem), 42rem">
    <img src="/images/inline-images/20230919_182155_hu_8fda70cd1cbb2287.jpg" width="960" height="1280"
      alt="Broad ledges of exposed rock beside the river" loading="lazy" decoding="async">
  </picture></p>
]]></content>
    <author><name>Codatory</name></author>
    <summary type="text">If you google for things to do along I-91 in Vermont, one of the top things on the list will inevitably be Quechee Gorge Trail. The state park made for a convenient and affordable stop for the night, with direct access to the trail and easy access to the shops nearby. Heads up though, the trail from the campground down is pretty serious so if you aren’t a big hiker take the shortcut out to the road and join the trail at the bridge where things are much easier.
</summary>
  </entry>
  <entry>
    <title type="html">The Journey Begins</title>
    <link href="https://www.codatory.page/2023/09/18/journey-begins.html" rel="alternate" type="text/html" title="The Journey Begins"/>
    <published>2023-09-18T01:00:00-04:00</published>
    <updated>2023-09-18T01:00:00-04:00</updated>
    <id>https://www.codatory.page/2023/09/18/journey-begins</id>
    <content type="html" xml:base="https://www.codatory.page/2023/09/18/journey-begins.html"><![CDATA[<p>It’s been an adventure all its own to kick off this season of travel. I gave up my
apartment as part of the kickoff, which required a lengthy and complex move of
everything into storage. On top of that, in the middle of the move I had to take
the RV back to the factory to get some long delayed repairs made.</p>
<p>Thankfully, with the help of my family and friends, I was able to get everything
going and into good shape and it’s time to begin my travels.</p>
<p>The first leg of travel in this season is to the New England area, because I haven’t
had a chance to spend time in that part of the country before and September / October
are great times to see the foliage. Normally, I’d try to have an itinerary map to
start off a segment, but between some technical issues and some very off the cuff
planning I don’t really have a great one to share.</p>
<p>The general goal right now is to make my camping reservation at Acadia National Park
on the 24th of September, and after that I’ll be able to more or less bop around as
I won’t be on such a tight deadline.</p>
<p>Today, I’m enjoying the sound of rain on the metal roof in Pownal, VT at the lovely
<a href="https://www.pinehollowcamping.com/">Pine Hollow Campground</a> after spending the weekend
ripping across New York and Ohio. Tomorrow I’ll move on to Quechee State Park to hike
the Quechee Gorge Trail and Wednesday I’ll be heading to Shelborne, NH to finish out
the work week.</p>
<p>And now, for some photos from the trip so far…</p>
<h2 id="scioto-park-dublin-ohio">Scioto Park, Dublin, Ohio</h2>
<p><picture class="post-image">
    <source type="image/webp"
      srcset="/assets/images/responsive/20230915_090906-480.webp 480w, /assets/images/responsive/20230915_090906-960.webp 960w"
      sizes="auto, (max-width: 44rem) calc(100vw - 2rem), 42rem">
    <img src="/images/inline-images/20230915_090906_hu_4f9d6a908e6e4217.jpg" width="960" height="720"
      alt="Rocky riverbank shaded by trees at Scioto Park" loading="lazy" decoding="async">
  </picture></p>
<h2 id="gorman-nature-center-mansfield-ohio">Gorman Nature Center, Mansfield, Ohio</h2>
<p><picture class="post-image">
    <source type="image/webp"
      srcset="/assets/images/responsive/20230915_150442-480.webp 480w, /assets/images/responsive/20230915_150442-960.webp 960w"
      sizes="auto, (max-width: 44rem) calc(100vw - 2rem), 42rem">
    <img src="/images/inline-images/20230915_150442_hu_921019fa8482629e.jpg" width="960" height="720"
      alt="Woodland trail beneath tall trees at Gorman Nature Center" loading="lazy" decoding="async">
  </picture>
<picture class="post-image">
    <source type="image/webp"
      srcset="/assets/images/responsive/20230915_151858-480.webp 480w, /assets/images/responsive/20230915_151858-960.webp 960w"
      sizes="auto, (max-width: 44rem) calc(100vw - 2rem), 42rem">
    <img src="/images/inline-images/20230915_151858_hu_ddc5ce02378eff62.jpg" width="960" height="720"
      alt="Mown trail through a meadow at Gorman Nature Center" loading="lazy" decoding="async">
  </picture></p>
<h2 id="der-dutchman-bellville-ohio">Der Dutchman, Bellville, Ohio</h2>
<p><picture class="post-image">
    <source type="image/webp"
      srcset="/assets/images/responsive/20230915_181341-480.webp 480w, /assets/images/responsive/20230915_181341-960.webp 960w"
      sizes="auto, (max-width: 44rem) calc(100vw - 2rem), 42rem">
    <img src="/images/inline-images/20230915_181341_hu_21e7c990fbe8817c.jpg" width="960" height="720"
      alt="Plate of meat and noodles beside a dinner roll at Der Dutchman" loading="lazy" decoding="async">
  </picture>
<picture class="post-image">
    <source type="image/webp"
      srcset="/assets/images/responsive/20230915_183122-480.webp 480w, /assets/images/responsive/20230915_183122-960.webp 960w"
      sizes="auto, (max-width: 44rem) calc(100vw - 2rem), 42rem">
    <img src="/images/inline-images/20230915_183122_hu_a7d1ae7868b7db72.jpg" width="960" height="1280"
      alt="Tall slice of pie on a dessert plate" loading="lazy" decoding="async">
  </picture></p>
<h2 id="cuyahoga-valley-national-park">Cuyahoga Valley National Park</h2>
<p><picture class="post-image">
    <source type="image/webp"
      srcset="/assets/images/responsive/20230916_124744-480.webp 480w, /assets/images/responsive/20230916_124744-960.webp 960w"
      sizes="auto, (max-width: 44rem) calc(100vw - 2rem), 42rem">
    <img src="/images/inline-images/20230916_124744_hu_600f89a8af37f91a.jpg" width="960" height="720"
      alt="Stone and timber entrance sign for Cuyahoga Valley National Park" loading="lazy" decoding="async">
  </picture>
<picture class="post-image">
    <source type="image/webp"
      srcset="/assets/images/responsive/20230916_130157-480.webp 480w, /assets/images/responsive/20230916_130157-960.webp 960w"
      sizes="auto, (max-width: 44rem) calc(100vw - 2rem), 42rem">
    <img src="/images/inline-images/20230916_130157_hu_c6ec49e859bc5331.jpg" width="960" height="720"
      alt="Turtles lined up on a log in a pond" loading="lazy" decoding="async">
  </picture>
<picture class="post-image">
    <source type="image/webp"
      srcset="/assets/images/responsive/20230916_131105-480.webp 480w, /assets/images/responsive/20230916_131105-960.webp 960w"
      sizes="auto, (max-width: 44rem) calc(100vw - 2rem), 42rem">
    <img src="/images/inline-images/20230916_131105_hu_c0d7e0226be0a48b.jpg" width="960" height="1280"
      alt="Wooden boardwalk curving through the forest" loading="lazy" decoding="async">
  </picture>
<picture class="post-image">
    <source type="image/webp"
      srcset="/assets/images/responsive/20230916_132655-480.webp 480w, /assets/images/responsive/20230916_132655-960.webp 960w"
      sizes="auto, (max-width: 44rem) calc(100vw - 2rem), 42rem">
    <img src="/images/inline-images/20230916_132655_hu_b41af1e797403d14.jpg" width="960" height="1280"
      alt="Shallow creek running between wooded banks" loading="lazy" decoding="async">
  </picture></p>
]]></content>
    <author><name>Codatory</name></author>
    <summary type="text">It’s been an adventure all its own to kick off this season of travel. I gave up my apartment as part of the kickoff, which required a lengthy and complex move of everything into storage. On top of that, in the middle of the move I had to take the RV back to the factory to get some long delayed repairs made.
Thankfully, with the help of my family and friends, I was able to get everything going and into good shape and it’s time to begin my travels.
</summary>
  </entry>
  <entry>
    <title type="html">2022 Thor Tellaro L Year in Review</title>
    <link href="https://www.codatory.page/2023/04/24/2022-thor-tellaro-l-year-review.html" rel="alternate" type="text/html" title="2022 Thor Tellaro L Year in Review"/>
    <published>2023-04-24T01:00:00-04:00</published>
    <updated>2023-04-24T01:00:00-04:00</updated>
    <id>https://www.codatory.page/2023/04/24/2022-thor-tellaro-l-year-review</id>
    <content type="html" xml:base="https://www.codatory.page/2023/04/24/2022-thor-tellaro-l-year-review.html"><![CDATA[<p>The astute readers among you might recognize this post is a bit late for a
year-end review. Unfortunately, part of owning a new RV is dealing with
problems and my rig has been out of commission for about 8 weeks now due
to a failure in the electrical system. Unfortunately, my repair experience
will be one that, when complete, will join the horror stories you&rsquo;ve
undoubtedly heard before.</p>
<p>But, since that&rsquo;s currently a developing story, let&rsquo;s talk about the year
I had with the rig <em>before</em> it cut my trip short.</p>
<p>Let&rsquo;s start with the things that are good, because I kind of need to cheer
myself up to write the rest of this post.</p>
<ul>
<li>A Class B rig is super easy to get around in. Generally speaking, if a
full-size pickup fits, I fit. With no slides, I&rsquo;m barely longer than a
regular parking space and if parks in my driveway at home with no drama whatsoever.</li>
<li>The tanks are perfectly sized for me. I can plan on dumping and filling
once a week, and it only takes a few minutes.</li>
<li>The included features are quite reasonable for an entry-level Class B. The
furnace is quiet and efficient, the AC is effective, the kitchen and bathroom
is functional and generally speaking it&rsquo;s a nice place to hang out.</li>
<li>I&rsquo;ve gone on some pretty epic adventures.</li>
<li><a href="https://photos.app.goo.gl/M33xJX62gHaoRyMt7">https://photos.app.goo.gl/M33xJX62gHaoRyMt7</a></li>
</ul>
<p>Now, some of the changes or additions I&rsquo;ve made over the year&hellip;</p>
<ul>
<li>Garmin RV GPS - Just because I <em>can</em> fit anywhere most trucks can doesn&rsquo;t mean
it makes for a nice drive. A Garmin RV890 was added after my regular GPS decided
to route me through a mountain pass to save 10 minutes. I spent more than 10
minutes cleaning up the mess that shaking and rattling made!</li>
<li>Cradlepoint Dual modem 5G Router - Part of what makes RV travel appealing to me
is the ability to be gone for a long time, but I still need to keep connected.
Cradlepoint&rsquo;s products are the industry leaders and this thing has been an amazing
addition to my rig.</li>
<li>Black &amp; Decker FlexVAC - Pretty obvious, right?</li>
<li>Google Chromecast w/ Google TV - You need something to play stuff on the TV and
these are really cheap&hellip;</li>
</ul>
<p>What hasn&rsquo;t been so good, then?</p>
<p>Well, the electrical system still sucks. The Under-hood generator failed while I
was on my recent trip through Texas in a relatively spectacular manner. I&rsquo;ll
probably write up a whole post on what happened there whenever it finally gets
resolved. But more importantly, the dealer support after sales has been truly horrific.
My selling dealer, LazyDays of Elkhart (now <a href="https://rv.campingworld.com/dealer/elkhart-indiana">a Camping World location</a>),
was perfectly happy to schedule a service appointment to drop off the rig (3 hours away)
but once they had the rig in their possession refused to answer the phone, provide
any sort of status update or anything else. It wasn&rsquo;t until I sat down and repeatedly
called their number that someone accidentally answered and then basically shrugged me
off and said &ldquo;yeah, it&rsquo;s fixed, come pick it up.&rdquo;</p>
<p>When I went to pick it up, I can just say for sure it wasn&rsquo;t fixed. Now the coach is
in worse condition than when I dropped it off and Thor warranty support has been completely
unhelpful in finding a new option that might have some clue on how to work on the thing
(or at the very least answer the phone).</p>
]]></content>
    <author><name>Codatory</name></author>
    <summary type="text">The astute readers among you might recognize this post is a bit late for a year-end review. Unfortunately, part of owning a new RV is dealing with problems and my rig has been out of commission for about 8 weeks now due to a failure in the electrical system. Unfortunately, my repair experience will be one that, when complete, will join the horror stories you’ve undoubtedly heard before.
But, since that’s currently a developing story, let’s talk about the year I had with the rig before it cut my trip short.
</summary>
  </entry>
  <entry>
    <title type="html">Hello Keepalived</title>
    <link href="https://www.codatory.page/k8s/2022/12/03/hello-keepalived.html" rel="alternate" type="text/html" title="Hello Keepalived"/>
    <published>2022-12-03T08:00:00-05:00</published>
    <updated>2022-12-03T08:00:00-05:00</updated>
    <id>https://www.codatory.page/k8s/2022/12/03/hello-keepalived</id>
    <content type="html" xml:base="https://www.codatory.page/k8s/2022/12/03/hello-keepalived.html"><![CDATA[<p>My K8S cluster has been pretty flaky, with lots of errors on the KubeAPI and Metrics Server going unavailable regularly. I was also frequently unable to get logs from my pods. Turns out I should&rsquo;ve read the K0S documentation better.</p>
<blockquote>
<p>Control plane high availability requires a tcp load balancer, which acts as a single point of contact to access the controllers.</p>
</blockquote>
<p>Well, the hardware I have is really the hardware I want to use in this cluster. Sure I could spin up some VMs or Raspberry Pis to do the load balancing but I&rsquo;d much rather use the hardware that&rsquo;s there. We aren&rsquo;t pushing things super hard, so it shouldn&rsquo;t be super demanding or anything.</p>
<p>So, I pulled out my old pal Keepalived. My original plan was to use LVS to load balance the services, but after repeated problems with getting the port bindings to work reliably I decided load balancing wasn&rsquo;t really that necessary either. Instead, I&rsquo;m going to allow keepalived to float around an IP and k0s will bind to it directly. This means if I <em>do</em> get more API traffic than a single node can handle to the floating IP I&rsquo;ll have problems. I don&rsquo;t expect problems.</p>
<p>To make it work, you need to enable a Linux kernel feature called nonlocal bind. This allows services to bind to addresses that aren&rsquo;t physically present on the server. Then I have keepalived configured to monitor the K0S processes and float the IP address to the server with the most services working. Per usual, here&rsquo;s an <a href="https://gist.github.com/codatory/b6e59b3752cf97b56d8f0417ae9ce9fa">Ansible Playbook</a> with my configuration. You&rsquo;ll probably need to sub in your interface IDs and the IP you want to use as a floater.</p>
<p>Once it&rsquo;s configured, you&rsquo;ll need to update your k0sctl config to have it use the new floating IP. You do this by setting the externalAddress on the API Server and populating the SANs with all valid addresses (and hostnames) for your cluster.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-yaml" data-lang="yaml"><span class="line"><span class="cl"><span class="w">  </span><span class="nt">k0s</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">version</span><span class="p">:</span><span class="w"> </span><span class="m">1.25.4</span><span class="l">+k0s.0</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">dynamicConfig</span><span class="p">:</span><span class="w"> </span><span class="kc">false</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">config</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="nt">spec</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="nt">api</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">          </span><span class="nt">externalAddress</span><span class="p">:</span><span class="w"> </span><span class="m">10.8.0.10</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">          </span><span class="nt">sans</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">            </span>- <span class="m">10.8.0.10</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">            </span>- <span class="m">127.0.0.1</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">            </span>- <span class="m">10.8.0.11</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">            </span>- <span class="m">10.8.0.12</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">            </span>- <span class="m">10.8.0.13</span><span class="w">
</span></span></span></code></pre></div>]]></content>
    <author><name>Codatory</name></author>
    <category term="k8s"/>
    <summary type="text">My K8S cluster has been pretty flaky, with lots of errors on the KubeAPI and Metrics Server going unavailable regularly. I was also frequently unable to get logs from my pods. Turns out I should’ve read the K0S documentation better.
Control plane high availability requires a tcp load balancer, which acts as a single point of contact to access the controllers.
Well, the hardware I have is really the hardware I want to use in this cluster. Sure I could spin up some VMs or Raspberry Pis to do the load balancing but I’d much rather use the hardware that’s there. We aren’t pushing things super hard, so it shouldn’t be super demanding or anything.
</summary>
  </entry>
  <entry>
    <title type="html">Hello Host Patching</title>
    <link href="https://www.codatory.page/k8s/2022/11/20/hello-host-patching.html" rel="alternate" type="text/html" title="Hello Host Patching"/>
    <published>2022-11-20T08:00:00-05:00</published>
    <updated>2022-11-20T08:00:00-05:00</updated>
    <id>https://www.codatory.page/k8s/2022/11/20/hello-host-patching</id>
    <content type="html" xml:base="https://www.codatory.page/k8s/2022/11/20/hello-host-patching.html"><![CDATA[<p>Well, it&rsquo;s been a few days and now we want to check for updates on our host systems and be able to patch them. After all, we can&rsquo;t deploy workloads until we have reached some baseline operational maturity. While there are some cluster-native ways to orchestrate patching I&rsquo;m still happy to have my legacy tooling (Ansible) do it as a slightly simpler workflow.</p>
<p>Patching a K8S cluster isn&rsquo;t entirely difficult or entirely straightforward, there are a few things that need to happen in sequence to make sure everything goes off well. First off, you don&rsquo;t want to induce too much load on the cluster at once. Second off, becore you take a node offline you need to drain the pods off of it, and lastly when the node is ready you need to uncordon it to allow work to be scheduled on it again.</p>
<p>My <a href="https://gist.github.com/codatory/44e4944a1363e9ffadb9db2d0919b672">Ansible Playbook</a> to do that is here. It uses needrestart to check for services that need restarted and if a reboot is required does all the dran/uncordon work using kubectl on the admin workstation.</p>
]]></content>
    <author><name>Codatory</name></author>
    <category term="k8s"/>
    <summary type="text">Well, it’s been a few days and now we want to check for updates on our host systems and be able to patch them. After all, we can’t deploy workloads until we have reached some baseline operational maturity. While there are some cluster-native ways to orchestrate patching I’m still happy to have my legacy tooling (Ansible) do it as a slightly simpler workflow.
Patching a K8S cluster isn’t entirely difficult or entirely straightforward, there are a few things that need to happen in sequence to make sure everything goes off well. First off, you don’t want to induce too much load on the cluster at once. Second off, becore you take a node offline you need to drain the pods off of it, and lastly when the node is ready you need to uncordon it to allow work to be scheduled on it again.
</summary>
  </entry>
  <entry>
    <title type="html">Hello Monitoring</title>
    <link href="https://www.codatory.page/k8s/2022/11/19/hello-monitoring.html" rel="alternate" type="text/html" title="Hello Monitoring"/>
    <published>2022-11-19T09:00:00-05:00</published>
    <updated>2022-11-19T09:00:00-05:00</updated>
    <id>https://www.codatory.page/k8s/2022/11/19/hello-monitoring</id>
    <content type="html" xml:base="https://www.codatory.page/k8s/2022/11/19/hello-monitoring.html"><![CDATA[<p>Perfect, we&rsquo;ve got storage sorted out and now we can run real applications. Let&rsquo;s deploy monitoring to our cluster so we can see how it&rsquo;s performing and check that everything is working correctly. We&rsquo;ll be deploying the Prometheus Stack, as this is the most popular and best supported monitoring solution for Kubernetes. Any guesses how this starts?</p>
<p><code>helm repo add prometheus-community https://prometheus-community.github.io/helm-charts</code></p>
<p>Yep; a new helm repo. This chart needs enough options we&rsquo;ll go ahead and provide them with a <a href="https://gist.github.com/codatory/d6d62a02369d7ccf725b6a72bc92eeca">YAML file</a>. We&rsquo;re turning alertmanager off for now but you&rsquo;re welcome to learn how to configure it if you want. In Grafana we&rsquo;re setting a default timezone, enabling persistent storage, and exposing the service as a LoadBalancer (so that MetalLB will assign it an IP address) and working around a bug. The Prometheus section also has a long block to have it request storage as part of the deployment.</p>
<p><code>helm upgrade --install --wait --create-namespace --namespace monitoring prometheus-stack prometheus-community/kube-prometheus-stack --values=prometheus.yml</code></p>
<p>Once the deployment is completed, you should be able to run <code>kubectl get svc -n monitoring</code> to find the IP address for Grafana. Punch that into your browser and log in with admin prom-operator, and browse through the Dashboards page.</p>
]]></content>
    <author><name>Codatory</name></author>
    <category term="k8s"/>
    <summary type="text">Perfect, we’ve got storage sorted out and now we can run real applications. Let’s deploy monitoring to our cluster so we can see how it’s performing and check that everything is working correctly. We’ll be deploying the Prometheus Stack, as this is the most popular and best supported monitoring solution for Kubernetes. Any guesses how this starts?
helm repo add prometheus-community https://prometheus-community.github.io/helm-charts
Yep; a new helm repo. This chart needs enough options we’ll go ahead and provide them with a YAML file. We’re turning alertmanager off for now but you’re welcome to learn how to configure it if you want. In Grafana we’re setting a default timezone, enabling persistent storage, and exposing the service as a LoadBalancer (so that MetalLB will assign it an IP address) and working around a bug. The Prometheus section also has a long block to have it request storage as part of the deployment.
</summary>
  </entry>
  <entry>
    <title type="html">Hello NFS</title>
    <link href="https://www.codatory.page/k8s/2022/11/19/hello-nfs.html" rel="alternate" type="text/html" title="Hello NFS"/>
    <published>2022-11-19T08:00:00-05:00</published>
    <updated>2022-11-19T08:00:00-05:00</updated>
    <id>https://www.codatory.page/k8s/2022/11/19/hello-nfs</id>
    <content type="html" xml:base="https://www.codatory.page/k8s/2022/11/19/hello-nfs.html"><![CDATA[<p>Ok, now we have a problem. We haven&rsquo;t told Kubernetes where it can find storage for our apps. In this example, we&rsquo;re going to use NFS but there are loads of other options like OpenEBS and Gluster. I&rsquo;m going to assume you&rsquo;ve already configured your NFS server of choice, and you know the appropriate mount options.</p>
<p>Guess what? Yep, we&rsquo;re adding another helm repo.</p>
<p><code>helm repo add nfs-subdir-external-provisioner https://kubernetes-sigs.github.io/nfs-subdir-external-provisioner/</code></p>
<p>Now we&rsquo;re going to be lazy and create one NFS provisioner that will pick up requests for volumes and map them to NFS, and make sure it cleans them up when they&rsquo;re no longer needed. You can do a lot more, but for now just make sure the server and path are correct for your environment.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">helm install --create-namespace --namespace nfs-system <span class="se">\
</span></span></span><span class="line"><span class="cl">    nfs-subdir-external-provisioner <span class="se">\
</span></span></span><span class="line"><span class="cl">    nfs-subdir-external-provisioner/nfs-subdir-external-provisioner <span class="se">\
</span></span></span><span class="line"><span class="cl">    --set nfs.server<span class="o">=</span>10.8.0.3 <span class="se">\
</span></span></span><span class="line"><span class="cl">    --set nfs.path<span class="o">=</span>/KuberNFS <span class="se">\
</span></span></span><span class="line"><span class="cl">    --set storageClass.defaultClass<span class="o">=</span><span class="nb">true</span> <span class="se">\
</span></span></span><span class="line"><span class="cl">    --set storageClass.onDelete<span class="o">=</span>delete
</span></span></code></pre></div>]]></content>
    <author><name>Codatory</name></author>
    <category term="k8s"/>
    <summary type="text">Ok, now we have a problem. We haven’t told Kubernetes where it can find storage for our apps. In this example, we’re going to use NFS but there are loads of other options like OpenEBS and Gluster. I’m going to assume you’ve already configured your NFS server of choice, and you know the appropriate mount options.
Guess what? Yep, we’re adding another helm repo.
helm repo add nfs-subdir-external-provisioner https://kubernetes-sigs.github.io/nfs-subdir-external-provisioner/
Now we’re going to be lazy and create one NFS provisioner that will pick up requests for volumes and map them to NFS, and make sure it cleans them up when they’re no longer needed. You can do a lot more, but for now just make sure the server and path are correct for your environment.
</summary>
  </entry>
  <entry>
    <title type="html">Hello MetalLB</title>
    <link href="https://www.codatory.page/k8s/2022/11/18/hello-metallb.html" rel="alternate" type="text/html" title="Hello MetalLB"/>
    <published>2022-11-18T21:00:00-05:00</published>
    <updated>2022-11-18T21:00:00-05:00</updated>
    <id>https://www.codatory.page/k8s/2022/11/18/hello-metallb</id>
    <content type="html" xml:base="https://www.codatory.page/k8s/2022/11/18/hello-metallb.html"><![CDATA[<p>Ok, we need an easy way to connect services running in our cluster to the external network. The method I chose is MetalLB, because it&rsquo;s a very simple and flexible way to expose services without relying on an external load balancer. MetalLB plays well with the CNI (Kube-Proxy) used by k0s, so we don&rsquo;t need to do anything special to prepare for the installation. I already have Helm installed on my administration system, so deploying MetalLB is really simple. First we need to add the repository to Helm.</p>
<p><code>helm repo add metallb https://metallb.github.io/metallb</code></p>
<p>Once the repository is added, we can issue a command to have helm install (or update) MetalLB for us.</p>
<p><code>helm upgrade --install --create-namespace --namespace metallb-system metallb metallb/metallb</code></p>
<p>Once the chart has been installed, all the necessary pods will be downloaded and started on the appropriate servers. Lastly, we need to give the system some IP addresses to assign to services. We do this with a <a href="https://gist.github.com/codatory/d3a647a68955d5fdcc1d07383ab78cee">YAML file</a> that we apply with <code>kubectl apply -f</code>. Be sure to select addresses that are available on the network your servers are attached to!</p>
<p>Oh did it fail for you too? In both of my installs applying the YAML file failed with a webhook error until I re-started the controller pod. No idea why. <code>kubectl -n metallb-system get pod | grep control | awk '{print $1}' | xargs kubectl delete -n metallb-system pod </code>ought to do the job to get you going.</p>
<p>Now, let&rsquo;s deploy something so we can test and make sure this thing is working. We&rsquo;ll deploy something called in Ingress, which is basically a shared web server that allows us to route traffic into the cluster using HTTP. The details don&rsquo;t matter right now, so let&rsquo;s just get going.</p>
<p>One again we need to add a repository to Helm:</p>
<p><code>helm repo add traefik https://traefik.github.io/charts</code></p>
<p>Then we will deploy the chart.</p>
<p><code>helm upgrade --install --create-namespace --namespace traefik-system traefik traefik/traefik</code></p>
<p>This will go and deploy some stuff for us, and once it&rsquo;s done we can run <code>kubectl -n traefik-system get services</code> and in the External-IP column you should have an IP that was in the range in the YAML file you provided. If you try and load that IP you should get a 404 error. Congrats!</p>
]]></content>
    <author><name>Codatory</name></author>
    <category term="k8s"/>
    <summary type="text">Ok, we need an easy way to connect services running in our cluster to the external network. The method I chose is MetalLB, because it’s a very simple and flexible way to expose services without relying on an external load balancer. MetalLB plays well with the CNI (Kube-Proxy) used by k0s, so we don’t need to do anything special to prepare for the installation. I already have Helm installed on my administration system, so deploying MetalLB is really simple. First we need to add the repository to Helm.
</summary>
  </entry>
</feed>
