spegel/main.go

137 lines
4.1 KiB
Go
Raw Normal View History

2023-01-24 15:47:27 +01:00
package main
import (
"context"
2023-01-24 16:40:11 +01:00
"errors"
2023-01-24 15:47:27 +01:00
"fmt"
2023-01-24 16:40:11 +01:00
"net/http"
2023-01-24 15:47:27 +01:00
"net/url"
"os"
"os/signal"
"syscall"
2023-01-24 16:40:11 +01:00
"time"
2023-01-24 15:47:27 +01:00
"github.com/alexflint/go-arg"
"github.com/containerd/containerd"
"github.com/go-logr/logr"
"github.com/go-logr/zapr"
2023-01-24 16:40:11 +01:00
"github.com/prometheus/client_golang/prometheus/promhttp"
2023-01-24 15:47:27 +01:00
"github.com/spf13/afero"
"go.uber.org/zap"
"golang.org/x/sync/errgroup"
2023-01-25 15:05:40 +01:00
"github.com/xenitab/spegel/internal/discover"
2023-01-24 15:47:27 +01:00
"github.com/xenitab/spegel/internal/mirror"
"github.com/xenitab/spegel/internal/registry"
"github.com/xenitab/spegel/internal/state"
"github.com/xenitab/spegel/internal/store"
)
type arguments struct {
PodIP string `arg:"--pod-ip,required"`
ServiceName string `arg:"--service-name,required"`
RegistryAddr string `arg:"--registry-addr" default:":5000"`
2023-01-24 16:40:11 +01:00
MetricsAddr string `arg:"--metrics-addr" default:":9090"`
2023-01-25 13:14:41 +01:00
RedisAddr string `arg:"--redis-addr, required"`
MirrorRegistries []url.URL `arg:"--mirror-registries,required"`
ImageFilter string `arg:"--image-filter"`
2023-01-24 15:47:27 +01:00
ContainerdSock string `arg:"--containerd-sock" default:"/run/containerd/containerd.sock"`
ContainerdNamespace string `arg:"--containerd-namespace" default:"k8s.io"`
ContainerdRegistryConfigPath string `arg:"--containerd-registry-config-path" default:"/etc/containerd/certs.d"`
ContainerdMirrorAdd bool `arg:"--containerd-mirror-add" default:"true"`
ContainerdMirrorRemove bool `arg:"--containerd-mirror-remove" default:"true"`
}
func main() {
args := &arguments{}
arg.MustParse(args)
zapLog, err := zap.NewProduction()
if err != nil {
panic(fmt.Sprintf("who watches the watchmen (%v)?", err))
}
log := zapr.NewLogger(zapLog)
ctx := logr.NewContext(context.Background(), log)
ctx, cancel := signal.NotifyContext(ctx, syscall.SIGTERM)
2023-01-24 15:47:27 +01:00
defer cancel()
g, ctx := errgroup.WithContext(ctx)
containerdClient, err := containerd.New(args.ContainerdSock, containerd.WithDefaultNamespace(args.ContainerdNamespace))
if err != nil {
log.Error(err, "could not create containerd client")
os.Exit(1)
}
defer containerdClient.Close()
2023-01-24 16:40:11 +01:00
// Start metrics server
mux := http.NewServeMux()
mux.Handle("/metrics", promhttp.Handler())
srv := &http.Server{
Addr: args.MetricsAddr,
Handler: mux,
}
g.Go(func() error {
if err := srv.ListenAndServe(); err != nil && !errors.Is(err, http.ErrServerClosed) {
return err
}
return nil
})
g.Go(func() error {
<-ctx.Done()
shutdownCtx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
return srv.Shutdown(shutdownCtx)
})
2023-01-24 15:47:27 +01:00
// Setup and run store
2023-01-25 15:05:40 +01:00
store, err := store.NewRedisStore(args.PodIP, discover.NewDNS(args.ServiceName), args.RedisAddr)
2023-01-24 15:47:27 +01:00
if err != nil {
log.Error(err, "could not create store")
os.Exit(1)
}
g.Go(func() error {
2023-01-25 00:24:38 +01:00
return state.Track(ctx, containerdClient, store, args.ImageFilter)
2023-01-24 15:47:27 +01:00
})
// Configure mirrors
2023-01-25 11:23:30 +01:00
// TODO: Wait to write mirror configuration until registry is up and running.
2023-01-24 15:47:27 +01:00
if args.ContainerdMirrorAdd {
fs := afero.NewOsFs()
err := mirror.AddMirrorConfiguration(ctx, fs, args.ContainerdRegistryConfigPath, args.RegistryAddr, args.MirrorRegistries)
if err != nil {
log.Error(err, "could not configure containerd mirror")
os.Exit(1)
}
// TODO: Validate clean up is run if error occurs before start.
if args.ContainerdMirrorRemove {
g.Go(func() error {
<-ctx.Done()
return mirror.RemoveMirrorConfiguration(ctx, fs, args.ContainerdRegistryConfigPath, args.MirrorRegistries)
})
}
}
// Setup and run registry
reg, err := registry.NewRegistry(ctx, args.RegistryAddr, containerdClient, store)
if err != nil {
log.Error(err, "could not create registry")
os.Exit(1)
}
g.Go(func() error {
return reg.ListenAndServe(ctx)
})
g.Go(func() error {
<-ctx.Done()
return reg.Shutdown()
})
log.Info("running registry", "addr", args.RegistryAddr)
err = g.Wait()
if err != nil {
log.Error(err, "exiting with error")
os.Exit(1)
}
log.Info("gracefully shutdown registry")
}