github.com/grahambrereton-form3/tilt@v0.10.18/internal/k8s/registry.go (about) 1 package k8s 2 3 import ( 4 "context" 5 "fmt" 6 "net" 7 "sync" 8 9 "k8s.io/apimachinery/pkg/api/errors" 10 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 11 apiv1 "k8s.io/client-go/kubernetes/typed/core/v1" 12 13 "github.com/windmilleng/tilt/internal/container" 14 "github.com/windmilleng/tilt/pkg/logger" 15 ) 16 17 const microk8sRegistryNamespace = "container-registry" 18 const microk8sRegistryName = "registry" 19 20 type RuntimeSource interface { 21 Runtime(ctx context.Context) container.Runtime 22 } 23 24 type NaiveRuntimeSource struct { 25 runtime container.Runtime 26 } 27 28 func NewNaiveRuntimeSource(r container.Runtime) NaiveRuntimeSource { 29 return NaiveRuntimeSource{runtime: r} 30 } 31 32 func (s NaiveRuntimeSource) Runtime(ctx context.Context) container.Runtime { 33 return s.runtime 34 } 35 36 type registryAsync struct { 37 env Env 38 core apiv1.CoreV1Interface 39 runtimeSource RuntimeSource 40 registry container.Registry 41 once sync.Once 42 } 43 44 func newRegistryAsync(env Env, core apiv1.CoreV1Interface, runtimeSource RuntimeSource) *registryAsync { 45 return ®istryAsync{ 46 env: env, 47 core: core, 48 runtimeSource: runtimeSource, 49 } 50 } 51 52 func (r *registryAsync) Registry(ctx context.Context) container.Registry { 53 r.once.Do(func() { 54 // Right now, we only recognize the microk8s private registry. 55 if r.env != EnvMicroK8s { 56 return 57 } 58 59 // If Microk8s is using the docker runtime, we can just use the microk8s docker daemon 60 // instead of the registry. 61 runtime := r.runtimeSource.Runtime(ctx) 62 if runtime == container.RuntimeDocker { 63 return 64 } 65 66 // Microk8s might have a registry enabled. 67 // https://microk8s.io/docs/working 68 svc, err := r.core.Services(microk8sRegistryNamespace).Get(microk8sRegistryName, metav1.GetOptions{}) 69 if err != nil { 70 if errors.IsNotFound(err) { 71 logger.Get(ctx).Infof("WARNING: You are running microk8s without a local image registry.\n" + 72 "Run: `sudo microk8s.enable registry`\n" + 73 "Tilt will use the local registry to speed up builds\n") 74 } else { 75 logger.Get(ctx).Debugf("Error fetching services: %v", err) 76 } 77 return 78 } 79 80 portSpecs := svc.Spec.Ports 81 if len(portSpecs) == 0 { 82 return 83 } 84 85 // Check to make sure localhost resolves to an IPv4 address. If it doesn't, 86 // then we won't be able to connect to the registry. See: 87 // https://github.com/windmilleng/tilt/issues/2369 88 ips, err := net.LookupIP("localhost") 89 if err != nil || len(ips) == 0 || ips[0].To4() == nil { 90 logger.Get(ctx).Infof("WARNING: Your /etc/hosts is resolving localhost to ::1 (IPv6).\n" + 91 "This breaks the microk8s image registry.\n" + 92 "Please fix your /etc/hosts to default to IPv4. This will make image pushes much faster.") 93 return 94 } 95 96 portSpec := portSpecs[0] 97 r.registry = container.Registry(fmt.Sprintf("localhost:%d", portSpec.NodePort)) 98 }) 99 return r.registry 100 } 101 102 func (c K8sClient) PrivateRegistry(ctx context.Context) container.Registry { 103 return c.registryAsync.Registry(ctx) 104 } 105 106 func ProvideContainerRegistry(ctx context.Context, kCli Client) container.Registry { 107 return kCli.PrivateRegistry(ctx) 108 }