Building a tiny docker image

For a while, and purely for fun and experimentation, I've wanted to create a Docker image which does something useful and isn't huge. I knew that it's possible to use gcc to compile C code with the -static flag and then run it standalone inside a Docker container, but I'd never actually tried it. It's just one of those things I wanted to do. It means you can build your Docker image from scratch and not need any other OS files from another distribution. I was aiming for something that could be measured in kilobytes rather than megabytes.

So ... I decided to try and build my mini-webserver, dweb with the -static flag, then pack it down with upx before setting it up to run in Docker. I thought that I could get it to run the webserver in the container, but serve up files from a location on the host machine. I have no real need to do that, but I thought that it would be interesting. I'm not suggesting that this is a really good idea, but I do like the idea of avoiding bloat in docker images.

The result is on Docker Hub here and GitHub here. The compressed size of the image comes in at just 364 KB. That makes a nice change.

Well, that was fun. Perhaps one day I'll use this technique to do something useful, but at least I know how.

Another HooToo HT-TM02

A while back, my wife noticed that the HooToo HT-TM02 was on a special deal at Amazon. So she bought me another one. This is the second one I have. The one I got before is in daily use as an internet radio and is doing a fantastic job. But the problem is that I don't want to mess about with it, because I might break my radio! So this *second* one gives me something to actually play about with...

As before, I immediately installed OpenWrt on it. The installation procedure involves adding some extra storage which gives some additional space during the install process. So you need to plug in a correctly formatted USB thumbdrive. The instructions advise you to check whatever USB storage you have added is working before proceeding. But when I did it this time I forgot to check, so there was a slightly tense moment! Anyway it must have been fine, because the install went without a hitch. Phew.

Then I upgraded to the latest released version of OpenWrt (which was Chaos Calmer 15.05.1) and reset it to the default configuration. I like to work from a clean starting point. So this gives me a good hackable little linux toy to play with. I expect that most of my effort will be continue to be programmed in Nim and cross-compiled.

So here are my notes on configuring the basics when setting up a HooToo HT-TM02 with OpenWrt. This should make it easy to repeat if I need to do a factory reset. It assumes that there is a home router with an address of 192.168.1.1, so works around that. Obviously, it assumes that OpenWrt has already been installed on the HooToo. The aim is to have the HooToo connecting to an existing wifi network, so you can get to it wirelessly, and it can download packages and updates. But also, a network cable still works if required. Here goes:

  1. Start with OpenWrt defaults. Connect with a network cable and get an IP address from DHCP
  2. Don't connect to any other networks, because it will clash with the router
  3. Now point a browser to 192.168.1.1
  4. Log-in without a password and then set a new password straight away
  5. Edit the LAN address of the HooToo to 192.168.0.1 but leave DHCP on
  6. Save and then reboot the HooToo, it now should not clash with your router
  7. After the reboot, unplug and re-plug the network cable, just to be sure
  8. Point your browser to the new address, 192.168.0.1 and log in again
  9. Now, scan for your own wifi and click "Join Network"
  10. Enter your wifi passphrase
  11. Assign the wifi connection to the firewall zone "LAN", but otherwise, use the defaults and save
  12. Check the HooToo has an internet connection (eg go to: System->Software and click "Update Lists")

Connecting via a cable should now give a DHCP address in the 192.168.0.x range, so using a cable is also possible in case wifi is not an option. For me, this is a pretty good starting point; now the fun stuff begins.

Retro terminal on macOS

In the February 2017 issue of Linux Magazine (in the Linux Voice section), there was mention of Cool-Retro-Term. It gives you a terminal emulator that tries to duplicate the experience of using an old cathode ray tube monitor. But I also noticed that it comes with a dmg for installing on macOS.

And since I like a bit of retro technology, I couldn't resist trying it out. So I went a put a copy on my MacBook Pro. It really is quite cool looking, and visually reproduces an ancient monitor quite well. It even has the bend at the edge of the screen. Personally, I've turned off the glow line feature because I found it distracting. I have also made the font smaller, so that I can get more text on the screen - that's probably cheating - but it made the terminal more usable. Currently, I'm using the Apple II font from 1977.

Here I am using it to mess about with streaming radio from Madplay on one of my routers running OpenWrt:

It was really simple to install on macOS, and it really does faithfully reproduce the monitors from the old days. It's good nostalgic fun.

Upgrading to the latest release of Nim

I have had some fun in the last few of days. I decided to upgrade to the latest version of Nim ... because I had gotten a couple of releases behind I think. It is not a hard thing to do, but was just something that I had not gotten round to.

Anyway, for some reason, I decided to rebuild everything, including the Aporia IDE whilst I was at it. That's where things went a bit wrong, and sadly I had already binned the previous version of Aporia. So I was at risk of not having my IDE for Nim.

Whenever I tried to use Nimble (Nim's package manager) to rebuild Aporia, I was getting errors about dependency conflicts with GTK. Eventually, I grabbed the Aporia repository and was able to hack the aporia.nimble file. If you're really interested, I found that removing #head from where it says it requires gtk2 did the trick. Finally, I was able to build the latest Aporia. Phew, panic over.

After having figured all that out, I was looking at the Nimble repository on GitHub and noticed this build failure:

So ... it looked like bad timing. Not being able to install Aporia was being worked on. This must be due to the Nim incarnation of dependency hell I guess. But I can now report that this problem has been fixed anyway. It seems that I had just chosen the wrong moment to do my rebuild. It happens.

After a little more digging and some discussion on GitHub, it appears that I had been using a bleeding-edge copy of the Nimble package manager. So it's understandable that things might break. When I retraced my steps, I realised that I had installed Nimble from a script included with the release of Nim I had been using. That script installs the bleeding edge version, which is probably the wrong thing to do. So I logged that as an issue on the Nim repository. But it seems like the next release of Nim is just round the corner anyway. I'll try to upgrade to that version more quickly this time!

So, for the time being all is well. I have the latest release of Nim installed and Aporia is back. I've also replaced Nimble on my machine with the latest tagged version (manually), so in the meantime I should have a more stable setup. And I kind of enjoyed all this stuff anyway, so no worries.

Wifi problems with Elementary OS Freya on the ideapad 100

This week I had a problem where wifi suddenly stopped working on my Lenovo ideapad 100 15iby running Elementary OS Freya. I don't know what happened, but suddenly the machine refused to work with any access points. It would say I was connected, and I would have an IP address from DHCP... but there was no actual connection working. Chrome would just complain there was no internet, for example.

I ended up having to rebuild the Realtek rtl8723be wifi driver from the source repository here: https://github.com/lwfinger/rtlwifi_new/ but actually that was not too bad, because the instructions are quite simple. I just had to follow this post which seemed to work fine for me. But I did need to disable the sleep feature of the driver, which is mentioned as an extra step in the instructions. Otherwise the connection would keep dropping and then prompting me for my wifi password all the time.

So that was a slightly annoying problem! But I am pleased to have it sorted out. As I'm writing this I'm downloading a 750Mb file to make sure it's all OK. I'm currently at 500Mb and all is fine, so hopefully that's a job well done.

I have also noticed that Elementary OS Loki is now released, but there is no upgrade route from Freya, so I need to find some free time to do a backup and clean install. Hopefully that will be a smooth process... maybe I'll try running it 'live' first, without installing, to make sure that things work beforehand. That's a job for another day.

Vanishing mouse on my Lenovo ideapad

One problem I have found with my new Lenovo ideapad 100 15iby running Elementary OS Freya is an issue with the mouse pointer vanishing, as reported here. It seems that if you lock the machine, close the lid, or let it go to sleep, then after signing back in there is no mouse pointer. It's annoying because neither the trackpad or an external mouse seems to work.

Anyway, the solution which seems to work for me is just to replace Light-Locker with Gnome Screensaver. It means that the lock screen is not as pretty looking, but I'd rather have a mouse that works!

It's an easy fix and worth it, although it looks like future updates won't suffer from the same problem. So I look forward to trying that out when I upgrade to Elementary OS Loki. But I'm waiting for it to be released rather than using the beta.

New laptop for Linux experiments

So my trusty old Toshiba Satellite T130 has started to fail. The keyboard has started to go wrong, it seems to miss out random keystrokes, which is really annoying. It's a shame, because apart from that the machine is still working fine. But I decided that it was time for it to be replaced. I didn't want to spend very much money on a new laptop, because the old Toshiba was running Elementary OS very nicely. So I didn't need a super fast processor or anything. I ended up going for the cheapest laptop with 4GB RAM that I could find. So I am typing this on a Lenovo ideapad 100 15iby. It was less than £190, which is pretty reasonable I think. So far I am pretty happy with it.

This machine does feel cheap. It seems very plasticy and the touchpad buttons rattle a little bit as I type. I don't think that it is as robust as the Toshiba, but for the price it seems like good value. It only has a Celeron processor, but it still seems to fly along when running Elementary OS. When I first got the machine, it was running Windows and that was a slightly more painful experience. Although I only kept Windows for a few minutes - just long enough to apply the firmware updates from Lenovo so that I had the most recent BIOS. After that, I blew everything away and installed Elementary OS Freya from a DVD (the ideapad does have an internal DVD drive). I don't have anything against Windows, but I don't think that I'd be happy running Windows on this laptop - I think I would find it too slow on this hardware.

I had no problems installing Linux, everything worked right out of the box - even the special volume and brightness buttons on the keyboard.

After installing the OS, the next things I installed were:

  • Docker
  • Kate / Konsole (for coding in C)
  • Spotify
  • Chrome (and the Chromecast plugin)
  • Nim / Nimble / Aporia
  • FileZilla
  • TLP in the hope of getting more out of the battery

The ideapad version I've got does not appear to have bluetooth (I think that it's an optional extra on this machine) but I managed to find a tiny Bluetooth dongle on Amazon which seems to do the trick. So anyway, let's see how it goes!

A little more about Nim

I am still tinkering with the Nim programming language, and quite enjoying it. I find the language to be well thought out, and it's very easy to build little libraries which have unit tests included in them. I like that idea.

But I have noticed that the binaries can be quite a lot bigger than my equivalent C programs, which I suppose is to be expected. So I have also been experimenting with the UPX packer which helps to keep the file size down ... this could be useful if you want to run your Nim programs on something tiny, like a router.

In the end, I did buy a copy of the Nim in Action book, available through Manning's early access program. I'd recommend this book to people who are learning Nim, I found it easy to follow and enjoyable to read.

Nim in Action book

Because Nim has not reached v1 yet, for the moment I'm only using it for experimentation and hobbyist type stuff. But when it actually hits v1, I think that I'd consider using it for real work too.

Updated!

I have just migrated this blog to a newer version, so hopefully everything will work and all the old content will have been transferred over...  And I should be able to continue blogging again soon ... as long as I can tear myself away from learning Nim.

First steps into the world of Nim

I was recently doing a bit of reading up on the Rust programming language, but a stray comment somewhere about the Nim programming language sent me off on a bit of a tangent. The thing that really got me interested in Nim was that it compiles to C, and I noticed that this brings quite some options for portability. One of the reasons why I like programming in C is that you can run the code on all kinds of machines, from tiny embedded devices to supercomputers. But that does come at a cost, because it takes longer and you often have lots more typing to do because of all that boilerpate stuff.

But it looks like Nim would allow you to be quite productive, whilst the resulting executables should still be efficient and fast. To get some ideas, I went off to Rosetta Code and found the Nim code for a simple webserver which looks like this:

import asynchttpserver, asyncdispatch
 
proc cb(req: Request) {.async.} =
  await req.respond(Http200, "Hello, World!")
 
asyncCheck newAsyncHttpServer().serve(Port(8080), cb)
runForever()

Being able to create a webserver with just a few lines of code, and with the potential for the code to be portable and run on all kinds of devices seemed very tempting! By this point, I'd forgotten about Rust and wanted to explore Nim a bit further.

So whilst Nim has not reached v1.0 yet, it certainly looked very compelling. The compiler documentation made it look like cross-compilation was not that difficult, so I decided to try and cross-compile some code for a router running OpenWrt. Before going off and spendng a lot of time learning a new language, I wanted to see that I *really* can write portable code. I was very happy to see that in just a few minutes I had the example webserver code running on my TP-Link WR740N, as shown here:

To my amazement and joy, this really wasn't that hard. After installing Nim, I had to edit Nim/config/nim.cfg to point to my cross-compile toolchain, so I ended up with these lines:

mips.linux.gcc.exe =
 "/home/openwrt/openwrt/staging_dir/toolchain-mips_34kc_gcc-4.8-linaro_uClibc-0.9.33.2/
bin/mips-openwrt-linux-gcc"
mips.linux.gcc.linkerexe =
 "/home/openwrt/openwrt/staging_dir/toolchain-mips_34kc_gcc-4.8-linaro_uClibc-0.9.33.2/
bin/mips-openwrt-linux-gcc"

Then, after doing that I simply needed to pass the correct parameters to the Nim compiler, like this:

nim c --cpu:mips --os:linux webserver.nim

Which cross-compiled the example webserver ready for it to run on my TP-Link WR740N. That actually seems pretty awesome. I think that I need to learn more, perhaps I'll even go and buy the Nim in Action book. All this stuff worked perfectly without any trouble, which is pretty rare, so I am left feeling very impressed so far.