by Lyle Scott, III

Alpine Linux on Raspberry Pi2 notes

I've been using Alpine Linux for some weeks now in most of my Docker containers with great success. I recently bought a Raspberry Pi2 to hook up to AWS IoT and thought Alpine Linux would make a great fit given the small foot print and emphasis on security.

Download Raspberry Pi Alpline Linux image

Download an Alpine Linux archive for use with Raspberry Pi from https://alpinelinux.org/downloads/.

Prepare SD card

First, you'll need to reformat the MicroSD card to have a (bootable) FAT32 filesystem. To do this from OSX, follow these instructions. If you are in Linux, use gparted or fdisk to format the SD card to a FAT32 partition type and mark it as bootable. I'm not sure what to use for Windows.

One you've got a mountable FAT32 partition, copy over the Alpine Linux archive files. Again, I'm on OSX so I've used Disk Utility to mount the filesystem to a volume with the pattaren of /Volumes/$PARTITION_NAME/. If you were in Linux, you'd sudo mount /dev/$your_msdos_parititon /mnt/rasppi2 or some-such.

# Decompress the downloaded archive and extract to the mounted SD card.
sudo tar xvf /path/to/alpine/archive.tar.gz -C /path/to/msdos/mount/point

# OSX example.
tar xvf ~/Downloads/alpine-rpi-3.3.3-armhf.rpi.tar.gz -C /Volumes/RASPINE/

Unmount the MS-DOS partition before you remove the SD card from your machine! Strange things can happen.

Your Raspberry Pi should now boot up when you install the SD card in the Raspberry Pi.

Initial Setup

Log in with root (no password!). Run alpine-setup and answer the questions to expedite the setup process. 

setup-alpine

If you want wireless connectivity, be sure to configure the wlan0 interface when it prompts you. If you choose dhcp, that's fine but it might fail if you need WPA authentication info for the wireless connection. This can easily be solved later, so just keep moving.

If you picked chrony as your NTP daemon (timeserver), you'll need to make it start at boot.

rc-update add chronyd boot

Setup Wireless Connection (WPA)

# Install dependency packages.
apk add wireless-tools wpa_supplicant

# Scan for available wireless networks.
iwlist wlan0 scanning | grep SSID

# Generate WPA passphrase secret
wpa_passphrase "YOUR SSID" > /etc/wpa.conf
<type passphase and hit enter>

# OPTIONAL, remove plain text password.
# edit /etc/wpa.conf and remove commented out plain text password.

Now that you have everything setup for wireless, enable it for the wireless interface on boot.

Create/edit /etc/network/interfaces to contain the following (you could have some of this there already).

auto wlan0
iface wlan0 inet dhcp
    hostname YOUR_HOSTNAME
    wireless-essid YOUR SSID
    pre-up wpa_supplicant -B -D wext -i wlan0 -c /etc/wpa.conf

Bring up the interface and you should be all good.

ifup wlan0

See if you can contact the internet world by doing a ping 4.2.2.1 or some-such.

If you are now online, it would be a great time to grab grab the time from a NTP server and install some updates!

# if you picked chronyd in setup-alpine
service chronyd restart

apk update
apk upgrade

Commit Changes

Remember, only /etc changes are persisted accross reboots and only if you have committed the changes...so commit all of the hard work.

lbu commit

Add a non-root user

This is technically optional, but highly advised. Also, you'll want to add a non-root user if you want to SSH to your Raspberry Pi.

apk add sudo
adduser lyle -G wheel

# Running the following will put you into the vi editor.
​visudo

# Uncomment the line for %wheel
# If you are new to vi...
#   1. press "/" to search
#   2. enter "%wheel" and hit [enter]
#   3. hit "x" twice at the beginning of the line to delete the first 2 characters
#      (this makes the line active and not commented anymore)
#   4. hit Escape (to go back into command mode)
#   5. enter in ":wq" and hit [enter] to write and quit

# persist /etc
lbu commit

Persistent Storage

I'd like some files to be able to change and persist between reboot. To do this, you'll need to create a filesystem to store files on.

I only care about /usr and /home, but adjust to what you need to persist, keeping in mind the media of your persisted filesystem.

# Create a small writable filesystem (1GB).
mount /media/mmcblk0p1 -o rw,remount
sed -i 's/vfat\ ro,/vfat\ rw,/' /etc/fstab
dd if=/dev/zero of=/media/mmcblk0p1/persist.img bs=1024 count=0 seek=1048576
apk add e2fsprogs
mkfs.ext4 /media/mmcblk0p1/persist.img

# Mount storage.
echo "/media/mmcblk0p1/persist.img /media/persist ext4 rw,relatime,errors=remount-ro 0 0" >> /etc/fstab
mkdir /media/persist
mount -a

# Create overlay directories.
mkdir /media/persist/usr
mkdir /media/persist/home
mkdir /media/persist/.work
echo "overlay /usr overlay lowerdir=/usr,upperdir=/media/persist/usr,workdir=/media/persist/.work 0 0" >> /etc/fstab
echo "overlay /home overlay lowerdir=/home,upperdir=/media/persist/home,workdir=/media/persist/.work 0 0" >> /etc/fstab
mount -a

# Persist /etc
lbu commit

Next Steps

So, hopefully you have a Raspberry Pi up and running Alpine Linux. Happy hacking! I've posted some helpful links below:

Getting started with a Raspberry Pi and AWS IoT

This is a part 2 to another article I started about putting Alpine Linux on a Raspberry Pi.

Setup a Thing in AWS IoT

A "Thing" in AWS IoT talk represents an addressable device with various configurable state (properties). In this scnario, the Raspberry Pi is the device.

Assuming you have an AWS account, head over to https://console.aws.amazon.com/iot/home and click "Get Started" if you don't currently have any Things.

Follow along at http://docs.aws.amazon.com/iot/latest/developerguide/iot-device-sdk-node.html to get a Thing created with a Device connected to it. Make sure you choose the Node SDK option and not the C SDK option (for this tutorial, anyways).

You should end up at a screen where you download the public key, private key, and certificate. Keep these handy. 

Example of pushing state data to AWS IoT

Using the AWS IoT Node SDK, you can easy publish state data to your Thing. The following example stores some meta data about the system into Thing properties.

mkdir -p ~/awsiot/certs
wget https://www.symantec.com/content/en/us/enterprise/verisign/roots/VeriSign-Class%203-Public-Primary-Certification-Authority-G5.pem -O ~/awsiot/certs/rootCA.pem

Also, put the private key and certificate files that were downloaded earlier into ~/awsiot/certs. This is used for Thing authorization for talking to AWS IoT.

Let's create a small node app to push some basic state information about the running device.

mkdir -p ~/awsiot/node
cd ~/awsiot/node
npm init  # use main.js as the entrypoint.
npm install --save aws-iot-device-sdk
wget 

 

 

If a baby crawls off a cliff, who's fault was it, really? Why a software engineering process matters.

I realize it's a click bait title, but it hits the nail on the head for this post (and I thought I actually came up with something witty). The anology deserves a bit of an explanation, as well. A baby is crawling towards a cliff with a parent nearby, occupied with whatever. The baby crawls toward a cliff and falls off. The parent says, "damn it, that baby really screwed up" while passer bys would argue the parent is the one that really screwed up. Bare with me here.

The topic in question: why having a software engineering process is a good thing and I'll highlight some recent situations that really validated some core philiosophies of mine involving what a proper process looks like to me. (I mean that is the least arrogant way possible, but its always nice to have that "I told ya so" moment with yourself!)

The actors

So the recent situation i've found myself in the middle of lately is dealing with a team containing 2 people: a senior front end developer paired with a junior developer.

It has come to my attention, as a dev lead at a startup, that there were some ... differences ... between the two. It's not my place to manage personalities, but I do tend to step in when I notice it effecting the engineering of an awesome product I care about, especially as it related to code quality and developer velocity. I've made it a point to get both sides of the story, watch things more closer than I have time for, and had a deep think about it as a post-mortem.

The tail of two perspectives

The junior dev feels as though the senior dev gets pissed at them for code breaks, doing things "wrong", and generally feels as though they are not being managed in a way such that she can learn to step up their code skills; "given a chance", you could say.

The senior dev feels as though the junior dev breaks code often, does things a different way than they would have done, and generally feels the need to rewrite what work the junior does accomplish.

My perspective

Upon closer inspection, it's a firework display of what I consider red flags. 

  1. junior developer is merging feature branches straight into the dev branch, where lots of work happens, whenever they want
    1. it should be noted, the dev branch is continously deployed, so changes are active on a dev site people pop in to from time to time
  2. no code reviews are in place
  3. the two devs are constantly dealing with merge conflicts in the same few files
  4. communication is not happening
  5. deployed code is visibly screwed up (UI facing code)
  6. a test suit is non existent
  7. i get a lot of "oh, crap.. i just forgot to run thiis thing to build the JavaScript files for the deployed site but not needed for my local dev site" from the both of them and in commit history for their repository. It turns out they need to manually run some programs to build all their JavaScript files that the build server deploys for them.

My philosophy

My usual "role" whereever I work is devopper and backend developer. I've been fortunate enough to work at places with awesome development processes and, for better or for worse, been able to work at places with little or no processes and be the implementer of new processes that have worked well and been the author of some train wrecks (though, I blame selenium...).

I'd argue the complete disregard of a software development process lets this situation explode. Now, it's just a ticking timebomb since the the junior most likely feels helpless and doomed while the senior person has, in their head atleast, taken nearly all further chances to let the junior prove themselves away and will most likely demoted them to tiny uninteresting morsels of tasks that the senior person feels he is too good to be bothered with. After all, that is the easy way out and covers the team's ass. From a developer perspective, I get it.

I am a part of and lead a backend team of developers, myself. I would be pretty upset to see dev broken in a super obvious manner. To me, it's much more larger than a single bad commit, as we have a process that should allow us to fail fast and early while limiting disruption. In my mind, we've made a litany of failures if we let something obvious go by or if a junior member is constantly causing havoc.

  1. the feature developer failed to find the issue and didn't think of it beforehand
  2. the code reviewers did not catch the problem
  3. unittests and integration tests that we have a whole Jenkins server with lots of plugins devoted to it, did not find the problem
  4. QA (we have >=1 developer or QA test code before we merge into dev) didn't find the problem
  5. The tooling that I put forth to improve velocity and code quality failed to find the issue

At this point everyone has failed, incuding me. Including the process, quite possibly.

My solution to their problem

code reviews

This will reduce friction. I'd much rather type out some feedback, criticisms, or possibly even rant about how "I would have done it this way" during a code review than exclaim that in my head, though with much more profanity, as I check out a the dev branch that is completely broken, caused a distraction, and just made my day a bit sour. Don't even get me started if I saw that on a deployed instance (if it was something super trivial).

Code reviews are a venue for the junior person to learn and receive feedback so that there is no excuse for them to not step up their game over time. If they continually make the same errors or they don't improve over time, you also have proof and some quantification of that. I understand levels of coaching may vary, deadlines are looming, etc etc...but even simple comments can go a long way for addressing screw ups and misunderstandings. The big thing is, you are catching it early and have localized the impact to code that no one uses, yet.

In much the same vein, it holds the junior person accountable. They might get fried on a code review from time to time, but they will think twice before blindly pulling in code from Stack Overflow they they had no idea how it works and hopefully not get away with sloppy code to "just get it done." I will slay a code cowboy on a code review.

It's also a way to learn what other people expect. Over time, you sort of learn nuances of senior members' expectations. At the end of the day, there often isn't a "correct answer" in the boolean sense to a programming solution, so "correct" is often up to reviewers interpretations and philosophies. In much the same way you know which buttons to not press on your parents or significant other to make them happy or piss them off, you learn what NOT to do and what people like to see in code reviews.

build tools

I have a ton to say about this, but I'll keep it short. If you don't have tests, basic style tests, and generally just tools to run the freak'n code you are about to deploy to look for show stopping errors...you deserve every bug you get, quite frankly. Completely screwed up a merge conflict and left the code in an unbuildable state, then it should have been caught. Bonus for unit and integration tests.

Much like a code review, it's about finding an issue early and limiting the impact. In most cases, the developer gets a build failure notice, possibly a moment of shame for the build being broken being spammed out to various notification outlets, and then gets to work fixing the issue without ruining people's flow.

Also, I'd like to point out a perfect example that would have helped greatly in the situation I've mentioned. Do build things that need to happen 100% of the time on the freak'n build server. You worry about creating good code and let the build server do the must-haves. In this case, there was no reason that every developer on almost every commit should have to rebuild all the code that will be on the deployed version. Humans are stupid at tasks like these and it's a waste of everyone's time, quite frankly. Not to mention, your commit history and diffs probably look awful.

quality assurance

This one is very optional. Not everyone has a QA team and in a lot of times it can be a waste of time, but if a feature is complex, I often get a QA person or another developer to give it a once-through. You'd be surprised how much you get tunnel vision and overlook obvious things or unconciously think "oh well THAT situation doesn't matter" because you're subconciously being quite ignorant. You're human, it happens... until another person looks at you in dismay and wonders why you haven't thought of what is super obvious to them. If anything, it's good to talk through these types of things.

Again, it's about involving just a person. Not disrupting a whole team of people and possibly users.

treat the dev branch as code that can be deployed at any time

Branching stratagies vary, so I'll try to be generic. If other people are heavily working out of a mainline branch, think twice about committing. Run through everything in your head, maybe do some final testing, definately merge the mainline branch you are going to merge your feature into in your feature branch to pre-test that everything jives well together. 

Basically, I treat the mainline branch as a deployable artifact. It could be deployed and I wouldn't lose too much sleep over it.

final words

Yeah, processes can suck. Overzelous and adventurous people often introduce impediments that are far more of a pain in the ass than the harm that could be caused if the process was never introduced. I've been an author of my share of those (but they seem so great in your head...). 

The thing is, there is a happy medium for every place and team size. I'm not advocating to find every nook and spider web so that nothing bad ever happens or having a junior proof deployment system. What I am advocating for is that you put atleast a little effort into your tools and processes so that simple mistakes are limited and, what I find most important, people's time and patience is not constantly a punching bag. 

If you routinely let a child fall off a cliff, it's only your fault. It shouldn't be that easy. You're Doing It Wrong.