1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
|
<!doctype html><html lang=en-us><meta charset=utf-8><meta name=viewport content="width=device-width,initial-scale=1"><meta name=generator content="JBMAFP - github.com/mitjafelicijan/jbmafp"><link href="data:image/x-icon;base64,AAABAAEAEBAAAAEAIABoBAAAFgAAACgAAAAQAAAAIAAAAAEAIAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAL69vf8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAv76+/8LBwQkAAAAAAAAAAAAAAAC+vb3/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAL+9vf/Bv78JAAAAAAAAAAAAAAAAu7q6/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAC7ubr/vr29CAAAAAAAAAAAy8nJAZ6foP8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAnqGj/6GipAoAAAAAHLjU/xcXHf/BwsL/I8XY/yPK3v8XGiD/IbjL/yPF2f8XGiD/Fxkf/yLF2f8gnK3/Fxog/62ztv8fwNf/FRcd/x271v8mz93/GRsi/xkXHf8p097/GiIp/xobIv8p0t3/KdPe/xocIv8fYmr/KNPe/xoZH/8aHCL/J87c/xy81/8VFxz/IsPZ/8zS0/8XGiD/Ir/R/yPH2/8XGiD/Fxkf/yPH2/8dd4T/GBog/yPJ3f8jyNr/uru9/xcUGv8cudb/EhITDKi5vRKlvMP/RUpOERwcHRAdOj4QHTk8EBwdHRAdNTgQHTo/EBwcHRAcHB0QSGduEKW4vf+koqQfHzg+EBqz0ewSFRv7EyMr/xq51vsTERb7ExUb+xq41fsau9j7ExUb+xiPp/sZudb7ExUb+xMVG/sZuNX/GKvI/BIUGfMdvdn/IrfL/xcaIP8n1eb/J9Dh/xkcIf8ZGR7/J8/f/xxCSv8ZGyH/J9Dg/ybQ4P8ZHCL/FSQs/yPK3/8UExj/GE1b/ybS5P8ZGB7/Ghwj/ynW5P8p2Ob/Ghwi/yWrtv8p1eH/Ghwi/xocIv8p1uT/J8XT/xkcIv8m1un/Hb7d/xUYH/8hzOr/HtHu/xcaIf8XGB//I8vi/xgxOv8XGSD/I8rg/yPK4P8XGiD/GUFL/yPP6f8SERj/Fhkh/x3A4f8AAAAAJ2f9/ydr//8mZPH/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAlYu38J2v//ydo/f8AAAAAAAAAAAd8/fkFqf//Iob8sAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMY39awWr//8FfP3/AAAAAAAAAAAFm/7/SfD//wR+/f8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOB/f9B7v//BaX+/wAAAAAAAAAAQ878SAyZ/v9n1v4KAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADu9v8DDJb+/z3N/XgAAAAA3/sAAN/7AADf+wAA3/sAAAAAAAAAAAAAAAAAAN/7AAAAAAAAAAAAAAAAAAAAAAAAj/EAAI/5AACP8QAA3/sAAA==" rel=icon type=image/x-icon><title>Running Golang application as PID 1 with Linux kernel</title><meta name=description content="Unikernels, kernels, and alikeI have been reading a lot aboutunikernernels lately and found themvery intriguing."><link rel=alternate type=application/rss+xml title="Mitja Felicijan's posts" href=https://mitjafelicijan.com/index.xml><link rel=alternate type=application/rss+xml title="Mitja Felicijan's notes" href=https://mitjafelicijan.com/notes.xml><style>:root{--border-color:gainsboro;--border-size:2px;--link-color:blue;--bg-color:#eee}body{padding:2.5rem;max-width:1900px;background:#fff;font-family:sans-serif;line-height:1.35rem;font-size:16px}hr{border:0;border-bottom:var(--border-size)solid var(--border-color);margin-block-start:1.5rem}a{color:var(--link-color);text-decoration:none}h1,h2,h3{line-height:initial}h1{font-size:xx-large}footer{margin-block-start:2rem}cap{text-transform:capitalize}blockquote{font-style:italic}table{max-width:100%;border:var(--border-size)solid var(--border-color);border-collapse:separate;border-spacing:0}table thead tr th{border-bottom:var(--border-size)solid var(--border-color);text-align:left}table th,table td{padding:.5em .8em}ul.list li{padding:.2em 0}ul{line-height:1.35em}pre{text-wrap:nowrap;overflow-x:auto;padding:0 1em;border:var(--border-size)solid var(--border-color)}code{padding:0 3px;font-size:14px;border:0;background:var(--bg-color)}pre code{line-height:1.3em;background:#fff}pre,code,pre *,code *{font-family:monospace}figure{margin-inline-start:0;margin-inline-end:0}figcaption{text-align:center}figcaption p{margin:.3em 0 0}img,video,audio{width:800px;max-width:100%}header nav{display:flex;gap:.9rem}audio::-webkit-media-controls-enclosure{border-radius:0}@media only screen and (max-width:600px){body{padding:.5em;word-wrap:break-word}header nav{gap:.7rem}header nav .hob{display:none}a{word-wrap:break-word}}</style><header><nav class=main itemscope itemtype=http://schema.org/SiteNavigationElement role=toolbar><a href=/>Home</a>
<a href=/#posts>Posts</a>
<a href=/#notes>Notes</a>
<a href=/#sideprojects class=hob>Side Projects</a>
<a href=/vault.html>Vault</a>
<a href=https://github.com/mitjafelicijan target=_blank>Code</a>
<a href=/mitjafelicijan.pgp.pub.txt target=_blank class=hob>PGP</a>
<a href=/curriculum-vitae.html>CV</a>
<a href=/index.xml target=_blank class=hob>RSS</a></nav></header><main role=main><article itemtype=http://schema.org/Article><h1 itemtype=headline>Running Golang application as PID 1 with Linux kernel</h1><p><cap>post</cap>, Dec 25, 2021 on <a href=https://mitjafelicijan.com>Mitja Felicijan's blog</a><div><h2 id=unikernels-kernels-and-alike>Unikernels, kernels, and alike</h2><p>I have been reading a lot about
<a href=https://en.wikipedia.org/wiki/Unikernel>unikernernels</a> lately and found them
very intriguing. When you push away all the marketing speak and look at the
idea, it makes a lot of sense.<blockquote><p>A unikernel is a specialized, single address space machine image constructed
by using library operating systems. (<a href=https://en.wikipedia.org/wiki/Unikernel>Wikipedia</a>)</blockquote><p>I really like the explanation from the article
<a href="https://queue.acm.org/detail.cfm?id=2566628">Unikernels: Rise of the Virtual Library Operating System</a>.
Really worth a read.<p>If we compare a normal operating system to a unikernel side by side, they would
look something like this.<figure><img loading="lazy" src=/posts/pid1/unikernels.png alt="Virtual machines vs Containers vs Unikernels"></figure><p>From this image, we can see how the complexity significantly decreases with
the use of Unikernels. This comes with a price, of course. Unikernels are hard
to get running and require a lot of work since you don't have an actual proper
kernel running in the background providing network access and drivers etc.<p>So as a half step to make the stack simpler, I started looking into using
Linux kernel as a base and going from there. I came across this
<a href="https://www.youtube.com/watch?v=Sk9TatW9ino">Youtube video talking about Building the Simplest Possible Linux System</a>
by <a href=https://landley.net>Rob Landley</a> and apart from statically compiling the
application to be run as PID1 there was really no other obstacles.<h2 id=what-is-pid-1>What is PID 1?</h2><p>PID 1 is the first process that Linux kernel starts after the boot process.
It also has a couple of unique properties that are unique to it.<ul><li>When the process with PID 1 dies for any reason, all other processes are
killed with KILL signal.<li>When any process having children dies for any reason, its children are
re-parented to process with PID 1.<li>Many signals which have default action of Term do not have one for PID 1.<li>When the process with PID 1 dies for any reason, kernel panics, which
result in system crash.</ul><p>PID 1 is considered as an Init application which takes care of running other
and handling services like:<ul><li>sshd,<li>nginx,<li>pulseaudio,<li>etc.</ul><p>If you are on a Linux machine, you can check what your process is with PID 1
by running the following.<pre tabindex=0 style=background-color:#fff><code><span style=display:flex><span>$ cat /proc/1/status
</span></span><span style=display:flex><span>Name: systemd
</span></span><span style=display:flex><span>Umask: 0000
</span></span><span style=display:flex><span>State: S (sleeping)
</span></span><span style=display:flex><span>Tgid: 1
</span></span><span style=display:flex><span>Ngid: 0
</span></span><span style=display:flex><span>Pid: 1
</span></span><span style=display:flex><span>PPid: 0
</span></span><span style=display:flex><span>...
</span></span></code></pre><p>As we can see on my machine the process with id of 1 is <a href=https://systemd.io/>systemd</a>
which is a software suite that provides an array of system components for Linux
operating systems. If you look closely you can also see that the <code>PPid</code>
(process id of the parent process) is <code>0</code> which additionally confirms that
this process doesn't have a parent.<h2 id=so-why-even-run-application-as-pid-1-instead-of-just-using-a-container>So why even run application as PID 1 instead of just using a container?</h2><p>Containers are wonderful, but they come with a lot of baggage. And because they
are in their nature layered, the images require quite a lot of space and also a
lot of additional software to handle them. They are not as lightweight as they
seem, and many popular images require 500 MB plus disk space.<p>The idea of running this as PID 1 would result in a significantly smaller footprint,
as we will see later in the post.<blockquote><p>You could run a simple init system inside Docker container described more
in this article <a href=https://blog.phusion.nl/2015/01/20/docker-and-the-pid-1-zombie-reaping-problem/>Docker and the PID 1 zombie reaping problem</a>.</blockquote><h2 id=the-master-plan>The master plan</h2><ol><li>Compile Linux kernel with the default definitions.<li>Prepare a Hello World application in Golang that is statically compiled.<li>Run it with <a href=https://www.qemu.org/>QEMU</a> and providing Golang application
as init application / PID 1.</ol><p>For the sake of simplicity we will not be cross-compiling any of it and just
use the 64bit version.<h2 id=compiling-linux-kernel>Compiling Linux kernel</h2><pre tabindex=0 style=background-color:#fff><code><span style=display:flex><span>$ wget https://cdn.kernel.org/pub/linux/kernel/v5.x/linux-5.15.7.tar.xz
</span></span><span style=display:flex><span>$ tar xf linux-5.15.7.tar.xz
</span></span><span style=display:flex><span>
</span></span><span style=display:flex><span>$ cd linux-5.15.7
</span></span><span style=display:flex><span>
</span></span><span style=display:flex><span>$ make clean
</span></span><span style=display:flex><span>
</span></span><span style=display:flex><span><span style=color:green># read more about this https://stackoverflow.com/a/41886394</span>
</span></span><span style=display:flex><span>$ make defconfig
</span></span><span style=display:flex><span>
</span></span><span style=display:flex><span>$ time make -j <span style=color:#a31515>`</span>nproc<span style=color:#a31515>`</span>
</span></span><span style=display:flex><span>
</span></span><span style=display:flex><span>$ cd ..
</span></span></code></pre><p>At this point we have kernel image that is located in <code>arch/x86_64/boot/bzImage</code>.
We will use this in QEMU later.<p>To make our lives a bit easier lets move the kernel image to another place.
Lets create a folder <code>bin/</code> in the root of our project with <code>mkdir -p bin</code>.<p>At this point we can copy <code>bzImage</code> to <code>bin/</code> folder with
<code>cp linux-5.15.7/arch/x86_64/boot/bzImage bin/bzImage</code>.<p>The folder structure of this experiment should look like this.<pre tabindex=0 style=background-color:#fff><code><span style=display:flex><span>pid1/
</span></span><span style=display:flex><span> bin/
</span></span><span style=display:flex><span> bzImage
</span></span><span style=display:flex><span> linux-5.15.7/
</span></span><span style=display:flex><span> linux-5.15.7.tar.xz
</span></span></code></pre><h2 id=preparing-pid-1-application-in-golang>Preparing PID 1 application in Golang</h2><p>This step is relatively easy. The only thing we must have in mind that we will
need to compile the binary as a static one.<p>Let's create <code>init.go</code> file in the root of the project.<pre tabindex=0 style=background-color:#fff><code><span style=display:flex><span><span style=color:#00f>package</span> main
</span></span><span style=display:flex><span>
</span></span><span style=display:flex><span><span style=color:#00f>import</span> (
</span></span><span style=display:flex><span> <span style=color:#a31515>"fmt"</span>
</span></span><span style=display:flex><span> <span style=color:#a31515>"time"</span>
</span></span><span style=display:flex><span>)
</span></span><span style=display:flex><span>
</span></span><span style=display:flex><span><span style=color:#00f>func</span> main() {
</span></span><span style=display:flex><span> <span style=color:#00f>for</span> {
</span></span><span style=display:flex><span> fmt.Println(<span style=color:#a31515>"Hello from Golang"</span>)
</span></span><span style=display:flex><span> time.Sleep(1 * time.Second)
</span></span><span style=display:flex><span> }
</span></span><span style=display:flex><span>}
</span></span></code></pre><p>If you notice, we have a forever loop in the main, with a simple sleep of 1
second to not overwhelm the CPU. This is because PID 1 should never complete
and/or exit. That would result in a kernel panic. Which is BAD!<p>There are two ways of compiling Golang application. Statically and dynamically.<p>To statically compile the binary, use the following command.<pre tabindex=0 style=background-color:#fff><code><span style=display:flex><span>$ go build -ldflags=<span style=color:#a31515>"-extldflags=-static"</span> init.go
</span></span></code></pre><p>We can also check if the binary is statically compiled with:<pre tabindex=0 style=background-color:#fff><code><span style=display:flex><span>$ file init
</span></span><span style=display:flex><span>init: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), statically linked, Go BuildID=Ypu8Zw_4NBxm1Yxg2OYO/H5x721rQ9uTPiDVh-VqP/vZN7kXfGG1zhX_qdHMgH/9vBfmK81tFrygfOXDEOo, not stripped
</span></span><span style=display:flex><span>
</span></span><span style=display:flex><span>$ ldd init
</span></span><span style=display:flex><span>not a dynamic executable
</span></span></code></pre><p>At this point, we need to create <a href=https://www.linuxfromscratch.org/blfs/view/svn/postlfs/initramfs.html>initramfs</a>
(abbreviated from "initial RAM file system", is the successor of initrd. It
is a cpio archive of the initial file system that gets loaded into memory
during the Linux startup process).<pre tabindex=0 style=background-color:#fff><code><span style=display:flex><span>$ echo init | cpio -o --format=newc > initramfs
</span></span><span style=display:flex><span>$ mv initramfs bin/initramfs
</span></span></code></pre><p>The projects at this stage should look like this.<pre tabindex=0 style=background-color:#fff><code><span style=display:flex><span>pid1/
</span></span><span style=display:flex><span> bin/
</span></span><span style=display:flex><span> bzImage
</span></span><span style=display:flex><span> initramfs
</span></span><span style=display:flex><span> linux-5.15.7/
</span></span><span style=display:flex><span> linux-5.15.7.tar.xz
</span></span><span style=display:flex><span> init.go
</span></span></code></pre><h2 id=running-all-of-it-with-qemu>Running all of it with QEMU</h2><p><a href=https://www.qemu.org/>QEMU</a> is a free and open-source hypervisor. It emulates
the machine's processor through dynamic binary translation and provides a set
of different hardware and device models for the machine, enabling it to run a
variety of guest operating systems.<pre tabindex=0 style=background-color:#fff><code><span style=display:flex><span>$ qemu-system-x86_64 -serial stdio -kernel bin/bzImage -initrd bin/initramfs -append <span style=color:#a31515>"console=ttyS0"</span> -m 128
</span></span></code></pre><pre tabindex=0 style=background-color:#fff><code><span style=display:flex><span>$ qemu-system-x86_64 -serial stdio -kernel bin/bzImage -initrd bin/initramfs -append <span style=color:#a31515>"console=ttyS0"</span> -m 128
</span></span><span style=display:flex><span>[ 0.000000] Linux version 5.15.7 (m@khan) (gcc (GCC) 11.2.1 20211203 (Red Hat 11.2.1-7), GNU ld version 2.37-10.fc35) <span style=color:green>#7 SMP Mon Dec 13 10:23:25 CET 2021</span>
</span></span><span style=display:flex><span>[ 0.000000] Command line: console=ttyS0
</span></span><span style=display:flex><span>[ 0.000000] x86/fpu: x87 FPU will use FXSAVE
</span></span><span style=display:flex><span>[ 0.000000] signal: max sigframe size: 1440
</span></span><span style=display:flex><span>[ 0.000000] BIOS-provided physical RAM map:
</span></span><span style=display:flex><span>[ 0.000000] BIOS-e820: [mem 0x0000000000000000-0x000000000009fbff] usable
</span></span><span style=display:flex><span>[ 0.000000] BIOS-e820: [mem 0x000000000009fc00-0x000000000009ffff] reserved
</span></span><span style=display:flex><span>[ 0.000000] BIOS-e820: [mem 0x00000000000f0000-0x00000000000fffff] reserved
</span></span><span style=display:flex><span>[ 0.000000] BIOS-e820: [mem 0x0000000000100000-0x0000000007fdffff] usable
</span></span><span style=display:flex><span>[ 0.000000] BIOS-e820: [mem 0x0000000007fe0000-0x0000000007ffffff] reserved
</span></span><span style=display:flex><span>[ 0.000000] BIOS-e820: [mem 0x00000000fffc0000-0x00000000ffffffff] reserved
</span></span><span style=display:flex><span>[ 0.000000] NX (Execute Disable) protection: active
</span></span><span style=display:flex><span>[ 0.000000] SMBIOS 2.8 present.
</span></span><span style=display:flex><span>[ 0.000000] DMI: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.14.0-6.fc35 04/01/2014
</span></span><span style=display:flex><span>[ 0.000000] tsc: Fast TSC calibration failed
</span></span><span style=display:flex><span>...
</span></span><span style=display:flex><span>[ 2.016106] ALSA device list:
</span></span><span style=display:flex><span>[ 2.016329] No soundcards found.
</span></span><span style=display:flex><span>[ 2.053176] Freeing unused kernel image (initmem) memory: 1368K
</span></span><span style=display:flex><span>[ 2.056095] Write protecting the kernel read-only data: 20480k
</span></span><span style=display:flex><span>[ 2.058248] Freeing unused kernel image (text/rodata gap) memory: 2032K
</span></span><span style=display:flex><span>[ 2.058811] Freeing unused kernel image (rodata/data gap) memory: 500K
</span></span><span style=display:flex><span>[ 2.059164] Run /init as init process
</span></span><span style=display:flex><span>Hello from Golang
</span></span><span style=display:flex><span>[ 2.386879] tsc: Refined TSC clocksource calibration: 3192.032 MHz
</span></span><span style=display:flex><span>[ 2.387114] clocksource: tsc: mask: 0xffffffffffffffff max_cycles: 0x2e02e31fa14, max_idle_ns: 440795264947 ns
</span></span><span style=display:flex><span>[ 2.387380] clocksource: Switched to clocksource tsc
</span></span><span style=display:flex><span>[ 2.587895] input: ImExPS/2 Generic Explorer Mouse as /devices/platform/i8042/serio1/input/input3
</span></span><span style=display:flex><span>Hello from Golang
</span></span><span style=display:flex><span>Hello from Golang
</span></span><span style=display:flex><span>Hello from Golang
</span></span></code></pre><p>The whole <a href=/posts/pid1/qemu.log>log file here</a>.<h2 id=size-comparison>Size comparison</h2><p>The cool thing about this approach is that the Linux kernel and the application
together only take around 12 MB, which is impressive as hell. And we need to
also know that the size of bzImage (Linux kernel) could be greatly decreased
by going into <code>make menuconfig</code> and removing a ton of features from the kernel,
making the size even smaller. I managed to get kernel size down to 2 MB and
still working properly.<pre tabindex=0 style=background-color:#fff><code><span style=display:flex><span>total 12M
</span></span><span style=display:flex><span>-rw-r--r--. 1 m m 9.3M Dec 13 10:24 bzImage
</span></span><span style=display:flex><span>-rw-r--r--. 1 m m 1.9M Dec 27 01:19 initramfs
</span></span></code></pre><h2 id=creating-iso-image-and-running-it-with-gnome-boxes>Creating ISO image and running it with Gnome Boxes</h2><p>First we need to create proper folder structure with <code>mkdir -p iso/boot/grub</code>.<p>Then we need to download the <a href=https://github.com/littleosbook/littleosbook/raw/master/files/stage2_eltorito>grub binary</a>.
You can read more about this program on <a href=https://github.com/littleosbook/littleosbook>https://github.com/littleosbook/littleosbook</a>.<pre tabindex=0 style=background-color:#fff><code><span style=display:flex><span>$ wget -O iso/boot/grub/stage2_eltorito https://github.com/littleosbook/littleosbook/raw/master/files/stage2_eltorito
</span></span></code></pre><pre tabindex=0 style=background-color:#fff><code><span style=display:flex><span>$ tree iso/boot/
</span></span><span style=display:flex><span>iso/boot/
</span></span><span style=display:flex><span>├── bzImage
</span></span><span style=display:flex><span>├── grub
</span></span><span style=display:flex><span>│ ├── menu.lst
</span></span><span style=display:flex><span>│ └── stage2_eltorito
</span></span><span style=display:flex><span>└── initramfs
</span></span></code></pre><p>Let's copy files into proper folders.<pre tabindex=0 style=background-color:#fff><code><span style=display:flex><span>$ cp stage2_eltorito iso/boot/grub/
</span></span><span style=display:flex><span>$ cp bin/bzImage iso/boot/
</span></span><span style=display:flex><span>$ cp bin/initramfs iso/boot/
</span></span></code></pre><p>Lets create a GRUB config file at <code>nano iso/boot/grub/menu.lst</code> with contents.<pre tabindex=0 style=background-color:#fff><code><span style=display:flex><span>default=<span style=color:#a31515>0</span>
</span></span><span style=display:flex><span>timeout=<span style=color:#a31515>5</span>
</span></span><span style=display:flex><span>
</span></span><span style=display:flex><span>title GoAsPID1
</span></span><span style=display:flex><span>kernel /boot/bzImage
</span></span><span style=display:flex><span>initrd /boot/initramfs
</span></span></code></pre><p>Let's create iso file by using genisoimage:<pre tabindex=0 style=background-color:#fff><code><span style=display:flex><span>genisoimage -R <span style=color:#a31515>\
</span></span></span><span style=display:flex><span><span style=color:#a31515></span> -b boot/grub/stage2_eltorito <span style=color:#a31515>\
</span></span></span><span style=display:flex><span><span style=color:#a31515></span> -no-emul-boot <span style=color:#a31515>\
</span></span></span><span style=display:flex><span><span style=color:#a31515></span> -boot-load-size 4 <span style=color:#a31515>\
</span></span></span><span style=display:flex><span><span style=color:#a31515></span> -A os <span style=color:#a31515>\
</span></span></span><span style=display:flex><span><span style=color:#a31515></span> -input-charset utf8 <span style=color:#a31515>\
</span></span></span><span style=display:flex><span><span style=color:#a31515></span> -quiet <span style=color:#a31515>\
</span></span></span><span style=display:flex><span><span style=color:#a31515></span> -boot-info-table <span style=color:#a31515>\
</span></span></span><span style=display:flex><span><span style=color:#a31515></span> -o GoAsPID1.iso <span style=color:#a31515>\
</span></span></span><span style=display:flex><span><span style=color:#a31515></span> iso
</span></span></code></pre><p>This will produce <code>GoAsPID1.iso</code> which you can use with <a href=https://www.virtualbox.org/>Virtualbox</a>
or <a href=https://apps.gnome.org/app/org.gnome.Boxes/>Gnome Boxes</a>.<p><video src=/posts/pid1/boxes.mp4 controls></video><h2 id=is-running-applications-as-pid-1-even-worth-it>Is running applications as PID 1 even worth it?</h2><p>Well, the answer to this is not as simple as one would think. Sometimes it is
and sometimes it's not. For embedded systems and very specialized applications
it is worth for sure. But in normal uses, I don't think so. It was an interesting
exercise in compiling kernels and looking at the guts of the Linux kernel,
but sticking to containers for most of the things is a better option in my
opinion.<p>An interesting experiment would be creating an image that supports networking
and could be deployed to AWS as an EC2 instance and observing how it fares.
But in that case, we would need to write some sort of supervisor that would
run on a separate EC2 that would check if other EC2 instances are running
properly. Remember that if your application fails, kernel panics and the
whole machine is inoperable in this case.</div></article></main><section><hr><h2>Posts from blogs I follow around the net</h2><ul><li><a href=https://utcc.utoronto.ca/~cks/space/blog/linux/NFSv4ServerLockClients target=_blank rel=noopener>Finding which NFSv4 client owns a lock on a Linux NFS(v4) server</a> — <a href=https://utcc.utoronto.ca/~cks/space/blog/>Chris's Wiki :: blog</a><div>A while back I wrote an entry about finding which NFS client owns
a lock on a Linux NFS server, which turned
out to be specific to NFS v3 (which I really should have seen coming,
since it involved NLM and lockd). Finding the NFS v4 client that
owns a lock is, depending on your perspective, either simpl…<li><a href=http://www.landley.net/notes-2023.html#28-10-2023 target=_blank rel=noopener>October 28, 2023</a> — <a href=http://www.landley.net/notes-2023.html>Rob Landley's Blog Thing for 2023</a><div>Oh good grief, two of my least favorite licensing people, Larry Rosen
and Bradley Kuhn, are interacting on the OSI's license-discuss
list where the're doing
bad computer history and insisting that a guy Larry Rosen
coincidentally interviewed for a book years ago is clearly the origin of
somethin…<li><a href="http://offbeatpursuit.com:80/blog/?id=25" target=_blank rel=noopener>A fix by any other name</a> — <a href=http://offbeatpursuit.com:80/blog/>WLOG - blog</a><div>tags:
i2c, plan9
Another month, another file system.
Well, if you can’t fix it in software, fix it in hardware (looking at
you, bme680, we’re not
done yet). The show must go on, as they say, and I would like my
experiments to go on.
So a “new” addition to the environmental sensor family connected to
the h…<li><a href=https://mirzapandzo.com/next-image-url-parameter-is-valid-but-upstream-response-is-invalid target=_blank rel=noopener>Next/Image "url" parameter is valid but upstream response is invalid</a> — <a href=https://mirzapandzo.com/>Mirza Pandzo's Blog</a><div>Getting "url" parameter is valid but upstream response is invalid error with Next/Image on WSL2<li><a href=https://drewdevault.com/2023/10/13/Going-off-script.html target=_blank rel=noopener>Going off-script</a> — <a href=https://drewdevault.com>Drew DeVault's blog</a><div>There is a phenomenon in society which I find quite bizarre. Upon our entry to
this mortal coil, we are endowed with self-awareness, agency, and free will.
Each of the 8 billion members of this human race represents a unique person, a
unique worldview, and a unique agency. Yet, many of us have the sam…<li><a href=https://szymonkaliski.com/writing/2023-10-02-building-a-diy-pen-plotter/ target=_blank rel=noopener>Building a DIY Pen Plotter</a> — <a href=http://github.com/dylang/node-rss>Szymon Kaliski</a><div>This article documents my learnings from designing and building a DIY Pen Plotter during the summer of 2023.
My ultimate goal is to build my…<li><a href=https://neil.computer/notes/chart-of-accounts-for-startups-and-saas-companies/ target=_blank rel=noopener>Chart of Accounts for Startups and SaaS Companies</a> — <a href=https://neil.computer/>Neil Panchal</a><div>Accounting is fundamental to starting a business. You need to have a basic understanding of accounting principles and essential bookkeeping. I had to learn it. There was no choice. For filing taxes, your CPA is going to ask you for an Income Statement (also known as P/L statement). If<li><a href=https://journal.valeriansaliou.name/deploy-a-nomad-cluster-on-alpine-linux-with-vultr/ target=_blank rel=noopener>Deploy a Nomad Cluster on Alpine Linux with Vultr</a> — <a href=https://journal.valeriansaliou.name/>Valerian Saliou</a><div>After spending countless hours trying to understand how to deploy my apps on Kubernetes for the first time to host Mirage, an AI API service that I run, I ended up making myself a promise that the next app I work on would be using a more productive & simpler<li><a href=https://jcs.org/2023/10/25/wifi_da target=_blank rel=noopener>BlueSCSI Wi-Fi Desk Accessory 1.0 Released</a> — <a href=https://jcs.org/>joshua stein</a><div>BlueSCSI Wi-Fi Desk Accessory
1.0 has been released:
wifi_da-1.0.sit
(StuffIt 3 archive)
SHA256: ccfc9d27dd5da7412d10cef73b81119a1fec3848e4d1d88ff652a07ffdc6a69aSHA1: ff124972f202ceda6d7fa4788110a67ccda6a13a
This is the initial public release of my BlueSCSI Wi-Fi Desk Accessory for
classic MacOS.<li><a href=https://michael.stapelberg.ch/posts/2023-10-25-my-all-flash-zfs-network-storage-build/ target=_blank rel=noopener>My 2023 all-flash ZFS NAS (Network Storage) build</a> — <a href=https://michael.stapelberg.ch/>Michael Stapelbergs Website</a><div>For over 10 years now, I run two self-built NAS (Network Storage) devices which serve media (currently via Jellyfin) and run daily backups of all my PCs and servers.
In this article, I describe my goals, which hardware I picked for my new build (and why) and how I set it up.
Design Goals
I use my netw…</ul><p>Generated with <a href=https://git.sr.ht/~sircmpwn/openring target=_blank rel=noopener>openring</a>.</section><footer><hr><p><big><strong>Want to comment or have something to add?</strong></big><p>You can write me an email
at <a href=mailto:mitja.felicijan@gmail.com>mitja.felicijan@gmail.com</a> or
catch up with me <a href=https://telegram.me/mitjafelicijan target=_blank>on Telegram</a>.<hr><p>This website does not track you. Content is made available under the <a href=https://creativecommons.org/licenses/by/4.0/ target=_blank rel=noreferrer>CC BY 4.0 license</a> unless
specified otherwise. Blog is also available as <a href=/index.xml target=_blank>RSS feed</a>.</footer><script>
window.va = window.va || function () { (window.vaq = window.vaq || []).push(arguments); };
</script><script defer src=/_vercel/insights/script.js></script>
|