-
Notifications
You must be signed in to change notification settings - Fork 13
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
1 changed file
with
73 additions
and
18 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 |
---|---|---|
@@ -1,37 +1,92 @@ | ||
This is a big release that overhauls the networking stack and adds a new kind | ||
of value: a *thunk addr*. | ||
|
||
Thunks can now provide ports: | ||
|
||
```clojure | ||
(-> ($ python -m http.server 80) | ||
(with-image (linux/python)) | ||
(with-port :http 80)) | ||
``` | ||
|
||
Ports can be referenced using a [thunk addr]. A thunk addr is a lot like a | ||
[thunk path] except it represents to a TCP address instead of a filesystem | ||
path. | ||
## thunk ports & addrs | ||
|
||
Thunks can now provide TCP ports using [`with-port`] which can be referenced | ||
with [`addr`] to construct a [thunk addr]: | ||
|
||
```clojure | ||
(def srv | ||
(-> ($ python -m http.server 80) | ||
(-> ($ python -m http.server "80") | ||
(with-image (linux/python)) | ||
(with-port :http 80))) | ||
|
||
(-> ($ wget (addr srv :http "http://$host:$port")) | ||
(with-image (linux/ubuntu)) | ||
(with-image (linux/alpine)) | ||
run) | ||
``` | ||
|
||
The server thunk runs lazily. The client thunk doesn't run until the server's | ||
ports are listening. | ||
A thunk addr is a lot like a [thunk path] except it represents to a TCP address | ||
instead of a filesystem path. | ||
|
||
When using a thunk addr you don't need to worry about managing the lifecycle of | ||
the service that the thunk represents. The service will be run lazily, | ||
de-duplicated across multiple Bass runs, and stopped when all clients go away. | ||
|
||
The advantage of this approach over traditional service lifecycle management | ||
parallels the advantages of using thunk paths instead of managing state in a | ||
local filesystem. It allows thunks that depend on services provided by other | ||
thunks to remain reproducible, just like thunks that depend on files created by | ||
other thunks. | ||
|
||
Thunks no longer run in the host network. Instead they run in a [bridge | ||
network] to prevent port collisions. | ||
[`with-port`]: https://bass-lang.org/stdlib.html#binding-with-port | ||
[`addr`]: https://bass-lang.org/stdlib.html#binding-addr | ||
[thunk path]: https://bass-lang.org/bassics.html#term-thunk%20path | ||
[thunk addr]: https://bass-lang.org/bassics.html#term-thunk%20addr | ||
|
||
Thunks use DNS to address each other in order to maximize caching. (Using IPs | ||
would introduce a source of randomness!) | ||
|
||
## bridge networking & DNS | ||
|
||
To prevent port collisions, thunks no longer run in the host network. Instead | ||
they run in a [bridge network] where each thunk has its own IP and reaches | ||
other thunks using DNS. | ||
|
||
Using DNS is important because IPs are not reproducible. If thunks reached each | ||
other using direct container IPs then caches would be busted every time a | ||
service runs. | ||
|
||
Now that thunks run in their own network, you can't use Bass to run and expose | ||
services to the host machine. This may be added in a future release via port | ||
forwarding. Alternatively you could take the `path-name` (a bit of a misnomer) | ||
of the thunk and reverse-proxy to its container port using the same DNS server | ||
that thunks use. | ||
|
||
[bridge network]: https://www.cni.dev/plugins/current/main/bridge/ | ||
[`path-name`]: https://bass-lang.org/stdlib.html#binding-path-name | ||
|
||
|
||
## automatic TLS | ||
|
||
Thunks may also use TLS. A unique "bass" certificate authority is generated by | ||
the runtime and automaticaly trusted by all thunks that it runs. | ||
|
||
To generate a certificate for a thunk, use [`with-tls`]: | ||
|
||
```clojure | ||
(def registry-mirror | ||
(let [config {:version "0.1" | ||
:http {:addr "0.0.0.0:5000" | ||
:tls {:certificate "/registry.crt" | ||
:key "/registry.key"}} | ||
:storage {:filesystem {:rootdirectory "/var/lib/registry"}} | ||
:proxy {:remoteurl "https://registry-1.docker.io"}}] | ||
(-> ($ registry serve (mkfile ./config.yml (json config))) | ||
(with-image (linux/registry)) | ||
(with-tls /registry.crt /registry.key) | ||
(with-port :http 5000)))) | ||
|
||
(defn main [] | ||
(-> (from (linux/alpine) | ||
($ apk add curl) | ||
($ curl (addr registry-mirror :http "https://$host:$port/v2/"))) | ||
run)) | ||
``` | ||
|
||
Generating TLS certs is a necessary part of the puzzle because thunks use their | ||
own hash as their hostname and DNS entry. It would be impossible to generate a | ||
cert ahead of time and pass it to the thunk because doing so would change the | ||
hash! | ||
|
||
[`with-tls`]: https://bass-lang.org/stdlib.html#binding-with-tls |