Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

cni: set hostname as K8S_POD_NAME #3044

Merged
merged 4 commits into from
Aug 24, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 14 additions & 2 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ ARG ROOTLESSKIT_VERSION=v0.14.6
ARG CNI_VERSION=v1.1.0
ARG STARGZ_SNAPSHOTTER_VERSION=v0.12.0
ARG NERDCTL_VERSION=v0.17.1
ARG DNSNAME_VERSION=v1.3.1

# ALPINE_VERSION sets version for the base layers
ARG ALPINE_VERSION=3.15
Expand Down Expand Up @@ -50,6 +51,15 @@ RUN --mount=from=runc-src,src=/usr/src/runc,target=. --mount=target=/root/.cache
CGO_ENABLED=1 xx-go build -mod=vendor -ldflags '-extldflags -static' -tags 'apparmor seccomp netgo cgo static_build osusergo' -o /usr/bin/runc ./ && \
xx-verify --static /usr/bin/runc

# dnsname CNI plugin for testing
FROM gobuild-base AS dnsname
ARG DNSNAME_VERSION
WORKDIR /go/dnsname
RUN git clone https://github.com/containers/dnsname.git . \
&& git checkout -q "$DNSNAME_VERSION"
RUN --mount=target=/root/.cache,type=cache \
set -e; make binaries; mv bin/dnsname /usr/bin/dnsname

FROM gobuild-base AS buildkit-base
WORKDIR /src
ENV GOFLAGS=-mod=vendor
Expand Down Expand Up @@ -224,11 +234,12 @@ ARG TARGETOS
ARG TARGETARCH
WORKDIR /opt/cni/bin
RUN curl -Ls https://github.com/containernetworking/plugins/releases/download/$CNI_VERSION/cni-plugins-$TARGETOS-$TARGETARCH-$CNI_VERSION.tgz | tar xzv
COPY --link --from=dnsname /usr/bin/dnsname /opt/cni/bin/

FROM buildkit-base AS integration-tests-base
ENV BUILDKIT_INTEGRATION_ROOTLESS_IDPAIR="1000:1000"
ARG NERDCTL_VERSION
RUN apk add --no-cache shadow shadow-uidmap sudo vim iptables fuse curl \
RUN apk add --no-cache shadow shadow-uidmap sudo vim iptables ip6tables dnsmasq fuse curl \
&& useradd --create-home --home-dir /home/user --uid 1000 -s /bin/sh user \
&& echo "XDG_RUNTIME_DIR=/run/user/1000; export XDG_RUNTIME_DIR" >> /home/user/.profile \
&& mkdir -m 0700 -p /run/user/1000 \
Expand All @@ -248,8 +259,9 @@ COPY --link --from=containerd-alt-15 /out/containerd* /opt/containerd-alt-15/bin
COPY --link --from=registry /bin/registry /usr/bin/
COPY --link --from=runc /usr/bin/runc /usr/bin/
COPY --link --from=containerd /out/containerd* /usr/bin/
COPY --link --from=cni-plugins /opt/cni/bin/bridge /opt/cni/bin/host-local /opt/cni/bin/loopback /opt/cni/bin/
COPY --link --from=cni-plugins /opt/cni/bin/bridge /opt/cni/bin/host-local /opt/cni/bin/loopback /opt/cni/bin/firewall /opt/cni/bin/dnsname /opt/cni/bin/
COPY --link hack/fixtures/cni.json /etc/buildkit/cni.json
COPY --link hack/fixtures/dns-cni.conflist /etc/buildkit/dns-cni.conflist
COPY --link --from=binaries / /usr/bin/

# integration-tests prepares an image suitable for running all tests
Expand Down
67 changes: 67 additions & 0 deletions client/client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,15 @@ func TestIntegration(t *testing.T) {
"host": hostNetwork,
}),
)

integration.Run(t, integration.TestFuncs(
testBridgeNetworkingDNSNoRootless,
),
mirrors,
integration.WithMatrix("netmode", map[string]interface{}{
"dns": bridgeDNSNetwork,
}),
)
}

func newContainerd(cdAddress string) (*containerd.Client, error) {
Expand Down Expand Up @@ -263,6 +272,45 @@ func testBridgeNetworking(t *testing.T, sb integration.Sandbox) {
_, err = c.Solve(sb.Context(), def, SolveOpt{}, nil)
require.Error(t, err)
}

func testBridgeNetworkingDNSNoRootless(t *testing.T, sb integration.Sandbox) {
if os.Getenv("BUILDKIT_RUN_NETWORK_INTEGRATION_TESTS") == "" {
t.SkipNow()
}

c, err := New(sb.Context(), sb.Address())
require.NoError(t, err)
defer c.Close()

name := identity.NewID()
server, err := llb.Image("busybox").
Run(
llb.Shlexf(`sh -c 'test "$(nc -l -p 1234)" = "foo"'`),
llb.Hostname(name),
).
Marshal(sb.Context())
require.NoError(t, err)

client, err := llb.Image("busybox").
Run(
llb.Shlexf("sh -c 'until echo foo | nc " + name + " 1234 -w0; do sleep 0.1; done'"),
).
Marshal(sb.Context())
require.NoError(t, err)

eg, ctx := errgroup.WithContext(context.Background())
eg.Go(func() error {
_, err := c.Solve(ctx, server, SolveOpt{}, nil)
return err
})
eg.Go(func() error {
_, err := c.Solve(ctx, client, SolveOpt{}, nil)
return err
})
err = eg.Wait()
require.NoError(t, err)
}

func testHostNetworking(t *testing.T, sb integration.Sandbox) {
if os.Getenv("BUILDKIT_RUN_NETWORK_INTEGRATION_TESTS") == "" {
t.SkipNow()
Expand Down Expand Up @@ -6317,8 +6365,27 @@ func (*netModeDefault) UpdateConfigFile(in string) string {
return in
}

type netModeBridgeDNS struct{}

func (*netModeBridgeDNS) UpdateConfigFile(in string) string {
return in + `
# configure bridge networking
[worker.oci]
networkMode = "cni"
cniConfigPath = "/etc/buildkit/dns-cni.conflist"

[worker.containerd]
networkMode = "cni"
cniConfigPath = "/etc/buildkit/dns-cni.conflist"

[dns]
nameservers = ["10.11.0.1"]
`
}

var hostNetwork integration.ConfigUpdater = &netModeHost{}
var defaultNetwork integration.ConfigUpdater = &netModeDefault{}
var bridgeDNSNetwork integration.ConfigUpdater = &netModeBridgeDNS{}

func fixedWriteCloser(wc io.WriteCloser) func(map[string]string) (io.WriteCloser, error) {
return func(map[string]string) (io.WriteCloser, error) {
Expand Down
2 changes: 1 addition & 1 deletion executor/containerdexecutor/executor.go
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,7 @@ func (w *containerdExecutor) Run(ctx context.Context, id string, root executor.M
if !ok {
return errors.Errorf("unknown network mode %s", meta.NetMode)
}
namespace, err := provider.New()
namespace, err := provider.New(meta.Hostname)
if err != nil {
return err
}
Expand Down
2 changes: 1 addition & 1 deletion executor/runcexecutor/executor.go
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,7 @@ func (w *runcExecutor) Run(ctx context.Context, id string, root executor.Mount,
if !ok {
return errors.Errorf("unknown network mode %s", meta.NetMode)
}
namespace, err := provider.New()
namespace, err := provider.New(meta.Hostname)
if err != nil {
return err
}
Expand Down
28 changes: 28 additions & 0 deletions hack/fixtures/dns-cni.conflist
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
{
"cniVersion": "0.4.0",
"name": "buildkitdns",
"plugins": [
{
"type": "bridge",
"bridge": "buildkitdns0",
"isDefaultGateway": true,
"ipMasq": true,
"hairpinMode": true,
"ipam": {
"type": "host-local",
"ranges": [
[
{ "subnet": "10.11.0.0/16" }
]
]
}
},
{
"type": "firewall"
},
{
"type": "dnsname",
"domainName": "dns.buildkit"
}
]
}
23 changes: 18 additions & 5 deletions util/network/cniprovider/cni.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,40 +67,53 @@ func (c *cniProvider) initNetwork() error {
}
defer l.Unlock()
}
ns, err := c.New()
ns, err := c.New("")
if err != nil {
return err
}
return ns.Close()
}

func (c *cniProvider) New() (network.Namespace, error) {
func (c *cniProvider) New(hostname string) (network.Namespace, error) {
id := identity.NewID()
nativeID, err := createNetNS(c, id)
if err != nil {
return nil, err
}

if _, err := c.CNI.Setup(context.TODO(), id, nativeID); err != nil {
nsOpts := []cni.NamespaceOpts{}

if hostname != "" {
nsOpts = append(nsOpts,
// NB: K8S_POD_NAME is a semi-well-known arg set by k8s and podman and
// leveraged by the dnsname CNI plugin. a more generic name would be nice.
cni.WithArgs("K8S_POD_NAME", hostname),

// must be set for plugins that don't understand K8S_POD_NAME
cni.WithArgs("IgnoreUnknown", "1"))
}

if _, err := c.CNI.Setup(context.TODO(), id, nativeID, nsOpts...); err != nil {
deleteNetNS(nativeID)
return nil, errors.Wrap(err, "CNI setup error")
}

return &cniNS{nativeID: nativeID, id: id, handle: c.CNI}, nil
return &cniNS{nativeID: nativeID, id: id, handle: c.CNI, opts: nsOpts}, nil
}

type cniNS struct {
handle cni.CNI
id string
nativeID string
opts []cni.NamespaceOpts
}

func (ns *cniNS) Set(s *specs.Spec) error {
return setNetNS(s, ns.nativeID)
}

func (ns *cniNS) Close() error {
err := ns.handle.Remove(context.TODO(), ns.id, ns.nativeID)
err := ns.handle.Remove(context.TODO(), ns.id, ns.nativeID, ns.opts...)
if err1 := unmountNetNS(ns.nativeID); err1 != nil && err == nil {
err = err1
}
Expand Down
2 changes: 1 addition & 1 deletion util/network/host.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ func NewHostProvider() Provider {
type host struct {
}

func (h *host) New() (Namespace, error) {
func (h *host) New(hostname string) (Namespace, error) {
return &hostNS{}, nil
}

Expand Down
2 changes: 1 addition & 1 deletion util/network/network.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import (

// Provider interface for Network
type Provider interface {
New() (Namespace, error)
New(hostname string) (Namespace, error)
}

// Namespace of network for workers
Expand Down
2 changes: 1 addition & 1 deletion util/network/none.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ func NewNoneProvider() Provider {
type none struct {
}

func (h *none) New() (Namespace, error) {
func (h *none) New(hostname string) (Namespace, error) {
return &noneNS{}, nil
}

Expand Down
4 changes: 4 additions & 0 deletions util/testutil/integration/containerd.go
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,10 @@ func (c *containerd) Name() string {
return c.name
}

func (c *containerd) Rootless() bool {
return c.uid != 0
}

func (c *containerd) New(ctx context.Context, cfg *BackendConfig) (b Backend, cl func() error, err error) {
if err := lookupBinary(c.containerd); err != nil {
return nil, nil, err
Expand Down
4 changes: 4 additions & 0 deletions util/testutil/integration/dockerd.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,10 @@ func (c dockerd) Name() string {
return dockerdBinary
}

func (c dockerd) Rootless() bool {
return false
}

func (c dockerd) New(ctx context.Context, cfg *BackendConfig) (b Backend, cl func() error, err error) {
if err := requireRoot(); err != nil {
return nil, nil, err
Expand Down
4 changes: 4 additions & 0 deletions util/testutil/integration/oci.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,10 @@ func (s *oci) Name() string {
return "oci"
}

func (s *oci) Rootless() bool {
return s.uid != 0
}

func (s *oci) New(ctx context.Context, cfg *BackendConfig) (Backend, func() error, error) {
if err := lookupBinary("buildkitd"); err != nil {
return nil, nil, err
Expand Down
5 changes: 5 additions & 0 deletions util/testutil/integration/run.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ type BackendConfig struct {
type Worker interface {
New(context.Context, *BackendConfig) (Backend, func() error, error)
Name() string
Rootless() bool
}

type ConfigUpdater interface {
Expand Down Expand Up @@ -166,6 +167,10 @@ func Run(t *testing.T, testCases []Test, opt ...TestOpt) {
name := fn + "/worker=" + br.Name() + mv.functionSuffix()
func(fn, testName string, br Worker, tc Test, mv matrixValue) {
ok := t.Run(testName, func(t *testing.T) {
if strings.Contains(fn, "NoRootless") && br.Rootless() {
// skip sandbox setup
t.Skip("rootless")
}
ctx := appcontext.Context()
if !strings.HasSuffix(fn, "NoParallel") {
t.Parallel()
Expand Down