Skip to content

Commit 9152f20

Browse files
committed
split data store by addrhash
See docs/dir.md Signed-off-by: Akihiro Suda <akihiro.suda.cz@hco.ntt.co.jp>
1 parent 4e20954 commit 9152f20

13 files changed

Lines changed: 158 additions & 61 deletions

File tree

client.go

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,11 +19,13 @@ package main
1919

2020
import (
2121
"context"
22+
"os"
2223
"path/filepath"
2324
"strings"
2425

2526
"github.com/containerd/containerd"
2627
"github.com/containerd/containerd/namespaces"
28+
"github.com/opencontainers/go-digest"
2729
"github.com/pkg/errors"
2830
"github.com/urfave/cli/v2"
2931
"golang.org/x/sys/unix"
@@ -61,3 +63,36 @@ func isSocketAccessible(s string) error {
6163
// set AT_EACCESS to allow running nerdctl as a setuid binary
6264
return unix.Faccessat(-1, abs, unix.R_OK|unix.W_OK, unix.AT_EACCESS)
6365
}
66+
67+
// getDataStore returns a string like "/var/lib/nerdctl/1935db59".
68+
// "1935db9" is from `$(echo -n "/run/containerd/containerd.sock" | sha256sum | cut -c1-8)``
69+
func getDataStore(clicontext *cli.Context) (string, error) {
70+
dataRoot := clicontext.String("data-root")
71+
if err := os.MkdirAll(dataRoot, 0700); err != nil {
72+
return "", err
73+
}
74+
addrHash, err := getAddrHash(clicontext.String("address"))
75+
if err != nil {
76+
return "", err
77+
}
78+
dataStore := filepath.Join(dataRoot, addrHash)
79+
if err := os.MkdirAll(dataStore, 0700); err != nil {
80+
return "", err
81+
}
82+
return dataStore, nil
83+
}
84+
85+
func getAddrHash(addr string) (string, error) {
86+
const addrHashLen = 8
87+
88+
addr = strings.TrimPrefix(addr, "unix://")
89+
var err error
90+
addr, err = filepath.EvalSymlinks(addr)
91+
if err != nil {
92+
return "", err
93+
}
94+
95+
d := digest.SHA256.FromString(addr)
96+
h := d.Encoded()[0:addrHashLen]
97+
return h, nil
98+
}

docs/dir.md

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
# nerdctl directory layout
2+
3+
## Data
4+
### `<DATAROOT>`
5+
e.g. `/var/lib/nerdctl`
6+
7+
Can be overriden with `nerdctl --data-root=<DATAROOT>` flag.
8+
9+
The directory is solely managed by nerdctl, not by containerd.
10+
The directory has nothing to do with containerd data root `/var/lib/containerd`.
11+
12+
### `<DATAROOT>/<ADDRHASH>`
13+
e.g. `/var/lib/nerdctl/1935db59`
14+
15+
`1935db9` is from `$(echo -n "/run/containerd/containerd.sock" | sha256sum | cut -c1-8)`
16+
17+
This directory is also called "data store" in the implementation.
18+
19+
### `<DATAROOT>/<ADDRHASH>/containers/<NAMESPACE>/<CID>`
20+
e.g. `/var/lib/nerdctl/1935db59/containers/default/c4ed811cc361d26faffdee8d696ddbc45a9d93c571b5b3c54d3da01cb29caeb1`
21+
22+
Files:
23+
- `resolv.conf`: mounted to the container as `/etc/resolv.conf`
24+
- `<CID>-json.log`: used by `nerdctl logs`
25+
- `oci-hook.*.log`: logs of the OCI hook
26+
27+
### `<DATAROOT>/<ADDRHASH>/names/<NAMESPACE>`
28+
e.g. `/var/lib/nerdctl/1935db59/names/default`
29+
30+
Files:
31+
- `<NAME>`: contains the container ID (CID). Represents that the name is taken by that container.
32+
33+
Files must be operated with a `LOCK_EX` lock against the `<DATAROOT>/<ADDRHASH>/names/<NAMESPACE>` directory.
34+
35+
### `<DATAROOT>/<ADDRHASH>/etchosts/<NAMESPACE>/<CID>`
36+
e.g. `/var/lib/nerdctl/1935db59/etchosts/default/c4ed811cc361d26faffdee8d696ddbc45a9d93c571b5b3c54d3da01cb29caeb1`
37+
38+
Files:
39+
- `hosts`: mounted to the container as `/etc/hosts`
40+
- `meta.json`: metadata
41+
42+
Files must be operated with a `LOCK_EX` lock against the `<DATAROOT>/<ADDRHASH>/etchosts` directory.
43+
44+
## CNI
45+
46+
### `<NETCONFPATH>`
47+
e.g. `/etc/cni/net.d`
48+
49+
Can be overriden with `nerdctl --cni-netconfpath=<NETCONFPATH>` flag and environment variable `$NETCONFPATH`.
50+
51+
Files:
52+
- `nerdctl-<NWNAME>.conflist`: CNI conf list created by nerdctl

internal_oci_hook.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,12 @@ func internalOCIHookAction(clicontext *cli.Context) error {
3434
if event == "" {
3535
return errors.New("event type needs to be passed")
3636
}
37+
dataStore, err := getDataStore(clicontext)
38+
if err != nil {
39+
return err
40+
}
3741
return ocihook.Run(clicontext.App.Reader, clicontext.App.ErrWriter, event,
38-
clicontext.String("data-root"),
42+
dataStore,
3943
clicontext.String("cni-path"),
4044
clicontext.String("cni-netconfpath"),
4145
)

logs.go

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,10 @@ func logsAction(clicontext *cli.Context) error {
4040
return errors.Errorf("requires exactly 1 argument")
4141
}
4242

43-
dataRoot := clicontext.String("data-root")
43+
dataStore, err := getDataStore(clicontext)
44+
if err != nil {
45+
return err
46+
}
4447

4548
ns := clicontext.String("namespace")
4649
switch ns {
@@ -60,7 +63,7 @@ func logsAction(clicontext *cli.Context) error {
6063
if found.MatchCount > 1 {
6164
return errors.Errorf("ambiguous ID %q", found.Req)
6265
}
63-
logJSONFilePath := jsonfile.Path(dataRoot, ns, found.Container.ID())
66+
logJSONFilePath := jsonfile.Path(dataStore, ns, found.Container.ID())
6467
f, err := os.Open(logJSONFilePath)
6568
if err != nil {
6669
return errors.Wrapf(err, "failed to open %q, container is not created with `nerdctl run -d`?", logJSONFilePath)

pkg/dnsutil/hostsstore/hostsstore.go

Lines changed: 17 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
limitations under the License.
1616
*/
1717

18-
// Package hoststore provides the interface for /var/lib/nerdctl/etchosts .
18+
// Package hoststore provides the interface for /var/lib/nerdctl/<ADDRHASH>/etchosts .
1919
// Prioritize simplicity over scalability.
2020
package hostsstore
2121

@@ -32,18 +32,18 @@ import (
3232
)
3333

3434
const (
35-
// hostsDirBasename is the base name of /var/lib/nerdctl/etchosts
35+
// hostsDirBasename is the base name of /var/lib/nerdctl/<ADDRHASH>/etchosts
3636
hostsDirBasename = "etchosts"
37-
// metaJSON is stored as /var/lib/nerdctl/etchosts/<NS>/<ID>/meta.json
37+
// metaJSON is stored as /var/lib/nerdctl/<ADDRHASH>/etchosts/<NS>/<ID>/meta.json
3838
metaJSON = "meta.json"
3939
)
4040

41-
// HostsPath returns "/var/lib/nerdctl/etchosts/<NS>/<ID>/hosts"
42-
func HostsPath(dataRoot, ns, id string) string {
43-
if dataRoot == "" || ns == "" || id == "" {
41+
// HostsPath returns "/var/lib/nerdctl/<ADDRHASH>/etchosts/<NS>/<ID>/hosts"
42+
func HostsPath(dataStore, ns, id string) string {
43+
if dataStore == "" || ns == "" || id == "" {
4444
panic(errdefs.ErrInvalidArgument)
4545
}
46-
return filepath.Join(dataRoot, hostsDirBasename, ns, id, "hosts")
46+
return filepath.Join(dataStore, hostsDirBasename, ns, id, "hosts")
4747
}
4848

4949
// ensureFile ensures a file with permission 0644.
@@ -66,23 +66,23 @@ func ensureFile(path string) error {
6666

6767
// EnsureHostsFile is used for creating mount-bindable /etc/hosts file.
6868
// The file is initialized with no content.
69-
func EnsureHostsFile(dataRoot, ns, id string) (string, error) {
70-
lockDir := filepath.Join(dataRoot, hostsDirBasename)
69+
func EnsureHostsFile(dataStore, ns, id string) (string, error) {
70+
lockDir := filepath.Join(dataStore, hostsDirBasename)
7171
if err := os.MkdirAll(lockDir, 0700); err != nil {
7272
return "", err
7373
}
74-
path := HostsPath(dataRoot, ns, id)
74+
path := HostsPath(dataStore, ns, id)
7575
fn := func() error {
7676
return ensureFile(path)
7777
}
7878
err := lockutil.WithDirLock(lockDir, fn)
7979
return path, err
8080
}
8181

82-
func NewStore(dataRoot string) (Store, error) {
82+
func NewStore(dataStore string) (Store, error) {
8383
store := &store{
84-
dataRoot: dataRoot,
85-
hostsD: filepath.Join(dataRoot, hostsDirBasename),
84+
dataStore: dataStore,
85+
hostsD: filepath.Join(dataStore, hostsDirBasename),
8686
}
8787
return store, os.MkdirAll(store.hostsD, 0700)
8888
}
@@ -101,15 +101,15 @@ type Store interface {
101101
}
102102

103103
type store struct {
104-
// dataRoot is /var/lib/nerdctl
105-
dataRoot string
106-
// hostsD is /var/lib/nerdctl/etchosts
104+
// dataStore is /var/lib/nerdctl/<ADDRHASH>
105+
dataStore string
106+
// hostsD is /var/lib/nerdctl/<ADDRHASH>/etchosts
107107
hostsD string
108108
}
109109

110110
func (x *store) Acquire(meta Meta) error {
111111
fn := func() error {
112-
hostsPath := HostsPath(x.dataRoot, meta.Namespace, meta.ID)
112+
hostsPath := HostsPath(x.dataStore, meta.Namespace, meta.ID)
113113
if err := ensureFile(hostsPath); err != nil {
114114
return err
115115
}

pkg/dnsutil/hostsstore/updater.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ import (
3131
"github.com/sirupsen/logrus"
3232
)
3333

34-
// newUpdater creates an updater for hostsD (/var/lib/nerdctl/hosts.d)
34+
// newUpdater creates an updater for hostsD (/var/lib/nerdctl/<ADDRHASH>/etchosts)
3535
func newUpdater(hostsD string) *updater {
3636
u := &updater{
3737
hostsD: hostsD,
@@ -43,9 +43,9 @@ func newUpdater(hostsD string) *updater {
4343

4444
// updater is the struct for updater.update()
4545
type updater struct {
46-
hostsD string // "/varlib/nerdctl/hosts.d"
46+
hostsD string // "/var/lib/nerdctl/<ADDRHASH>/etchosts"
4747
metaByIPStr map[string]*Meta // key: IP string
48-
metaByDir map[string]*Meta // key: "/var/lib/nerdctl/hosts.d/<NS>/<ID>"
48+
metaByDir map[string]*Meta // key: "/var/lib/nerdctl/<ADDRHASH>/etchosts/<NS>/<ID>"
4949
}
5050

5151
// update updates the hostsD tree.

pkg/labels/labels.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ const (
3333
// Hostname
3434
Hostname = Prefix + "hostname"
3535

36-
// StateDir is "/var/lib/nerdctl/c/<NAMESPACE>/<ID>"
36+
// StateDir is "/var/lib/nerdctl/<ADDRHASH>/containers/<NAMESPACE>/<ID>"
3737
StateDir = Prefix + "state-dir"
3838

3939
// Networks is a JSON-marshalled string of []string, e.g. []string{"bridge"}.

pkg/logging/jsonfile/jsonfile.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,9 +35,9 @@ type Entry struct {
3535
Time time.Time `json:"time"` // e.g. "2020-12-11T20:29:41.939902251Z"
3636
}
3737

38-
func Path(dataRoot, ns, id string) string {
38+
func Path(dataStore, ns, id string) string {
3939
// the file name corresponds to Docker
40-
return filepath.Join(dataRoot, "containers", ns, id, id+"-json.log")
40+
return filepath.Join(dataStore, "containers", ns, id, id+"-json.log")
4141
}
4242

4343
func Encode(w io.Writer, stdout, stderr io.Reader) error {

pkg/logging/logging.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -42,15 +42,15 @@ func Main(argv2 string) error {
4242
return nil
4343
}
4444

45-
func getLoggerFunc(dataRoot string) (logging.LoggerFunc, error) {
46-
if dataRoot == "" {
47-
return nil, errors.New("got empty data-root")
45+
func getLoggerFunc(dataStore string) (logging.LoggerFunc, error) {
46+
if dataStore == "" {
47+
return nil, errors.New("got empty data store")
4848
}
4949
return func(_ context.Context, config *logging.Config, ready func() error) error {
5050
if config.Namespace == "" || config.ID == "" {
5151
return errors.New("got invalid config")
5252
}
53-
logJSONFilePath := jsonfile.Path(dataRoot, config.Namespace, config.ID)
53+
logJSONFilePath := jsonfile.Path(dataStore, config.Namespace, config.ID)
5454
if err := os.MkdirAll(filepath.Dir(logJSONFilePath), 0700); err != nil {
5555
return err
5656
}

pkg/namestore/namestore.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,8 @@ import (
2727
"github.com/pkg/errors"
2828
)
2929

30-
func New(dataRoot, ns string) (NameStore, error) {
31-
dir := filepath.Join(dataRoot, "names", ns)
30+
func New(dataStore, ns string) (NameStore, error) {
31+
dir := filepath.Join(dataStore, "names", ns)
3232
if err := os.MkdirAll(dir, 0700); err != nil {
3333
return nil, err
3434
}

0 commit comments

Comments
 (0)