Thoughts on Docker

Docker has been causing a lot of ripples in all sorts of ponds in recent years. I first started playing with it nearly a year ago now, after hearing about it from someone else at work. At first I didn't really understand what problems it was trying to solve. The more I played with it, however, the more interesting it became.

Gripes About Docker

There were plenty of things that I didn't care for about Docker. The most prominent strike against it was how slow it was to start, stop, and destroy containers. I soon learned that if I store my Docker data on a btrfs partition, things become much faster. And it was great! Things that used to take 10 minutes started taking 2 or 3 minutes. Very significant improvement.

But then it was still slow to actually build any containers that are less than trivial. For example, we've been using Docker for one of my side projects since April 2014 (coming from vagrant). Installing all of the correct packages and whatnot inside of a our base Docker image took several minutes. Much longer than it does on iron or even in virtual machines. It was just slow. Anytime we had to update dependencies, we'd invalidate the image cache and spend a large chunk of time just waiting for an image to build. It was/is painful.

On top of that, pushing and pulling from the public registry is much slower than a lot of us would like it to be. We set up a private registry for that side project, but it was still slower than it should be for something like that.

Many of you reading this article have probably read most or all of those gripes from other Docker critics. They're fairly common complaints.

Lately, one of the things about using Docker for development that's become increasingly more frustrating is communication between containers on different hosts. Docker uses environment variables to tell one container how to reach services on another container running on the same host. Using environment variables is a great way to avoid hardcoding IPs and ports in your applications. I love it. However, when your development environment consists of 8+ distinct containers, the behavior around those environment variables is annoying (in my opinion).

Looking For Alternatives

I don't really feel like going into more detail on that right now. Let's just say it was frustating enough for me to look at alternatives (more out of curiosity than really wanting to switch away from Docker). This search led me to straight Linux containers (LXC), upon which Docker was originally built.

I remembered trying to use LXC for a little while back in 2012, and it wasn't a very successful endeavor--probably because I didn't understand containers very well at the time. I also distinctly remember being very fond of Docker when I first tried it because it made LXC easy to use. That's actually how I pitched it to folks.

Long story short, I have been playing with LXC for the past while now. I'm quite happy with it this time around. It seems to better fit the bill for most of the things we have been doing with Docker. In my limited experience with LXC so far, it's generally faster, more flexible, and more mature than Docker.

What proof do I have that it's faster? I have no hard numbers right now, but building one of our Docker images could take anywhere from 10 to 20 minutes. And that was building on top of an already existing base image. The base image took a few minutes to build too, but it was built much less regularly than this other image. So 10-20 minutes just to install the application-specific packages. Not the core packages. Not configure things. Just install additional packages.

Building an entire LXC container from scratch, installing all dependencies, and configuring basically an all-in-one version of the 8 different containers (along with a significant number of other things for monitoring and such) has consistently taken less than 3 minutes on my 2010 laptop. The speed difference is phenominal, and I don't even need btrfs. Lauching the full container is basically as fast as launching a single-purpose Docker container.

What proof do I have that LXC is more flexible than Docker? Have you tried running systemd inside of a Docker container? Yeah, it's not the most intuitive thing in the world (or at least it wasn't the last time I bothered to try it). LXC will let you use systemd without any fuss (that I've noticed, anyway). This probably isn't the greatest example of flexibility in the world of containers, but it certainly works for me.

You also get some pretty interesting networking options, from what I read. Not all of your containers need to be NAT'ed. Some can be NAT'ed and some can be bridged to appear on the same network as the host. I'm still exploring all of these goodies, so don't ask for details about them from me just yet ;)

What proof do I have that LXC is more mature than Docker? Prior to Docker version 0.9, its default execution environment was LXC. Version 0.9 introduced libcontainer, which eliminated Docker's need for LXC. The LXC project has been around since August 2008; Docker has been around since March 2013. That's nearly 5 entire years that LXC has had to mature before Docker was even a thing.

What Now?

Does all of this mean I'll never use Docker again? That I'll use LXC for everything that Docker used to handle for me? No. I will still continue to use Docker for the foreseeable future. I'll just be more particular about when I use it vs when I use LXC.

I still find Docker to be incredibly useful and valuable. I don't think it's as suitable for long-running development environments or to replace a fair amount of what folks have been using Vagrant to do. It can certainly handle that stuff, but LXC seems better suited to the task, at least in my experience.

Why do I think Docker is still useful and valuable? Well, let me share an example from work. We occasionally use a program with rather silly Java requirements. It requires a specific revision, and it must be 32-bit. It's really dumb. Installing and using this program on Ubuntu is really quite easy. Using the program on CentOS, however, is .... quite an adventure. But not an adventure you really want to take. You just want to use that program.

All I had to do was compose a Dockerfile based on Ubuntu, toss a couple apt-get lines in there, build an image, and push it to our registry. Now any of our systems with Docker installed can happily use that program without having to deal with any of the particularities about that one program. The only real requirement now is an operational installation of Docker.

Doing something like that is certainly doable with LXC, but it's not quite as cut and dry. In addition to having LXC installed, you also have to make sure that the container configuration file is suitable for each system where the program will run. This means making sure there's a bridged network adapter on the host, the configuration file uses the correct interface name, at the configuration file doesn't try to use an IP address that's already claimed, etc etc.

Also, Docker gives you port forwarding, bind mounts, and other good stuff with some simple command line parameters. Again, port forwarding and bind mounts are perfectly doable with straight LXC, but it's more complicated than just passing some additional command line parameters.

Anyway. I just wanted to get that out there. LXC will likely replace most of my Linux-based virtual machines for the next while, but Docker still has a place in my toolbox.

InstArch

My blog has obviously been quite inactive the past year. I've started a bunch of new projects and worked on some really interesting stuff in that time. I'm going to try to gradually describe the things I've been playing with here.

One project I started in the summer of 2013 is a personal Arch-based LiveCD. My goal in building this LiveCD was purely personal: I wanted to have a LiveCD with my preferred programs and settings just in case I hosed my main system somehow. I want to have minimal downtime, particularly when I need to keep producing for work. That was the idea behind this project. I called it InstArch, as in "instant Arch".

The build scripts for this project are hosted on bitbucket, while the ISOs I build are hosted on sourceforge. InstArch was recently added to Softpedia, and it has received a bit of interest because of that. Again, the idea behind this project was entirely personal--I'm not trying to make a new distribution or community because I'm dissatisfied with Arch or anything like that. There is some erroneous information about InstArch on Softpedia, but I haven't yet written them to ask them to fix it. Soon enough :)

If you're interested in playing with my live CD, feel free to download it and offer suggestions on the issue tracker. I may or may not implement any suggestions :) I've already had one person email me asking about the default username and password for InstArch. If you also find yourself needing this information:

  • username: inst
  • password: arch

You shouldn't need this information unless you try to use sudo or try to switch desktop sessions.

Here's a video of my live CD in action.

Also note that I haven't built/published a new live CD for several months.


Another part of the InstArch project, which I started looong before the actual LiveCD, was to create my own personal Arch repository. It tracks a bunch of packages that I build from the AUR and other personal Arch packages. Anyone is free to use this repo, and it's one that's built into my live CD.

If you wish to use this repository, add my key:

pacman-key -r 051680AC
pacman-key --lsign-key 051680AC

Then add this to your /etc/pacman.conf:

[instarch]
SigLevel = PackageRequired
Server = http://instarch.codekoala.com/$arch/

Another I-Heart-Linux Story

Just had another experience that represents much of what I love about Linux and free software, and I thought I would share.

I just got my first bluray burner. I have it in a USB3-capable enclosure to use with my USB2-capable laptop. I knew burn speeds would be much lower than the drive is rated to handle primarily because of this arrangement.

A good portion of yesterday included me trying to burn my first bluray in Linux. Unfortunately, the nature of bluray standards and Linux still don't jive very well. My usual burning applications didn't have any trouble at all detecting the burner or the media, but none of them seemed to want to actually burn anything. K3b made a coaster out of one disc; Brasero did nothing. I didn't try using the command line burning tricks that I found on the interwebs.

I decided to give ImgBurn a shot. I installed it with WINE, and it ran beautifully. However, I failed to realize that I left K3b's coaster in the drive and couldn't get a disc to burn. In my own defense, the coaster was still recognized by the computer as a blank BD-R. It was at this point that I just rebooted into Windows just to verify that the drive itself worked for burning.

Windows obviously burned the first disc fine (after I realized the coaster was still in the drive and replaced it with a fresh disc). The media I have are only rated for 4x burn speeds, while the drive itself is rated for 14x burning. Windows only managed to achieve ~2x for the duration of the burn (using ImgBurn again). Also, Windows seemed to struggle trying to keep the buffers full. Every 70 seconds or so, ImgBurn would stop burning to allow the buffers to fill up again and for the hard drive to settle down a bit. But it did end up working--the disc worked in my bluray player that's hooked up to the TV!!! Success!

I decided to give ImgBurn in WINE another shot. I popped a fresh BD-R into the drive, specified the files I wanted to burn, and initiated the burn process. Right off the bat, ImgBurn under WINE was burning at 2.4x. I watched the process for 10 minutes or so before heading upstairs to let it finish. Not once was the main buffer depleted. The drive buffer (4MB) was up and down every so often, but it was never empty from the time the burn began until the time when I left my computer.

I realize that some of you out there will just see the moral of this story being something like, "Linux doesn't support burning bluray discs very well, and Windows worked on the first try." If you find yourself in this boat, you're probably not part of the intended audience of this tale. This is probably because you have some bias against any operating system that isn't the one you're currently using. No, this story is intended for people who like to tinker and don't think it's a waste of time to go through exercises like this.

Anyway, the real reason I wrote this story was to illustrate one of my favorite things about Linux: it's fast! Burning a bluray disc using an application that was written for Windows, running with a (free, open source, community-driven) Windows compatibility layer in Linux is still faster than the same program running natively on Windows. Sure, it might not always be the case, but in my ~12 years of hands-on experience with Linux, I find that it usually is the case.

UPDATE

So I've burned another 5 blurays under Linux with ImgBurn. Here's the interesting part of my most recent burn log:

I 00:51:40 Operation Started!
I 00:51:40 Source File: -==/\/[BUILD IMAGE]\/\==-
I 00:51:40 Source File Sectors: 11,978,272 (MODE1/2048)
I 00:51:40 Source File Size: 24,531,501,056 bytes
I 00:51:40 Source File Volume Identifier: Stargate - Disc 6
I 00:51:40 Source File Volume Set Identifier: 4222067200B6C611
I 00:51:40 Source File Application Identifier: IMGBURN V2.5.7.0 - THE ULTIMATE IMAGE BURNER!
I 00:51:40 Source File Implementation Identifier: ImgBurn
I 00:51:40 Source File File System(s): ISO9660, UDF (1.02)
I 00:51:40 Destination Device: [3:0:0] HL-DT-ST BD-RE  WH14NS40 1.00
I 00:51:40 Destination Media Type: BD-R (Disc ID: PHILIP-R04-000)
I 00:51:40 Destination Media Supported Write Speeds: 4x, 6x, 8x
I 00:51:40 Destination Media Sectors: 12,219,392
I 00:51:40 Write Mode: BD
I 00:51:40 Write Type: DAO
I 00:51:40 Write Speed: MAX
I 00:51:41 Hardware Defect Management Active: No
I 00:51:41 BD-R Verify Not Required: Yes
I 00:51:41 Link Size: Auto
I 00:51:41 Lock Volume: Yes
I 00:51:41 Test Mode: No
I 00:51:41 OPC: No
I 00:51:41 BURN-Proof: Enabled
I 00:51:41 Write Speed Successfully Set! - Effective: 35,968 KB/s (8x)
I 00:52:00 Filling Buffer... (80 MB)
I 00:52:02 Writing LeadIn...
I 00:52:03 Writing Session 1 of 1... (1 Track, LBA: 0 - 11978271)
I 00:52:03 Writing Track 1 of 1... (MODE1/2048, LBA: 0 - 11978271)
I 01:18:33 Synchronising Cache...
I 01:18:34 Closing Track...
I 01:18:35 Finalising Disc...
I 01:18:50 Exporting Graph Data...
I 01:18:50 Graph Data File: C:\users\wheaties\Application Data\ImgBurn\Graph Data Files\HL-DT-ST_BD-RE_WH14NS40_1.00_WEDNESDAY-JANUARY-02-2013_12-51_AM_PHILIP-R04-000_MAX.ibg
I 01:18:50 Export Successfully Completed!
I 01:18:50 Operation Successfully Completed! - Duration: 00:27:09
I 01:18:50 Average Write Rate: 15,067 KB/s (3.4x) - Maximum Write Rate: 18,615 KB/s (4.1x)

As you can see, the last line suggests things are working quite nicely in Linux:

I 01:18:50 Average Write Rate: 15,067 KB/s (3.4x) - Maximum Write Rate: 18,615 KB/s (4.1x)

I would like to note also that two of the discs I've burned so far have had some problems being read on the computer afterwards. These discs do, however, work quite nicely in the bluray player for my TV. Might just be circumstance.

Installing Arch Linux On EeePC 701 4G

I know, I know, a lot of you are asking, "Why on earth would you want to do anything with a machine that's 5 years old?!" The hardware is crap now, and it was crap when the EeePC came out. Well, my friends, that's one of the great things about Linux! It will put new life into old hardware. Granted, the EeePC 701 4G came with Linux on it and all that, but I'm talking about putting something modern on it. Regardless, this guide will hopefully be useful for others who are trying to get Linux installed using LVM that uses something like an SD card as part of the primary volume group.

I've had Arch Linux installed on my EeePC for quite a while, but I only recently began to appreciate the benefits of LVM. The key requirement for this installation was to use LVM partitioning instead of traditional partitioning. I wanted the built-in 4GB SSD and the 8GB SD card to appear as one hard drive to the operating system so I would have that much more space to actually use.

Another key requirement for this installation was that I wanted to do it using a PXE server instead of the usual USB/external CD drive method. I've used PXE servers in the past, but I never really did much with them. I wanted to use this as an excuse to learn a bit more about them.

Prerequisites

If you're following along at home, I'm assuming that you have (access to) the following:

  • An EeePC 701 4G
  • An SD card that will be a permanent fixture in your EeePC
  • A router running DD-WRT that serves as the DHCP server for your network (I am running v24-sp2). Alternatively, just use a USB/CD to install.

PXE Setup

If you want to save some time and just use a USB/CD to install Arch, go ahead and skip to the Arch Installation section.

For those who are unfamiliar with PXE servers, PXE stands for "Preboot eXecution Environment." It allows you to boot your computer over the network using images stored on a different machine. Since I didn't want to plug in my USB key or external DVD drive, this was a perfect option.

I used my main laptop as the PXE server. All I really did was install atftp from the AUR, copy ipxe.pxe from the Arch Linux Netboot page (from the "Using an iPXE image" section), and put it in /var/tftpboot. After that, it was a matter of running atftpd:

rc.d start atftpd

The next step required tweaking the dnsmasq configuration on my router. Here's what I did:

  • Login to router

  • Go to the Services tab

  • Find the DNSMasq section (mine is already enabled for other purposes, so I assume you will want to make sure yours is enabled)

  • In the "Additional DNSMasq Options" box, make sure you have something like:

    dhcp-boot=ipxe.pxe,[your PXE server's name],[your PXE server's IP]
    
  • Apply the changes. I rebooted my router just to be sure.

That's all there really is to the PXE side of things.

EeePC Setup

You'll want to make sure that booting from the network is enabled in your BIOS. I'll post a list of my BIOS settings later.

Then you should be able to boot your EeePC from the network. If your EeePC isn't configured to boot from the network first, you can simply hit Escape while the BIOS POST screen is still showing and select it from the menu that appears.

If all goes according to plan, your EeePC should receive an IP address and download the boot images from your PXE server. Once you select the appropriate Arch Install option from the menu, it should go out and download the ISO and boot it up. It's pretty neat to see in action. Maybe one day I'll try to tweak this to use an ISO image that's available on the local network instead of downloading it from the Internet every time.

Arch Installation

Installing Arch Linux should be fairly simple if you follow the installation guide (which is also available during installation these days at /root/install.txt). The key thing to remember, if you want to use the built-in SSD and a permanent SD card as one hard drive, is to use LVM partitioning.

LVM Partitioning

The Arch Linux LVM guide will likely be an invaluable resource if you're new to LVM. Here I will simply give a short list of commands that I think I used to get my EeePC setup (I did this several days ago, so I might miss something along the way...sorry)

It's important to note that, while it's supposedly possible, I've never had any luck keeping my boot partition in an LVM setup. As such, I first partition my SSD and SD cards using fdisk. There are plenty of resources for fdisk and cfdisk out there, so I'll skip over the specifics of how to use each one and just give you an idea of what needs to be done.

  • Wipe all partitions from both /dev/sda (the SSD) and /dev/sdb (the SD card)
  • Create a 50-100MB primary partition at the beginning of /dev/sda. Mark it as bootable. Set the partition type to 83 (Linux).
  • Create another primary partition on /dev/sda that consumes the remaining disk space. Set the partition type to 8e (Linux LVM).
  • Create a primary partition on /dev/sdb that consumes all space on the SD card. Set the partition type to 8e (Linux LVM).

Now that we have some "Linux LVM" partitions to deal with, we can begin using LVM. Each partition we wish to use (both /dev/sda2 and /dev/sdb1) needs to be configured as an LVM "physical volume":

pvcreate /dev/sda2
pvcreate /dev/sdb1

Next, we create an LVM volume group that uses both of our physical volumes:

vgcreate vg0 /dev/sda2
vgextend vg0 /dev/sdb1

Lastly, create the LVM logical volumes. It's up to you how you setup your partitions, but I chose to create a swap partition (since my EeePC only has 512MB RAM) and a root partition. To create a swap partition, you simply do something like this:

lvcreate -C y -l 1G vg0 -n swap

And here's what the arguments mean:

  • -C y: make the partition contiguous
  • -l 1G: number of logical extents to allocate for the new logical drive
  • vg0: the name of the volume group we created earlier
  • -n swap: the name of the new logical volume

I created my root partition to fill the remaining space in the volume group as follows:

lvcreate -l +100%FREE vg0 -n root

Then it's just a matter of formatting your partitions. I'm not up-to-date on the debate regarding which FS is ideal for solid state media, so I just chose ext2:

mkfs.ext2 /dev/sda1
mkfs.ext2 /dev/mapper/vg0-root
mkswap /dev/mapper/vg0-swap

It's probably worth noting that you now have several ways to reference your newly-created LVM volumes. Here are my favorites:

  • /dev/[volume group name]/[volume name]
  • /dev/mapper/[volume group name]-[volume name]

Install Arch

I really don't want to duplicate the Arch Linux installation guide, so I'll just leave you to follow along there. Go ahead and mount your new partitions, pacstrap everything you want, and arch-chroot your heart away. But you might want to come back before you exit the chroot, otherwise your EeePC might not boot and you'll have to waste some time trying to figure out why.

Help The EeePC Boot With LVM

Before you reboot, you'll probably want to modify your /etc/mkinitcpio.conf to let your EeePC understand your LVM setup. The two key lines are MODULES and HOOKS. Here's what I have:

MODULES="usb-storage scsi-mod sd-mod libata usbcore uhci-hcd ehci-hcd"
HOOKS="base udev autodetect pata scsi sata lvm2 filesystems usbinput fsck"

The key here is to ensure that lvm2 appears before filesystems in your HOOKS list. Also, you want to load some modules to allow the SD card to be detected before the LVM hook attempts to find your partitions. I'm not sure if you need all of those modules, but they worked on the first try for me. To make the changes useful, rebuild your boot images:

mkinitcpio -p linux

To go along with detecting your SD card at boot, you want to give it enough time to settle before LVM tries to use it. In my case, 3 seconds is sufficient, so I added this to my /boot/syslinux/syslinux.cfg:

lvmwait=/dev/vg0/root rootdelay=3

You should be able to add that to the APPEND lines in your syslinux.cfg or the kernel line in your GRUB configuration file. Or whatever it is with GRUB these days.

Also, while you're editing your bootloader configuration, be sure to change the root partition to /dev/vg0/root (or whatever you chose when you did your LVM partitioning). The default syslinux.cfg includes root=/dev/sda3, so I just changed that to root=/dev/vg0/root. Most bootloaders allow you to modify the boot line before you actually boot into Linux if you forgot this step.

Tweak Arch

I'll leave you to install and configure the packages that you find useful. I plan on using my EeePC as a jump box into my home network, so it doesn't need a GUI of any sort. Just OpenSSH and some other goodies.

You might also be interested in my previous article about bonding eth0 and wlan0 now that you have Arch on your EeePC though!

Bonding eth0 and wlan0 on Arch Linux

Bonding eth0 and wlan0 on Arch Linux

Yesterday at work, a couple of my coworkers were trying to bond two ethernet ports on a Synology NAS. For whatever reason, this made me want to play with bonding network interfaces on my own computers. So I began trying to come up with a good reason to use valuable time to play with interface bonding.

One thing that has always driven me nuts about laptops is that connections are severed when I have to unplug my ethernet cable and take the laptop elsewhere. It never seemed to matter if I was using NetworkManager or anything else--connections were dropped, and the resulting annoyances ranged from minor to much rage. Having Pidgin drop connections and reconnect was a minor annoyance. Downloading a 4.2GB linux ISO and having the connection cut at 96% caused much rage.

Anyway, I decided to see if I could use bonding to reduce the frustration with such situations. Since my laptop is usually plugged into the ethernet, I wanted to use eth0 as my primary interface. It's faster and more reliable than wireless. When my ethernet connection fails, for whatever reason, I wanted it to fall back to wlan0. Ideally, things like downloads or streaming music/movies would continue uninterrupted.

Furthermore, I wanted my KVM to be able to use the bonded interfaces inside of my virtual machines. This called for a bridge.

To quickly see this in action, check the videos below!

Software

I configured this on a relatively new Arch Linux installation. Here's the software I used:

  • linux: 3.4.8-1
  • initscripts: 2012.08.2-1
  • netcfg: 2.8.9-1
  • netcfg-bonding: 1.5.1-1
  • ifenslave: 1.1.0-7
  • bridge-utils: 1.5-1

Configuration

The first thing you need to do to get this working, after installing all of the above packages, is load the bonding kernel module. In my particular case, as I mentioned earlier, I wanted to use eth0 when available and use wlan0 otherwise. As such, I used the active-backup bonding mode. If you're interested in the other bonding modes, I would suggest reading up on bonding. I'm pretty new to all of this bonding magic, so I can't guarantee that I'll be of any use if you don't follow my instructions :)

Back to configuration. I placed my bonding configuration in /etc/modprobe.d/bonding.conf. The only thing that may not be self-explanatory is the miimon setting. I learned from this bonding article that this option "specifies the MII link monitoring frequency in milliseconds." In other words, this is how often the system will check to see if a failover is necessary.

/etc/modprobe.d/bonding.conf

options bonding mode=active-backup
options bonding miimon=100
options bonding primary=eth0

After creating that file, you simply insert the module into the kernel:

modprobe bonding

To get bonding to work when you reboot your machine, you should either add bonding to your MODULES array in /etc/rc.conf or, if you're using more recent initscripts stuff, place a file in /etc/modules-load.d. I chose the latter solution.

/etc/modules-load.d/bonding.conf

bonding

Next, you must create some network profiles for netcfg. Prior to this bonding project, I had been using wicd or networkmanager to handle most of my networking needs. It seems like a bad idea to try using either of these, or the standard network daemon even, if you plan to use a configuration similar to what follows. Just FYI.

I created a network profile for the bonded interfaces as such:

/etc/network.d/bonded

CONNECTION="bonding"
INTERFACE="bond0"
SLAVES="eth0"
IP="dhcp"
DHCP_TIMEOUT=10
SLAVE_TIMEOUT=5

Notice that wlan0 isn't in the SLAVES list. This is because I also have a network profile for my home wireless connection to handle the authentication and whatnot:

/etc/network.d/home

CONNECTION="wireless"
DESCRIPTION="Home connection"
INTERFACE="wlan0"
SECURITY="wpa"

ESSID="wouldntyouliketoknow"
KEY="derpies"

IP="static"
IFOPTS="0.0.0.0"
PRE_UP="ifenslave bond0 wlan0"
PRE_DOWN="ifenslave -d bond0 wlan0"

I have one more network profile for the bridged interface that allows my KVM guests to live on the same network as everything else. If you're not using KVM or don't want a bridged interface, you don't need this one.

/etc/network.d/br0

INTERFACE="br0"
CONNECTION="bridge"
DESCRIPTION="KVM Bridge Connection"
BRIDGE_INTERFACES="bond0"
IP="dhcp"
POST_UP="brctl setfd br0 0"

Finally, I added these profiles to my /etc/conf.d/netcfg:

NETWORKS=(bonded home br0)

Again, if you don't need a bridged interface, you don't need to include the br0 profile in there.

You may or may not want to test your individual network profiles by doing something like:

netcfg -u home # try to bring the profile up
netcfg -d home # bring the profile down

If you have problems connecting to your wireless access point, I suggest tweaking and testing your profile until it works. If you use MAC address filtering for wireless security on your router, you might want to make sure that the MAC of your ethernet interface is in the list of permitted MAC addresses. When you setup bonding, all of the bonded interfaces seem to share the same MAC.

Try It Out

Pretty much all that's left is starting up the new network configuration! To do this, first make sure your previous networking daemon is turned off. For example, you might run one of the following commands:

rc.d stop network
rc.d stop wicd
rc.d stop networkmanager

Once you've done that, you simply run:

rc.d start net-profiles

If your setup is anything like mine, you might see ifconfig output similar to this (notice that my MAC addresses have been changed, but that they're identical for bond0, br0, eth0, and wlan0):

bond0: flags=5443<UP,BROADCAST,RUNNING,PROMISC,MASTER,MULTICAST>  mtu 1500
        ether 00:24:be:00:24:be  txqueuelen 0  (Ethernet)
        RX packets 7318719  bytes 8578112000 (7.9 GiB)
        RX errors 0  dropped 33241  overruns 0  frame 0
        TX packets 3404477  bytes 3562828808 (3.3 GiB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

br0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet 192.168.128.55  netmask 255.255.255.128  broadcast 192.168.128.127
        inet6 fe80::224:beff:fec7:9895  prefixlen 64  scopeid 0x20<link>
        ether 00:24:be:00:24:be  txqueuelen 0  (Ethernet)
        RX packets 4759641  bytes 4771378631 (4.4 GiB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 2119926  bytes 3491247232 (3.2 GiB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

eth0: flags=6211<UP,BROADCAST,RUNNING,SLAVE,MULTICAST>  mtu 1500
        ether 00:24:be:00:24:be  txqueuelen 1000  (Ethernet)
        RX packets 7243938  bytes 8512402737 (7.9 GiB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 3388055  bytes 3561344335 (3.3 GiB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0
        device interrupt 18

lo: flags=73<UP,LOOPBACK,RUNNING>  mtu 16436
        inet 127.0.0.1  netmask 255.0.0.0
        inet6 ::1  prefixlen 128  scopeid 0x10<host>
        loop  txqueuelen 0  (Local Loopback)
        RX packets 338869  bytes 263959385 (251.7 MiB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 338869  bytes 263959385 (251.7 MiB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

virbr0: flags=4099<UP,BROADCAST,MULTICAST>  mtu 1500
        inet 192.168.122.1  netmask 255.255.255.0  broadcast 192.168.122.255
        ether 36:11:59:de:92:73  txqueuelen 0  (Ethernet)
        RX packets 0  bytes 0 (0.0 B)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 0  bytes 0 (0.0 B)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

wlan0: flags=6211<UP,BROADCAST,RUNNING,SLAVE,MULTICAST>  mtu 1500
        ether 00:24:be:00:24:be  txqueuelen 1000  (Ethernet)
        RX packets 74781  bytes 65709263 (62.6 MiB)
        RX errors 0  dropped 33241  overruns 0  frame 0
        TX packets 16422  bytes 1484473 (1.4 MiB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

Also, if you haven't been using netcfg already, you will probably want to update your DAEMONS array in /etc/rc.conf. Again, be sure you disable your previous networking daemon (if necessary) by placing a ! before the daemon's name (or just remove it from the array). Then add net-profiles into the array somewhere, probably closer to the beginning of the array.

Hopefully that works for you! Please share your experiences (both good and bad) in the comments! If you run into troubles, I will try to be of use, and hopefully others will chime in too.

Videos

Here are a couple of videos for those of you who are interested. The first is a lower-quality, but maybe easier-to-read-on-small-screens video. The second is just shy of 1080p size-wise.

Command Line Progress Bar With Python

Wow, it's been a very long time since I've posted on my blog. It's amazing how much time twins take up! Now they're almost 6 months old, and things are starting to calm down a bit. I will try to make time to keep my blog updated more regularly now.

Earlier today, a good friend asked me how I would handle displaying a progress bar on the command line in a Python program. I suggested a couple of things, including leaving his already working program alone for the most part and just having a separate thread display the progress bar. I'm not sure exactly why, but he decided to not use a separate thread. It didn't seem like it would be very difficult, so I spent a few minutes mocking up a quick little demo.

This is by no means the most perfect of solutions, but I think it might be useful for others who find themselves in similar circumstances. Please feel free to comment with your suggestions! This is literally my first stab at something like this, and I only spent about 5 minutes hacking it up.

Arduino-Powered Webcam Mount

Earlier this month, I completed yet another journey around the biggest star in our galaxy. Some of my beloved family members thought this would be a good occasion to send me some cash, and I also got a gift card for being plain awesome at work. Even though we really do need a bigger car and whatnot, my wife insisted that I only spend this money on myself and whatever I wanted.

Little did she know the can of worms she just opened up.

I took pretty much all of the money and blew it on stuff for my electronics projects. Up to this point, my projects have all been pretty boring simply because nothing ever moved--it was mostly just lights turning on and off or changing colors. Sure, that's fun, but things really start to get interesting when you actually interact with the physical world. With the birthday money, I was finally able to buy a bunch of servos to begin living out my childhood dream of building robots.

My first project since getting all of my new toys was a motorized webcam mount. My parents bought me a Logitech C910 for my birthday because they were tired of trying to see their grandchildren with the crappy webcam that is built into my laptop. It was a perfect opportunity to use SparkFun's tutorial for some facial tracking (thanks to OpenCV) using their Pan/Tilt Servo Bracket.

It took a little while to get everything setup properly, but SparkFun's tutorial explains perfectly how you can get everything setup if you want to repeat this project.

The problem I had with the SparkFun tutorial, though, is that it basically only gives you a standalone program that does the facial tracking and displays your webcam feed. What good is that? I actually wanted to use this rig to chat with people!! That's when I set out to figure out how to do this.

While the Processing sketch ran absolutely perfect on Windows, it didn't want to work on my Arch Linux system due to some missing dependencies that I didn't know how/care to satisfy. As such, I opted to rewrite the sketch using Python so I could do the facial tracking in Linux.

This is still a work in progress, but here's the current facial tracking program which tells the Arduino where the webcam should be pointing, along with the Arduino sketch.

Now that I could track a face and move my webcam in Linux, I still faced the same problem as before: how can I use my face-tracking, webcam-moving program during a chat with my mom? I had no idea how to accomplish this. I figured I would have to either intercept the webcam feed as it was going to Skype or the Google Talk Plugin, or I'd have to somehow consume the webcam feed and proxy it back out as a V4L2 device that the Google Talk Plugin could then use.

Trying to come up with a way of doing that seemed rather impossible (at least in straight Python), but I eventually stumbled upon a couple little gems.

So the GStreamer tutorial walks you step-by-step through different ways of using a gst-launch utility, and I found this information very useful. I learned that you can use tee to split a webcam feed and do two different things with it. I wondered if it would be possible to split one webcam feed and send it to two other V4L2 devices.

Enter v4l2loopback.

I was able to install this module from Arch's AUR, and using it was super easy (you should be root for this):

modprobe v4l2loopback devices=2

This created two new /dev/video* devices on my system, which happened to be /dev/video4 and /dev/video5 (yeah... been playing with a lot of webcams and whatnot). One device, video4, is for consumption by my face-tracking program. The other, video5, is for VLC, Skype, Google+ Hangouts, etc. After creating those devices, I simply ran the following command as a regular user:

gst-launch-0.10 v4l2src device=/dev/video1 ! \
    'video/x-raw-yuv,width=640,height=480,framerate=30/1' ! \
    tee name=t_vid ! queue ! \
    v4l2sink sync=false device=/dev/video4 t_vid. ! \
    queue ! videorate ! 'video/x-raw-yuv,framerate=30/1' ! \
    v4l2sink device=/dev/video5

There's a whole lot of stuff going on in that command that I honestly do not understand. All I know is that it made it so both my face-tracking Python program AND VLC can consume the same video feed via two different V4L2 devices! A co-worker of mine agreed to have a quick Google+ Hangout with me to test this setup under "real" circumstances (thx man). It worked :D Objective reached!

I had really hoped to find a way to handle this stuff inside Python, but I have to admit that this is a pretty slick setup. A lot of things are still hardcoded, but I do plan on making things a little more generic soon enough.

So here's my little rig (why yes, I did mount it on top of an old Kool-Aid powder thingy lid):

And a video of it in action. Please excuse the subject of the webcam video, I'm not sure where that guy came from or why he's playing with my webcam.

VirtualBox Slowing Down Mah Linux (gasp!)

As I booted up my laptop tonight, I noticed that things were extremely sluggish. It didn't take long at all to realize just how painfully slow things were. The problem didn't appear to be during boot, as the boot sequence was about as fast as it usually is. No, the speed was attacked as X was being loaded.

It has been a few days since I had time to use my laptop, and I thought I might have had to do a hard shutdown the last time I used it (for whatever reason). This lead me to wonder if it could have been something with the filesystem being corrupted. Usually a reboot solves these sort of problems for me, so that's what I chose to do. Unfortunately, it didn't do the trick. Upon rebooting, the laptop started up fine during boot, but as soon as X started up everything was slow again.

Some time when I was trying to see why my computer was running so slow, I pulled up the system monitor to see if any processes were obviously hoarding the CPU power. There were a few processes that stood out, and they all started with VBox. The next thing I thought of was the last system update I did. It involved a new kernel, and that last system update was done the last time I used my laptop.

It dawned on me that I hadn't recompiled my VirtualBox drivers since I did my system update. I kicked off the usual /etc/init.d/vboxdrv setup command. As soon as it was done, my computer was all the sudden very responsive--the way it usually is.

Whoa! Another Reason To Love Vim

I've been struggling with some misconfigured appliances at work for the past couple of days, and I was getting tired of manually diff-ing things. On a whim, I decided to ask Google if there is a better way. Turns out there is, and it uses what I already know and love: VIM. Here's a command that lets you diff two remote file using vimdiff:

vimdiff scp://user@host//path/to/file scp://user@otherhost//path/to/file

This is going to save me so much time! I hope it is as useful to you all as it is to me.

SVN Commits By User

The other day at work, I found myself needing to see a list of Subversion commits by a specific user. I spent a few minutes looking at the svn log help, but nothing seemed to be designed to show commits by user. It took me a while to find something to do the trick, but this is it:

svn log | sed -n '/username/,/-----$/ p'

Gotta love sed!