mirror of
https://gitea.com/Lydanne/buildx.git
synced 2025-05-18 09:17:49 +08:00

Tested with `kind` and GKE. Note: "nodes" shown in `docker buildx ls` are unrelated to Kubernetes "nodes". Probably buildx should come up with an alternative term. Usage: $ kind create cluster $ export KUBECONFIG="$(kind get kubeconfig-path --name="kind")" $ docker buildx create --driver kubernetes --driver-opt replicas=3 --use $ docker buildx build -t foo --load . `--load` loads the image into the local Docker. Driver opts: - `image=IMAGE` - Sets the container image to be used for running buildkit. - `namespace=NS` - Sets the Kubernetes namespace. Defaults to the current namespace. - `replicas=N` - Sets the number of `Pod` replicas. Defaults to 1. - `rootless=(true|false)` - Run the container as a non-root user without `securityContext.privileged`. Defaults to false. - `loadbalance=(sticky|random)` - Load-balancing strategy. If set to "sticky", the pod is chosen using the hash of the context path. Defaults to "sticky" Signed-off-by: Akihiro Suda <akihiro.suda.cz@hco.ntt.co.jp>
98 lines
2.4 KiB
Go
98 lines
2.4 KiB
Go
package podchooser
|
|
|
|
import (
|
|
"context"
|
|
"math/rand"
|
|
"sort"
|
|
"time"
|
|
|
|
"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 {
|
|
ChoosePod(ctx context.Context) (*corev1.Pod, error)
|
|
}
|
|
|
|
type RandomPodChooser struct {
|
|
RandSource rand.Source
|
|
PodClient clientcorev1.PodInterface
|
|
Deployment *appsv1.Deployment
|
|
}
|
|
|
|
func (pc *RandomPodChooser) ChoosePod(ctx context.Context) (*corev1.Pod, error) {
|
|
pods, err := ListRunningPods(pc.PodClient, pc.Deployment)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
randSource := pc.RandSource
|
|
if randSource == nil {
|
|
randSource = rand.NewSource(time.Now().Unix())
|
|
}
|
|
rnd := rand.New(randSource)
|
|
n := rnd.Int() % len(pods)
|
|
logrus.Debugf("RandomPodChooser.ChoosePod(): len(pods)=%d, n=%d", len(pods), n)
|
|
return pods[n], nil
|
|
}
|
|
|
|
type StickyPodChooser struct {
|
|
Key string
|
|
PodClient clientcorev1.PodInterface
|
|
Deployment *appsv1.Deployment
|
|
}
|
|
|
|
func (pc *StickyPodChooser) ChoosePod(ctx context.Context) (*corev1.Pod, error) {
|
|
pods, err := ListRunningPods(pc.PodClient, pc.Deployment)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
var podNames []string
|
|
podMap := make(map[string]*corev1.Pod, len(pods))
|
|
for _, pod := range pods {
|
|
podNames = append(podNames, pod.Name)
|
|
podMap[pod.Name] = pod
|
|
}
|
|
ring := hashring.New(podNames)
|
|
chosen, ok := ring.GetNode(pc.Key)
|
|
if !ok {
|
|
// NOTREACHED
|
|
logrus.Errorf("no pod found for key %q", pc.Key)
|
|
rpc := &RandomPodChooser{
|
|
PodClient: pc.PodClient,
|
|
Deployment: pc.Deployment,
|
|
}
|
|
return rpc.ChoosePod(ctx)
|
|
}
|
|
return podMap[chosen], nil
|
|
}
|
|
|
|
func ListRunningPods(client clientcorev1.PodInterface, depl *appsv1.Deployment) ([]*corev1.Pod, error) {
|
|
selector, err := metav1.LabelSelectorAsSelector(depl.Spec.Selector)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
listOpts := metav1.ListOptions{
|
|
LabelSelector: selector.String(),
|
|
}
|
|
podList, err := client.List(listOpts)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
var runningPods []*corev1.Pod
|
|
for i := range podList.Items {
|
|
pod := &podList.Items[i]
|
|
if pod.Status.Phase == corev1.PodRunning {
|
|
logrus.Debugf("pod runnning: %q", pod.Name)
|
|
runningPods = append(runningPods, pod)
|
|
}
|
|
}
|
|
sort.Slice(runningPods, func(i, j int) bool {
|
|
return runningPods[i].Name < runningPods[j].Name
|
|
})
|
|
return runningPods, nil
|
|
}
|