feat(dns-server): use embedded DNS server for all service containers

This commit is contained in:
Pavel Sviderski
2025-05-01 11:27:27 +10:00
parent 769f5e47c3
commit cf7e333579
3 changed files with 30 additions and 8 deletions
+4
View File
@@ -36,6 +36,10 @@ demo-reset:
ssh root@5.223.45.199 "AUTO_CONFIRM=true sudo -E uncloud-uninstall"
ssh spy@192.168.40.243 "AUTO_CONFIRM=true sudo -E uncloud-uninstall"
.PHONY: ucind-cluster
ucind-cluster:
go run ./cmd/ucind cluster rm && go run ./cmd/ucind cluster create -m 3
.PHONY: proto
proto:
protoc --go_out=. --go_opt=paths=source_relative --go-grpc_out=. --go-grpc_opt=paths=source_relative \
+17 -1
View File
@@ -8,6 +8,7 @@ import (
"fmt"
"io"
"log/slog"
"net/netip"
"regexp"
"slices"
"strconv"
@@ -30,6 +31,7 @@ import (
"github.com/opencontainers/go-digest"
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
"github.com/psviderski/uncloud/internal/machine/api/pb"
"github.com/psviderski/uncloud/internal/machine/dns"
"github.com/psviderski/uncloud/internal/secret"
"github.com/psviderski/uncloud/pkg/api"
"google.golang.org/grpc"
@@ -45,13 +47,17 @@ type Server struct {
pb.UnimplementedDockerServer
client *client.Client
db *sqlx.DB
// internalDNSIP is a function that returns the IP address of the internal DNS server. It may return an empty
// address if the address is unknown (e.g. when the machine is not initialised yet).
internalDNSIP func() netip.Addr
}
// NewServer creates a new Docker gRPC server with the provided Docker client.
func NewServer(cli *client.Client, db *sqlx.DB) *Server {
func NewServer(cli *client.Client, db *sqlx.DB, internalDNSIP func() netip.Addr) *Server {
return &Server{
client: cli,
db: db,
internalDNSIP: internalDNSIP,
}
}
@@ -505,6 +511,16 @@ func (s *Server) CreateServiceContainer(
},
}
// Configure the container to use the internal DNS server if it's available.
dnsIP := s.internalDNSIP()
if dnsIP.IsValid() {
hostConfig.DNS = []string{dnsIP.String()}
// Optimize DNS resolution for service discovery by appending the search domain to names without a dot.
// For example, the first attempt for "my-service" will be "my-service.internal".
hostConfig.DNSOptions = []string{"ndots:1"}
hostConfig.DNSSearch = []string{dns.InternalDomain}
}
if spec.Container.LogDriver != nil {
hostConfig.LogConfig = container.LogConfig{
Type: spec.Container.LogDriver.Name,
+7 -5
View File
@@ -220,7 +220,6 @@ func NewMachine(config *Config) (*Machine, error) {
if err != nil {
return nil, fmt.Errorf("init machine database: %w", err)
}
dockerServer := machinedocker.NewServer(dockerCli, db)
// Init a local gRPC proxy server that proxies requests to the local or remote machine API servers.
proxyDirector := apiproxy.NewDirector(config.MachineSockPath, APIPort)
@@ -238,11 +237,16 @@ func NewMachine(config *Config) (*Machine, error) {
initialised: make(chan struct{}, 1),
store: corroStore,
cluster: c,
docker: dockerServer,
localProxyServer: localProxyServer,
proxyDirector: proxyDirector,
}
m.localMachineServer = newGRPCServer(m, c, dockerServer)
// Machine IP will only be available after the machine is initialised as a cluster member so wrap it in a function.
internalDNSIP := func() netip.Addr {
return m.IP()
}
m.docker = machinedocker.NewServer(dockerCli, db, internalDNSIP)
m.localMachineServer = newGRPCServer(m, c, m.docker)
if m.Initialised() {
m.initialised <- struct{}{}
@@ -359,8 +363,6 @@ func (m *Machine) Run(ctx context.Context) error {
var err error
m.cluster.UpdateMachineID(m.state.ID)
// TODO: set DNS server to m.IP() on the docker server so it knows which addr to pass as --dns
// for service containers.
// Ensure the corrosion config is up to date, including a new gossip address if the machine
// has just joined a cluster.