Uncloud L4
Natively Uncloud doesn’t do L4 forwarding. This is an open issue as we are figuring out how to actually do this. But it turns out you can already do this with the current code - well almost.
Buckle up, because there is quite some stuff you may need:
- A patched Uncloud, see this PR for that.
- A custom Caddy build, with the L4 plugin.
- A DNS server, I use atomdns of course.
Note I use a fork + merge requests I need that is available at: https://github.com/miekg/uncloudplus .
Caddy⌗
With the following Dockerfile you create a custom caddy image that we will use.
FROM caddy:2.11.2-builder AS builder
RUN xcaddy build \
--with github.com/mholt/caddy-l4
FROM caddy:2.11.2
COPY --from=builder /usr/bin/caddy /usr/bin/caddy
The compose.yaml is remarkably short, but we also need a Caddyfile, both are listed here, the Caddyfile first, this tells caddy to forward the DNS traffic to the internal address of the DNS server.
{
layer4 {
udp/:53 {
route {
proxy udp/atomdns.internal:53
}
}
tcp/:53 {
route {
proxy tcp/atomdns.internal:53
}
}
}
}
And the compose.yaml:
services:
caddy:
image: registry.science.ru.nl/cncz/sys/image/caddy:latest
command: caddy run -c /config/Caddyfile
environment:
CADDY_ADMIN: unix//run/caddy/admin.sock
volumes:
- /var/lib/uncloud/caddy:/data
- /var/lib/uncloud/caddy:/config
- /run/uncloud/caddy:/run/caddy
x-ports:
- 80:80@host
- 443:443@host
- 443:443/udp@host
- 131.174.88.0/24:53:53@host
- 131.174.88.0/24:53:53/udp@host
x-caddy: Caddyfile
deploy:
mode: global
Where I want to highlight 131.174.88.0/24:53:53@host and udp variant which is what the pull requests
adds. This adds to listen on a (CIDR) prefix, uncloud will match this prefix to interfaces and only listen on
those that actually have an address contained in the prefix. This way the caddy service can still be globally
deployed. If I were to bind on all interfaces (the default for Uncloud) I trample on uncloudd own use of
the port 53.
If you are in the directory where you saved the above files you can just run uc deploy -y and have caddy
running.
atomdns⌗
We use this Dockerfile to build atomdns ourselves.
ARG BUILD_IMAGE=golang:latest
ARG BASE=alpine:latest
FROM --platform=$BUILDPLATFORM ${BUILD_IMAGE} AS build
WORKDIR /tmp
RUN git clone --depth 1 https://codeberg.org/miekg/dns
WORKDIR /tmp/dns/cmd/atomdns
RUN go mod download
RUN CGO_ENABLED=0 go build
FROM ${BASE}
COPY --from=build /tmp/dns/cmd/atomdns/atomdns /atomdns
WORKDIR /
EXPOSE 53 53/udp 443
ENTRYPOINT ["/atomdns"]
The compose file a longer, and includes the Conffile for atomdns to use:
# This compose file configures an atomdns that can be used as the cluster-dns' server.
services:
atomdns:
image: registry.science.ru.nl/cncz/sys/image/atomdns:v0.1.15
configs:
- source: atomdns_config
target: /etc/Conffile
mode: 0444
- source: atomdns_file
target: /etc/u.science.ru.nl
mode: 0444
command:
- /etc/Conffile
deploy:
mode: global
volumes:
- atomdns_data:/var/lib/atomdns
volumes:
atomdns_data:
labels:
nl.ru.science.backup: "kopia"
configs:
atomdns_file:
content: |
$$TTL 60
$$ORIGIN u.science.ru.nl.
@ IN SOA uncloud1.vm.science.ru.nl. postmaster.science.ru.nl. (
1778503939 ; serial
4H ; refresh
1H ; retry
2H ; expire
4H ; minimum
)
IN NS uncloud1.vm.science.ru.nl.
IN NS uncloud2.vm.science.ru.nl.
*.ctrl IN A 131.174.88.77
IN A 131.174.88.78
atomdns_config:
content: |
{
log
root /var/lib/atomdns
dns {
addr [::]:53
}
}
u.science.ru.nl {
log
dbfile /etc/u.science.ru.nl
}
# for debugging purposes
example.org {
whoami
log
}
Also deploy that. The example.org zone is there to help in debugging. This now assumes DNS is setup to point
to the cluster. With uc dns set ctrl.u.science.ru.nl you set the cluster’s domain name.
When running the above you can send DNS queries to your cluster and they will get answers
% uc ls
NAME MODE REPLICAS IMAGE ENDPOINTS
atomdns glboal 2 registry.science.ru.nl/cncz/sys/image/atomdns:v0.1.16
caddy global 2 registry.science.ru.nl/cncz/sys/image/caddy:latest (custom Caddy config)
debug replicated 1 registry.science.ru.nl/cncz/sys/image/debug:latest
And dig @uncloud1.vm.science.ru.nl a whoami.example.org returns an answer. With +tcp too.