<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: David Mynors</title>
    <description>The latest articles on DEV Community by David Mynors (@idmyn).</description>
    <link>https://dev.to/idmyn</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F282775%2Fe6f05fa2-b3a9-445c-8373-e7f22e59283b.jpg</url>
      <title>DEV Community: David Mynors</title>
      <link>https://dev.to/idmyn</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/idmyn"/>
    <language>en</language>
    <item>
      <title>Slick Docker Deploys on Raspberry Pi</title>
      <dc:creator>David Mynors</dc:creator>
      <pubDate>Sat, 29 Feb 2020 15:13:01 +0000</pubDate>
      <link>https://dev.to/idmyn/slick-docker-deploys-on-raspberry-pi-2f0j</link>
      <guid>https://dev.to/idmyn/slick-docker-deploys-on-raspberry-pi-2f0j</guid>
      <description>&lt;p&gt;In my spare moments this past week I’ve been working on a Telegram bot for basic image processing, and as it’s gotten closer and closer to the functionality I’m after, I’ve started to think about how I want to deploy it. This isn’t my first rodeo, mind. Around a year ago at a university hackathon I built &lt;a href="https://github.com/idmyn/MainLibraryBusyBot"&gt;a very basic Telegram bot&lt;/a&gt; for querying the occupancy of the main library, which I ended up deploying on my Raspberry Pi (model 3B) with a &lt;code&gt;git clone&lt;/code&gt;, &lt;code&gt;npm install&lt;/code&gt;, and &lt;code&gt;npm start&lt;/code&gt;. This time, however, I have bigger ambitions. I've decided that I’m going to containerise it with docker and deploy it that way. My mission is to minimise the time spent in &lt;code&gt;ssh&lt;/code&gt;. As a dry-run of sorts (and a sweet excuse to procrastinate), I spent most of yesterday re-deploying my library bot with docker. There were some ups and downs, but it turned out alright in the end — the perfect recipe for a blog post, if you ask me. &lt;/p&gt;

&lt;h1&gt;
  
  
  How I would have liked to do it
&lt;/h1&gt;

&lt;p&gt;Before containerising the library bot, I did a bit of research about docker on Raspberry Pi. I found out that &lt;a href="%5BAdd%20support%20to%20install%20Docker%20on%20raspbian/jessie%20by%20DieterReuter%20%C2%B7%20Pull%20Request%20#24815%20%C2%B7%20moby/moby%20%C2%B7%20GitHub%5Dhttps://github.com/moby/moby/pull/24815"&gt;docker officially supports Raspbian&lt;/a&gt; (the official OS for Raspberry Pis), which was great news, so I moved on to the question of the easiest way to get a Raspberry Pi with docker up and running. I figured there would probably be an image or script to bootstrap a clean OS install with docker on a Pi, and I was right. &lt;a href="https://github.com/hypriot/image-builder-rpi/releases"&gt;HypriotOS&lt;/a&gt; &lt;a href="https://blog.hypriot.com/about/"&gt;sells itself&lt;/a&gt; as “a minimal Debian-based operating systems that is optimized to run Docker”, and makes the impressive claim that “from start to finish it takes a user less than 5 minutes to get started with Docker on Raspberry Pi”. It sounded perfect, so I gave it a try. I used their &lt;a href="https://github.com/hypriot/flash"&gt;flash&lt;/a&gt; script to flash the HypriotOS image onto my microSD card and it seemed to work as advertised. &lt;/p&gt;

&lt;p&gt;It would have been negligent to leave the system running with the default username and password, though, so I looked into securing the system. More good news! I found a guest post on their blog titled &lt;a href="https://blog.hypriot.com/post/cloud-init-cloud-on-hypriot-x64/"&gt;“Bootstrapping a Cloud with Cloud-Init and HypriotOS”&lt;/a&gt;. It describes the process of flashing the HypriotOS image alongside a &lt;a href="https://cloudinit.readthedocs.io/en/latest/index.html"&gt;cloud-init&lt;/a&gt; config file. It seemed like the perfect solution to my problem: I could change the username and hostname in the config file, and even add my public ssh key! Unfortunately, I couldn’t get the cloud-init config to work. After a good hour of trial, error, and &lt;a href="https://github.com/hypriot/flash/issues/155"&gt;patience&lt;/a&gt;, I decided to do things the old-fashioned way. After all, I’m not expecting to be purging my Pi and reinstalling a fresh OS all that often. &lt;/p&gt;

&lt;h1&gt;
  
  
  My steps to get a fresh, secure Raspbian install with docker on a Raspberry Pi:
&lt;/h1&gt;

&lt;ol&gt;
&lt;li&gt;Download the Raspbian Buster Lite image from &lt;a href="https://www.raspberrypi.org/downloads/raspbian/"&gt;the Raspberry Pi website&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Unzip it, double click to mount it (so it appears like a USB drive), and paste an empty file called &lt;code&gt;ssh&lt;/code&gt; with no file extension into the root of the image (this enables you to connect to it in step 6)&lt;/li&gt;
&lt;li&gt;Flash the image onto the MicroSD card you want to use for your Pi (I recommend &lt;a href="https://github.com/hypriot/flash"&gt;flash&lt;/a&gt; for this)&lt;/li&gt;
&lt;li&gt;Insert the flashed MicroSD into your Pi, connect it to your router via ethernet, and turn it on&lt;/li&gt;
&lt;li&gt;Find the IP address of your Pi (I use &lt;a href="https://raspberrypi.stackexchange.com/a/13937"&gt;this terminal command&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;SSH into your Pi (&lt;code&gt;ssh pi@IP_ADDRESS&lt;/code&gt; with password &lt;code&gt;raspberry&lt;/code&gt; when prompted)&lt;/li&gt;
&lt;li&gt;Follow all of the steps from the &lt;a href="https://www.raspberrypi.org/documentation/configuration/security.md"&gt;“Securing your Raspberry Pi”&lt;/a&gt; section of the Raspberry Pi documentation (including deleting the &lt;code&gt;pi&lt;/code&gt; user)&lt;/li&gt;
&lt;li&gt;As the new user you just created on your Pi, install docker with &lt;code&gt;curl -sSL https://get.docker.com | sh&lt;/code&gt;, and install docker-compose with &lt;code&gt;sudo apt-get install docker-compose&lt;/code&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Deploying containers
&lt;/h2&gt;

&lt;p&gt;To preserve the beautiful clean slate of my fresh Raspbian install, I wanted a really slick deploy process for my docker containers. My solution was a &lt;code&gt;docker-compose.yml&lt;/code&gt; looking a bit like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;3"&lt;/span&gt;
&lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;busybot&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;idmyn/busy-bot:arm"&lt;/span&gt;
    &lt;span class="na"&gt;restart&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;always&lt;/span&gt;
    &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;TOKEN=*********************************&lt;/span&gt;
  &lt;span class="na"&gt;watchtower&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;containrrr/watchtower:latest&lt;/span&gt;
    &lt;span class="na"&gt;restart&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;always&lt;/span&gt;
    &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;/var/run/docker.sock:/var/run/docker.sock&lt;/span&gt;
    &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;WATCHTOWER_CLEANUP=true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;It’s wonderful. I just had to send that single file to my Pi with &lt;code&gt;scp docker-compose.yml USER@IP_ADDRESS:~/docker-compose.yml&lt;/code&gt;, &lt;code&gt;ssh&lt;/code&gt; into the Pi, and run &lt;code&gt;docker-compose up -d&lt;/code&gt; to spin up the containers. The &lt;a href="https://containrrr.github.io/watchtower/usage-overview/"&gt;watchtower&lt;/a&gt; container watches for image updates on &lt;a href="https://hub.docker.com"&gt;Docker Hub&lt;/a&gt;, and you can automate docker image builds on pushes to &lt;code&gt;master&lt;/code&gt; with &lt;a href="https://github.com/features/actions"&gt;GitHub Actions&lt;/a&gt; for a totally hands-off CI pipeline. Here’s my workflow for that:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;buildx&lt;/span&gt;

&lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;pull_request&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;branches&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;master&lt;/span&gt;
  &lt;span class="na"&gt;push&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;branches&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;master&lt;/span&gt;

&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;buildx&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;
    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt;
        &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Checkout&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v1&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt;
        &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Set up Docker Buildx&lt;/span&gt;
        &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;buildx&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;crazy-max/ghaction-docker-buildx@v1&lt;/span&gt;
        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;latest&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt;   
        &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Docker Login&lt;/span&gt;
        &lt;span class="na"&gt;env&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;DOCKER_PASSWORD&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.DOCKER_PASSWORD }}&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
          &lt;span class="s"&gt;echo "${DOCKER_PASSWORD}" | docker login —username idmyn —password-stdin&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt;
        &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Run Buildx&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
          &lt;span class="s"&gt;docker buildx build \&lt;/span&gt;
            &lt;span class="s"&gt;-t idmyn/transparency-bot:arm \&lt;/span&gt;
            &lt;span class="s"&gt;—platform linux/arm/v7 \&lt;/span&gt;
            &lt;span class="s"&gt;—push .&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;NOTE: for containers to run on a Raspberry Pi, they need to be built for its ARM architecture. There’s an informative post about this on &lt;a href="https://www.docker.com/blog/multi-arch-images/"&gt;the Docker Blog&lt;/a&gt; but, for what’s it’s worth, my build command looks like this:&lt;/strong&gt; &lt;br&gt;
&lt;code&gt;docker buildx build -t idmyn/busy-bot:arm --platform linux/arm/v7 --push .&lt;/code&gt;&lt;/p&gt;

</description>
      <category>devops</category>
      <category>docker</category>
      <category>raspberrypi</category>
      <category>ci</category>
    </item>
  </channel>
</rss>
