-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Signed-off-by: Twilight Sparkle <[email protected]>
- Loading branch information
Showing
8 changed files
with
194 additions
and
175 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
brew "deno" | ||
brew "flyctl" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,104 @@ | ||
{ | ||
"entries": { | ||
"brew": { | ||
"deno": { | ||
"version": "1.45.5_1", | ||
"bottle": { | ||
"rebuild": 0, | ||
"root_url": "https://ghcr.io/v2/homebrew/core", | ||
"files": { | ||
"arm64_sonoma": { | ||
"cellar": ":any", | ||
"url": "https://ghcr.io/v2/homebrew/core/deno/blobs/sha256:b7721546c2b27ddb503267aa1d47934624ef4b6fbce469a58f82560373858ff2", | ||
"sha256": "b7721546c2b27ddb503267aa1d47934624ef4b6fbce469a58f82560373858ff2" | ||
}, | ||
"arm64_ventura": { | ||
"cellar": ":any", | ||
"url": "https://ghcr.io/v2/homebrew/core/deno/blobs/sha256:9d23dec3e544306fcc4a6f22ec2f63608d40144e57c6a790288d9dd5553d2c8f", | ||
"sha256": "9d23dec3e544306fcc4a6f22ec2f63608d40144e57c6a790288d9dd5553d2c8f" | ||
}, | ||
"arm64_monterey": { | ||
"cellar": ":any", | ||
"url": "https://ghcr.io/v2/homebrew/core/deno/blobs/sha256:096e7402a9f3b1d18ec3a5b6638b0e9a53b86165cd14f69b56cfabb8c7a875b5", | ||
"sha256": "096e7402a9f3b1d18ec3a5b6638b0e9a53b86165cd14f69b56cfabb8c7a875b5" | ||
}, | ||
"sonoma": { | ||
"cellar": ":any", | ||
"url": "https://ghcr.io/v2/homebrew/core/deno/blobs/sha256:57b30e1a4ab84f2d70d369dd2b0c41ab4025b8017417c1a6aa62577ce6f2afb8", | ||
"sha256": "57b30e1a4ab84f2d70d369dd2b0c41ab4025b8017417c1a6aa62577ce6f2afb8" | ||
}, | ||
"ventura": { | ||
"cellar": ":any", | ||
"url": "https://ghcr.io/v2/homebrew/core/deno/blobs/sha256:605c5ce1c5b142cc422f36c76a2f6cc0dcdf238ef351274704fb8bb8e0d29f4a", | ||
"sha256": "605c5ce1c5b142cc422f36c76a2f6cc0dcdf238ef351274704fb8bb8e0d29f4a" | ||
}, | ||
"monterey": { | ||
"cellar": ":any", | ||
"url": "https://ghcr.io/v2/homebrew/core/deno/blobs/sha256:a0c7f0982940b3b71d36106c3222356ea13e9436b793c7ea57f0778af0618776", | ||
"sha256": "a0c7f0982940b3b71d36106c3222356ea13e9436b793c7ea57f0778af0618776" | ||
}, | ||
"x86_64_linux": { | ||
"cellar": ":any_skip_relocation", | ||
"url": "https://ghcr.io/v2/homebrew/core/deno/blobs/sha256:6c78e31f84e8c56f1ae9318e88078501acce7e95bc7d2201203267ffc4fdc2d0", | ||
"sha256": "6c78e31f84e8c56f1ae9318e88078501acce7e95bc7d2201203267ffc4fdc2d0" | ||
} | ||
} | ||
} | ||
}, | ||
"flyctl": { | ||
"version": "0.2.122", | ||
"bottle": { | ||
"rebuild": 0, | ||
"root_url": "https://ghcr.io/v2/homebrew/core", | ||
"files": { | ||
"arm64_sonoma": { | ||
"cellar": ":any_skip_relocation", | ||
"url": "https://ghcr.io/v2/homebrew/core/flyctl/blobs/sha256:ce38d28c57c450f86920140e696e2dab59a133b6f9d7dfd9ebe2fd5a53e3a74b", | ||
"sha256": "ce38d28c57c450f86920140e696e2dab59a133b6f9d7dfd9ebe2fd5a53e3a74b" | ||
}, | ||
"arm64_ventura": { | ||
"cellar": ":any_skip_relocation", | ||
"url": "https://ghcr.io/v2/homebrew/core/flyctl/blobs/sha256:ce38d28c57c450f86920140e696e2dab59a133b6f9d7dfd9ebe2fd5a53e3a74b", | ||
"sha256": "ce38d28c57c450f86920140e696e2dab59a133b6f9d7dfd9ebe2fd5a53e3a74b" | ||
}, | ||
"arm64_monterey": { | ||
"cellar": ":any_skip_relocation", | ||
"url": "https://ghcr.io/v2/homebrew/core/flyctl/blobs/sha256:ce38d28c57c450f86920140e696e2dab59a133b6f9d7dfd9ebe2fd5a53e3a74b", | ||
"sha256": "ce38d28c57c450f86920140e696e2dab59a133b6f9d7dfd9ebe2fd5a53e3a74b" | ||
}, | ||
"sonoma": { | ||
"cellar": ":any_skip_relocation", | ||
"url": "https://ghcr.io/v2/homebrew/core/flyctl/blobs/sha256:0b9da6d5e865e4f1d6ee9fccf3f5d3bf42d2a6388be85958d90e8e168e673ca5", | ||
"sha256": "0b9da6d5e865e4f1d6ee9fccf3f5d3bf42d2a6388be85958d90e8e168e673ca5" | ||
}, | ||
"ventura": { | ||
"cellar": ":any_skip_relocation", | ||
"url": "https://ghcr.io/v2/homebrew/core/flyctl/blobs/sha256:0b9da6d5e865e4f1d6ee9fccf3f5d3bf42d2a6388be85958d90e8e168e673ca5", | ||
"sha256": "0b9da6d5e865e4f1d6ee9fccf3f5d3bf42d2a6388be85958d90e8e168e673ca5" | ||
}, | ||
"monterey": { | ||
"cellar": ":any_skip_relocation", | ||
"url": "https://ghcr.io/v2/homebrew/core/flyctl/blobs/sha256:0b9da6d5e865e4f1d6ee9fccf3f5d3bf42d2a6388be85958d90e8e168e673ca5", | ||
"sha256": "0b9da6d5e865e4f1d6ee9fccf3f5d3bf42d2a6388be85958d90e8e168e673ca5" | ||
}, | ||
"x86_64_linux": { | ||
"cellar": ":any_skip_relocation", | ||
"url": "https://ghcr.io/v2/homebrew/core/flyctl/blobs/sha256:07c5d5ec255612db34f4e788aecf872e33d20c7a83fe8ffc157a8c7349e65c92", | ||
"sha256": "07c5d5ec255612db34f4e788aecf872e33d20c7a83fe8ffc157a8c7349e65c92" | ||
} | ||
} | ||
} | ||
} | ||
} | ||
}, | ||
"system": { | ||
"linux": { | ||
"Ubuntu 24.04 LTS (noble)": { | ||
"HOMEBREW_VERSION": "4.3.18", | ||
"HOMEBREW_PREFIX": "/home/linuxbrew/.linuxbrew", | ||
"Homebrew/homebrew-core": "api", | ||
"GCC": "13.2.0" | ||
} | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,83 @@ | ||
--- | ||
title: "How I learned to stop worrying and love userspace networking" | ||
date: 2024-08-28 | ||
summary: | ||
image: /images/glaceon.webp | ||
--- | ||
|
||
I like self-hosting things when I can. I have a little server running [k3s](https://k3s.io/) at home that I run stuff on. I also have a few things in the cloud on [fly.io](https://fly.io) (those cheap L40ses are great btw). I wanted my workloads on k3s to access the AI server on fly, but I didn't want to set up a VPN to my private network because mixing VPNs and Kubernetes is painful. I also didn't want to expose the AI server to the internet because it's not really meant to be public, and every time it gets poked, it costs me money. | ||
|
||
Who says you need to do networking in the kernel though? Networking is just a program that takes in bytes and sometimes puts out different bytes. It's usually exposed to programs via the kernel and system calls, but there's nothing stopping you from doing it in userspace. This'd give you all the fun of fucking about with the network but none of those pesky sudo commands or risks of breaking your network stack until you reboot. | ||
|
||
So I looked around and found [wireguard-go has support for netstack](golang.zx2c4.com/wireguard/tun/netstack), a userspace TCP/IP stack for Go programs. It's pretty poorly documented, but I figured out I could dial sockets once I loaded it with config and messed around with the "uapi" a bit. I had to bring in an ini parser to load the WireGuard configs, which is probably wrong, but it works enough. | ||
|
||
Figuring out how to do that was a huge pain. I had to `strace` the `wg-quick` command and everything it was doing, but eventually I got the wire form of the config and I was able to make HTTP requests. I also found out that the uapi form had to pre-resolve DNS addresses, the hard way, of course. | ||
|
||
I got things working and published it on the GitHubs as [`glaceon`](https://github.com/Twi/glaceon). It's a Go program that exposes an HTTP reverse proxy to a given remote host over WireGuard. It's also the most minimal example I can find for how to use wireguard-go from userspace. Maybe how this works is is worth documenting in another post. | ||
|
||
I was just spawning them manually on k3s when I was told that [operator-sdk](https://sdk.operatorframework.io/) would let me make [my own operator](https://github.com/Twi/glaceon-operator). This is an opinionated template that makes it easy to program Kubernetes operators based on "best practices". I kinda hate working with the Go in this framework, but at the very least everything is separated out and all the concerns are easily understood. | ||
|
||
Once it was working, I was able to do something incredibly cheeky: | ||
|
||
```yaml | ||
apiVersion: v1 | ||
kind: Namespace | ||
metadata: | ||
name: flycast | ||
--- | ||
apiVersion: glaceon.friendshipcastle.zip/v1alpha1 | ||
kind: MachineProxy | ||
metadata: | ||
name: twi-ollama | ||
namespace: flycast | ||
spec: | ||
org: personal | ||
region: yyz | ||
target: http://twi-ollama.flycast | ||
port: 80 | ||
``` | ||
This let my apps access my Ollama server via `http://twi-ollama.flycast` in k3s, just like they can on fly. | ||
|
||
## Installing | ||
|
||
Installing this is easy. First, install the operator: | ||
|
||
```sh | ||
kubectl apply -f \ | ||
https://raw.githubusercontent.com/Twi/glaceon-operator/main/config/rendered.yaml | ||
``` | ||
|
||
Then create a token for the fly org you want to expose to your Kubernetes cluster: | ||
|
||
```sh | ||
fly tokens create org personal | ||
``` | ||
|
||
Copy that into the Kubernetes secret `glaceon-operator` in the namespace `glaceon-operator-system` with the name `FLY_API_TOKEN`: | ||
|
||
```sh | ||
kubectl create secret generic \ | ||
glaceon-operator \ | ||
--from-literal=FLY_API_TOKEN=<your-token-value> \ | ||
-n glaceon-operator-system | ||
``` | ||
|
||
Then you can create a MachineProxy resource: | ||
|
||
```sh | ||
cat <<'EOF' | kubectl apply -f - | ||
apiVersion: glaceon.friendshipcastle.zip/v1alpha1 | ||
kind: MachineProxy | ||
metadata: | ||
name: twi-ollama | ||
namespace: flycast | ||
spec: | ||
org: personal | ||
region: yyz | ||
target: http://twi-ollama.flycast | ||
port: 80 | ||
EOF | ||
``` | ||
|
||
And that's it! |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -9,14 +9,14 @@ | |
"lock": false, | ||
"compilerOptions": { "jsx": "react-jsx", "jsxImportSource": "preact" }, | ||
"imports": { | ||
"preact": "https://esm.sh/[email protected].2", | ||
"preact/": "https://esm.sh/[email protected].2/", | ||
"preact": "https://esm.sh/[email protected].6", | ||
"preact/": "https://esm.sh/[email protected].6/", | ||
"preact-render-to-string": "https://esm.sh/*[email protected]", | ||
"@preact/signals": "https://esm.sh/*@preact/[email protected].1", | ||
"@preact/signals-core": "https://esm.sh/*@preact/[email protected].0", | ||
"@preact/signals": "https://esm.sh/*@preact/[email protected].2", | ||
"@preact/signals-core": "https://esm.sh/*@preact/[email protected].1", | ||
"std/": "https://deno.land/[email protected]/", | ||
"@reading-time-estimator": "https://esm.sh/v113/[email protected]", | ||
"$fresh/": "https://deno.land/x/[email protected].1/", | ||
"$fresh/": "https://deno.land/x/[email protected].8/", | ||
"$icons/": "https://deno.land/x/[email protected]/tsx/", | ||
"$ttl": "https://deno.land/x/[email protected]/mod.ts", | ||
"@twind/core": "https://esm.sh/v111/@twind/[email protected]", | ||
|
This file was deleted.
Oops, something went wrong.
Binary file not shown.