gokrazy/website/content/prototyping.html
2020-05-31 20:29:57 +02:00

209 lines
7.5 KiB
HTML
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

---
layout: default
title: gokrazy prototyping
aliases:
- /prototyping.html
---
<div class="row">
<div class="col-lg-12">
<h1>Prototyping</h1>
<p>
To realize the full benefits of gokrazy, you need to use only
software written in Go. If there is no Go software for what you want
to do, creating that piece of software can pose a seemingly
unsurmountable hurdle. To make some quick progress and figure out if
your idea can be implemented, it might make sense to temporarily use
existing software before starting your own implementation.
</p>
<p>
This article shows a couple of techniques for getting non-Go
software to work on gokrazy, in increasing order of complexity.
</p>
<p>
Note that software which is manually installed like shown
here <strong>will not be automatically updated</strong> by gokrazy
and hence poses a security risk. Use these techniques only for
prototyping.
</p>
<h2>Go software not written for gokrazy: node-exporter</h2>
<p>
The Prometheus node-exporter doesnt use cgo and needs no
command-line parameters, configuration files or other assets can be
added to the <code>gokr-packer</code> command line.
</p>
<h2>Go software not written for gokrazy: Grafana</h2>
<p>
It would not suffice to add Grafana to your <code>gokr-packer</code>
command, as the resulting Grafana binary requires assets, supports
plugins, keeps state, etc.
</p>
<p>
Hence, you need to manually install Grafana into a directory
underneath <code>/perm</code>. A convenient way to do that is to
use <a href="https://github.com/gokrazy/breakglass">breakglass</a>
to download the “Standalone Linux Binaries” release from
<a href="https://grafana.com/grafana/download?platform=arm">https://grafana.com/grafana/download?platform=arm</a>. Note
that I am serving the file from my computer because my busybox
version supports neither HTTPS nor DNS.
</p>
<pre>
/tmp/breakglass531810560 # wget http://10.0.0.76:4080/grafana-5.3.2.linux-arm64.tar.gz
/tmp/breakglass531810560 # tar xf grafana-5.3.2.linux-arm64.tar.gz</pre>
<p>
We cannot start Grafana yet, as its binary is dynamically
linked. One way to fix this is to place the sources which correspond
to the release you just unpacked (e.g. from
<a href="https://github.com/grafana/grafana/tree/v5.3.2">https://github.com/grafana/grafana/tree/v5.3.2</a>)
in your <code>$GOPATH</code> and recompile the binaries:
</p>
<pre>GOARCH=arm64 CGO_ENABLED=1 CC=aarch64-linux-gnu-gcc go install \
-ldflags "-linkmode external -extldflags -static" \
github.com/grafana/grafana/pkg/cmd/...</pre>
<p>
Note that it is usually easier to set the environment
variable <code>CGO_ENABLED=0</code> to get a statically linked
binary, but Grafana uses sqlite3, which is written in C, so we
resort to the <code>-ldflags</code> variant.
</p>
<p>
At this point, we can start Grafana from breakglass:
</p>
<pre>
/tmp/breakglass531810560 # cd grafana-5.3.2
/tmp/breakglass531810560/grafana-5.3.2 # wget http://10.0.0.76:4080/grafana-server
/tmp/breakglass531810560/grafana-5.3.2 # install -m 755 grafana-server bin/ && rm grafana-server
/tmp/breakglass531810560/grafana-5.3.2 # ./bin/grafana-server
INFO[10-30|19:27:51] Starting Grafana logger=server version=5.0.0 commit=NA compiled=2018-10-30T19:27:51+0100
</pre>
<p>
To have gokrazy start Grafana, we can use a Go package like this:
</p>
<pre>
package main
import (
"log"
"syscall"
)
func main() {
const bin = "/perm/grafana/bin/grafana-server"
if err := syscall.Exec(bin, []string{bin, "-homepath=/perm/grafana"}, nil); err != nil {
log.Fatal(err)
}
}
</pre>
<h2>C software: WireGuard</h2>
<p>
WireGuard is a modern VPN tunnel, which consists of a Linux kernel
module and a configuration
tool. See <a href="https://github.com/rtr7/kernel/commit/c7afbc1fd2efdb9e1149d271c4d2be59cc5c98f4">rtr7/kernel@c7afbc1f</a>
for how the kernel module was added to the router7 kernel.
</p>
<p>
The configuration tool can be statically cross-compiled. We can run
Debian in a Docker container to not mess with our host system:
</p>
<pre>
% mkdir /tmp/wg
% cd /tmp/wg
% docker run -t -i debian
root@d1728eaaa6e1:/# dpkg --add-architecture arm64
root@d1728eaaa6e1:/# apt update
root@d1728eaaa6e1:/# apt install libmnl-dev:arm64 libelf-dev:arm64 linux-headers-amd64 crossbuild-essential-arm64 pkg-config wget
root@d1728eaaa6e1:/# wget https://git.zx2c4.com/WireGuard/snapshot/WireGuard-0.0.20181018.tar.xz
root@d1728eaaa6e1:/# tar xf WireGuard-0.0.20181018.tar.xz
root@d1728eaaa6e1:/# cd WireGuard-0.0.20181018/src/tools
root@d1728eaaa6e1:/# make CC=aarch64-linux-gnu-gcc LDFLAGS=-static
root@d1728eaaa6e1:/# exit
% docker cp -L d1728eaaa6e1:/WireGuard-0.0.20181018/src/tools/wg .</pre>
<p>
Now we can copy and run the <code>wg</code> binary via breakglass:
</p>
<pre>
/tmp/breakglass531810560 # wget http://10.0.0.76:4080/wg
/tmp/breakglass531810560 # chmod +x wg
/tmp/breakglass531810560 # ./wg --help
Usage: ./wg &lt;cmd&gt; [&lt;args&gt;]
</pre>
<h2>C software: tc</h2>
<p>
Linuxs Traffic Control system (used e.g. for traffic shaping) is
configured with the <code>tc</code> tool.
</p>
<p>
<code>tc</code> is a special case in that it requires to be
dynamically linked. The different queueing disciplines are
implemented as plugins, and statically linking <code>tc</code>
results in a binary which starts but wont be able to display or
change queueing disciplines.
</p>
<p>
Because gokrazy doesnt include a C runtime environment, well need
to copy not only the <code>tc</code> binary, but also the dynamic
loader and all required shared libraries. We can run Debian in a
Docker container to not mess with our host system:
</p>
<pre>
% mkdir /tmp/iproute
% cd /tmp/iproute
% docker run -t -i debian
root@6e530a973d45:/# dpkg --add-architecture arm64
root@6e530a973d45:/# apt update
root@6e530a973d45:/# apt install iproute2:arm64 qemu-user-static
root@6e530a973d45:/# LD_TRACE_LOADED_OBJECTS=1 qemu-aarch64-static /sbin/tc
libelf.so.1 => /usr/lib/aarch64-linux-gnu/libelf.so.1 (0x00000040008a6000)
libm.so.6 => /lib/aarch64-linux-gnu/libm.so.6 (0x00000040008cb000)
libdl.so.2 => /lib/aarch64-linux-gnu/libdl.so.2 (0x0000004000976000)
libc.so.6 => /lib/aarch64-linux-gnu/libc.so.6 (0x0000004000989000)
/lib/ld-linux-aarch64.so.1 (0x0000004000870000)
libz.so.1 => /lib/aarch64-linux-gnu/libz.so.1 (0x0000004000ad3000)
root@6e530a973d45:/# exit
% docker cp -L 6e530a973d45:/sbin/tc .
% docker cp -L 6e530a973d45:/lib/ld-linux-aarch64.so.1 .
% docker cp -L 6e530a973d45:/usr/lib/aarch64-linux-gnu/libelf.so.1 .
% docker cp -L 6e530a973d45:/lib/aarch64-linux-gnu/libm.so.6 .
% docker cp -L 6e530a973d45:/lib/aarch64-linux-gnu/libdl.so.2 .
% docker cp -L 6e530a973d45:/lib/aarch64-linux-gnu/libc.so.6 .
% docker cp -L 6e530a973d45:/lib/aarch64-linux-gnu/libz.so.1 .</pre>
<p>
Now we can copy the contents of the temporary directory to
e.g. <code>/perm/tc</code> and run the <code>tc</code> command in
breakglass:
</p>
<pre>
/tmp/breakglass531810560 # wget -O- http://10.0.0.76:4080/tc.tar | tar xf -
/tmp/breakglass531810560 # LD_LIBRARY_PATH=$PWD ./ld-linux-aarch64.so.1 ./tc
Usage: tc [ OPTIONS ] OBJECT { COMMAND | help }
</pre>
</div>
</div>