Skip to content

Commit 9b7ab3b

Browse files
committed
tests: kubernetes worker
Signed-off-by: CrazyMax <[email protected]>
1 parent a6ef9db commit 9b7ab3b

File tree

6 files changed

+247
-1
lines changed

6 files changed

+247
-1
lines changed

.github/workflows/build.yml

+1
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ jobs:
6060
worker:
6161
- docker-container
6262
- remote
63+
- kubernetes
6364
pkg:
6465
- ./tests
6566
mode:

Dockerfile

+32
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ ARG GOTESTSUM_VERSION=v1.12.0
1010
ARG REGISTRY_VERSION=2.8.3
1111
ARG BUILDKIT_VERSION=v0.17.1
1212
ARG UNDOCK_VERSION=0.8.0
13+
ARG K3S_VERSION=v1.21.2-k3s1
1314

1415
FROM --platform=$BUILDPLATFORM tonistiigi/xx:${XX_VERSION} AS xx
1516
FROM --platform=$BUILDPLATFORM golang:${GO_VERSION}-alpine AS golatest
@@ -18,6 +19,7 @@ FROM dockereng/cli-bin:$DOCKER_CLI_VERSION AS docker-cli
1819
FROM registry:$REGISTRY_VERSION AS registry
1920
FROM moby/buildkit:$BUILDKIT_VERSION AS buildkit
2021
FROM crazymax/undock:$UNDOCK_VERSION AS undock
22+
FROM rancher/k3s:${K3S_VERSION} AS k3s
2123

2224
FROM golatest AS gobase
2325
COPY --from=xx / /
@@ -118,14 +120,44 @@ RUN apk add --no-cache \
118120
shadow-uidmap \
119121
xfsprogs \
120122
xz
123+
# k3s deps
124+
RUN apk add --no-cache \
125+
busybox-binsh \
126+
cni-plugins \
127+
cni-plugin-flannel \
128+
conntrack-tools \
129+
coreutils \
130+
dbus \
131+
findutils \
132+
ipset
133+
ENV PATH="/usr/libexec/cni:${PATH}"
121134
COPY --link --from=gotestsum /out /usr/bin/
122135
COPY --link --from=registry /bin/registry /usr/bin/
123136
COPY --link --from=docker-engine / /usr/bin/
124137
COPY --link --from=docker-cli / /usr/bin/
138+
COPY --link --from=k3s /bin/k3s /usr/bin/
139+
COPY --link --from=k3s /bin/kubectl /usr/bin/
125140
COPY --link --from=buildkit /usr/bin/buildkitd /usr/bin/
126141
COPY --link --from=buildkit /usr/bin/buildctl /usr/bin/
127142
COPY --link --from=undock /usr/local/bin/undock /usr/bin/
128143
COPY --link --from=binaries /buildx /usr/bin/
144+
COPY --chmod=755 <<-"EOF" /entrypoint.sh
145+
#!/bin/sh
146+
set -e
147+
# cgroup v2: enable nesting
148+
# https://github.com/moby/moby/blob/v25.0.0/hack/dind#L59-L69
149+
if [ -f /sys/fs/cgroup/cgroup.controllers ]; then
150+
# move the processes from the root group to the /init group,
151+
# otherwise writing subtree_control fails with EBUSY.
152+
# An error during moving non-existent process (i.e., "cat") is ignored.
153+
mkdir -p /sys/fs/cgroup/init
154+
xargs -rn1 < /sys/fs/cgroup/cgroup.procs > /sys/fs/cgroup/init/cgroup.procs || :
155+
# enable controllers
156+
sed -e 's/ / +/g' -e 's/^/+/' < /sys/fs/cgroup/cgroup.controllers > /sys/fs/cgroup/cgroup.subtree_control
157+
fi
158+
exec "$@"
159+
EOF
160+
ENTRYPOINT ["/entrypoint.sh"]
129161

130162
FROM integration-test-base AS integration-test
131163
COPY . .

go.mod

+1-1
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ require (
66
github.com/Masterminds/semver/v3 v3.2.1
77
github.com/Microsoft/go-winio v0.6.2
88
github.com/aws/aws-sdk-go-v2/config v1.26.6
9+
github.com/cenkalti/backoff/v4 v4.2.1
910
github.com/compose-spec/compose-go/v2 v2.4.2
1011
github.com/containerd/console v1.0.4
1112
github.com/containerd/containerd v1.7.22
@@ -82,7 +83,6 @@ require (
8283
github.com/aws/aws-sdk-go-v2/service/sts v1.26.7 // indirect
8384
github.com/aws/smithy-go v1.19.0 // indirect
8485
github.com/beorn7/perks v1.0.1 // indirect
85-
github.com/cenkalti/backoff/v4 v4.2.1 // indirect
8686
github.com/cespare/xxhash/v2 v2.3.0 // indirect
8787
github.com/containerd/containerd/api v1.7.19 // indirect
8888
github.com/containerd/ttrpc v1.2.5 // indirect

tests/helpers/k3s.go

+112
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
package helpers
2+
3+
import (
4+
"bytes"
5+
"net"
6+
"os"
7+
"os/exec"
8+
"strconv"
9+
"time"
10+
11+
"github.com/cenkalti/backoff/v4"
12+
"github.com/moby/buildkit/util/testutil/integration"
13+
"github.com/pkg/errors"
14+
)
15+
16+
const (
17+
k3sBin = "k3s"
18+
kubeCtlBin = "kubectl"
19+
)
20+
21+
func NewK3sServer(cfg *integration.BackendConfig) (kubeConfig string, cl func() error, err error) {
22+
if _, err := exec.LookPath(k3sBin); err != nil {
23+
return "", nil, errors.Wrapf(err, "failed to lookup %s binary", k3sBin)
24+
}
25+
if _, err := exec.LookPath(kubeCtlBin); err != nil {
26+
return "", nil, errors.Wrapf(err, "failed to lookup %s binary", kubeCtlBin)
27+
}
28+
29+
deferF := &integration.MultiCloser{}
30+
cl = deferF.F()
31+
32+
defer func() {
33+
if err != nil {
34+
deferF.F()()
35+
cl = nil
36+
}
37+
}()
38+
39+
cfgfile, err := os.CreateTemp("", "kubeconfig*.yml")
40+
if err != nil {
41+
return "", nil, err
42+
}
43+
kubeConfig = cfgfile.Name()
44+
deferF.Append(func() error {
45+
return os.Remove(cfgfile.Name())
46+
})
47+
48+
k3sDataDir, err := os.MkdirTemp("", "kubedata")
49+
if err != nil {
50+
return "", nil, err
51+
}
52+
deferF.Append(func() error {
53+
return os.RemoveAll(k3sDataDir)
54+
})
55+
56+
l, err := net.Listen("tcp", "localhost:0")
57+
if err != nil {
58+
return "", nil, err
59+
}
60+
_ = l.Close()
61+
62+
lport := strconv.Itoa(l.Addr().(*net.TCPAddr).Port)
63+
nodeName := "integrationk3s"
64+
65+
stop, err := integration.StartCmd(exec.Command(k3sBin, "server",
66+
"--bind-address", "127.0.0.1",
67+
"--https-listen-port", lport,
68+
"--data-dir", k3sDataDir, // write to /tmp for overlayfs support
69+
"--write-kubeconfig", cfgfile.Name(),
70+
"--write-kubeconfig-mode", "666",
71+
"--node-name", nodeName,
72+
), cfg.Logs)
73+
if err != nil {
74+
return "", nil, err
75+
}
76+
77+
if err = waitK3s(cfg, kubeConfig, nodeName); err != nil {
78+
stop()
79+
return "", nil, errors.Wrapf(err, "k3s did not start up: %s", integration.FormatLogs(cfg.Logs))
80+
}
81+
82+
deferF.Append(stop)
83+
return
84+
}
85+
86+
func waitK3s(cfg *integration.BackendConfig, kubeConfig string, nodeName string) error {
87+
logbuf := new(bytes.Buffer)
88+
defer func() {
89+
if logbuf.Len() > 0 {
90+
cfg.Logs["waitK3s: "] = logbuf
91+
}
92+
}()
93+
94+
boff := backoff.NewExponentialBackOff()
95+
boff.InitialInterval = 3 * time.Second
96+
boff.MaxInterval = 5 * time.Second
97+
boff.MaxElapsedTime = 2 * time.Minute
98+
99+
if err := backoff.Retry(func() error {
100+
cmd := exec.Command(kubeCtlBin, "--kubeconfig", kubeConfig, "wait", "--for=condition=Ready", "node/"+nodeName)
101+
out, err := cmd.CombinedOutput()
102+
if err == nil && bytes.Contains(out, []byte("condition met")) {
103+
return nil
104+
}
105+
return errors.Wrapf(err, "node is not ready: %s %s", cmd.String(), string(out))
106+
}, boff); err != nil {
107+
logbuf.WriteString(errors.Unwrap(err).Error())
108+
return err
109+
}
110+
111+
return nil
112+
}

tests/integration_test.go

+1
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ func init() {
1616
workers.InitDockerContainerWorker()
1717
} else {
1818
workers.InitRemoteWorker()
19+
workers.InitKubernetesWorker()
1920
}
2021
}
2122

tests/workers/kubernetes.go

+100
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
package workers
2+
3+
import (
4+
"context"
5+
"os"
6+
"os/exec"
7+
"path/filepath"
8+
"sync"
9+
10+
"github.com/docker/buildx/tests/helpers"
11+
"github.com/moby/buildkit/identity"
12+
"github.com/moby/buildkit/util/testutil/integration"
13+
"github.com/pkg/errors"
14+
)
15+
16+
func InitKubernetesWorker() {
17+
integration.Register(&kubernetesWorker{
18+
id: "kubernetes",
19+
})
20+
}
21+
22+
type kubernetesWorker struct {
23+
id string
24+
25+
unsupported []string
26+
27+
k3sConfig string
28+
k3sClose func() error
29+
k3sErr error
30+
k3sOnce sync.Once
31+
}
32+
33+
func (w *kubernetesWorker) Name() string {
34+
return w.id
35+
}
36+
37+
func (w *kubernetesWorker) Rootless() bool {
38+
return false
39+
}
40+
41+
func (w *kubernetesWorker) NetNSDetached() bool {
42+
return false
43+
}
44+
45+
func (w *kubernetesWorker) New(ctx context.Context, cfg *integration.BackendConfig) (integration.Backend, func() error, error) {
46+
var err error
47+
48+
w.k3sOnce.Do(func() {
49+
w.k3sConfig, w.k3sClose, w.k3sErr = helpers.NewK3sServer(cfg)
50+
})
51+
if w.k3sErr != nil {
52+
return nil, w.k3sClose, w.k3sErr
53+
}
54+
55+
cfgfile, err := integration.WriteConfig(cfg.DaemonConfig)
56+
if err != nil {
57+
return nil, nil, err
58+
}
59+
defer os.RemoveAll(filepath.Dir(cfgfile))
60+
61+
name := "integration-kubernetes-" + identity.NewID()
62+
cmd := exec.Command("buildx", "create",
63+
"--bootstrap",
64+
"--name="+name,
65+
"--config="+cfgfile,
66+
"--driver=kubernetes",
67+
)
68+
cmd.Env = append(
69+
os.Environ(),
70+
"BUILDX_CONFIG=/tmp/buildx-"+name,
71+
"KUBECONFIG="+w.k3sConfig,
72+
)
73+
if err := cmd.Run(); err != nil {
74+
return nil, nil, errors.Wrapf(err, "failed to create buildx instance %s", name)
75+
}
76+
77+
cl := func() error {
78+
cmd := exec.Command("buildx", "rm", "-f", name)
79+
return cmd.Run()
80+
}
81+
82+
return &backend{
83+
builder: name,
84+
unsupportedFeatures: w.unsupported,
85+
}, cl, nil
86+
}
87+
88+
func (w *kubernetesWorker) Close() error {
89+
if c := w.k3sClose; c != nil {
90+
return c()
91+
}
92+
93+
// reset the worker to be ready to go again
94+
w.k3sConfig = ""
95+
w.k3sClose = nil
96+
w.k3sErr = nil
97+
w.k3sOnce = sync.Once{}
98+
99+
return nil
100+
}

0 commit comments

Comments
 (0)