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

add CNI bridge network provider #4352

Merged
merged 1 commit into from
Jan 10, 2024
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
64 changes: 39 additions & 25 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -148,10 +148,49 @@ RUN --mount=target=. --mount=target=/root/.cache,type=cache \
fi
EOT

# dnsname source
FROM git AS dnsname-src
ARG DNSNAME_VERSION
WORKDIR /usr/src
RUN git clone https://github.com/containers/dnsname.git dnsname \
&& cd dnsname && git checkout -q "$DNSNAME_VERSION"

# build dnsname CNI plugin for testing
FROM gobuild-base AS dnsname
WORKDIR /go/src/github.com/containers/dnsname
ARG TARGETPLATFORM
RUN --mount=from=dnsname-src,src=/usr/src/dnsname,target=.,rw \
--mount=target=/root/.cache,type=cache \
CGO_ENABLED=0 xx-go build -o /usr/bin/dnsname ./plugins/meta/dnsname && \
xx-verify --static /usr/bin/dnsname

FROM --platform=$BUILDPLATFORM alpine:${ALPINE_VERSION} AS cni-plugins
RUN apk add --no-cache curl
COPY --from=xx / /
ARG CNI_VERSION
ARG TARGETOS
ARG TARGETARCH
ARG TARGETPLATFORM
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
RUN xx-verify --static bridge loopback host-local
COPY --link --from=dnsname /usr/bin/dnsname /opt/cni/bin/

FROM scratch AS cni-plugins-export
COPY --link --from=cni-plugins /opt/cni/bin/bridge /buildkit-cni-bridge
COPY --link --from=cni-plugins /opt/cni/bin/loopback /buildkit-cni-loopback
COPY --link --from=cni-plugins /opt/cni/bin/host-local /buildkit-cni-host-local
COPY --link --from=cni-plugins /opt/cni/bin/firewall /buildkit-cni-firewall

FROM scratch AS cni-plugins-export-squashed
COPY --from=cni-plugins-export / /


FROM scratch AS binaries-linux
COPY --link --from=runc /usr/bin/runc /buildkit-runc
# built from https://github.com/tonistiigi/binfmt/releases/tag/buildkit%2Fv7.1.0-30
COPY --link --from=tonistiigi/binfmt:buildkit-v7.1.0-30@sha256:45dd57b4ba2f24e2354f71f1e4e51f073cb7a28fd848ce6f5f2a7701142a6bf0 / /
COPY --link --from=cni-plugins-export-squashed / /
COPY --link --from=buildctl /usr/bin/buildctl /
COPY --link --from=buildkitd /usr/bin/buildkitd /

Expand Down Expand Up @@ -286,31 +325,6 @@ FROM binaries AS buildkit-windows
# this is not in binaries-windows because it is not intended for release yet, just CI
COPY --link --from=buildkitd /usr/bin/buildkitd /buildkitd.exe

# dnsname source
FROM git AS dnsname-src
ARG DNSNAME_VERSION
WORKDIR /usr/src
RUN git clone https://github.com/containers/dnsname.git dnsname \
&& cd dnsname && git checkout -q "$DNSNAME_VERSION"

# build dnsname CNI plugin for testing
FROM gobuild-base AS dnsname
WORKDIR /go/src/github.com/containers/dnsname
ARG TARGETPLATFORM
RUN --mount=from=dnsname-src,src=/usr/src/dnsname,target=.,rw \
--mount=target=/root/.cache,type=cache \
CGO_ENABLED=0 xx-go build -o /usr/bin/dnsname ./plugins/meta/dnsname && \
xx-verify --static /usr/bin/dnsname

FROM --platform=$BUILDPLATFORM alpine:${ALPINE_VERSION} AS cni-plugins
RUN apk add --no-cache curl
ARG CNI_VERSION
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"
RUN apk add --no-cache shadow shadow-uidmap sudo vim iptables ip6tables dnsmasq fuse curl git-daemon openssh-client \
Expand Down
2 changes: 2 additions & 0 deletions cmd/buildkitd/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,8 @@ type NetworkConfig struct {
CNIConfigPath string `toml:"cniConfigPath"`
CNIBinaryPath string `toml:"cniBinaryPath"`
CNIPoolSize int `toml:"cniPoolSize"`
BridgeName string `toml:"bridgeName"`
BridgeSubnet string `toml:"bridgeSubnet"`
}

type OCIConfig struct {
Expand Down
6 changes: 6 additions & 0 deletions cmd/buildkitd/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -453,6 +453,12 @@ func setDefaultNetworkConfig(nc config.NetworkConfig) config.NetworkConfig {
if nc.CNIBinaryPath == "" {
nc.CNIBinaryPath = appdefaults.DefaultCNIBinDir
}
if nc.BridgeName == "" {
nc.BridgeName = "buildkit0"
}
if nc.BridgeSubnet == "" {
nc.BridgeSubnet = "10.10.0.0/16"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In a follow up PR, could you add a documentation to explain this default CIDR and other configuration?

}
return nc
}

Expand Down
10 changes: 6 additions & 4 deletions cmd/buildkitd/main_containerd_worker.go
Original file line number Diff line number Diff line change
Expand Up @@ -290,10 +290,12 @@ func containerdWorkerInitializer(c *cli.Context, common workerInitializerOpt) ([
nc := netproviders.Opt{
Mode: common.config.Workers.Containerd.NetworkConfig.Mode,
CNI: cniprovider.Opt{
Root: common.config.Root,
ConfigPath: common.config.Workers.Containerd.CNIConfigPath,
BinaryDir: common.config.Workers.Containerd.CNIBinaryPath,
PoolSize: common.config.Workers.Containerd.CNIPoolSize,
Root: common.config.Root,
ConfigPath: common.config.Workers.Containerd.CNIConfigPath,
BinaryDir: common.config.Workers.Containerd.CNIBinaryPath,
PoolSize: common.config.Workers.Containerd.CNIPoolSize,
BridgeName: common.config.Workers.Containerd.BridgeName,
BridgeSubnet: common.config.Workers.Containerd.BridgeSubnet,
},
}

Expand Down
10 changes: 6 additions & 4 deletions cmd/buildkitd/main_oci_worker.go
Original file line number Diff line number Diff line change
Expand Up @@ -297,10 +297,12 @@ func ociWorkerInitializer(c *cli.Context, common workerInitializerOpt) ([]worker
nc := netproviders.Opt{
Mode: common.config.Workers.OCI.NetworkConfig.Mode,
CNI: cniprovider.Opt{
Root: common.config.Root,
ConfigPath: common.config.Workers.OCI.CNIConfigPath,
BinaryDir: common.config.Workers.OCI.CNIBinaryPath,
PoolSize: common.config.Workers.OCI.CNIPoolSize,
Root: common.config.Root,
ConfigPath: common.config.Workers.OCI.CNIConfigPath,
BinaryDir: common.config.Workers.OCI.CNIBinaryPath,
PoolSize: common.config.Workers.OCI.CNIPoolSize,
BridgeName: common.config.Workers.OCI.BridgeName,
BridgeSubnet: common.config.Workers.OCI.BridgeSubnet,
},
}

Expand Down
2 changes: 2 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ require (
github.com/tonistiigi/units v0.0.0-20180711220420-6950e57a87ea
github.com/tonistiigi/vt100 v0.0.0-20230623042737-f9a4f7ef6531
github.com/urfave/cli v1.22.12
github.com/vishvananda/netlink v1.2.1-beta.2
go.etcd.io/bbolt v1.3.7
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.45.0
go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace v0.45.0
Expand Down Expand Up @@ -158,6 +159,7 @@ require (
github.com/secure-systems-lab/go-securesystemslib v0.4.0 // indirect
github.com/shibumi/go-pathspec v1.3.0 // indirect
github.com/vbatts/tar-split v0.11.3 // indirect
github.com/vishvananda/netns v0.0.0-20210104183010-2eb08e3e575f // indirect
go.opencensus.io v0.24.0 // indirect
go.opentelemetry.io/otel/exporters/otlp/otlpmetric v0.42.0 // indirect
golang.org/x/mod v0.11.0 // indirect
Expand Down
6 changes: 6 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -1238,8 +1238,13 @@ github.com/vbatts/tar-split v0.11.3/go.mod h1:9QlHN18E+fEH7RdG+QAJJcuya3rqT7eXST
github.com/vdemeester/k8s-pkg-credentialprovider v1.17.4/go.mod h1:inCTmtUdr5KJbreVojo06krnTgaeAz/Z7lynpPk/Q2c=
github.com/vishvananda/netlink v0.0.0-20181108222139-023a6dafdcdf/go.mod h1:+SR5DhBJrl6ZM7CoCKvpw5BKroDKQ+PJqOg65H/2ktk=
github.com/vishvananda/netlink v1.1.0/go.mod h1:cTgwzPIzzgDAYoQrMm0EdrjRUBkTqKYppBueQtXaqoE=
github.com/vishvananda/netlink v1.2.1-beta.2 h1:Llsql0lnQEbHj0I1OuKyp8otXp0r3q0mPkuhwHfStVs=
github.com/vishvananda/netlink v1.2.1-beta.2/go.mod h1:twkDnbuQxJYemMlGd4JFIcuhgX83tXhKS2B/PRMpOho=
github.com/vishvananda/netns v0.0.0-20180720170159-13995c7128cc/go.mod h1:ZjcWmFBXmLKZu9Nxj3WKYEafiSqer2rnvPr0en9UNpI=
github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df/go.mod h1:JP3t17pCcGlemwknint6hfoeCVQrEMVwxRLRjXpq+BU=
github.com/vishvananda/netns v0.0.0-20200728191858-db3c7e526aae/go.mod h1:DD4vA1DwXk04H54A1oHXtwZmA0grkVMdPxx/VGLCah0=
github.com/vishvananda/netns v0.0.0-20210104183010-2eb08e3e575f h1:p4VB7kIXpOQvVn1ZaTIVp+3vuYAXFe3OJEvjbUYJLaA=
github.com/vishvananda/netns v0.0.0-20210104183010-2eb08e3e575f/go.mod h1:DD4vA1DwXk04H54A1oHXtwZmA0grkVMdPxx/VGLCah0=
github.com/vmware/govmomi v0.20.3/go.mod h1:URlwyTFZX72RmxtxuaFL2Uj3fD1JTvZdx59bHWk6aFU=
github.com/willf/bitset v1.1.11-0.20200630133818-d5bec3311243/go.mod h1:RjeCKbqT1RxIR/KWY6phxZiaY1IyutSBfGjNPySAYV4=
github.com/willf/bitset v1.1.11/go.mod h1:83CECat5yLh5zVOf4P1ErAgKA5UDvKtgyUABdr3+MjI=
Expand Down Expand Up @@ -1507,6 +1512,7 @@ golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20200124204421-9fbb57f87de9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200217220822-9197077df867/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
Expand Down
2 changes: 1 addition & 1 deletion hack/shell
Original file line number Diff line number Diff line change
Expand Up @@ -21,4 +21,4 @@ if [ -n "$MOUNT_BUILDKIT_SOURCE" ]; then
fi

set -x
docker run $SSH $volumes -it --privileged -v /tmp --net=host -e BUILDKIT_REGISTRY_MIRROR_DIR=/root/.cache/registry --rm $(cat $iidfile) ash
docker run $SSH $volumes -it --privileged -v /tmp -e BUILDKIT_REGISTRY_MIRROR_DIR=/root/.cache/registry --rm $(cat $iidfile) ash
168 changes: 168 additions & 0 deletions util/network/cniprovider/bridge.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,168 @@
//go:build linux
// +build linux

package cniprovider

import (
"context"
"fmt"
"os"
"os/exec"
"path/filepath"

cni "github.com/containerd/go-cni"
"github.com/moby/buildkit/util/bklog"
"github.com/moby/buildkit/util/network"
"github.com/pkg/errors"
"github.com/vishvananda/netlink"
)

func NewBridge(opt Opt) (network.Provider, error) {
cniOptions := []cni.Opt{cni.WithInterfacePrefix("eth")}
bridgeBinName := "bridge"
loopbackBinName := "loopback"
hostLocalBinName := "host-local"
firewallBinName := "firewall"
var setup bool
// binaries shipping with buildkit
for {
var dirs []string

bridgePath, err := exec.LookPath("buildkit-cni-bridge")
if err != nil {
break
}
var bridgeDir string
bridgeDir, bridgeBinName = filepath.Split(bridgePath)
dirs = append(dirs, bridgeDir)

loopbackPath, err := exec.LookPath("buildkit-cni-loopback")
if err != nil {
break
}
var loopbackDir string
loopbackDir, loopbackBinName = filepath.Split(loopbackPath)
if loopbackDir != bridgeDir {
dirs = append(dirs, loopbackDir)
}

hostLocalPath, err := exec.LookPath("buildkit-cni-host-local")
if err != nil {
break
}
var hostLocalDir string
hostLocalDir, hostLocalBinName = filepath.Split(hostLocalPath)
if hostLocalDir != bridgeDir && hostLocalDir != loopbackDir {
dirs = append(dirs, hostLocalDir)
}

firewallPath, err := exec.LookPath("buildkit-cni-firewall")
if err != nil {
break
}
var firewallDir string
firewallDir, firewallBinName = filepath.Split(firewallPath)
if firewallDir != bridgeDir && firewallDir != loopbackDir && firewallDir != hostLocalDir {
dirs = append(dirs, firewallDir)
}

cniOptions = append(cniOptions, cni.WithPluginDir(dirs))
setup = true
break //nolint: staticcheck
}

if !setup {
fn := filepath.Join(opt.BinaryDir, "bridge")
if _, err := os.Stat(fn); err != nil {
return nil, errors.Wrapf(err, "failed to find CNI bridge %q or buildkit-cni-bridge", fn)
}

cniOptions = append(cniOptions, cni.WithPluginDir([]string{opt.BinaryDir}))
}

cniOptions = append(cniOptions, cni.WithConfListBytes([]byte(fmt.Sprintf(`{
"cniVersion": "1.0.0",
"name": "buildkit",
"plugins": [
{
"type": "%s"
},
{
"type": "%s",
"bridge": "%s",
"isDefaultGateway": true,
"ipMasq": true,
"ipam": {
"type": "%s",
"ranges": [
[
{ "subnet": "%s" }
]
]
}
},
{
"type": "%s",
"ingressPolicy": "same-bridge"
}
]
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we have ingressPolicy": "same-bridge" ?
https://www.cni.dev/plugins/current/meta/firewall/#ingress-policy

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So this would be another plugin we would need to include?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes (firewall plugin)

}`, loopbackBinName, bridgeBinName, opt.BridgeName, hostLocalBinName, opt.BridgeSubnet, firewallBinName))))

unlock, err := initLock()
if err != nil {
return nil, err
}
defer unlock()

createBridge := true
if _, err := bridgeByName(opt.BridgeName); err == nil {
createBridge = false
}

cniHandle, err := cni.New(cniOptions...)
if err != nil {
return nil, err
}
cp := &cniProvider{
CNI: cniHandle,
root: opt.Root,
}

if createBridge {
cp.release = func() error {
if err := removeBridge(opt.BridgeName); err != nil {
bklog.L.Errorf("failed to remove bridge %q: %v", opt.BridgeName, err)
}
return nil
}
}

cleanOldNamespaces(cp)

cp.nsPool = &cniPool{targetSize: opt.PoolSize, provider: cp}
if err := cp.initNetwork(false); err != nil {
return nil, err
}
go cp.nsPool.fillPool(context.TODO())
return cp, nil
}

func bridgeByName(name string) (*netlink.Bridge, error) {
l, err := netlink.LinkByName(name)
if err != nil {
return nil, errors.Wrapf(err, "could not lookup %q", name)
}
br, ok := l.(*netlink.Bridge)
if !ok {
return nil, errors.Errorf("%q already exists but is not a bridge", name)
}
return br, nil
}

func removeBridge(name string) error {
br, err := bridgeByName(name)
if err != nil {
return err
}
return netlink.LinkDel(br)
}
Loading