<?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: Istvan</title>
    <description>The latest articles on DEV Community by Istvan (@l1x).</description>
    <link>https://dev.to/l1x</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%2F34460%2F36429066-a65c-4c6f-be22-b48dd4ba50d9.jpeg</url>
      <title>DEV Community: Istvan</title>
      <link>https://dev.to/l1x</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/l1x"/>
    <language>en</language>
    <item>
      <title>Misusing Ninja</title>
      <dc:creator>Istvan</dc:creator>
      <pubDate>Tue, 21 Feb 2023 16:04:55 +0000</pubDate>
      <link>https://dev.to/l1x/misusing-ninja-3964</link>
      <guid>https://dev.to/l1x/misusing-ninja-3964</guid>
      <description>&lt;p&gt;Originally posted on: &lt;a href="https://dev.l1x.be/posts/2023/02/21/misusing-ninja/" rel="noopener noreferrer"&gt;https://dev.l1x.be/posts/2023/02/21/misusing-ninja/&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Abstract
&lt;/h2&gt;

&lt;p&gt;In the world of software development, build systems are essential tools for compiling and linking source code into executables. While there are many build systems available (make, cmake), one of the most popular and powerful is the Ninja build system.&lt;/p&gt;

&lt;p&gt;Developed by Evan Martin while working on the Chromium project at Google, Ninja is a fast, scalable, and cross-platform build system that has gained widespread adoption in the software development community. In this blog post, we'll take a closer look at the Ninja build system and its key features.&lt;/p&gt;

&lt;h2&gt;
  
  
  How Ninja Works
&lt;/h2&gt;

&lt;p&gt;At its core, Ninja is a simple, low-level build system that aims to be fast and efficient. Ninja works by generating a graph of dependencies between input files and output files and then executing a series of build commands to transform the input files into the output files.&lt;/p&gt;

&lt;p&gt;The input files are typically source code files written in a programming language such as C++, Rust, or in our case Python. The output files are the compiled object files, libraries, and executables that result from the build process. And this is where it gets interesting. You can safely ignore this part of Ninja and just use it as a dag orchestrator that executes commands in a certain order.&lt;/p&gt;

&lt;p&gt;Ninja uses a file format called "build.ninja" to define the build graph and specify the build commands. The build.ninja file is a text file that describes the dependencies between the input and output files or in our case the build steps.&lt;/p&gt;

&lt;h2&gt;
  
  
  Key Features of Ninja
&lt;/h2&gt;

&lt;p&gt;One of the main advantages of Ninja is its speed. Because Ninja generates a build graph that only includes the necessary build steps, it can execute builds quickly and efficiently. Additionally, Ninja can scale to handle large projects with many dependencies, making it a popular choice for building complex software applications. For our use case, it is not that much use but in case you are using it for a C++ project it is pretty good.&lt;/p&gt;

&lt;p&gt;Another key feature of Ninja is its cross-platform support. Ninja is designed to work on multiple operating systems, including Windows, macOS, and Linux, which makes it easy to use in a variety of development environments. This is true if you have a way of making sure that the tools that are used in the build are present and have the same CLI on all systems you run your builds on.&lt;/p&gt;

&lt;h2&gt;
  
  
  Getting Started with Ninja
&lt;/h2&gt;

&lt;p&gt;I usually learn by example and there aren't many examples around. I have read the original documentation and tried a few things out but finally, I understand how all things hang together.&lt;/p&gt;

&lt;p&gt;There are 3 things that you need to know about a ninja build file:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;rule&lt;/li&gt;
&lt;li&gt;build&lt;/li&gt;
&lt;li&gt;dependency&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A rule is a description and a command that gets executed when the rule is invoked.&lt;/p&gt;

&lt;p&gt;A build step is just calling a rule (or potentially multiple rules using dependencies).&lt;/p&gt;

&lt;p&gt;A dependency is a concept of describing a relationship between rules.&lt;/p&gt;

&lt;p&gt;Let's have a look at a basic example.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;rule ok
  command = echo "ok"

build ok: ok
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Invoking it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;❯ ninja ok
&lt;span class="o"&gt;[&lt;/span&gt;1/1] &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"ok"&lt;/span&gt;
ok
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's add a build that has two steps (sometimes called stages or targets).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;rule one
  command = echo "one"

rule two
  command = echo "two"

build one: one
build two: two || one
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With two pipe characters, we can express dependency between the build stages.&lt;/p&gt;

&lt;p&gt;Invoking the build:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;❯ ninja one
&lt;span class="o"&gt;[&lt;/span&gt;1/1] &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"one"&lt;/span&gt;
one
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;❯ ninja two
&lt;span class="o"&gt;[&lt;/span&gt;1/2] &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"one"&lt;/span&gt;
one
&lt;span class="o"&gt;[&lt;/span&gt;2/2] &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"two"&lt;/span&gt;
two
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This means we cannot forget to execute the first step when executing the second.&lt;/p&gt;

&lt;h2&gt;
  
  
  Using Ninja for building and deploying to the cloud
&lt;/h2&gt;

&lt;p&gt;There is no point in writing an article without Docker in it so let's put Docker into Ninja.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;version   = 0.6.0
aws_account_id = 11111111111


rule login-to-ecr
  command = aws ecr get-login-password --region eu-west-1 | docker login --username AWS --password-stdin ${aws_account_id}.dkr.ecr.eu-west-1.amazonaws.com
  description = Logging in to ECR

rule init
  command = env | egrep AWS_PROFILE
  description = Displaying AWS_PROFILE


rule build-image
  command = docker build . -t depoxy:backend-api-${version} --file Dockerfile
  description = Building depoxy:backend-api-${version}

rule tag-image
  command = docker tag depoxy:backend-api-${version} ${aws_account_id}.dkr.ecr.eu-west-1.amazonaws.com/depoxy:backend-api-${version}
  description = Tagging depoxy:backend-api-${version}

rule upload-image
  command = docker push ${aws_account_id}.dkr.ecr.eu-west-1.amazonaws.com/depoxy:backend-api-${version}
  description = Push depoxy:backend-api-${version}



build login-to-ecr: login-to-ecr
build init: init || login-to-ecr
build build-image: build-image || init
build tag-image: tag-image || build-image
build upload-image: upload-image || tag-image

default login-to-ecr init build-image tag-image upload-image
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There goes, a simple docker workflow implemented in Ninja. We use similar workflows to upload files to AWS and deploy with Terraform too. This unified our different build efforts mostly using YAML for CI/CD and made sure we do not forget anything while not needing to write a tonne of YAML.&lt;/p&gt;

&lt;p&gt;The reduction from the YAML-based workflows is pretty significant:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;+229 −1,633
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  To get started with Ninja
&lt;/h2&gt;

&lt;p&gt;To get started with Ninja, you'll need to install the Ninja build system on your development machine. Ninja can be installed from package managers on the most popular operating systems, or you can download the source code and build it manually.&lt;/p&gt;

&lt;p&gt;Once you have Ninja installed, you'll need to create a build.ninja file that describes your project's build process. You can create this file manually, or you can use a build system generator such as gn or Meson to generate it automatically.&lt;/p&gt;

&lt;p&gt;Finally, you can run the Ninja build command to execute the build process and create the output files. Ninja will automatically track changes to input files and re-execute the build commands as needed, ensuring that your output files are always up-to-date.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;The Ninja build system is a powerful and efficient tool for building software applications. With its speed, scalability, and cross-platform support, Ninja is a great choice for developers working on a wide range of projects. Whether you're building a small utility or a large, complex application, Ninja can help you streamline your build process and get your software up and running quickly. It helped us to move from YAML to a much better alternative while reducing the complexity of the CI/CD workflows. The next is to find a CI/CD platform that supports Ninja files or maybe to create a project that does exactly that.&lt;/p&gt;

</description>
      <category>ninja</category>
      <category>aws</category>
      <category>cloud</category>
      <category>devops</category>
    </item>
    <item>
      <title>Diving into Firecracker with Alpine</title>
      <dc:creator>Istvan</dc:creator>
      <pubDate>Sun, 13 Dec 2020 22:23:03 +0000</pubDate>
      <link>https://dev.to/l1x/diving-into-firecracker-with-alpine-2h2</link>
      <guid>https://dev.to/l1x/diving-into-firecracker-with-alpine-2h2</guid>
      <description>&lt;h2&gt;
  
  
  Article series
&lt;/h2&gt;

&lt;p&gt;Originally posted on:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;1st part :: &lt;a href="https://dev.l1x.be/posts/2020/11/22/getting-started-with-firecracker-on-raspberry-pi/" rel="noopener noreferrer"&gt;https://dev.l1x.be/posts/2020/11/22/getting-started-with-firecracker-on-raspberry-pi/&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;2nd part :: &lt;a href="https://dev.l1x.be/posts/2020/12/13/diving-into-firecracker-with-alpine/" rel="noopener noreferrer"&gt;https://dev.l1x.be/posts/2020/12/13/diving-into-firecracker-with-alpine/&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Intro
&lt;/h2&gt;

&lt;p&gt;Last time in the 1st article I briefly introduced Firecracker as a lightweight virtualization/containerization solution for extreme-scale (like AWS Lambda functions). This time around I am going to dig a bit deeper into the API and the management of microVMs. I am going to install Alpine on RPI, install Rust and Python, Docker, get the Linux kernel source and compile a new kernel with minimal config, compile our own Firecracker and then create a new rootfs to be able to boot up a guest. Most of these steps are optional, you can use the stock kernel the Firecracker team provides or download Firecracker release from Github.&lt;/p&gt;

&lt;h2&gt;
  
  
  Setup Alpine
&lt;/h2&gt;

&lt;p&gt;If you do not care about Alpine on RPI you can jump to the Firecracker section.&lt;/p&gt;

&lt;p&gt;I would like to keep going with &lt;a href="https://amzn.to/2Klb9fx" rel="noopener noreferrer"&gt;Raspberry Pi 4B 8GB&lt;/a&gt; or &lt;a href="https://amzn.to/2KeohTO" rel="noopener noreferrer"&gt;Raspberry Pi 4B 4GB&lt;/a&gt; for many reasons. It is a small system that you can easily hack on without any change on your desktop. It is also an ARM64 (ARM Cortex-A72) system that has great performance even without active cooling. I usually use it with a &lt;a href="https://amzn.to/3naOS2L" rel="noopener noreferrer"&gt;alu case&lt;/a&gt; that provides the best heat dispersion and a cool CPU. It has enough CPU power and memory to compile any software including Firecracker, the Linux kernel, and more. Since this project is a side project I don't care how long it takes to finish a new kernel, usually finishes within 2 hours (I might get exact timing later).&lt;/p&gt;

&lt;p&gt;Another item on my to-do list is to get Alpine Linux as both the host and the guest system. For those who do not know Alpine is a small Linux distribution designed for security, simplicity, and resource efficiency. It comes with sane defaults and Musl as its C standard library. Alpine uses its own package management system, apk-tools, providing super-fast package installation. Alpine allows a very small system with minimal installation being around 130 MB. The init system is the lightweight OpenRC, Alpine does not use systemd. This was the primary reason I wanted to get into Alpine.&lt;/p&gt;

&lt;h3&gt;
  
  
  Installing Alpine on RPI 4
&lt;/h3&gt;

&lt;p&gt;This is the most complicated part of the setup because RPI has a special boot procedure that uses a FAT partition and the GPU. When installing Alpine first you need to create a FAT partition at the beginning of the SD card with MBR. I am using MacOS this time. I am pretty sure it is easy to translate this to Linux (not sure about Windows.)&lt;/p&gt;

&lt;h4&gt;
  
  
  Creating the partition
&lt;/h4&gt;

&lt;p&gt;My microSD card is /dev/disk6. I create a partition with the name ALP (1024MB), then activate it with fdisk.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;diskutil list
diskutil partitionDisk /dev/disk6 MBR &lt;span class="s2"&gt;"FAT32"&lt;/span&gt; ALP 1024MB &lt;span class="s2"&gt;"Free Space"&lt;/span&gt; SYS R
&lt;span class="nb"&gt;sudo &lt;/span&gt;fdisk &lt;span class="nt"&gt;-e&lt;/span&gt; /dev/disk6
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; f 1
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; w
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;exit&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After this command runs successfully MacOS mounts the newly created partition in /Volumes/ALP.&lt;/p&gt;

&lt;h4&gt;
  
  
  Downloading Alpine and writing it to the SD card
&lt;/h4&gt;

&lt;p&gt;You can initiate the download anywhere, make sure the previously created partition is mounted.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;wget http://dl-cdn.alpinelinux.org/alpine/v3.12/releases/aarch64/alpine-rpi-3.12.1-aarch64.tar.gz
&lt;span class="nb"&gt;tar &lt;/span&gt;xzvf alpine-rpi-3.12.1-aarch64.tar.gz &lt;span class="nt"&gt;-C&lt;/span&gt; /Volumes/ALP/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Configuring RPI boot
&lt;/h4&gt;

&lt;p&gt;This part is optional, you can disable audio, wifi, Bluetooth, etc and enable UART, configure GPU mem. The full documentation is here:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.raspberrypi.org/documentation/configuration/config-txt/" rel="noopener noreferrer"&gt;https://www.raspberrypi.org/documentation/configuration/config-txt/&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cd&lt;/span&gt; /Volumes/ALP/
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s1"&gt;'dtparam=audio=off'&lt;/span&gt;          &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; usercfg.txt
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s1"&gt;'dtoverlay=pi3-disable-wifi'&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; usercfg.txt
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s1"&gt;'enable_uart=1'&lt;/span&gt;              &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; usercfg.txt
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s1"&gt;'gpu_mem=64'&lt;/span&gt;                 &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; usercfg.txt
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s1"&gt;'disable_overscan=1'&lt;/span&gt;         &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; usercfg.txt
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You are ready to remove the SD card.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cd
&lt;/span&gt;diskutil eject /dev/disk6
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Booting and configuring Alpine
&lt;/h4&gt;

&lt;p&gt;After inserting the SD card into the RPI you can boot it up. I am using a special converter that converts the mini HDMI to a normal HDMI &lt;a href="https://amzn.to/3452Ziz" rel="noopener noreferrer"&gt;converter&lt;/a&gt; that makes it easy to connect a TV or a monitor to the PI. I usually connect the device to the network with an ethernet cable and plug in a wired USB keyboard.&lt;/p&gt;

&lt;p&gt;Once the device is booting up you can login with root (no password).&lt;/p&gt;

&lt;p&gt;Alpine has a neat tool to configure a new system. It asks a few questions about keyboard layout and timezone, also makes you create a root password.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;setup-alpine
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once setup-alpine is done you need to change a few things around because up to this moment you operated on the FAT partition. After updating the system and adding cfdisk you can create a new partition and use the remaining space on the SD card to have a proper system. In cfdisk, select “Free space” and the option “New”. It suggests using the entire available space, just press enter, then select the option “primary”, followed by “Write”. Type “yes” to write the partition table to disk, then select “Quit”.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;apk update
apk upgrade
apk add cfdisk e2fsprogs
cfdisk /dev/mmcblk0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once our new partition is ready you need to create a filesystem on it and install a basic Alpine system with setup-disk. In "sys" mode, it's an installer, it permanently installs Alpine on the disk. Ignore the errors, there might be some while executing setup-disk.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;mkfs.ext4 /dev/mmcblk0p2
mount /dev/mmcblk0p2 /mnt
setup-disk &lt;span class="nt"&gt;-m&lt;/span&gt; sys /mnt
mount &lt;span class="nt"&gt;-o&lt;/span&gt; remount,rw /media/mmcblk0p1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This section is what I found on the Alpine wiki and it works. There might be an easier way.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;rm&lt;/span&gt; &lt;span class="nt"&gt;-f&lt;/span&gt; /media/mmcblk0p1/boot/&lt;span class="k"&gt;*&lt;/span&gt;
&lt;span class="nb"&gt;cd&lt;/span&gt; /mnt
&lt;span class="nb"&gt;rm &lt;/span&gt;boot/boot
&lt;span class="nb"&gt;mv &lt;/span&gt;boot/&lt;span class="k"&gt;*&lt;/span&gt; /media/mmcblk0p1/boot/
&lt;span class="nb"&gt;rm&lt;/span&gt; &lt;span class="nt"&gt;-Rf&lt;/span&gt; boot
&lt;span class="nb"&gt;mkdir &lt;/span&gt;media/mmcblk0p1
&lt;span class="nb"&gt;ln&lt;/span&gt; &lt;span class="nt"&gt;-s&lt;/span&gt; media/mmcblk0p1/boot boot
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There are only two steps left, adjusting fstab and cmdline.txt.&lt;/p&gt;

&lt;p&gt;Fstab:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;UUID&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;your-uui-id  /                 ext4  rw,relatime  0 0
/dev/mmcblk0p1    /media/mmcblk0p1  vfat  rw           0 0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Add the following content to etc/fstab (please note no starting /).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;vi etc/fstab
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Appending the following to the cmdline.txt:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;root&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;/dev/mmcblk0p2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;vi /media/mmcblk0p1/cmdline.txt
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It looks like this for me:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cat&lt;/span&gt; /media/mmcblk0p1/cmdline.txt
&lt;span class="nv"&gt;modules&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;loop,squashfs,sd-mod,usb-storage quiet &lt;span class="nv"&gt;console&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;tty1 &lt;span class="nv"&gt;root&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;/dev/mmcblk0p2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I am not sure if lbu commit is necessary here. When Alpine Linux boots in diskless mode, initially it only loads a few required packages from the boot device by default. But local adjustments in RAM are possible, e.g. by installing a package or adjusting some configuration.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;lbu commit &lt;span class="nt"&gt;-d&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can reboot and log in with root and verify everything is working. Going forward it is best to have a user other than root.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;adduser l1x
addgroup l1x wheel
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I usually add the following packages and start to use sudo going forward:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;apk add tmux fish ninja clang g++ &lt;span class="nb"&gt;sudo &lt;/span&gt;git python3 socat curl vim procps
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Make sure that wheel group can use sudo:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;%wheel &lt;span class="nv"&gt;ALL&lt;/span&gt;&lt;span class="o"&gt;=(&lt;/span&gt;ALL&lt;span class="o"&gt;)&lt;/span&gt; NOPASSWD: ALL
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Changing my shell to fish:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;l1x:x:1000:1000:Linux User,,,:/home/l1x:/usr/bin/fish
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Hopefully, by now you have a working environment. I use a bigger drive for /data where I store all the development folders.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;l1x@alpine ~&amp;gt; mount | column &lt;span class="nt"&gt;-t&lt;/span&gt; | egrep &lt;span class="s1"&gt;'^/dev'&lt;/span&gt;
/dev/mmcblk0p2  on  /                 &lt;span class="nb"&gt;type  &lt;/span&gt;ext4        &lt;span class="o"&gt;(&lt;/span&gt;rw,relatime&lt;span class="o"&gt;)&lt;/span&gt;
/dev/mmcblk0p1  on  /media/mmcblk0p1  &lt;span class="nb"&gt;type  &lt;/span&gt;vfat        &lt;span class="o"&gt;(&lt;/span&gt;rw,relatime,fmask&lt;span class="o"&gt;=&lt;/span&gt;0022,dmask&lt;span class="o"&gt;=&lt;/span&gt;0022,codepage&lt;span class="o"&gt;=&lt;/span&gt;437,...&lt;span class="o"&gt;)&lt;/span&gt;
/dev/sda1       on  /data             &lt;span class="nb"&gt;type  &lt;/span&gt;xfs         &lt;span class="o"&gt;(&lt;/span&gt;rw,relatime,attr2,inode64,logbufs&lt;span class="o"&gt;=&lt;/span&gt;8,logbsize&lt;span class="o"&gt;=&lt;/span&gt;32k,...&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Setting up Firecracker dev environment
&lt;/h2&gt;

&lt;p&gt;Once you logged in via SSH to your Alpine system make sure you have the dev tools you are going to need. I usually use the following tools, and some more:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;apk add tmux git python3 curl vim
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I was trying to figure out how to install Rust on ARM64 linux and the most straightforward way looks like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;--proto&lt;/span&gt; &lt;span class="s1"&gt;'=https'&lt;/span&gt; &lt;span class="nt"&gt;--tlsv1&lt;/span&gt;.2 &lt;span class="nt"&gt;-sSf&lt;/span&gt; https://sh.rustup.rs | sh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you want to compile Firecracker yourself you also need Docker. Docker for this version of Alpine lives in the community repo. Simply append the community line to your repositories:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cat&lt;/span&gt; /etc/apk/repositories
&lt;span class="c"&gt;#/media/mmcblk0p1/apks&lt;/span&gt;
http://your.nearest.mirror/mirrors/pub/alpine/v3.12/main
http://your.nearest.mirror/mirrors/pub/alpine/v3.12/community
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Installing Docker:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;apk add docker
&lt;span class="nb"&gt;sudo &lt;/span&gt;addgroup &lt;span class="nv"&gt;$USER&lt;/span&gt; docker
&lt;span class="nb"&gt;sudo &lt;/span&gt;rc-update add docker boot
&lt;span class="nb"&gt;sudo &lt;/span&gt;service docker start
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After Docker is running you can clone the Firecracker repo:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone git@github.com:firecracker-microvm/firecracker.git
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Before you can compile a release you need to install two more packages:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;apk add bash ncurses
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now you can compile the Firecracker binaries:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;./tools/devtool build &lt;span class="nt"&gt;--release&lt;/span&gt; &lt;span class="nt"&gt;--libc&lt;/span&gt; musl
&lt;span class="o"&gt;[&lt;/span&gt;Firecracker devtool] About to pull docker image fcuvm/dev:v24
&lt;span class="o"&gt;[&lt;/span&gt;Firecracker devtool] Continue? &lt;span class="o"&gt;(&lt;/span&gt;y/n&lt;span class="o"&gt;)&lt;/span&gt; y
Digest: sha256:12b8efe9a91d31349a6241b7d81c26d50bf913e369b5845a921be720e5de5796
Status: Downloaded newer image &lt;span class="k"&gt;for &lt;/span&gt;fcuvm/dev:v24
docker.io/fcuvm/dev:v24
&lt;span class="o"&gt;[&lt;/span&gt;Firecracker devtool] Starting build &lt;span class="o"&gt;(&lt;/span&gt;release, musl&lt;span class="o"&gt;)&lt;/span&gt; ...


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There are few binaries generated:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;ls &lt;/span&gt;build/cargo_target/aarch64-unknown-linux-musl/release/&lt;span class="o"&gt;{&lt;/span&gt;firecracker,jailer&lt;span class="o"&gt;}&lt;/span&gt;
 build/cargo_target/aarch64-unknown-linux-musl/release/firecracker&lt;span class="k"&gt;*&lt;/span&gt;
 build/cargo_target/aarch64-unknown-linux-musl/release/jailer&lt;span class="k"&gt;*&lt;/span&gt;
file build/cargo_target/aarch64-unknown-linux-musl/release/&lt;span class="o"&gt;{&lt;/span&gt;firecracker,jailer&lt;span class="o"&gt;}&lt;/span&gt;
build/cargo_target/aarch64-unknown-linux-musl/release/firecracker:
ELF 64-bit LSB executable, ARM aarch64, version 1 &lt;span class="o"&gt;(&lt;/span&gt;GNU/Linux&lt;span class="o"&gt;)&lt;/span&gt;,
statically linked, BuildID[sha1]&lt;span class="o"&gt;=&lt;/span&gt;4da58d970ac0c51aad276309866f2b701cc397cd, with debug_info, not stripped
build/cargo_target/aarch64-unknown-linux-musl/release/jailer:
ELF 64-bit LSB executable, ARM aarch64, version 1 &lt;span class="o"&gt;(&lt;/span&gt;GNU/Linux&lt;span class="o"&gt;)&lt;/span&gt;,
statically linked, BuildID[sha1]&lt;span class="o"&gt;=&lt;/span&gt;3e3c780b4e0fbd74b661c54f11192f9a15b89cba, with debug_info, not stripped
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Using these binaries we can create the VMs.&lt;/p&gt;

&lt;h2&gt;
  
  
  Creating a microVM
&lt;/h2&gt;

&lt;p&gt;Before getting started, there are multiple ways to start a microVM with Firecracker. Here are a few:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;starting up the Firecracker binary and through the Unix socket configure it and then start a VM&lt;/li&gt;
&lt;li&gt;starting Firecracker with a complete VM config without the Unix socket API&lt;/li&gt;
&lt;li&gt;starting Firecracker with Jailer so it uses cgroups to containerize the VM&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We are going to check out the first way.&lt;/p&gt;

&lt;p&gt;When I started to fiddle with FC I was trying to use the official CLI (Firectl) and because it is written in Go you need to have a Go compiler if you would like to build it yourself. I did not like this option too much so I have created a new CLI called &lt;a href="https://github.com/l1x/pattacu" rel="noopener noreferrer"&gt;Pattacu&lt;/a&gt; written in Python.&lt;/p&gt;

&lt;h3&gt;
  
  
  Compiling a new kernel
&lt;/h3&gt;

&lt;p&gt;This is optional. You can download the official kernel from Firecracker:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/firecracker-microvm/firecracker/blob/master/docs/rootfs-and-kernel-setup.md" rel="noopener noreferrer"&gt;https://github.com/firecracker-microvm/firecracker/blob/master/docs/rootfs-and-kernel-setup.md&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you decided to compile a new Linux kernel there are few things you need to have.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;kernel-source&lt;/li&gt;
&lt;li&gt;tools to compile&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I usually use one of the long term releases:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://cdn.kernel.org/pub/linux/kernel/v4.x/linux-4.14.212.tar.xz" rel="noopener noreferrer"&gt;https://cdn.kernel.org/pub/linux/kernel/v4.x/linux-4.14.212.tar.xz&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://cdn.kernel.org/pub/linux/kernel/v4.x/linux-4.19.163.tar.xz" rel="noopener noreferrer"&gt;https://cdn.kernel.org/pub/linux/kernel/v4.x/linux-4.19.163.tar.xz&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://cdn.kernel.org/pub/linux/kernel/v5.x/linux-5.4.83.tar.xz" rel="noopener noreferrer"&gt;https://cdn.kernel.org/pub/linux/kernel/v5.x/linux-5.4.83.tar.xz&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;After extracting the kernel source to a folder you can grab the config I have prepared with some help from an OpenWrt developer:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;wget https://raw.githubusercontent.com/l1x/pattacu/main/kernel-config/microvm-kernel-arm64.4.19.config &lt;span class="nt"&gt;-O&lt;/span&gt; .config
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There are more tools required for building a new kernel:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;apk add bison clang make flex linux-headers openssl-dev perl
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With these the kernel can be compiled:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;make olddefconfig
&lt;span class="nb"&gt;time &lt;/span&gt;make Image.gz
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is going to take a while. After that, the kernel file we need for the microVM will be arch/arm64/boot/Image.&lt;/p&gt;

&lt;h3&gt;
  
  
  Creating a new rootfs
&lt;/h3&gt;

&lt;p&gt;This is optional. You can download the official rootfs from Firecracker:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/firecracker-microvm/firecracker/blob/master/docs/rootfs-and-kernel-setup.md" rel="noopener noreferrer"&gt;https://github.com/firecracker-microvm/firecracker/blob/master/docs/rootfs-and-kernel-setup.md&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;There is a project that can be used to create an Alpine rootfs. With a bit of additional shell scripting, we can create a customized rootfs that can boot up in Firecracker.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;wget https://raw.githubusercontent.com/alpinelinux/alpine-make-rootfs/v0.5.1/alpine-make-rootfs &lt;span class="nt"&gt;-O&lt;/span&gt; alpine-make-rootfs &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s1"&gt;'a7159f17b01ad5a06419b83ea3ca9bbe7d3f8c03 alpine-make-rootfs'&lt;/span&gt; | &lt;span class="nb"&gt;sha1sum&lt;/span&gt; &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nb"&gt;exit &lt;/span&gt;1
&lt;span class="nb"&gt;chmod&lt;/span&gt; +x alpine-make-rootfs
&lt;span class="nb"&gt;sudo&lt;/span&gt; ./alpine-make-rootfs &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--branch&lt;/span&gt; v3.12 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--packages&lt;/span&gt; &lt;span class="s1"&gt;'openrc util-linux'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--timezone&lt;/span&gt; &lt;span class="s1"&gt;'Europe/Budapest'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--script-chroot&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    rootfs-&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;date&lt;/span&gt; +%Y%m%d&lt;span class="si"&gt;)&lt;/span&gt;.tar.gz - &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="no"&gt;SHELL&lt;/span&gt;&lt;span class="sh"&gt;'
    ln -s agetty /etc/init.d/agetty.ttyS0
    echo ttyS0 &amp;gt; /etc/securetty
    echo 'nameserver 1.1.1.1' &amp;gt; /etc/resolv.conf
    rc-update add agetty.ttyS0 default
    rc-update add devfs boot
    rc-update add procfs boot
    rc-update add sysfs boot
&lt;/span&gt;&lt;span class="no"&gt;SHELL

&lt;/span&gt;&lt;span class="nb"&gt;dd &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;/dev/zero &lt;span class="nv"&gt;of&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;alpine.ext4 &lt;span class="nv"&gt;bs&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;1 &lt;span class="nv"&gt;count&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;1 &lt;span class="nv"&gt;seek&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;256M
mkfs.ext4 alpine.ext4
&lt;span class="nb"&gt;sudo mkdir&lt;/span&gt; /tmp/alpine-rootfs
&lt;span class="nb"&gt;sudo &lt;/span&gt;mount alpine.ext4 /tmp/alpine-rootfs
&lt;span class="nb"&gt;sudo tar &lt;/span&gt;xzvf rootfs-&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;date&lt;/span&gt; +%Y%m%d&lt;span class="si"&gt;)&lt;/span&gt;.tar.gz &lt;span class="nt"&gt;-C&lt;/span&gt; /tmp/alpine-rootfs
&lt;span class="nb"&gt;sudo &lt;/span&gt;umount /tmp/alpine-rootfs
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Configuring host networking
&lt;/h3&gt;

&lt;p&gt;If you would like to use networking with Firecracker the host network has to be configured to support this.&lt;/p&gt;

&lt;p&gt;First loading the kernel driver, installing iproute2 (the ip command):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;modprobe tun
&lt;span class="nb"&gt;sudo &lt;/span&gt;apk add iproute2 acl
&lt;span class="nb"&gt;sudo &lt;/span&gt;ip tuntap add tap0 mode tap
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Second, configuring networking and forwarding:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;ip addr add 172.16.0.1/24 dev tap0
&lt;span class="nb"&gt;sudo &lt;/span&gt;ip &lt;span class="nb"&gt;link set &lt;/span&gt;tap0 up
&lt;span class="nb"&gt;sudo &lt;/span&gt;sh &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="s2"&gt;"echo 1 &amp;gt; /proc/sys/net/ipv4/ip_forward"&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;iptables &lt;span class="nt"&gt;-t&lt;/span&gt; nat &lt;span class="nt"&gt;-A&lt;/span&gt; POSTROUTING &lt;span class="nt"&gt;-o&lt;/span&gt; eth0 &lt;span class="nt"&gt;-j&lt;/span&gt; MASQUERADE
&lt;span class="nb"&gt;sudo &lt;/span&gt;iptables &lt;span class="nt"&gt;-A&lt;/span&gt; FORWARD &lt;span class="nt"&gt;-m&lt;/span&gt; conntrack &lt;span class="nt"&gt;--ctstate&lt;/span&gt; RELATED,ESTABLISHED &lt;span class="nt"&gt;-j&lt;/span&gt; ACCEPT
&lt;span class="nb"&gt;sudo &lt;/span&gt;iptables &lt;span class="nt"&gt;-A&lt;/span&gt; FORWARD &lt;span class="nt"&gt;-i&lt;/span&gt; tap0 &lt;span class="nt"&gt;-o&lt;/span&gt; eth0 &lt;span class="nt"&gt;-j&lt;/span&gt; ACCEPT
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Enablig non-root access
&lt;/h3&gt;

&lt;p&gt;I like to run Firecracker as a non-root user and it is easy to achieve:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;setfacl &lt;span class="nt"&gt;-m&lt;/span&gt; u:&lt;span class="nv"&gt;$USER&lt;/span&gt;:rw /dev/kvm
&lt;span class="nb"&gt;sudo &lt;/span&gt;setcap &lt;span class="nv"&gt;cap_net_bind_service&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;+ep /usr/bin/socat
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This gives your user access to /dev/kvm and enabled socat bind to port 80 without root, using the new Linux kernel capabilities.&lt;/p&gt;

&lt;h3&gt;
  
  
  Booting up the microVM using Pattacu
&lt;/h3&gt;

&lt;p&gt;For running Pattacu the only dependency is Python3 (I have not tested it with Python2).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;apk add python3
&lt;span class="nb"&gt;cd
&lt;/span&gt;python3 &lt;span class="nt"&gt;-m&lt;/span&gt; venv venv
&lt;span class="c"&gt;# Depending on your shell&lt;/span&gt;
&lt;span class="nb"&gt;.&lt;/span&gt; ~/venv/bin/activate.fish
&lt;span class="nb"&gt;cd&lt;/span&gt; /where/you/store/repos
git clone git@github.com:l1x/pattacu.git
&lt;span class="nb"&gt;cd &lt;/span&gt;pattacu
pip &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-r&lt;/span&gt; requirements.txt
./bin/pattacu &lt;span class="nt"&gt;-h&lt;/span&gt;
./bin/pattacu &lt;span class="nt"&gt;-h&lt;/span&gt;
usage: pattacu &lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="nt"&gt;-h&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;describe-instance,put-boot-source,put-drives,put-machine-config,put-network-interfaces,put-actions&lt;span class="o"&gt;}&lt;/span&gt; ...

positional arguments:
  &lt;span class="o"&gt;{&lt;/span&gt;describe-instance,put-boot-source,put-drives,put-machine-config,put-network-interfaces,put-actions&lt;span class="o"&gt;}&lt;/span&gt;

optional arguments:
  &lt;span class="nt"&gt;-h&lt;/span&gt;, &lt;span class="nt"&gt;--help&lt;/span&gt;            show this &lt;span class="nb"&gt;help &lt;/span&gt;message and &lt;span class="nb"&gt;exit
&lt;/span&gt;2020-12-13 20:35:01 INFO Quitting...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For starting up a microVM there are few things to be configured:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;starting Firecracker&lt;/li&gt;
&lt;li&gt;starting socat&lt;/li&gt;
&lt;li&gt;configuring which kernel to boot up as the guest&lt;/li&gt;
&lt;li&gt;configuring which rootfs to be used by the guest&lt;/li&gt;
&lt;li&gt;configuring guest machine config&lt;/li&gt;
&lt;li&gt;configuring guest networking&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In this order:&lt;/p&gt;

&lt;h4&gt;
  
  
  Starting Firecracker
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;socket_path&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;/data/fc/firecracker.socket
&lt;span class="nb"&gt;rm&lt;/span&gt; &lt;span class="nt"&gt;-f&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$socket_path&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
./firecracker &lt;span class="nt"&gt;--api-sock&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$socket_path&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="nt"&gt;--level&lt;/span&gt; Debug &lt;span class="nt"&gt;--log-path&lt;/span&gt; firecracker.log &lt;span class="nt"&gt;--show-log-origin&lt;/span&gt; &lt;span class="nt"&gt;--id&lt;/span&gt; fc-test
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Starting socat
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;socat &lt;span class="nt"&gt;-v&lt;/span&gt; &lt;span class="nt"&gt;-v&lt;/span&gt; TCP-LISTEN:80,reuseaddr,fork UNIX-CLIENT:&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$socket_path&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Configuring which kernel to boot up as the guest
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;./bin/pattacu put-boot-source &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--boot-args&lt;/span&gt; &lt;span class="s2"&gt;"keep_bootcon console=ttyS0 reboot=k panic=1 pci=off ip=172.16.0.42::172.16.0.1:255.255.255.0::eth0:off"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--kernel-image-path&lt;/span&gt; /linux/arm64/kernel/4.14.210.image

2020-12-13 20:44:12 INFO ARGS: Namespace&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;boot_args&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'keep_bootcon console=ttyS0
reboot=k panic=1 pci=off ip=172.16.0.42::172.16.0.1:255.255.255.0::eth0:off'&lt;/span&gt;, &lt;span class="nv"&gt;func&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'put-boot-source'&lt;/span&gt;,
&lt;span class="nv"&gt;initrd_path&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;None, &lt;span class="nv"&gt;kernel_image_path&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'/linux/arm64/kernel/4.14.210.image'&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
2020-12-13 20:44:12 INFO &lt;span class="o"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;"boot_args"&lt;/span&gt;: &lt;span class="s2"&gt;"keep_bootcon console=ttyS0 reboot=k
panic=1 pci=off ip=172.16.0.42::172.16.0.1:255.255.255.0::eth0:off"&lt;/span&gt;,
&lt;span class="s2"&gt;"kernel_image_path"&lt;/span&gt;: &lt;span class="s2"&gt;"/linux/arm64/kernel/4.14.210.image"&lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;
2020-12-13 20:44:12 INFO HTTP Status: 204 HTTP Reason:  HTTP body: &lt;span class="s2"&gt;""&lt;/span&gt;
2020-12-13 20:44:12 INFO Quitting...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Configuring which rootfs to be used by the guest
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;./bin/pattacu put-drives &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--drive-id&lt;/span&gt; rootfs &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--path&lt;/span&gt; /data/pattacu/rootfs/example-20201213.tar.gz &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--read-only&lt;/span&gt; &lt;span class="nb"&gt;false&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--root-device&lt;/span&gt; &lt;span class="nb"&gt;true
&lt;/span&gt;2020-12-13 20:46:30 INFO ARGS: Namespace&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;drive_id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'rootfs'&lt;/span&gt;,
&lt;span class="nv"&gt;func&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'put-drives'&lt;/span&gt;, &lt;span class="nv"&gt;path&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'/data/pattacu/rootfs/example-20201213.tar.gz'&lt;/span&gt;, &lt;span class="nv"&gt;read_only&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;False, &lt;span class="nv"&gt;root_device&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;True&lt;span class="o"&gt;)&lt;/span&gt;
2020-12-13 20:46:30 INFO &lt;span class="o"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;"drive_id"&lt;/span&gt;: &lt;span class="s2"&gt;"rootfs"&lt;/span&gt;, &lt;span class="s2"&gt;"path_on_host"&lt;/span&gt;:
&lt;span class="s2"&gt;"/data/pattacu/rootfs/example-20201213.tar.gz"&lt;/span&gt;, &lt;span class="s2"&gt;"is_root_device"&lt;/span&gt;: &lt;span class="nb"&gt;true&lt;/span&gt;, &lt;span class="s2"&gt;"is_read_only"&lt;/span&gt;: &lt;span class="nb"&gt;false&lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;
2020-12-13 20:46:30 INFO HTTP Status: 204 HTTP Reason:  HTTP body: &lt;span class="s2"&gt;""&lt;/span&gt;
2020-12-13 20:46:30 INFO Quitting...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Configuring guest machine config
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;./bin/pattacu put-machine-config &lt;span class="nt"&gt;--mem-size-mib&lt;/span&gt; 128 &lt;span class="nt"&gt;--vcpu-count&lt;/span&gt; 2 &lt;span class="nt"&gt;--ht-enabled&lt;/span&gt; &lt;span class="nb"&gt;false

&lt;/span&gt;2020-12-13 20:47:58 INFO ARGS: Namespace&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;cpu_template&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;None, &lt;span class="nv"&gt;func&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'put-machine-config'&lt;/span&gt;,
&lt;span class="nv"&gt;ht_enabled&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;False, &lt;span class="nv"&gt;mem_size_mib&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;128, &lt;span class="nv"&gt;track_dirty_pages&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;None, &lt;span class="nv"&gt;vcpu_count&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;2&lt;span class="o"&gt;)&lt;/span&gt;
2020-12-13 20:47:58 INFO &lt;span class="o"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;"vcpu_count"&lt;/span&gt;: 2, &lt;span class="s2"&gt;"mem_size_mib"&lt;/span&gt;: 128, &lt;span class="s2"&gt;"ht_enabled"&lt;/span&gt;: &lt;span class="nb"&gt;false&lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;
2020-12-13 20:47:58 INFO HTTP Status: 204 HTTP Reason:  HTTP body: &lt;span class="s2"&gt;""&lt;/span&gt;
2020-12-13 20:47:58 INFO Quitting...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Configuring guest networking
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;./bin/pattacu put-network-interfaces &lt;span class="nt"&gt;--iface-id&lt;/span&gt; eth0 &lt;span class="nt"&gt;--guest-mac&lt;/span&gt; &lt;span class="s2"&gt;"AA:FC:00:00:00:01"&lt;/span&gt; &lt;span class="nt"&gt;--host-dev-name&lt;/span&gt; tap0
2020-12-13 20:48:57 INFO ARGS: Namespace&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;func&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'put-network-interfaces'&lt;/span&gt;,
&lt;span class="nv"&gt;guest_mac&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'AA:FC:00:00:00:01'&lt;/span&gt;, &lt;span class="nv"&gt;host_dev_name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'tap0'&lt;/span&gt;, &lt;span class="nv"&gt;iface_id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'eth0'&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
2020-12-13 20:48:57 INFO &lt;span class="o"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;"iface_id"&lt;/span&gt;: &lt;span class="s2"&gt;"eth0"&lt;/span&gt;,
&lt;span class="s2"&gt;"guest_mac"&lt;/span&gt;: &lt;span class="s2"&gt;"AA:FC:00:00:00:01"&lt;/span&gt;, &lt;span class="s2"&gt;"host_dev_name"&lt;/span&gt;: &lt;span class="s2"&gt;"tap0"&lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;
2020-12-13 20:48:58 INFO HTTP Status: 204 HTTP Reason:  HTTP body: &lt;span class="s2"&gt;""&lt;/span&gt;
2020-12-13 20:48:58 INFO Quitting...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Starting up the instance
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;./bin/pattacu put-actions &lt;span class="nt"&gt;--action-type&lt;/span&gt; InstanceStart
2020-12-13 20:49:19 INFO ARGS: Namespace&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;action_type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'InstanceStart'&lt;/span&gt;, &lt;span class="nv"&gt;func&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'put-actions'&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
2020-12-13 20:49:19 INFO &lt;span class="o"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;"action_type"&lt;/span&gt;: &lt;span class="s2"&gt;"InstanceStart"&lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;
2020-12-13 20:49:20 INFO HTTP Status: 204 HTTP Reason:  HTTP body: &lt;span class="s2"&gt;""&lt;/span&gt;
2020-12-13 20:49:20 INFO Quitting...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can switch to the other tmux window and see the system booting up.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="o"&gt;[&lt;/span&gt;    1.739745] random: fast init &lt;span class="k"&gt;done&lt;/span&gt;                                                                                                                            &lt;span class="o"&gt;[&lt;/span&gt;27/1844]
 &lt;span class="o"&gt;[&lt;/span&gt; ok &lt;span class="o"&gt;]&lt;/span&gt;
 &lt;span class="k"&gt;*&lt;/span&gt; Mounting /sys ... &lt;span class="o"&gt;[&lt;/span&gt; ok &lt;span class="o"&gt;]&lt;/span&gt;
 &lt;span class="k"&gt;*&lt;/span&gt; Mounting security filesystem ... &lt;span class="o"&gt;[&lt;/span&gt; ok &lt;span class="o"&gt;]&lt;/span&gt;
 &lt;span class="k"&gt;*&lt;/span&gt; Mounting debug filesystem ... &lt;span class="o"&gt;[&lt;/span&gt; ok &lt;span class="o"&gt;]&lt;/span&gt;
 &lt;span class="k"&gt;*&lt;/span&gt; Mounting SELinux filesystem ... &lt;span class="o"&gt;[&lt;/span&gt; ok &lt;span class="o"&gt;]&lt;/span&gt;
 &lt;span class="k"&gt;*&lt;/span&gt; Mounting persistent storage &lt;span class="o"&gt;(&lt;/span&gt;pstore&lt;span class="o"&gt;)&lt;/span&gt; filesystem ... &lt;span class="o"&gt;[&lt;/span&gt; ok &lt;span class="o"&gt;]&lt;/span&gt;

Welcome to Alpine Linux 3.12
Kernel 4.20.0 on an aarch64 &lt;span class="o"&gt;(&lt;/span&gt;ttyS0&lt;span class="o"&gt;)&lt;/span&gt;

172 login: root
Welcome to Alpine!

The Alpine Wiki contains a large number of how-to guides and general
information about administrating Alpine systems.
See &amp;lt;http://wiki.alpinelinux.org/&amp;gt;.

You can &lt;span class="nb"&gt;set &lt;/span&gt;up the system with the &lt;span class="nb"&gt;command&lt;/span&gt;: setup-alpine

You may change this message by editing /etc/motd.

login[840]: root login on &lt;span class="s1"&gt;'ttyS0'&lt;/span&gt;
172:~# ping hackernews.org
PING hackernews.org &lt;span class="o"&gt;(&lt;/span&gt;162.255.119.249&lt;span class="o"&gt;)&lt;/span&gt;: 56 data bytes
64 bytes from 162.255.119.249: &lt;span class="nb"&gt;seq&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0 &lt;span class="nv"&gt;ttl&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;42 &lt;span class="nb"&gt;time&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;180.868 ms
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Closing
&lt;/h2&gt;

&lt;p&gt;I think Firecracker has a great potential to be the next platform for containerization especially because of its lean nature. If we could create a reasonable service that hosts FC images that are easy to deploy it could replace Docker easily. I hope it takes off.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;172:~# poweroff
The system is going down NOW!
Sent SIGTERM to all processes
Sent SIGKILL to all processes
Requesting system poweroff
&lt;span class="o"&gt;[&lt;/span&gt;  202.707132] reboot: Power down
&lt;span class="o"&gt;[&lt;/span&gt;  202.707132] reboot: Power down
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>containerisation</category>
      <category>virtualisation</category>
      <category>linux</category>
    </item>
    <item>
      <title>Getting started with Firecracker on Raspberry Pi</title>
      <dc:creator>Istvan</dc:creator>
      <pubDate>Sun, 22 Nov 2020 20:20:58 +0000</pubDate>
      <link>https://dev.to/l1x/getting-started-with-firecracker-on-raspberry-pi-1pbc</link>
      <guid>https://dev.to/l1x/getting-started-with-firecracker-on-raspberry-pi-1pbc</guid>
      <description>&lt;p&gt;This was originally was posted:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://dev.l1x.be/posts/2020/11/22/getting-started-with-firecracker-on-raspberry-pi/" rel="noopener noreferrer"&gt;https://dev.l1x.be/posts/2020/11/22/getting-started-with-firecracker-on-raspberry-pi/&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Abstract
&lt;/h2&gt;

&lt;p&gt;Traditionally services were deployed on bare metal and in the last decades we have seen the rise of virtualisation (running additional operating systems in a operating system process) and lately containerisation (running an operating system process in a separate security context from the rest of processes on the same host). Virtualisation and containerisation offers different levels of isolation by moving some operating system functionality to the guest systems.&lt;/p&gt;

&lt;p&gt;The following chart illustrates that pretty well:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev.l1x.be%2Fimg%2Fisolation.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev.l1x.be%2Fimg%2Fisolation.png" alt="OS functionality location" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Source: &lt;a href="https://research.cs.wisc.edu/multifacet/papers/vee20_blending.pdf" rel="noopener noreferrer"&gt;https://research.cs.wisc.edu/multifacet/papers/vee20_blending.pdf&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In this article, I perform a deep dive into Firecracker and how it can be used for deploying services on Raspberry Pi (4B).&lt;/p&gt;

&lt;h2&gt;
  
  
  Getting started
&lt;/h2&gt;

&lt;p&gt;There are few paths to take here. First I am going to try the easy one, using Ubuntu. Later on we can investigate the use of Alpine Linux which is much more lightweight than Ubuntu, ideal for devices like RPI.&lt;/p&gt;

&lt;h3&gt;
  
  
  Installing the image on a microSD card
&lt;/h3&gt;

&lt;p&gt;We need a 64 bit Ubuntu image and a microsd card. For the imaging I use &lt;a href="https://www.balena.io/etcher/" rel="noopener noreferrer"&gt;Balena Etcher&lt;/a&gt; that makes the imaging process super easy.&lt;/p&gt;

&lt;p&gt;Getting the pre-installed image:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;wget https://cdimage.ubuntu.com/releases/20.04/release/&lt;span class="se"&gt;\&lt;/span&gt;
ubuntu-20.04.1-preinstalled-server-arm64+raspi.img.xz
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Preinstalled means that we get a fully working operating system and there is no need for additional installation steps after booting up. With Balena Etcher it is super easy to write the compressed image file to the sd card and boot the system up once ready. SSHD starts up after the installation and we can log in via ssh if we know the IP address that the DHCP server issues to our device (assuming DHCP server is present in our LAN).&lt;/p&gt;

&lt;p&gt;There are few mildly annoying things with Ubuntu (snaps, unattended-upgrades) that I usually remove. I also prefer to use Chrony over the systemd equivalent. Ansible repo for these is available here: &lt;a href="https://github.com/l1x/rpi/blob/main/ubuntu.20/ansible/roles/os/tasks/main.yml" rel="noopener noreferrer"&gt;https://github.com/l1x/rpi/blob/main/ubuntu.20/ansible/roles/os/tasks/main.yml&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Installing Firecracker, Jailer and Firectl
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Firecracker: The main component, it is a virtual machine monitor (VMM) that uses the Linux Kernel Virtual Machine (KVM) to create and run microVMs.&lt;/li&gt;
&lt;li&gt;Jailer: For starting Firecracker in production mode, applies a cgroup/namespace isolation barrier and then drops privileges. There&lt;/li&gt;
&lt;li&gt;Firectl: A command line utility for convenience&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Getting Firecracker and Jailer
&lt;/h4&gt;

&lt;p&gt;For the first two it is possible to download the release binaries from Github.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;version&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'v0.23.0'&lt;/span&gt;

wget https://github.com/firecracker-microvm/firecracker/&lt;span class="se"&gt;\&lt;/span&gt;
releases/download/&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;version&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;/firecracker-&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;version&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="nt"&gt;-aarch64&lt;/span&gt;
wget https://github.com/firecracker-microvm/firecracker/&lt;span class="se"&gt;\&lt;/span&gt;
releases/download/&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;version&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;/jailer-&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;version&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="nt"&gt;-aarch64&lt;/span&gt;

&lt;span class="nb"&gt;mv &lt;/span&gt;firecracker-&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;version&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="nt"&gt;-aarch64&lt;/span&gt; firecracker
&lt;span class="nb"&gt;mv &lt;/span&gt;jailer-&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;version&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="nt"&gt;-aarch64&lt;/span&gt; jailer

&lt;span class="nb"&gt;chmod&lt;/span&gt; +x firecracker jailer

./firecracker &lt;span class="nt"&gt;--help&lt;/span&gt;
./jailer &lt;span class="nt"&gt;--help&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Firectl
&lt;/h4&gt;

&lt;p&gt;Firectl is a bit trickier to install because there is no release binary and it requires Golang 1.14 to compile. We can do these in two steps.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;wget https://golang.org/dl/go1.14.12.linux-arm64.tar.gz
&lt;span class="nb"&gt;tar &lt;/span&gt;xzvf go1.14.12.linux-arm64.tar.gz
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After getting go we can get the source of firectl and compile it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone https://github.com/firecracker-microvm/firectl.git
&lt;span class="nb"&gt;cd &lt;/span&gt;firectl/
 ~/go/bin/go build &lt;span class="nt"&gt;-x&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Testing Firectl:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;./firectl &lt;span class="nt"&gt;--help&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We have all the tools we need for running our first microVM the only thing is missing: something to run.&lt;/p&gt;

&lt;h3&gt;
  
  
  Downloading our first image
&lt;/h3&gt;

&lt;p&gt;For a microVM there are two things necessary to have:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;an uncompressed linux kernel (vmlinux)&lt;/li&gt;
&lt;li&gt;a filesystem&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Later on we are going to investigate how we could create our own version of these, but for now we are going to use images from&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;wget https://s3.amazonaws.com/spec.ccfc.min/&lt;span class="se"&gt;\&lt;/span&gt;
img/aarch64/ubuntu_with_ssh/kernel/vmlinux.bin
wget https://s3.amazonaws.com/spec.ccfc.min/&lt;span class="se"&gt;\&lt;/span&gt;
img/aarch64/ubuntu_with_ssh/fsfiles/xenial.rootfs.ext4
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Configuring network
&lt;/h3&gt;

&lt;p&gt;For the microVM to function properly we need a networking device. For this scenario we are going to use tap and create a device:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;ip tuntap add dev tap0 mode tap
&lt;span class="nb"&gt;sudo &lt;/span&gt;ip addr add 172.16.0.1/24 dev tap0
&lt;span class="nb"&gt;sudo &lt;/span&gt;ip &lt;span class="nb"&gt;link set &lt;/span&gt;tap0 up
ip addr show dev tap0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If we want to give access to our VM we have to enable IP forwarding:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;DEVICE_NAME&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;eth0
&lt;span class="nb"&gt;sudo &lt;/span&gt;sh &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="s2"&gt;"echo 1 &amp;gt; /proc/sys/net/ipv4/ip_forward"&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;iptables &lt;span class="nt"&gt;-t&lt;/span&gt; nat &lt;span class="nt"&gt;-A&lt;/span&gt; POSTROUTING &lt;span class="nt"&gt;-o&lt;/span&gt; &lt;span class="nv"&gt;$DEVICE_NAME&lt;/span&gt; &lt;span class="nt"&gt;-j&lt;/span&gt; MASQUERADE
&lt;span class="nb"&gt;sudo &lt;/span&gt;iptables &lt;span class="nt"&gt;-A&lt;/span&gt; FORWARD &lt;span class="nt"&gt;-m&lt;/span&gt; conntrack &lt;span class="nt"&gt;--ctstate&lt;/span&gt; RELATED,ESTABLISHED &lt;span class="nt"&gt;-j&lt;/span&gt; ACCEPT
&lt;span class="nb"&gt;sudo &lt;/span&gt;iptables &lt;span class="nt"&gt;-A&lt;/span&gt; FORWARD &lt;span class="nt"&gt;-i&lt;/span&gt; tap0 &lt;span class="nt"&gt;-o&lt;/span&gt; &lt;span class="nv"&gt;$DEVICE_NAME&lt;/span&gt; &lt;span class="nt"&gt;-j&lt;/span&gt; ACCEPT
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Running our first microVM
&lt;/h3&gt;

&lt;p&gt;This is how we can start up our first microVM. I usually start it in screen so I can open a new session easily because it will use the standard input and output for the newly started of console (unless you redirect it).&lt;/p&gt;

&lt;p&gt;This is for debug mode, starting with sudo:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo&lt;/span&gt; ./firectl/firectl &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--firecracker-binary&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;./firecracker &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--kernel&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;vmlinux.bin &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--tap-device&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;tap0/aa:fc:00:00:00:01 &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--kernel-opts&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"console=ttyS0 reboot=k panic=1 pci=off ip=172.16.0.42::172.16.0.1:255.255.255.0::eth0:off"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--root-drive&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;./xenial.rootfs.ext4
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If everything went well you can see something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Ubuntu 18.04.2 LTS fadfdd4af58a ttyS0

fadfdd4af58a login:
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;User and password is root:root.&lt;/p&gt;

&lt;h3&gt;
  
  
  Testing networking
&lt;/h3&gt;

&lt;p&gt;For this we need to have a bit bigger image.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;dd &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;/dev/zero &lt;span class="nv"&gt;bs&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;1M &lt;span class="nv"&gt;count&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;800 &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; xenial.rootfs.ext4
resize2fs &lt;span class="nt"&gt;-f&lt;/span&gt; xenial.rootfs.ext4
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After starting up the usual way and logging in we need to fix few things:&lt;/p&gt;

&lt;p&gt;Adding some working nameserver:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s1"&gt;'nameserver 1.1.1.1'&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt;  /etc/resolv.conf
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now trying to update:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;root@fadfdd4af58a:~# apt update
Get:1 http://ports.ubuntu.com/ubuntu-ports bionic InRelease &lt;span class="o"&gt;[&lt;/span&gt;242 kB]
Get:2 http://ports.ubuntu.com/ubuntu-ports bionic-updates InRelease &lt;span class="o"&gt;[&lt;/span&gt;88.7 kB]
Hit:3 http://ports.ubuntu.com/ubuntu-ports bionic-backports InRelease
Hit:4 http://ports.ubuntu.com/ubuntu-ports bionic-security InRelease
Get:5 http://ports.ubuntu.com/ubuntu-ports bionic/universe arm64 Packages &lt;span class="o"&gt;[&lt;/span&gt;11.0 MB]
Get:6 http://ports.ubuntu.com/ubuntu-ports bionic/multiverse arm64 Packages &lt;span class="o"&gt;[&lt;/span&gt;153 kB]
Get:7 http://ports.ubuntu.com/ubuntu-ports bionic/main arm64 Packages &lt;span class="o"&gt;[&lt;/span&gt;1285 kB]
Get:8 http://ports.ubuntu.com/ubuntu-ports bionic/restricted arm64 Packages &lt;span class="o"&gt;[&lt;/span&gt;572 B]
Get:9 http://ports.ubuntu.com/ubuntu-ports bionic-updates/universe arm64 Packages &lt;span class="o"&gt;[&lt;/span&gt;1865 kB]
Get:10 http://ports.ubuntu.com/ubuntu-ports bionic-updates/restricted arm64 Packages &lt;span class="o"&gt;[&lt;/span&gt;2262 B]
Get:11 http://ports.ubuntu.com/ubuntu-ports bionic-updates/main arm64 Packages &lt;span class="o"&gt;[&lt;/span&gt;1431 kB]
Get:12 http://ports.ubuntu.com/ubuntu-ports bionic-updates/multiverse arm64 Packages &lt;span class="o"&gt;[&lt;/span&gt;5758 B]
Fetched 16.1 MB &lt;span class="k"&gt;in &lt;/span&gt;6s &lt;span class="o"&gt;(&lt;/span&gt;2543 kB/s&lt;span class="o"&gt;)&lt;/span&gt;
Reading package lists... Error!
E: flAbsPath on /var/lib/dpkg/status failed - &lt;span class="nb"&gt;realpath&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;2: No such file or directory&lt;span class="o"&gt;)&lt;/span&gt;
E: Could not open file  - open &lt;span class="o"&gt;(&lt;/span&gt;2: No such file or directory&lt;span class="o"&gt;)&lt;/span&gt;
E: Problem opening
E: The package lists or status file could not be parsed or opened.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Fixing the apt issues:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;mkdir&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; /var/lib/dpkg/&lt;span class="o"&gt;{&lt;/span&gt;info,alternatives&lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="nb"&gt;touch&lt;/span&gt; /var/lib/dpkg/status
apt &lt;span class="nb"&gt;install &lt;/span&gt;apt-utils &lt;span class="nt"&gt;-y&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Enjoy!&lt;/p&gt;

&lt;p&gt;Next time we can go through how to compile a new kernel and have a different rootfs (potentially using Alpine).&lt;/p&gt;

</description>
      <category>containerisation</category>
      <category>virtualisation</category>
      <category>linux</category>
      <category>cgroups</category>
    </item>
    <item>
      <title>Why I chose F# for our AWS Lambda project</title>
      <dc:creator>Istvan</dc:creator>
      <pubDate>Fri, 08 May 2020 08:34:04 +0000</pubDate>
      <link>https://dev.to/l1x/why-i-chose-f-for-our-aws-lambda-project-4978</link>
      <guid>https://dev.to/l1x/why-i-chose-f-for-our-aws-lambda-project-4978</guid>
      <description>&lt;h1&gt;
  
  
  The dilemma
&lt;/h1&gt;

&lt;p&gt;I wanted to create a simple Lambda function to be able to track how our users use the website and the web application without a 3rd party and a ton of external dependencies, especially avoiding 3rd party Javascript and leaking out data to mass surveillance companies. The easiest way is to use a simple tracking 1x1 pixel or beacon that collects just the right amount of information (strictly non-PII). This gives us enough information for creating basic funnels, that covers most of our needs.&lt;/p&gt;

&lt;h2&gt;
  
  
  First Option: Python
&lt;/h2&gt;

&lt;p&gt;My default language (regardless of what I am going to work on) is Python. It has many great features and it is easy to prototype in it and the performance is great once you are using a C++ or Rust backed library. This also introduces a few issues when you are trying to deploy to AWS Lambda. I develop mainly on macOS and Lambda runs on Linux. Once you need to compile anything it is hard to get it right because Python does not support compiling to a different platform.&lt;/p&gt;

&lt;p&gt;&lt;a href=""&gt;https://stackoverflow.com/questions/44490197/how-to-cross-compile-python-packages-with-pip&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I was running into packaging issues because on Mac it is not easy to cross-compile and package Python code, maybe if I would create a proper package but I could not find a simple way without Docket. It would extremely valuable if Python had a way to compile a package that you upload to AWS and it works, 100%. I was running into problems that it was working on my Mac and did not work on AWS. I haven't had enough time to investigate. &lt;/p&gt;

&lt;h2&gt;
  
  
  Second Option: Rust
&lt;/h2&gt;

&lt;p&gt;Rust became the rising star over the years and I try to use it as much as possible with mixed success. My biggest problem is with Rust the low-level nature and the quirky features, that are hard to reason about. From AWS Lambda examples:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nn"&gt;lambda&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;handler_fn&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nn"&gt;serde_json&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Value&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;Error&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Box&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;dyn&lt;/span&gt; &lt;span class="nn"&gt;std&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;error&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Error&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nb"&gt;Send&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;Sync&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nv"&gt;'static&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nd"&gt;#[tokio::main]&lt;/span&gt;
&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Result&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;Error&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;func&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;handler_fn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;func&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nn"&gt;lambda&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;func&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="py"&gt;.await&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nf"&gt;Ok&lt;/span&gt;&lt;span class="p"&gt;(())&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Result&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Error&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;Ok&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Do you think that everybody understands immediately what is going on here? I don't. Even if I do, how am I going to explain this to a junior dev? How long does it take to get productive in Rust? I know that for extreme performance we might need this, but our current application is super happy without Rust, we do not have a performance problem. It is more important that developers are productive and the code is super simple to understand.&lt;/p&gt;

&lt;h2&gt;
  
  
  And the winner is: Fsharp
&lt;/h2&gt;

&lt;p&gt;Member of the ML family, running on the .NET platform, pretty mature ecosystem. Developers can pick up quickly, especially the way we use it, simple functions will do with small types. The performance is great out of the box, in case you need more you have great tooling around it.&lt;/p&gt;

&lt;p&gt;Our handler function:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight fsharp"&gt;&lt;code&gt;  &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;handler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nc"&gt;APIGatewayProxyRequest&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt;

    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;httpResource&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt;
      &lt;span class="k"&gt;match&lt;/span&gt; &lt;span class="n"&gt;isNull&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Resource&lt;/span&gt; &lt;span class="k"&gt;with&lt;/span&gt;
      &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="bp"&gt;true&lt;/span&gt;  &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="s2"&gt;"None"&lt;/span&gt;
      &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="p"&gt;_&lt;/span&gt;     &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Resource&lt;/span&gt;

    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;httpMethod&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt;
      &lt;span class="k"&gt;match&lt;/span&gt; &lt;span class="n"&gt;isNull&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;HttpMethod&lt;/span&gt; &lt;span class="k"&gt;with&lt;/span&gt;
      &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="bp"&gt;true&lt;/span&gt;  &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="s2"&gt;"None"&lt;/span&gt;
      &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="p"&gt;_&lt;/span&gt;     &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;HttpMethod&lt;/span&gt;

    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;httpHeadersAccept&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt;
      &lt;span class="k"&gt;match&lt;/span&gt; &lt;span class="n"&gt;isNull&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Headers&lt;/span&gt; &lt;span class="k"&gt;with&lt;/span&gt;
      &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="bp"&gt;true&lt;/span&gt;  &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="s2"&gt;"None"&lt;/span&gt;
      &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="p"&gt;_&lt;/span&gt;     &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;getOrDefault&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Headers&lt;/span&gt;  &lt;span class="s2"&gt;"Accept"&lt;/span&gt; &lt;span class="s2"&gt;"None"&lt;/span&gt;

    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;acceptImage&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt;
      &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;pattern&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="s2"&gt;"image/"&lt;/span&gt;
      &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;Regex&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Match&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;httpHeadersAccept&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;pattern&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Success&lt;/span&gt;

    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;log&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;String&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"{0} :: {1} :: {2}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;httpResource&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;httpMethod&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;httpHeadersAccept&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nn"&gt;LambdaLogger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;match&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;httpResource&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;httpMethod&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;httpHeadersAccept&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;acceptImage&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;with&lt;/span&gt;
    &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"/trck"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;         &lt;span class="s2"&gt;"POST"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"application/json"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;_&lt;/span&gt;    &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;trckPost&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"/trck"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;         &lt;span class="s2"&gt;"GET"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="o"&gt;_,&lt;/span&gt;                  &lt;span class="bp"&gt;true&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;trckGet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"/trck/{image}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"GET"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="o"&gt;_,&lt;/span&gt;                  &lt;span class="bp"&gt;true&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;trckGet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"/echo"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;         &lt;span class="s2"&gt;"GET"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="o"&gt;_,&lt;/span&gt;                  &lt;span class="p"&gt;_&lt;/span&gt;    &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;echoGet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="o"&gt;(_,&lt;/span&gt;               &lt;span class="o"&gt;_,&lt;/span&gt;      &lt;span class="o"&gt;_,&lt;/span&gt;                  &lt;span class="p"&gt;_&lt;/span&gt;    &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;notFound&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Pretty readable code, sure, you have to deal with nulls but Fsharp gives you great tooling around it. It took me probably a couple of days from having zero experience with .NET to deploy the first working API that has all of the functionality we are looking for. I might not have idiomatic Fsharp yet, but I am happy with the results so far. In the last couple of weeks, I have written many small tools in Fsharp, mostly dealing with the AWS APIs, I like it so much that I replaced my Python first approach and I go and try to implement everything in F# first. I can develop at the same pace as with Python but the result is much more solid code and easier on deployments (goodbye pip). &lt;/p&gt;

&lt;p&gt;I think Fsharp is exactly in the sweet spot of programming languages, good enough performance, nice enough features, and a ton of great libraries. It does not have the problem that Python suffers, you can create a single zip that will work on all platforms. It also free from exposing the low-level details that I do not want to care about in business domain code, what Rust does.&lt;/p&gt;

</description>
      <category>f</category>
      <category>net</category>
      <category>awslambda</category>
      <category>serverless</category>
    </item>
    <item>
      <title>Matching binary patterns</title>
      <dc:creator>Istvan</dc:creator>
      <pubDate>Wed, 29 Apr 2020 18:56:01 +0000</pubDate>
      <link>https://dev.to/l1x/matching-binary-patterns-11kh</link>
      <guid>https://dev.to/l1x/matching-binary-patterns-11kh</guid>
      <description>&lt;p&gt;In Erlang, it is easy to construct binaries and bitstrings and matching binary patterns. I was running into Mitchell Perilstein's excellent work on NTP with Erlang and I thought I am going to use this to explain how bitstrings and binaries work in Erlang. &lt;/p&gt;

&lt;p&gt;Two concepts:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;A bitstring is a sequence of zero or more bits, where the number of bits does not need to be divisible by 8.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;A binary is when the number of bits is divisible by 8.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The syntax is as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight erlang"&gt;&lt;code&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="nv"&gt;B1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;B2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt; &lt;span class="nv"&gt;Bn&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Each element specifies a certain segment of the bitstring. A segment is a set of contiguous bits of the binary (not necessarily on a byte boundary). &lt;/p&gt;

&lt;p&gt;A real-life example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight erlang"&gt;&lt;code&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;:(&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="mi"&gt;32&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="mi"&gt;64&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's unpack a bit of what is going on here. For this, it is worth knowing the whole syntax.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight erlang"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="nv"&gt;Value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nv"&gt;Size&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nv"&gt;TypeSpecifierList&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;Value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nv"&gt;Size&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nv"&gt;TypeSpecifierList&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or alternatively:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight erlang"&gt;&lt;code&gt;&lt;span class="nv"&gt;Ei&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;Value&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt;
     &lt;span class="nv"&gt;Value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nv"&gt;Size&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt;
     &lt;span class="nv"&gt;Value&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nv"&gt;TypeSpecifierList&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt;
     &lt;span class="nv"&gt;Value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nv"&gt;Size&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nv"&gt;TypeSpecifierList&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This means in the real-life example, we have 0 as the value, 2 is the size (2 bits), four as a value, 3 bits as size, and so on. We did not specify any of the type specifiers.&lt;/p&gt;

&lt;p&gt;TypeSpecifierList is a list of type specifiers, in any order, separated by hyphens or dash (-). Default values are used for any omitted type specifier.&lt;/p&gt;

&lt;p&gt;The following type specifiers are supported:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight erlang"&gt;&lt;code&gt;&lt;span class="nv"&gt;Type&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;integer&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="nb"&gt;float&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="n"&gt;binary&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="n"&gt;bytes&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="n"&gt;bitstring&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="n"&gt;bits&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="n"&gt;utf8&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="n"&gt;utf16&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="n"&gt;utf32&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The default is an integer. bytes is a shorthand for binary and bits is a shorthand for bitstring.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight erlang"&gt;&lt;code&gt;&lt;span class="nv"&gt;Signedness&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;signed&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="n"&gt;unsigned&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It only matters for matching and when the type is an integer. The default is unsigned.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight erlang"&gt;&lt;code&gt;&lt;span class="nv"&gt;Endianness&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;big&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="n"&gt;little&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="n"&gt;native&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Native-endian means that the endianness is resolved at load time to be either big-endian or little-endian, depending on what is native for the CPU that the Erlang machine is run on. Endianness only matters when the Type is either integer, utf16, utf32, or float. The default is big.&lt;/p&gt;

&lt;h2&gt;
  
  
  A complete example
&lt;/h2&gt;

&lt;p&gt;One of the simplest protocols out there is NTP. The header file looks like the following:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fimigpr35l0uhlkpbbh74.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fimigpr35l0uhlkpbbh74.png" alt="Alt Text" width="800" height="1077"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is used for both the request and the response. Let's craft the request first.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight erlang"&gt;&lt;code&gt;&lt;span class="nf"&gt;create_ntp_request&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
  &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;:(&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="mi"&gt;32&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="mi"&gt;64&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Based on the header structure we can see that we have a 2-bit integer (Li), 3-bit integer version number, 3-bit integer mode, 8-bit stratum, 8-bit poll, 8-bit precision, and so on. We only need to set the first 3 values, the rest (376 bits) can be 0.&lt;/p&gt;

&lt;p&gt;Let's try this in the wild.&lt;/p&gt;

&lt;h3&gt;
  
  
  Creating the request
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight erlang"&gt;&lt;code&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;Request&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;:(&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="mi"&gt;32&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="mi"&gt;64&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
&lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="mi"&gt;35&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,...&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Sending and receiving
&lt;/h3&gt;

&lt;p&gt;We can use Erlang's built-in functions for this one, gen_udp has a pretty comprehensive low-level UDP implementation, that can do all we want.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight erlang"&gt;&lt;code&gt;
&lt;span class="c"&gt;% open a local socket, 0 indicates that it will pick a random local port
% active=false means we need to receive ourselves
&lt;/span&gt;
&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;ok&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;Socket&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;gen_udp&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nf"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;binary&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;active&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;false&lt;/span&gt;&lt;span class="p"&gt;}]),&lt;/span&gt;
&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nn"&gt;gen_udp&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nb"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;Socket&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"0.europe.pool.ntp.org"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;123&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;ok&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{_&lt;/span&gt;&lt;span class="nv"&gt;Address&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;_&lt;/span&gt;&lt;span class="nv"&gt;Port&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;Resp&lt;/span&gt;&lt;span class="p"&gt;}}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;gen_udp&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nf"&gt;recv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;Socket&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;500&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;ok&lt;/span&gt;&lt;span class="p"&gt;,{{&lt;/span&gt;&lt;span class="mi"&gt;212&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;59&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
     &lt;span class="mi"&gt;123&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
     &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="mi"&gt;36&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;231&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;110&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;25&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;212&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;59&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;226&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;84&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;62&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;89&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
       &lt;span class="mi"&gt;208&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;192&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;202&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;156&lt;/span&gt;&lt;span class="p"&gt;,...&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;}}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Processing the response, first few bits
&lt;/h3&gt;

&lt;p&gt;The response is just a binary that we need to slice and dice, similarly how we created the request.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight erlang"&gt;&lt;code&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;Resp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
&lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="mi"&gt;36&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;231&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;110&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;25&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;212&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;59&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;226&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;84&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;62&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;89&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="mi"&gt;208&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;192&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;202&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;156&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,...&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;First, we can just get the first few bits.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight erlang"&gt;&lt;code&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="nv"&gt;Li&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;Version&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;Mode&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;_&lt;/span&gt;&lt;span class="n"&gt;rest&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;binary&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;Resp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
&lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="mi"&gt;36&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;231&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;110&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;25&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;212&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;59&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;226&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;84&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;62&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;89&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="mi"&gt;208&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;192&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;202&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;156&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,...&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt;
&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;li&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;Li&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;version&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;Version&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;mode&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;Mode&lt;/span&gt;&lt;span class="p"&gt;}.&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;li&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;version&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;mode&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It works.&lt;/p&gt;

&lt;p&gt;The rest of the header a bit more tricky but with the bitstring syntax, it is easy to manage.&lt;/p&gt;

&lt;h3&gt;
  
  
  Processing the response, the rest
&lt;/h3&gt;

&lt;p&gt;Finally matching all the mandatory fields.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight erlang"&gt;&lt;code&gt;&lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;   &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="nv"&gt;LI&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;Version&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;Mode&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;Stratum&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;Poll&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;signed&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;Precision&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;signed&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;      &lt;span class="nv"&gt;RootDel&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;32&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;RootDisp&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;32&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;R1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;R2&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;R3&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;R4&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;RtsI&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;32&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;RtsF&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;32&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;      &lt;span class="nv"&gt;OtsI&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;32&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;OtsF&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;32&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;   &lt;span class="nv"&gt;RcvI&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;32&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;RcvF&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;32&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;XmtI&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;32&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;XmtF&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;32&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;Resp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
&lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="mi"&gt;36&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;231&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;110&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;25&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;212&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;59&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;226&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;84&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;62&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;89&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="mi"&gt;208&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;192&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;202&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;156&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,...&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Making sense of these values requires a bit more legwork. First, we need a utility function for binary fractions.&lt;/p&gt;

&lt;p&gt;In Erlang, function arity differentiates functions so we can do the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight erlang"&gt;&lt;code&gt;&lt;span class="nf"&gt;binfrac&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;Bin&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
  &lt;span class="nf"&gt;binfrac&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;Bin&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;
&lt;span class="nf"&gt;binfrac&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;_,&lt;/span&gt; &lt;span class="nv"&gt;Frac&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
  &lt;span class="nv"&gt;Frac&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nf"&gt;binfrac&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;Bin&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;N&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;Frac&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
  &lt;span class="nf"&gt;binfrac&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;Bin&lt;/span&gt; &lt;span class="ow"&gt;bsr&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;N&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;Frac&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;Bin&lt;/span&gt; &lt;span class="ow"&gt;band&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nv"&gt;N&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With this function, we can implement the one that processes the response and returns the values we are interested in.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight erlang"&gt;&lt;code&gt;&lt;span class="c"&gt;% 2208988800 is the offset (1900 to Unix epoch)
&lt;/span&gt;
&lt;span class="nf"&gt;process_ntp_response&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;Ntp_response&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
  &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="nv"&gt;LI&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;Version&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;Mode&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;Stratum&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;Poll&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;signed&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;Precision&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;signed&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
     &lt;span class="nv"&gt;RootDel&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;32&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;RootDisp&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;32&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;R1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;R2&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;R3&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;R4&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;RtsI&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;32&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;RtsF&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;32&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
     &lt;span class="nv"&gt;OtsI&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;32&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;OtsF&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;32&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;   &lt;span class="nv"&gt;RcvI&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;32&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;RcvF&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;32&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;XmtI&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;32&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;XmtF&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;32&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;Ntp_response&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nv"&gt;NowMS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;NowS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;NowUS&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;erlang&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nf"&gt;timestamp&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
  &lt;span class="nv"&gt;NowTimestamp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;NowMS&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="n"&gt;e6&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nv"&gt;NowS&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nv"&gt;NowUS&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nv"&gt;TransmitTimestamp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;XmtI&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;2208988800&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nf"&gt;binfrac&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;XmtF&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;li&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;LI&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;vn&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;Version&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;mode&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;Mode&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;stratum&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;Stratum&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;poll&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;Poll&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;precision&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;Precision&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;rootDelay&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;RootDel&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;rootDispersion&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;RootDisp&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;referenceId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;R1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;R2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;R3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;R4&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;referenceTimestamp&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;RtsI&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;2208988800&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nf"&gt;binfrac&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;RtsF&lt;/span&gt;&lt;span class="p"&gt;)},&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;originateTimestamp&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;OtsI&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;2208988800&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nf"&gt;binfrac&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;OtsF&lt;/span&gt;&lt;span class="p"&gt;)},&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;receiveTimestamp&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;   &lt;span class="nv"&gt;RcvI&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;2208988800&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nf"&gt;binfrac&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;RcvF&lt;/span&gt;&lt;span class="p"&gt;)},&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;transmitTimestamp&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="nv"&gt;TransmitTimestamp&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;clientReceiveTimestamp&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;NowTimestamp&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;offset&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;TransmitTimestamp&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nv"&gt;NowTimestamp&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;}.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And wit that we can just process the response.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight erlang"&gt;&lt;code&gt;&lt;span class="p"&gt;{{&lt;/span&gt;&lt;span class="n"&gt;li&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
 &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;vn&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
 &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;mode&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
 &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;stratum&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
 &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;poll&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
 &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;precision&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;24&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
 &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;rootDelay&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;9&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
 &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;rootDispersion&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;140&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
 &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;referenceId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;85&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;158&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;25&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;75&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
 &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;referenceTimestamp&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;1588186010&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;7517557&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
 &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;originateTimestamp&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;2208988800&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
 &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;receiveTimestamp&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;1588186048&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;3557627&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
 &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;transmitTimestamp&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;1588186048&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;8841336&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
 &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;clientReceiveTimestamp&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;1588186606&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;531&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
 &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;offset&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;557&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;6468663215637&lt;/span&gt;&lt;span class="p"&gt;}}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Please note, this is the first step in the NTP workflow and does not implement the complete NTP protocol. We do not take into consideration a bunch of details.&lt;/p&gt;

&lt;p&gt;Next time we might look into how to implement a simple server (like DNS) in Erlang.&lt;/p&gt;

&lt;p&gt;Michael's original work:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/mnp/erlang-ntp" rel="noopener noreferrer"&gt;https://github.com/mnp/erlang-ntp&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Up to date version and Elixir port:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://gist.github.com/l1x/b0a7f844b283ac08e3125d1ba6e81eeb" rel="noopener noreferrer"&gt;https://gist.github.com/l1x/b0a7f844b283ac08e3125d1ba6e81eeb&lt;/a&gt;&lt;/p&gt;

</description>
      <category>erlang</category>
      <category>elixir</category>
      <category>bits</category>
    </item>
    <item>
      <title>FreeNAS 11.3 upgrade issues</title>
      <dc:creator>Istvan</dc:creator>
      <pubDate>Wed, 29 Apr 2020 13:41:02 +0000</pubDate>
      <link>https://dev.to/l1x/freenas-11-3-upgrade-issues-124d</link>
      <guid>https://dev.to/l1x/freenas-11-3-upgrade-issues-124d</guid>
      <description>&lt;p&gt;I have an interesting experience with the latest upgrade of FreeNAS 11.3-U2.1. Applications that were deployed in the jail were gone. After fiddling with iocage (the tool that FreeNAS provides to manage jails) I could restore a previous state where all seems fine and dandy.&lt;/p&gt;

&lt;h2&gt;
  
  
  Steps to restore
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;list of snapshots
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;iocage snaplist &lt;span class="nb"&gt;tr&lt;/span&gt; &lt;span class="nt"&gt;-l&lt;/span&gt;
+-------------------------------------------------------------------------+-----------------------+-------+-------+
|                                  NAME                                   |        CREATED        | RSIZE | USED  |
+&lt;span class="o"&gt;=========================================================================&lt;/span&gt;+&lt;span class="o"&gt;=======================&lt;/span&gt;+&lt;span class="o"&gt;=======&lt;/span&gt;+&lt;span class="o"&gt;=======&lt;/span&gt;+
| fux/iocage/jails/tr/root@ioc_plugin_update_2020-04-29                   | Wed Apr 29 14:55 2020 | 799G  | 11.6K |
+-------------------------------------------------------------------------+-----------------------+-------+-------+
| fux/iocage/jails/tr/root@ioc_update_11.3-RELEASE-p8_2020-04-29_14-55-07 | Wed Apr 29 14:55 2020 | 799G  | 575K  |
+-------------------------------------------------------------------------+-----------------------+-------+-------+
| fux/iocage/jails/tr/root@ioc_update_11.3-RELEASE-p8_2020-04-29_14-55-22 | Wed Apr 29 14:55 2020 | 799G  | 11.6K |
+-------------------------------------------------------------------------+-----------------------+-------+-------+
| fux/iocage/jails/tr@ioc_plugin_update_2020-04-29                        | Wed Apr 29 14:55 2020 | 517K  | 81.4K |
+-------------------------------------------------------------------------+-----------------------+-------+-------+
| fux/iocage/jails/tr@ioc_update_11.3-RELEASE-p8_2020-04-29_14-55-07      | Wed Apr 29 14:55 2020 | 517K  | 81.4K |
+-------------------------------------------------------------------------+-----------------------+-------+-------+
| fux/iocage/jails/tr@ioc_update_11.3-RELEASE-p8_2020-04-29_14-55-22      | Wed Apr 29 14:55 2020 | 517K  | 81.4K |
+-------------------------------------------------------------------------+-----------------------+-------+-------+
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;stop the jail
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;root@freenas[~]# iocage stop &lt;span class="nb"&gt;tr&lt;/span&gt;
&lt;span class="k"&gt;*&lt;/span&gt; Stopping &lt;span class="nb"&gt;tr&lt;/span&gt;
  + Executing prestop OK
  + Stopping services OK
  + Tearing down VNET OK
  + Removing devfs_ruleset: 5 OK
  + Removing jail process OK
  + Executing poststop OK
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;rollback
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;root@freenas[~]# iocage rollback &lt;span class="nb"&gt;tr&lt;/span&gt; &lt;span class="nt"&gt;-n&lt;/span&gt; ioc_update_11.3-RELEASE-p8_2020-04-29_14-55-07

This will destroy ALL data created including ALL snapshots taken after the snapshot ioc_update_11.3-RELEASE-p8_2020-04-29_14-55-07

Are you sure? &lt;span class="o"&gt;[&lt;/span&gt;y/N]: y
Rolled back to: fux/iocage/jails/tr
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;start the jail
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;root@freenas[~]# iocage start &lt;span class="nb"&gt;tr
&lt;/span&gt;No default gateway found &lt;span class="k"&gt;for &lt;/span&gt;ipv6.
&lt;span class="k"&gt;*&lt;/span&gt; Starting &lt;span class="nb"&gt;tr&lt;/span&gt;
  + Started OK
  + Using devfs_ruleset: 5
  + Configuring VNET OK
  + Using IP options: vnet
  + Starting services OK
  + Executing poststart OK
  + DHCP Address: 192.168.1.111/24
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And we are back. &lt;/p&gt;

</description>
      <category>freebsd</category>
      <category>freenas</category>
      <category>rollback</category>
      <category>jail</category>
    </item>
    <item>
      <title>My Python environment</title>
      <dc:creator>Istvan</dc:creator>
      <pubDate>Tue, 11 Feb 2020 07:26:04 +0000</pubDate>
      <link>https://dev.to/l1x/my-python-environment-3o4p</link>
      <guid>https://dev.to/l1x/my-python-environment-3o4p</guid>
      <description>&lt;h2&gt;
  
  
  Virtualenv for the win
&lt;/h2&gt;

&lt;p&gt;After trying to use so many things for this, including conda, Linux in a VM + operating  system packages, pyenv and everything else that is out there, for years, I finally settled on venv, requirements.txt and a single virtualenv on my laptop. &lt;/p&gt;

&lt;h3&gt;
  
  
  Why?
&lt;/h3&gt;

&lt;p&gt;If you have tried to use some of these you might have run into some issues. Conda for example is absolutely nondeterministic, works some times and fails most of the time. I created a ticket about it but the response is to try to &lt;a href="https://github.com/conda/conda/issues/9059" rel="noopener noreferrer"&gt;turn it off and on again&lt;/a&gt;. These developers really like It Crowd. &lt;/p&gt;

&lt;p&gt;After wrestling with many of similar issues, finally I decided to go for dead simple approach.&lt;/p&gt;

&lt;p&gt;I install Python3 with brew. Create a venv in my home folder and source it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;brew &lt;span class="nb"&gt;install &lt;/span&gt;python3
&lt;span class="nb"&gt;cd
&lt;/span&gt;python3 &lt;span class="nt"&gt;-m&lt;/span&gt; venv venv
&lt;span class="nb"&gt;.&lt;/span&gt; ~/venv/bin/activate.fish
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Any time I work with a Python project I only use Python3 (RIP Python2 projects) and install all the packages into that single virtual environment. If there is a conflict I delete the entire directory and install the dependencies of the current project. I usually work on one Python project at a time. This gives me exactly what I need with an easy path to resolve local state issues, dependency problems and only using 1 directory instead of littering around all of my repositories and making backup slower. In production I do the same, I use venv to install the environment and install dependencies there. It does not matter if I use a Docker container or a non-containerized deployment the venv is specific to a single application. This gives my the best of both worlds, developer happiness and optimal environment in production. There are minor problems with this, Python development of AWS Lambda functions is not as easy because the architecture differences between Mac vs AWS Linux. This problem exists in Python which virtual environments have nothing to do with. In that case I usually package up software in a VM + Docker or use something else than Python, something that truly supports multi-platform development: Rust or F# for example. &lt;/p&gt;

</description>
      <category>python</category>
      <category>local</category>
      <category>dev</category>
      <category>macos</category>
    </item>
    <item>
      <title>Small Alpine Linux containers with Java</title>
      <dc:creator>Istvan</dc:creator>
      <pubDate>Wed, 24 Apr 2019 20:14:48 +0000</pubDate>
      <link>https://dev.to/l1x/small-alpine-linux-containers-with-java-13-63c</link>
      <guid>https://dev.to/l1x/small-alpine-linux-containers-with-java-13-63c</guid>
      <description>&lt;p&gt;&lt;a id="intro"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Update
&lt;/h2&gt;

&lt;h3&gt;
  
  
  2019.10.21
&lt;/h3&gt;

&lt;p&gt;The original post was about Java 13. Oracle is changing JDK versions quite frequently. The newest version of JDK is 14:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://download.java.net/java/early_access/alpine/15/binaries/openjdk-14-ea+15_linux-x64-musl_bin.tar.gz" rel="noopener noreferrer"&gt;https://download.java.net/java/early_access/alpine/15/binaries/openjdk-14-ea+15_linux-x64-musl_bin.tar.gz&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Intro
&lt;/h2&gt;

&lt;p&gt;Quite often I hear a complaint from developers that Java containers are too big and how much smaller this would be with Go or other languages. With this new project called &lt;a href="https://openjdk.java.net/projects/portola/" rel="noopener noreferrer"&gt;Portola&lt;/a&gt; it is possible to make very small (~40MB) containers running Java applications. Alpine Linux became the de facto standard for small containers but until now it was a rather complex process to create a Java environment using it. This is not anymore the case. Let's see how we can leverage Project Portola to create these small containers.&lt;/p&gt;

&lt;p&gt;&lt;a id="creating-containers"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Creating Containers
&lt;/h2&gt;

&lt;p&gt;First, we just create a container that has a new small size JDK.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;alpine:latest&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;build&lt;/span&gt;

&lt;span class="k"&gt;ADD&lt;/span&gt;&lt;span class="s"&gt; https://download.java.net/java/early_access/alpine/15/binaries/openjdk-14-ea+15_linux-x64-musl_bin.tar.gz /opt/jdk/&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;&lt;span class="nb"&gt;tar&lt;/span&gt; &lt;span class="nt"&gt;-xzvf&lt;/span&gt; /opt/jdk/openjdk-14-ea+15_linux-x64-musl_bin.tar.gz &lt;span class="nt"&gt;-C&lt;/span&gt; /opt/jdk/

&lt;span class="k"&gt;RUN &lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"/opt/jdk/jdk-14/bin/jlink"&lt;/span&gt;, &lt;span class="s2"&gt;"--compress=2"&lt;/span&gt;, &lt;span class="se"&gt;\
&lt;/span&gt;     &lt;span class="s2"&gt;"--module-path"&lt;/span&gt;, &lt;span class="s2"&gt;"/opt/jdk/jdk-14/jmods/"&lt;/span&gt;, &lt;span class="se"&gt;\
&lt;/span&gt;     &lt;span class="s2"&gt;"--add-modules"&lt;/span&gt;, &lt;span class="s2"&gt;"java.base"&lt;/span&gt;, &lt;span class="se"&gt;\
&lt;/span&gt;     &lt;span class="s2"&gt;"--output"&lt;/span&gt;, &lt;span class="s2"&gt;"/jlinked"&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;

&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="s"&gt; alpine:latest&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; --from=build /jlinked /opt/jdk/&lt;/span&gt;
&lt;span class="k"&gt;CMD&lt;/span&gt;&lt;span class="s"&gt; ["/opt/jdk/bin/java", "--version"]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The rest of the article is not concerned with JDK version. Output from docker build might reflect earlier version. &lt;/p&gt;

&lt;p&gt;We can start to build the container:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="o"&gt;[&lt;/span&gt;v@alpine-java jdk14_v]&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;docker build &lt;span class="nb"&gt;.&lt;/span&gt;
Sending build context to Docker daemon   2.56kB
Step 1/8 : FROM alpine:latest as build
latest: Pulling from library/alpine
bdf0201b3a05: Pull &lt;span class="nb"&gt;complete
&lt;/span&gt;Digest: sha256:28ef97b8686a0b5399129e9b763d5b7e5ff03576aa5580d6f4182a49c5fe1913
Status: Downloaded newer image &lt;span class="k"&gt;for &lt;/span&gt;alpine:latest
 &lt;span class="nt"&gt;---&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; cdf98d1859c1
Step 2/8 : ADD https://download.java.net/java/early_access/alpine/16/binaries/openjdk-13-ea+16_linux-x64-musl_bin.tar.gz /opt/jdk/
Downloading &lt;span class="o"&gt;[==================================================&amp;gt;]&lt;/span&gt;  195.2MB/195.2MB
 &lt;span class="nt"&gt;---&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; Using cache
 &lt;span class="nt"&gt;---&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; b1a444e9dde9
Step 3/7 : RUN &lt;span class="nb"&gt;tar&lt;/span&gt; &lt;span class="nt"&gt;-xzvf&lt;/span&gt; /opt/jdk/openjdk-13-ea+16_linux-x64-musl_bin.tar.gz &lt;span class="nt"&gt;-C&lt;/span&gt; /opt/jdk/
 &lt;span class="nt"&gt;---&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; Using cache
 &lt;span class="nt"&gt;---&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; ce2721c75ea0
Step 4/7 : RUN &lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"/opt/jdk/jdk-13/bin/jlink"&lt;/span&gt;, &lt;span class="s2"&gt;"--compress=2"&lt;/span&gt;,      &lt;span class="s2"&gt;"--module-path"&lt;/span&gt;, &lt;span class="s2"&gt;"/opt/jdk/jdk-13/jmods/"&lt;/span&gt;,      &lt;span class="s2"&gt;"--add-modules"&lt;/span&gt;, &lt;span class="s2"&gt;"java.base"&lt;/span&gt;,      &lt;span class="s2"&gt;"--output"&lt;/span&gt;, &lt;span class="s2"&gt;"/jlinked"&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
 &lt;span class="nt"&gt;---&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; Using cache
 &lt;span class="nt"&gt;---&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; d7b2793ed509
Step 5/7 : FROM alpine:latest
 &lt;span class="nt"&gt;---&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; cdf98d1859c1
Step 6/7 : COPY &lt;span class="nt"&gt;--from&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;build /jlinked /opt/jdk/
 &lt;span class="nt"&gt;---&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; Using cache
 &lt;span class="nt"&gt;---&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; 993fb106f2c2
Step 7/7 : CMD &lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"/opt/jdk/bin/java"&lt;/span&gt;, &lt;span class="s2"&gt;"--version"&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt; - to check JDK version
 &lt;span class="nt"&gt;---&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; Running &lt;span class="k"&gt;in &lt;/span&gt;8e1658f5f84d
Removing intermediate container 8e1658f5f84d
 &lt;span class="nt"&gt;---&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; 350dd3a72a7d
Successfully built 350dd3a72a7d
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Even though the JDK image is 195MB the build is only 41MB. We can tag the image.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="o"&gt;[&lt;/span&gt;v@alpine-java jdk13_v]&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
&amp;lt;none&amp;gt;              &amp;lt;none&amp;gt;              350dd3a72a7d        21 seconds ago      41.7MB
&amp;lt;none&amp;gt;              &amp;lt;none&amp;gt;              d7b2793ed509        25 minutes ago      565MB
alpine              latest              cdf98d1859c1        2 weeks ago         5.53MB
&lt;span class="o"&gt;[&lt;/span&gt;v@alpine-java jdk13_v]&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;docker tag 350dd3a72a7d jdk-13-musl/jdk-version:v1
&lt;span class="o"&gt;[&lt;/span&gt;v@alpine-java jdk13_v]&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;docker images
REPOSITORY                TAG                 IMAGE ID            CREATED              SIZE
jdk-13-musl/jdk-version   v1                  350dd3a72a7d        About a minute ago   41.7MB
&amp;lt;none&amp;gt;                    &amp;lt;none&amp;gt;              d7b2793ed509        27 minutes ago       565MB
alpine                    latest              cdf98d1859c1        2 weeks ago          5.53MB
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Running the container:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="o"&gt;[&lt;/span&gt;v@alpine-java jdk13_v]&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;docker run jdk-13-musl/jdk-version:v1
openjdk 13-ea 2019-09-17
OpenJDK Runtime Environment &lt;span class="o"&gt;(&lt;/span&gt;build 13-ea+16&lt;span class="o"&gt;)&lt;/span&gt;
OpenJDK 64-Bit Server VM &lt;span class="o"&gt;(&lt;/span&gt;build 13-ea+16, mixed mode&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a id="building-a-hello-world-app"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Building a HelloWorld application
&lt;/h2&gt;

&lt;p&gt;Now we have a base container that we can use to create one with a Java app. Lets use a simple HelloWorld.java.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;HelloWorld&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nc"&gt;System&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;out&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;println&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Hello, World"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Compile the Java code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;javac HelloWorld.java
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Having another Dockerfile for the app container:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="s"&gt; jdk-13-musl/jdk-version:v1&lt;/span&gt;
&lt;span class="k"&gt;ADD&lt;/span&gt;&lt;span class="s"&gt; HelloWorld.class /&lt;/span&gt;
&lt;span class="k"&gt;CMD&lt;/span&gt;&lt;span class="s"&gt; ["/opt/jdk/bin/java", "HelloWorld"]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Building container:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;docker build &lt;span class="nb"&gt;.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After tagging we can run HelloWorld:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;docker run jdk-13-musl/hello-world:v1
Hello, World
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The entire docker run takes around 600ms. Not bad for Java.&lt;/p&gt;

</description>
      <category>linux</category>
      <category>java</category>
      <category>docker</category>
      <category>devops</category>
    </item>
  </channel>
</rss>
