kubernetes: trim client-go dependency surface

Replace the full generated clientset and global Kubernetes scheme
with a small local REST client layer and minimal scheme registration.

This keeps the existing kubeconfig/auth and remote exec behavior while
significantly reducing the linked and vendored Kubernetes dependency set.

Signed-off-by: Tonis Tiigi <tonistiigi@gmail.com>
This commit is contained in:
Tonis Tiigi
2026-03-06 16:44:18 -08:00
parent bb481888f9
commit 5a7f7c286f
1913 changed files with 215 additions and 551638 deletions
+5 -9
View File
@@ -11,6 +11,7 @@ import (
"github.com/docker/buildx/driver"
"github.com/docker/buildx/driver/kubernetes/execconn"
"github.com/docker/buildx/driver/kubernetes/kubeclient"
"github.com/docker/buildx/driver/kubernetes/manifest"
"github.com/docker/buildx/driver/kubernetes/podchooser"
"github.com/docker/buildx/store"
@@ -24,9 +25,6 @@ import (
corev1 "k8s.io/api/core/v1"
apierrors "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/kubernetes"
clientappsv1 "k8s.io/client-go/kubernetes/typed/apps/v1"
clientcorev1 "k8s.io/client-go/kubernetes/typed/core/v1"
)
const (
@@ -49,10 +47,9 @@ type Driver struct {
minReplicas int
deployment *appsv1.Deployment
configMaps []*corev1.ConfigMap
clientset *kubernetes.Clientset
deploymentClient clientappsv1.DeploymentInterface
podClient clientcorev1.PodInterface
configMapClient clientcorev1.ConfigMapInterface
deploymentClient kubeclient.DeploymentClient
podClient kubeclient.PodClient
configMapClient kubeclient.ConfigMapClient
podChooser podchooser.PodChooser
defaultLoad bool
timeout time.Duration
@@ -201,7 +198,6 @@ func (d *Driver) Rm(ctx context.Context, force, rmVolume, rmDaemon bool) error {
}
func (d *Driver) Dial(ctx context.Context) (net.Conn, error) {
restClient := d.clientset.CoreV1().RESTClient()
restClientConfig, err := d.clientConfig.ClientConfig()
if err != nil {
return nil, err
@@ -221,7 +217,7 @@ func (d *Driver) Dial(ctx context.Context) (net.Conn, error) {
var conn net.Conn
err = tryWithBackoff(ctx, pod.Name, func() error {
var err error
conn, err = execconn.ExecConn(ctx, restClient, restClientConfig, pod.Namespace, pod.Name, containerName, cmd)
conn, err = execconn.ExecConn(ctx, d.podClient.RESTClient(), restClientConfig, pod.Namespace, pod.Name, containerName, cmd)
return err
})
return conn, err
+2 -2
View File
@@ -8,9 +8,9 @@ import (
"sync"
"time"
"github.com/docker/buildx/driver/kubernetes/kubeclient"
"github.com/sirupsen/logrus"
corev1 "k8s.io/api/core/v1"
"k8s.io/client-go/kubernetes/scheme"
"k8s.io/client-go/rest"
"k8s.io/client-go/tools/remotecommand"
)
@@ -29,7 +29,7 @@ func ExecConn(ctx context.Context, restClient rest.Interface, restConfig *rest.C
Stdout: true,
Stderr: true,
TTY: false,
}, scheme.ParameterCodec)
}, kubeclient.ParameterCodec)
exec, err := remotecommand.NewSPDYExecutor(restConfig, "POST", req.URL())
if err != nil {
return nil, err
+8 -9
View File
@@ -10,13 +10,13 @@ import (
"github.com/docker/buildx/driver"
"github.com/docker/buildx/driver/bkimage"
ctxkube "github.com/docker/buildx/driver/kubernetes/context"
"github.com/docker/buildx/driver/kubernetes/kubeclient"
"github.com/docker/buildx/driver/kubernetes/manifest"
"github.com/docker/buildx/driver/kubernetes/podchooser"
dockerclient "github.com/moby/moby/client"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
corev1 "k8s.io/api/core/v1"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/rest"
)
@@ -116,16 +116,11 @@ func (f *factory) New(ctx context.Context, cfg driver.InitConfig) (driver.Driver
if err != nil {
return nil, err
}
clientset, err := kubernetes.NewForConfig(restClientConfig)
if err != nil {
return nil, err
}
d := &Driver{
factory: f,
clientConfig: cc,
InitConfig: cfg,
clientset: clientset,
}
deploymentOpt, loadbalance, namespace, defaultLoad, timeout, err := f.processDriverOpts(deploymentName, namespace, cfg)
@@ -143,9 +138,13 @@ func (f *factory) New(ctx context.Context, cfg driver.InitConfig) (driver.Driver
d.minReplicas = int(deploymentOpt.Replicas)
d.deploymentClient = clientset.AppsV1().Deployments(namespace)
d.podClient = clientset.CoreV1().Pods(namespace)
d.configMapClient = clientset.CoreV1().ConfigMaps(namespace)
clients, err := kubeclient.New(restClientConfig, namespace)
if err != nil {
return nil, err
}
d.deploymentClient = clients.Deployments
d.podClient = clients.Pods
d.configMapClient = clients.ConfigMaps
switch loadbalance {
case LoadbalanceSticky:
+175
View File
@@ -0,0 +1,175 @@
package kubeclient
import (
"context"
"net/http"
appsv1 "k8s.io/api/apps/v1"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/client-go/rest"
)
type DeploymentClient interface {
Get(ctx context.Context, name string, opts metav1.GetOptions) (*appsv1.Deployment, error)
Create(ctx context.Context, deployment *appsv1.Deployment, opts metav1.CreateOptions) (*appsv1.Deployment, error)
Delete(ctx context.Context, name string, opts metav1.DeleteOptions) error
}
type ConfigMapClient interface {
Create(ctx context.Context, configMap *corev1.ConfigMap, opts metav1.CreateOptions) (*corev1.ConfigMap, error)
Update(ctx context.Context, configMap *corev1.ConfigMap, opts metav1.UpdateOptions) (*corev1.ConfigMap, error)
Delete(ctx context.Context, name string, opts metav1.DeleteOptions) error
}
type PodClient interface {
List(ctx context.Context, opts metav1.ListOptions) (*corev1.PodList, error)
RESTClient() rest.Interface
}
type Clients struct {
Deployments DeploymentClient
ConfigMaps ConfigMapClient
Pods PodClient
}
func New(config *rest.Config, namespace string) (*Clients, error) {
httpClient, err := rest.HTTPClientFor(config)
if err != nil {
return nil, err
}
appsClient, err := newRESTClient(config, httpClient, appsv1.SchemeGroupVersion, "/apis")
if err != nil {
return nil, err
}
coreClient, err := newRESTClient(config, httpClient, corev1.SchemeGroupVersion, "/api")
if err != nil {
return nil, err
}
return &Clients{
Deployments: &deploymentClient{client: appsClient, namespace: namespace},
ConfigMaps: &configMapClient{client: coreClient, namespace: namespace},
Pods: &podClient{client: coreClient, namespace: namespace},
}, nil
}
func newRESTClient(config *rest.Config, httpClient *http.Client, gv schema.GroupVersion, apiPath string) (rest.Interface, error) {
cfg := *config
cfg.GroupVersion = &gv
cfg.APIPath = apiPath
cfg.NegotiatedSerializer = rest.CodecFactoryForGeneratedClient(Scheme, Codecs).WithoutConversion()
if cfg.UserAgent == "" {
cfg.UserAgent = rest.DefaultKubernetesUserAgent()
}
return rest.RESTClientForConfigAndClient(&cfg, httpClient)
}
type deploymentClient struct {
client rest.Interface
namespace string
}
func (c *deploymentClient) Get(ctx context.Context, name string, opts metav1.GetOptions) (*appsv1.Deployment, error) {
result := &appsv1.Deployment{}
err := c.client.Get().
UseProtobufAsDefault().
Namespace(c.namespace).
Resource("deployments").
Name(name).
VersionedParams(&opts, ParameterCodec).
Do(ctx).
Into(result)
return result, err
}
func (c *deploymentClient) Create(ctx context.Context, deployment *appsv1.Deployment, opts metav1.CreateOptions) (*appsv1.Deployment, error) {
result := &appsv1.Deployment{}
err := c.client.Post().
UseProtobufAsDefault().
Namespace(c.namespace).
Resource("deployments").
VersionedParams(&opts, ParameterCodec).
Body(deployment).
Do(ctx).
Into(result)
return result, err
}
func (c *deploymentClient) Delete(ctx context.Context, name string, opts metav1.DeleteOptions) error {
return c.client.Delete().
UseProtobufAsDefault().
Namespace(c.namespace).
Resource("deployments").
Name(name).
Body(&opts).
Do(ctx).
Error()
}
type configMapClient struct {
client rest.Interface
namespace string
}
func (c *configMapClient) Create(ctx context.Context, configMap *corev1.ConfigMap, opts metav1.CreateOptions) (*corev1.ConfigMap, error) {
result := &corev1.ConfigMap{}
err := c.client.Post().
UseProtobufAsDefault().
Namespace(c.namespace).
Resource("configmaps").
VersionedParams(&opts, ParameterCodec).
Body(configMap).
Do(ctx).
Into(result)
return result, err
}
func (c *configMapClient) Update(ctx context.Context, configMap *corev1.ConfigMap, opts metav1.UpdateOptions) (*corev1.ConfigMap, error) {
result := &corev1.ConfigMap{}
err := c.client.Put().
UseProtobufAsDefault().
Namespace(c.namespace).
Resource("configmaps").
Name(configMap.Name).
VersionedParams(&opts, ParameterCodec).
Body(configMap).
Do(ctx).
Into(result)
return result, err
}
func (c *configMapClient) Delete(ctx context.Context, name string, opts metav1.DeleteOptions) error {
return c.client.Delete().
UseProtobufAsDefault().
Namespace(c.namespace).
Resource("configmaps").
Name(name).
Body(&opts).
Do(ctx).
Error()
}
type podClient struct {
client rest.Interface
namespace string
}
func (c *podClient) List(ctx context.Context, opts metav1.ListOptions) (*corev1.PodList, error) {
result := &corev1.PodList{}
err := c.client.Get().
UseProtobufAsDefault().
Namespace(c.namespace).
Resource("pods").
VersionedParams(&opts, ParameterCodec).
Do(ctx).
Into(result)
return result, err
}
func (c *podClient) RESTClient() rest.Interface {
return c.client
}
+21
View File
@@ -0,0 +1,21 @@
package kubeclient
import (
appsv1 "k8s.io/api/apps/v1"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apimachinery/pkg/runtime/serializer"
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
)
var Scheme = runtime.NewScheme()
var Codecs = serializer.NewCodecFactory(Scheme)
var ParameterCodec = runtime.NewParameterCodec(Scheme)
func init() {
metav1.AddToGroupVersion(Scheme, schema.GroupVersion{Version: "v1"})
utilruntime.Must(corev1.AddToScheme(Scheme))
utilruntime.Must(appsv1.AddToScheme(Scheme))
}
+4 -4
View File
@@ -6,13 +6,13 @@ import (
"sort"
"time"
"github.com/docker/buildx/driver/kubernetes/kubeclient"
"github.com/pkg/errors"
"github.com/serialx/hashring"
"github.com/sirupsen/logrus"
appsv1 "k8s.io/api/apps/v1"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
clientcorev1 "k8s.io/client-go/kubernetes/typed/core/v1"
)
type PodChooser interface {
@@ -21,7 +21,7 @@ type PodChooser interface {
type RandomPodChooser struct {
RandSource rand.Source
PodClient clientcorev1.PodInterface
PodClient kubeclient.PodClient
Deployment *appsv1.Deployment
}
@@ -45,7 +45,7 @@ func (pc *RandomPodChooser) ChoosePod(ctx context.Context) (*corev1.Pod, error)
type StickyPodChooser struct {
Key string
PodClient clientcorev1.PodInterface
PodClient kubeclient.PodClient
Deployment *appsv1.Deployment
}
@@ -74,7 +74,7 @@ func (pc *StickyPodChooser) ChoosePod(ctx context.Context) (*corev1.Pod, error)
return podMap[chosen], nil
}
func ListRunningPods(ctx context.Context, client clientcorev1.PodInterface, depl *appsv1.Deployment) ([]*corev1.Pod, error) {
func ListRunningPods(ctx context.Context, client kubeclient.PodClient, depl *appsv1.Deployment) ([]*corev1.Pod, error) {
selector, err := metav1.LabelSelectorAsSelector(depl.Spec.Selector)
if err != nil {
return nil, err