Skip to content

Commit

Permalink
Merge pull request #51 from AkihiroSuda/dev-cni
Browse files Browse the repository at this point in the history
add `nerdctl network create`
  • Loading branch information
AkihiroSuda committed Jan 19, 2021
2 parents de0d7b0 + 7061f50 commit 2cf7c82
Show file tree
Hide file tree
Showing 20 changed files with 801 additions and 124 deletions.
3 changes: 3 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ ARG CONTAINERIZED_SYSTEMD_VERSION=0.1.0
ARG CONTAINERD_VERSION=1.4.3
ARG RUNC_VERSION=1.0.0-rc92
ARG CNI_PLUGINS_VERSION=0.9.0
ARG CNI_ISOLATION_VERSION=0.0.3
ARG BUILDKIT_VERSION=0.8.1
ARG GO_VERSION=1.15.6

Expand All @@ -29,6 +30,8 @@ RUN curl -L -o /usr/local/sbin/runc https://github.com/opencontainers/runc/relea
ARG CNI_PLUGINS_VERSION
RUN mkdir -p /opt/cni/bin && \
curl -L https://github.com/containernetworking/plugins/releases/download/v${CNI_PLUGINS_VERSION}/cni-plugins-linux-${TARGETARCH:-amd64}-v${CNI_PLUGINS_VERSION}.tgz | tar xzvC /opt/cni/bin
ARG CNI_ISOLATION_VERSION
RUN curl -L https://github.com/AkihiroSuda/cni-isolation/releases/download/v${CNI_ISOLATION_VERSION}/cni-isolation-${TARGETARCH:-amd64}.tgz | tar xzvC /opt/cni/bin
ARG BUILDKIT_VERSION
RUN curl -L https://github.com/moby/buildkit/releases/download/v${BUILDKIT_VERSION}/buildkit-v${BUILDKIT_VERSION}.linux-${TARGETARCH:-amd64}.tar.gz | tar xzvC /usr/local && \
rm -f /usr/local/bin/buildkit-qemu-* /usr/local/bin/buildkit-runc
Expand Down
35 changes: 32 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,11 @@
- [:whale: nerdctl tag](#whale-nerdctl-tag)
- [:whale: nerdctl rmi](#whale-nerdctl-rmi)
- [:nerd_face: nerdctl image convert](#nerd_face-nerdctl-image-convert)
- [Network management](#network-management)
- [:whale: nerdctl network create](#whale-nerdctl-network-create)
- [:whale: nerdctl network ls](#whale-nerdctl-network-ls)
- [:whale: nerdctl network inspect](#whale-nerdctl-network-inspect)
- [:whale: nerdctl network rm](#whale-nerdctl-network-rm)
- [System](#system)
- [:whale: nerdctl events](#whale-nerdctl-events)
- [:whale: nerdctl info](#whale-nerdctl-info)
Expand All @@ -57,7 +62,7 @@

## Examples

To run a container with the default CNI network (10.4.0.0/16):
To run a container with the default CNI network (10.4.0.0/24):
```console
# nerdctl run -it --rm alpine
```
Expand All @@ -83,6 +88,7 @@ Binaries are available for amd64, arm64, and arm-v7: https://github.com/AkihiroS

In addition to containerd, the following components should be installed (optional):
- [CNI plugins](https://github.com/containernetworking/plugins): for using `nerdctl run`.
- [CNI isolation plugin](https://github.com/AkihiroSuda/cni-isolation): for isolating bridge networks (`nerdctl network create`)
- [BuildKit](https://github.com/moby/buildkit): for using `nerdctl build`. BuildKit daemon (`buildkitd`) needs to be running.

To run nerdctl inside Docker:
Expand Down Expand Up @@ -173,7 +179,6 @@ Basic flags:
Network flags:
- :whale: `--network=(bridge|host|none)`: Connect a container to a network
- Default: "bridge"
- :warning: No support for custom network (`nerdctl network create` yet
- :whale: `-p, --publish`: Publish a container's port(s) to the host
- :whale: `--dns`: Set custom DNS servers
- :whale: `-h, --hostname`: Container host name
Expand Down Expand Up @@ -347,6 +352,28 @@ Flags:
- `--platform=<PLATFORM>` : convert content for a specific platform
- `--all-platforms` : convert content for all platforms (default: false)

## Network management
### :whale: nerdctl network create
Create a network

:information_source: To isolate CNI bridge, [CNI isolation plugin](https://github.com/AkihiroSuda/cni-isolation) needs to be installed.

:warning: No support for looking up container IPs by their names yet

Flags:
- `--subnet`: Subnet in CIDR format that represents a network segment, e.g. "10.5.0.0/16"

### :whale: nerdctl network ls
List networks

### :whale: nerdctl network inspect
Display detailed information on one or more networks

:warning: The output format is not compatible with Docker.

### :whale: nerdctl network rm
Remove one or more networks

## System
### :whale: nerdctl events
Get real time events from the server.
Expand Down Expand Up @@ -398,7 +425,9 @@ Volume management:
- `docker volume *`

Network management:
- `docker network *`
- `docker network connect`
- `docker network disconnect`
- `docker network prune`

Registry:
- `docker login` and `docker logout`
Expand Down
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ require (
github.com/containerd/stargz-snapshotter v0.2.1-0.20210101143201-d58f43a8235e
github.com/containerd/stargz-snapshotter/estargz v0.0.0-00010101000000-000000000000
github.com/containerd/typeurl v1.0.1
github.com/containernetworking/cni v0.8.0
github.com/containernetworking/plugins v0.9.0
github.com/docker/cli v20.10.0+incompatible
github.com/docker/go-units v0.4.0
Expand Down
5 changes: 4 additions & 1 deletion internal_oci_hook.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,5 +34,8 @@ func internalOCIHookAction(clicontext *cli.Context) error {
if event == "" {
return errors.New("event type needs to be passed")
}
return ocihook.Run(clicontext.App.Reader, clicontext.App.ErrWriter, event, clicontext.String("cni-path"))
return ocihook.Run(clicontext.App.Reader, clicontext.App.ErrWriter, event,
clicontext.String("cni-path"),
clicontext.String("cni-netconfpath"),
)
}
14 changes: 12 additions & 2 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -84,11 +84,20 @@ func newApp() *cli.App {
Value: containerd.DefaultSnapshotter,
},
&cli.StringFlag{
Name: "cni-path",
Usage: "Set the cni-plugins binary directory",
Name: "cni-path",
Usage: "Set the cni-plugins binary directory",
// CNI_PATH is from https://www.cni.dev/docs/cnitool/
EnvVars: []string{"CNI_PATH"},
Value: gocni.DefaultCNIDir,
},
&cli.StringFlag{
Name: "cni-netconfpath",
Usage: "Set the CNI config directory",
// NETCONFPATH is from https://www.cni.dev/docs/cnitool/
EnvVars: []string{"NETCONFPATH"},
Value: gocni.DefaultNetDir,
},

&cli.StringFlag{
Name: "data-root",
Usage: "Root directory of persistent nerdctl state (managed by nerdctl, not by containerd)",
Expand Down Expand Up @@ -145,6 +154,7 @@ func newApp() *cli.App {
// Management
containerCommand,
imageCommand,
networkCommand,
systemCommand,
// Internal
internalCommand,
Expand Down
34 changes: 34 additions & 0 deletions network.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
/*
Copyright (C) nerdctl authors.
Copyright (C) containerd authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package main

import (
"github.com/urfave/cli/v2"
)

var networkCommand = &cli.Command{
Name: "network",
Usage: "Manage networks",
Category: CategoryManagement,
Subcommands: []*cli.Command{
networkLsCommand,
networkInspectCommand,
networkCreateCommand,
networkRmCommand,
},
}
114 changes: 114 additions & 0 deletions network_create.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
/*
Copyright (C) nerdctl authors.
Copyright (C) containerd authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package main

import (
"fmt"
"io/ioutil"
"os"
"path/filepath"
"regexp"

"github.com/AkihiroSuda/nerdctl/pkg/lockutil"
"github.com/AkihiroSuda/nerdctl/pkg/netutil"
"github.com/containerd/containerd/errdefs"
"github.com/pkg/errors"
"github.com/urfave/cli/v2"
)

var networkCreateCommand = &cli.Command{
Name: "create",
Usage: "Create a network",
Description: "NOTE: To isolate CNI bridge, CNI isolation plugin needs to be installed: https://github.com/AkihiroSuda/cni-isolation\n" + "\n" +
"No support for looking up container IPs by their names yet",
ArgsUsage: "[flags] NETWORK",
Flags: []cli.Flag{
&cli.StringFlag{
Name: "subnet",
Usage: "Subnet in CIDR format that represents a network segment, e.g. \"10.5.0.0/16\"",
},
},
Action: networkCreateAction,
}

func networkCreateAction(clicontext *cli.Context) error {
if clicontext.NArg() != 1 {
return errors.Errorf("requires exactly 1 argument")
}
name := clicontext.Args().First()
if !isValidNetName(name) {
return errors.Errorf("malformed name %s", name)
}
netconfpath := clicontext.String("cni-netconfpath")
if err := os.MkdirAll(netconfpath, 0755); err != nil {
return err
}

fn := func() error {
e := &netutil.CNIEnv{
Path: clicontext.String("cni-path"),
NetconfPath: netconfpath,
}
ll, err := netutil.ConfigLists(e)
if err != nil {
return err
}
for _, l := range ll {
if l.Name == name {
return errors.Errorf("network with name %s already exists", name)
}
// TODO: check CIDR collision
}
id, err := netutil.AcquireNextID(ll)
if err != nil {
return err
}

subnet := clicontext.String("subnet")
if subnet == "" {
if id > 255 {
return errors.Errorf("cannot determine subnet for ID %d, specify --subnet manually", id)
}
subnet = fmt.Sprintf("10.4.%d.0/24", id)
}

l, err := netutil.GenerateConfigList(e, id, name, subnet)
if err != nil {
return err
}
filename := filepath.Join(netconfpath, "nerdctl-"+name+".conflist")
if _, err := os.Stat(filename); err == nil {
return errdefs.ErrAlreadyExists
}
if err := ioutil.WriteFile(filename, l.Bytes, 0644); err != nil {
return err
}
fmt.Fprintf(clicontext.App.Writer, "%d\n", id)
return nil
}

return lockutil.WithDirLock(netconfpath, fn)
}

func isValidNetName(s string) bool {
ok, err := regexp.MatchString("^[a-zA-Z0-9-]+$", s)
if err != nil {
panic(err)
}
return ok
}
80 changes: 80 additions & 0 deletions network_inspect.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
/*
Copyright (C) nerdctl authors.
Copyright (C) containerd authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package main

import (
"encoding/json"
"fmt"

"github.com/AkihiroSuda/nerdctl/pkg/inspecttypes/native"
"github.com/AkihiroSuda/nerdctl/pkg/netutil"
"github.com/pkg/errors"
"github.com/urfave/cli/v2"
)

var networkInspectCommand = &cli.Command{
Name: "inspect",
Usage: "Display detailed information on one or more networks",
ArgsUsage: "[flags] NETWORK [NETWORK, ...]",
Description: "NOTE: The output format is not compatible with Docker.",
Action: networkInspectAction,
}

func networkInspectAction(clicontext *cli.Context) error {
if clicontext.NArg() == 0 {
return errors.Errorf("requires at least 1 argument")
}

e := &netutil.CNIEnv{
Path: clicontext.String("cni-path"),
NetconfPath: clicontext.String("cni-netconfpath"),
}

ll, err := netutil.ConfigLists(e)
if err != nil {
return err
}

llMap := make(map[string]*netutil.NetworkConfigList, len(ll))
for _, l := range ll {
llMap[l.Name] = l
}

result := make([]native.Network, clicontext.NArg())
for i, name := range clicontext.Args().Slice() {
if name == "host" || name == "none" {
return errors.Errorf("pseudo network %q cannot be inspected", name)
}
l, ok := llMap[name]
if !ok {
return errors.Errorf("no such network: %s", name)
}
r := native.Network{
CNI: json.RawMessage(l.Bytes),
NerdctlID: l.NerdctlID,
File: l.File,
}
result[i] = r
}
b, err := json.MarshalIndent(result, "", " ")
if err != nil {
return err
}
fmt.Fprintln(clicontext.App.Writer, string(b))
return nil
}
Loading

0 comments on commit 2cf7c82

Please sign in to comment.