Skip to content

Commit 3e6a97b

Browse files
authored
Merge pull request #1 from jschwinger23/master
OCI Wrapper for Integrating into CNI
2 parents 4877708 + f42681f commit 3e6a97b

21 files changed

Lines changed: 941 additions & 1 deletion

.github/workflows/goreleaser.yml

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
name: goreleaser
2+
3+
on:
4+
push:
5+
tags:
6+
- v*
7+
8+
jobs:
9+
goreleaser:
10+
runs-on: ubuntu-latest
11+
steps:
12+
- name: Checkout
13+
uses: actions/checkout@v2
14+
with:
15+
fetch-depth: 0
16+
17+
- name: Set up environment variables
18+
run: |
19+
echo "VERSION=$(git describe --tags $(git rev-list --tags --max-count=1))" >> $GITHUB_ENV
20+
21+
- name: Set up Go
22+
uses: actions/setup-go@v2
23+
with:
24+
go-version: 1.15
25+
26+
- name: Run GoReleaser
27+
uses: goreleaser/goreleaser-action@v2
28+
with:
29+
version: latest
30+
args: release --rm-dist
31+
env:
32+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
33+

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
vendor/
2+
docker-cni
3+
dist/

.goreleaser.yml

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
before:
2+
hooks:
3+
- go mod download
4+
5+
builds:
6+
- binary: docker-cni
7+
env:
8+
- CGO_ENABLED=0
9+
ldflags:
10+
- -X main.REVISION={{.Commit}}
11+
- -X main.VERSION={{.Env.VERSION}}
12+
- -X main.BUILTAT={{.Date}}
13+
goos:
14+
- linux
15+
goarch:
16+
- amd64
17+
18+
archives:
19+
- replacements:
20+
linux: Linux
21+
amd64: x86_64
22+
23+
checksum:
24+
name_template: 'checksums.txt'
25+
26+
release:
27+
prerelease: auto
28+
29+
snapshot:
30+
name_template: "{{ .Tag }}-next"
31+
32+
changelog:
33+
sort: asc
34+
filters:
35+
exclude:
36+
- '^docs:'
37+
- '^test:'

Makefile

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
.PHONY: binary
2+
3+
REVISION := $(shell git rev-parse HEAD || unknown)
4+
BUILTAT := $(shell date +%Y-%m-%dT%H:%M:%S)
5+
VERSION := $(shell git describe --tags $(shell git rev-list --tags --max-count=1))
6+
GO_LDFLAGS ?= -X main.REVISION=$(REVISION) \
7+
-X main.BUILTAT=$(BUILTAT) \
8+
-X main.VERSION=$(VERSION)
9+
10+
deps:
11+
env GO111MODULE=on go mod download
12+
env GO111MODULE=on go mod vendor
13+
14+
binary:
15+
CGO_ENABLED=0 go build -ldflags "$(GO_LDFLAGS)" -o docker-cni
16+
17+
build: deps binary

README.md

Lines changed: 67 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,78 @@
22

33
This repo aims to integrate [CNI](https://github.com/containernetworking/cni) with Dockerd.
44

5-
There is, [according to CNI repo](https://github.com/containernetworking/cni/blob/master/scripts/docker-run.sh), an approach to integrate by running a [pause] equivalent container ahead of the application container, but that's too pod-like for those who resent pod models.
5+
There is, [according to CNI repo](https://github.com/containernetworking/cni/blob/master/scripts/docker-run.sh), an approach to integrate by running a [pause](https://groups.google.com/g/kubernetes-users/c/jVjv0QK4b_o) equivalent container ahead of the application container, but that's too pod-like for those who resent pod models.
66

77
Let's figure out yet another solution.
88

99
# Usage
1010

11+
## 0. Prepare your CNI plugin
12+
13+
Make sure you have everything ready:
14+
15+
1. CNI binaries in the right place: for example, `/opt/cni/bin/calico` and `/opt/cni/bin/calico-ipam` binaries
16+
2. CNI configures in the right place: for exmaple, `/etc/cni/net.d/10-calico.conf`
17+
3. Other services needed: for example, `calico-node` container
18+
19+
Notes:
20+
21+
1. Provided there are multiple CNI configures in the dir, `docker-cni` will only use the first config in alphabet order.
22+
1123
## 1. Configure docker-cni
1224

25+
### 1.1 install docker-cni binary
26+
27+
Download the latest binary from [release](https://github.com/projecteru2/docker-cni/releases).
28+
29+
### 1.2 docker-cni configuration
30+
31+
```shell
32+
mkdir -p /etc/docker/
33+
cat <<!
34+
cni_conf_dir: /etc/cni/net.d/
35+
cni_bin_dir: /opt/cni/bin/
36+
log_driver: file:///var/run/log/docker-cni.log
37+
log_level: debug
38+
!
39+
```
40+
41+
You may revise the aforementioned configure with YOUR `cni_conf_dir` and `cni_bin_dir`.
42+
1343
## 2. Configure dockerd
44+
45+
### 2.1 dockerd daemon configuration
46+
47+
Add the additional `runtime` in docker daemon configure, which is usually located at `/etc/docker/daemon.json`:
48+
49+
```
50+
{
51+
...
52+
"runtimes": {
53+
"cni": {
54+
"path": "/usr/local/bin/docker-cni",
55+
"runtimeArgs": [
56+
"--config",
57+
"/etc/docker/cni.yaml",
58+
"--runtime-path",
59+
"/usr/bin/runc",
60+
"--"
61+
]
62+
}
63+
}
64+
}
65+
```
66+
67+
### 2.2 restart dockerd
68+
69+
```
70+
systemctl restart dockerd
71+
```
72+
73+
## 3. Create docker container with CNI
74+
75+
```
76+
docker run -td --runtime cni --net none bash bash
77+
```
78+
79+
That's everything.

cni.yaml.example

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
cni_conf_dir: /etc/cni/net.d/
2+
cni_bin_dir: /opt/cni/bin/
3+
log_driver: file:///var/run/log/docker-cni.log
4+
log_level: debug

cni/netns.go

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
package cni
2+
3+
import (
4+
"os"
5+
6+
"github.com/pkg/errors"
7+
"github.com/projecteru2/docker-cni/utils"
8+
)
9+
10+
func (p netnsManager) GetNetns(ID string) (netnsPath string, err error) {
11+
_, err = os.Stat(p.getNetnsPath(ID))
12+
return p.getNetnsPath(ID), errors.WithStack(err)
13+
}
14+
15+
func (p netnsManager) AddNetns(ID string) (netnsPath string, add, del *utils.Process, err error) {
16+
if add, err = utils.NewProcess("ip", []string{"net", "a", p.getID(ID)}, nil, nil); err != nil {
17+
return
18+
}
19+
del, err = p.DelNetns(ID)
20+
return p.getNetnsPath(ID), add, del, err
21+
}
22+
23+
func (p netnsManager) DelNetns(ID string) (*utils.Process, error) {
24+
return utils.NewProcess("ip", []string{"net", "d", p.getID(ID)}, nil, nil)
25+
}
26+
27+
func (p netnsManager) getNetnsPath(ID string) string {
28+
return "/var/run/netns/" + p.getID(ID)
29+
}
30+
31+
func (p netnsManager) getID(ID string) string {
32+
return ID[:12]
33+
}

cni/network.go

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
package cni
2+
3+
import (
4+
"github.com/pkg/errors"
5+
"github.com/projecteru2/docker-cni/config"
6+
"github.com/projecteru2/docker-cni/oci"
7+
"github.com/projecteru2/docker-cni/utils"
8+
log "github.com/sirupsen/logrus"
9+
)
10+
11+
// checkupNetwork checks the netns and invokes "CNI check" (not implemented yet)
12+
func (p *CNIPlugin) CheckupNetwork(conf config.Config, containerMeta *oci.ContainerMeta) (exist bool, cleanup []*utils.Process, err error) {
13+
netnsPath, err := p.GetNetns(containerMeta.ID)
14+
if err != nil {
15+
return false, nil, err
16+
}
17+
18+
delCNI, err := p.DelCNI(containerMeta.ID, netnsPath, DefaultIfname)
19+
if err != nil {
20+
return false, nil, errors.WithStack(err)
21+
}
22+
delNetns, err := p.DelNetns(containerMeta.ID)
23+
if err != nil {
24+
return false, nil, errors.WithStack(err)
25+
}
26+
return true, []*utils.Process{delCNI, delNetns}, nil
27+
}
28+
29+
func (p *CNIPlugin) SetupNetwork(conf config.Config, containerMeta *oci.ContainerMeta) (netnsPath string, cleanup []*utils.Process, err error) {
30+
netnsPath, addNetns, delNetns, err := p.AddNetns(containerMeta.ID)
31+
if err != nil {
32+
err = errors.WithStack(err)
33+
return
34+
}
35+
if _, _, err = addNetns.Run(); err != nil {
36+
err = errors.WithStack(err)
37+
return
38+
}
39+
defer func() {
40+
if err != nil {
41+
if _, _, e := delNetns.Run(); e != nil {
42+
log.Errorf("failed to rollback netns: %+v", e)
43+
}
44+
}
45+
}()
46+
47+
addCNI, delCNI, err := p.AddCNI(containerMeta.ID, netnsPath, DefaultIfname)
48+
if err != nil {
49+
return
50+
}
51+
stdoutBytes, stderrBytes, err := addCNI.Run()
52+
log.Infof("add cni stdout: %s", string(stdoutBytes))
53+
log.Debugf("add cni stderr: %s", string(stderrBytes))
54+
return netnsPath, []*utils.Process{
55+
delCNI,
56+
delNetns,
57+
}, err
58+
}

cni/operate.go

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
package cni
2+
3+
import (
4+
"github.com/projecteru2/docker-cni/utils"
5+
)
6+
7+
func (p *CNIPlugin) addCNI(ID, netnsPath, ifname string) (*utils.Process, error) {
8+
return utils.NewProcess(
9+
p.binPath, // path
10+
nil, // args
11+
[]string{
12+
"CNI_COMMAND=ADD",
13+
"CNI_CONTAINERID=" + ID,
14+
"CNI_NETNS=" + netnsPath,
15+
"CNI_IFNAME=" + ifname,
16+
"CNI_PATH=" + p.binDir,
17+
}, // env
18+
utils.NewStdio(p.specBytes), // stdio
19+
)
20+
}
21+
22+
func (p *CNIPlugin) DelCNI(ID, netnsPath, ifname string) (*utils.Process, error) {
23+
return utils.NewProcess(
24+
p.binPath, // path
25+
nil, // args
26+
[]string{
27+
"CNI_COMMAND=DEL",
28+
"CNI_CONTAINERID=" + ID,
29+
"CNI_NETNS=" + netnsPath,
30+
"CNI_IFNAME=" + ifname,
31+
"CNI_PATH=" + p.binDir,
32+
}, // env
33+
utils.NewStdio(p.specBytes), // stdio
34+
)
35+
}
36+
37+
func (p *CNIPlugin) AddCNI(ID, netnsPath, ifname string) (add, del *utils.Process, err error) {
38+
if add, err = p.addCNI(ID, netnsPath, ifname); err != nil {
39+
return
40+
}
41+
del, err = p.DelCNI(ID, netnsPath, ifname)
42+
return
43+
}

cni/types.go

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
package cni
2+
3+
import (
4+
"encoding/json"
5+
"io/ioutil"
6+
"path/filepath"
7+
"sort"
8+
9+
"github.com/pkg/errors"
10+
)
11+
12+
const (
13+
DefaultIfname = "eth0"
14+
)
15+
16+
type CNIPlugin struct {
17+
netnsManager
18+
19+
binDir string
20+
binPath string
21+
specBytes []byte
22+
}
23+
24+
type CNISpec struct {
25+
Type string `json:"type"`
26+
}
27+
28+
func NewCNIPlugin(specDir, binDir string) (_ *CNIPlugin, err error) {
29+
// walk thu the config_dir and get the first configure file in lexicographic order, the same behavior as kubelet: https://kubernetes.io/docs/concepts/extend-kubernetes/compute-storage-net/network-plugins/#cni
30+
31+
files, err := ioutil.ReadDir(specDir)
32+
if err != nil {
33+
return nil, errors.WithStack(err)
34+
}
35+
36+
if len(files) == 0 {
37+
return nil, errors.Errorf("cni configure not found: %s", specDir)
38+
}
39+
40+
sort.Slice(files, func(i, j int) bool { return files[i].Name() < files[j].Name() })
41+
content, err := ioutil.ReadFile(filepath.Join(specDir, files[0].Name()))
42+
if err != nil {
43+
return nil, errors.WithStack(err)
44+
}
45+
46+
spec := &CNISpec{}
47+
if err = json.Unmarshal(content, spec); err != nil {
48+
return nil, errors.WithStack(err)
49+
}
50+
51+
return &CNIPlugin{
52+
binDir: binDir,
53+
binPath: filepath.Join(binDir, spec.Type),
54+
specBytes: content,
55+
}, nil
56+
}
57+
58+
type netnsManager struct{}

0 commit comments

Comments
 (0)