aboutsummaryrefslogtreecommitdiff
path: root/articles
diff options
context:
space:
mode:
Diffstat (limited to 'articles')
-rw-r--r--articles/2024-05-03-replaced-infra.md107
1 files changed, 107 insertions, 0 deletions
diff --git a/articles/2024-05-03-replaced-infra.md b/articles/2024-05-03-replaced-infra.md
new file mode 100644
index 0000000..1177d7b
--- /dev/null
+++ b/articles/2024-05-03-replaced-infra.md
@@ -0,0 +1,107 @@
+# infra - my homebrew package and configuration manager
+
+The last 8 months I was configuring my server with my own little package manager
+[`infra`](https://codeberg.org/metamuffin/infra) before just recently replacing
+it again a few days ago for reasons I will mention later. This had multiple
+reasons; primarily that I want to version control all configuration of all my
+servers (the VPS and a Raspi) from one source-controlled repository.
+
+## infra good
+
+My "package manager" was actually more like a library where one would write code
+to specify how the machines were set up. This is similar to how Nix or Guix do
+it. My implementation however was written in Rust and initially hacked together
+in a few hours. Let's look at an example:
+
+```rs
+// You would pass credentials to the machine here
+let m = Machine::new(...);
+
+// Load a minimal gnix config without any hosts.
+let mut gnix = Gnix::load(include_str!("gnix_base.yaml"))
+
+m.install(Fastbangs {
+ // Here gnix automatically allocates a new port for internal proxying.
+ bind_addr: gnix.new_host("search.metamuffin.org"),
+ data_dir: "/var/local/fastbangs".into(),
+ ..Default::default()
+}.service());
+
+m.eu1.install(MetamuffinWebsite {
+ bind_addr: eu1_gnix.new_host("metamuffin.org"),
+}.service()); // `service` transforms the mere software configuration to a systemd service that uses it.
+
+m.install(gnix);
+```
+
+Infra would for this example automatically download, compile, install, configure
+and start/enable required services. It was a total solution. The current state
+of each machine (i.e. installed packages) was tracked locally. Whenever the
+deployment specification changes, a diff is calculated and applied
+incrementally. Applying an installation is very general term in infra, it could
+mean placing some configs somewhere but also starting and stopping systemd
+services or whatever.
+
+Procedurally generating the server configuration had more advantages than not
+struggling with port numbers, I could also create fully meshed Wireguard VPNs
+with ease. Something that is considerably more pain if done manually. The
+following excerpt creates such a network, automatically assigns IP addresses and
+even writes hostnames to `/etc/hosts`.
+
+```rs
+let mut hosts = HostsFile::default();
+let mut wg_myservers_subnet = IpSubnet([10, 123, 0, 0].into(), 16);
+let wg_myservers = WireguardMesh::new("myservers", 16);
+server1.install(wg_myservers.add_peer(
+ hosts.register(wg_myservers_subnet.next(), "server1"),
+ "server1.example.org:12345".into(),
+ "SECRET VALUE GOES HERE"
+));
+server2.install(wg_myservers.add_peer(
+ hosts.register(wg_myservers_subnet.next(), "server2"),
+ "server2.example.org:12345".into(),
+ "SECRET VALUE GOES HERE"
+));
+server3.install(wg_myservers.add_peer(
+ hosts.register(wg_myservers_subnet.next(), "server2"),
+ "server3.example.org:12345".into(),
+ "SECRET VALUE GOES HERE"
+))
+for s in [server1, server2, server3] {
+ s.install(hosts);
+}
+```
+
+## infra bad
+
+Like mentioned the state was tracked locally, which meant I was restricted to a
+single machine for maintaining my server.
+
+Also, and this is the worst part, infra would manage the server by connecting
+via SSH and executing random commands through a simple shell wrapper. This
+process will not take any feedback about the success about what it did.
+Obviously all commands are executed intelligently but if the connection broke or
+something else destabilized the system, there was no way to fix it trivially.
+
+Another problem was transparency. Although infra allows exporting an overview of
+your deployment as a directed graph, it still didn't suffice for a good
+understanding about what was configured where. Sometimes I would install two
+packages that wrote to the same configuration - something that infra does not
+worry about - and get unexpected results.
+
+It could also be considered a minor problem, that some configuration files just
+don't prettier when written with a Rust DSL.
+
+## infra useless?
+
+`infra` is flawed. It just doesn't work if you have anything serious to
+maintain. However the basic concept of generating configuration from code is
+quite nice and were somewhat elegant to use sometimes.
+
+In the last week I replaced infra in my deployments with a different system that
+I will describe in the next article. Going forward though I am thinking of
+taking the best from infra and turning it into a static configuration and script
+generator to be used in the new system.
+
+That's that. If you have any interesting feedback or thoughts on this topic,
+please [reach out](/contact).