Skip to content

Commit

Permalink
Add fuse-manager
Browse files Browse the repository at this point in the history
Signed-off-by: Zuti He <[email protected]>
  • Loading branch information
ilyee committed Aug 13, 2021
1 parent 4be9f92 commit 0cdde0e
Show file tree
Hide file tree
Showing 16 changed files with 1,667 additions and 29 deletions.
5 changes: 4 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ VERSION=$(shell git describe --match 'v[0-9]*' --dirty='.m' --always --tags)
REVISION=$(shell git rev-parse HEAD)$(shell if ! git diff --no-ext-diff --quiet --exit-code; then echo .m; fi)
GO_LD_FLAGS=-ldflags '-s -w -X $(PKG)/version.Version=$(VERSION) -X $(PKG)/version.Revision=$(REVISION) $(GO_EXTRA_LDFLAGS)'

CMD=containerd-stargz-grpc ctr-remote stargz-store
CMD=containerd-stargz-grpc ctr-remote stargz-store stargz-fuse-manager

CMD_BINARIES=$(addprefix $(PREFIX),$(CMD))

Expand All @@ -44,6 +44,9 @@ ctr-remote: FORCE
stargz-store: FORCE
GO111MODULE=$(GO111MODULE_VALUE) go build -o $(PREFIX)$@ $(GO_BUILD_FLAGS) $(GO_LD_FLAGS) -v ./cmd/stargz-store

stargz-fuse-manager: FORCE
GO111MODULE=$(GO111MODULE_VALUE) go build -o $(PREFIX)$@ $(GO_BUILD_FLAGS) $(GO_LD_FLAGS) -v ./cmd/stargz-fuse-manager

check:
@echo "$@"
@GO111MODULE=$(GO111MODULE_VALUE) golangci-lint run
Expand Down
65 changes: 57 additions & 8 deletions cmd/containerd-stargz-grpc/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import (
"net"
"net/http"
"os"
"os/exec"
"os/signal"
"path/filepath"
"time"
Expand All @@ -34,11 +35,13 @@ import (
"github.com/containerd/containerd/log"
"github.com/containerd/containerd/pkg/dialer"
"github.com/containerd/containerd/snapshots"
"github.com/containerd/stargz-snapshotter/fusemanager"
"github.com/containerd/stargz-snapshotter/service"
"github.com/containerd/stargz-snapshotter/service/keychain/cri"
"github.com/containerd/stargz-snapshotter/service/keychain/dockerconfig"
"github.com/containerd/stargz-snapshotter/service/keychain/kubeconfig"
"github.com/containerd/stargz-snapshotter/service/resolver"
snbase "github.com/containerd/stargz-snapshotter/snapshot"
"github.com/containerd/stargz-snapshotter/version"
sddaemon "github.com/coreos/go-systemd/v22/daemon"
metrics "github.com/docker/go-metrics"
Expand All @@ -57,14 +60,19 @@ const (
defaultLogLevel = logrus.InfoLevel
defaultRootDir = "/var/lib/containerd-stargz-grpc"
defaultImageServiceAddress = "/run/containerd/containerd.sock"
defaultFuseManagerAddress = "/run/containerd-stargz-grpc/fuse-namanger.sock"

fuseManagerBin = "stargz-fuse-manager"
fuseManagerAddress = "fuse-mananger.sock"
)

var (
address = flag.String("address", defaultAddress, "address for the snapshotter's GRPC server")
configPath = flag.String("config", defaultConfigPath, "path to the configuration file")
logLevel = flag.String("log-level", defaultLogLevel.String(), "set the logging level [trace, debug, info, warn, error, fatal, panic]")
rootDir = flag.String("root", defaultRootDir, "path to the root directory for this snapshotter")
printVersion = flag.Bool("version", false, "print the version")
address = flag.String("address", defaultAddress, "address for the snapshotter's GRPC server")
configPath = flag.String("config", defaultConfigPath, "path to the configuration file")
logLevel = flag.String("log-level", defaultLogLevel.String(), "set the logging level [trace, debug, info, warn, error, fatal, panic]")
rootDir = flag.String("root", defaultRootDir, "path to the root directory for this snapshotter")
detachFuseManager = flag.Bool("detach-fuse-manager", false, "whether detach fusemanager or not")
printVersion = flag.Bool("version", false, "print the version")
)

type snapshotterConfig struct {
Expand All @@ -75,6 +83,12 @@ type snapshotterConfig struct {

// NoPrometheus is a flag to disable the emission of the metrics
NoPrometheus bool `toml:"no_prometheus"`

// FuseManagerAddress is address for the fusemanager's GRPC server
FuseManagerAddress string `toml:"fusemanager_address"`

// FuseManagerPath is path to the fusemanager's executable
FuseManagerPath string `toml:"fusemanager_path"`
}

func main() {
Expand Down Expand Up @@ -156,9 +170,44 @@ func main() {
runtime.RegisterImageServiceServer(rpc, criServer)
credsFuncs = append(credsFuncs, f)
}
rs, err := service.NewStargzSnapshotterService(ctx, *rootDir, &config.Config, service.WithCredsFuncs(credsFuncs...))
if err != nil {
log.G(ctx).WithError(err).Fatalf("failed to configure snapshotter")

var rs snapshots.Snapshotter
if *detachFuseManager {
fmPath := config.FuseManagerPath
if fmPath == "" {
var err error
fmPath, err = exec.LookPath(fuseManagerBin)
if err != nil {
log.G(ctx).WithError(err).Fatalf("failed to find fusemanager bin")
}
}
fmAddr := config.FuseManagerAddress
if fmAddr == "" {
var err error
fmAddr, err = exec.LookPath(fuseManagerAddress)
if err != nil {
fmAddr = defaultFuseManagerAddress
}
}
err := service.StartFuseManager(ctx, fmPath, fmAddr, filepath.Join(*rootDir, "fusestore.db"), *logLevel, filepath.Join(*rootDir, "stargz-fuse-manager.log"))
if err != nil {
log.G(ctx).WithError(err).Fatalf("failed to start fusemanager")
}
fs, err := fusemanager.NewManagerClient(ctx, *rootDir, fmAddr, &config.Config)
if err != nil {
log.G(ctx).WithError(err).Fatalf("failed to configure fusemanager")
}
rs, err = snbase.NewSnapshotter(ctx, filepath.Join(*rootDir, "snapshotter"), fs, snbase.AsynchronousRemove)
if err != nil {
log.G(ctx).WithError(err).Fatalf("failed to configure snapshotter")
}
log.G(ctx).Infof("Start snapshotter with fusemanager mode")
} else {
rs, err = service.NewStargzSnapshotterService(ctx, *rootDir, &config.Config, service.WithCredsFuncs(credsFuncs...))
if err != nil {
log.G(ctx).WithError(err).Fatalf("failed to configure snapshotter")
}
log.G(ctx).Infof("Start snapshotter with builtin mode")
}

cleanup, err := serve(ctx, rpc, *address, rs, config)
Expand Down
25 changes: 25 additions & 0 deletions cmd/stargz-fuse-manager/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
/*
Copyright The 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 (
fusemanager "github.com/containerd/stargz-snapshotter/fusemanager"
)

func main() {
fusemanager.Run()
}
8 changes: 8 additions & 0 deletions docs/overview.md
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,14 @@ root@1d43741b8d29:/go# cat /.stargz-snapshotter/*
{"digest":"sha256:f077511be7d385c17ba88980379c5cd0aab7068844dffa7a1cefbf68cc3daea3","size":580,"fetchedSize":580,"fetchedPercent":100}
```

## Fuse manager

Remote snapshots are mounted using FUSE, its filesystem process are attached to stargz snapshotter. If stargz snapshotter restarts (The reason may be a change of configuration or a crash), all filesystem process will be killed and restarted, which cause the remount of FUSE mountpoints, making running containers unavailable.

To avoid this, we use a fuse daemon called fuse manager to handle filesystem process. Fuse manager is responsible for Mount and Unmount of remote snapshotters, its process is detached from stargz snapshotter main process to an independent one in a shim-like way during snapshotter's startup, so the restart of snapshotter won't affect filesystem process it manages, keeping mountpoints and running containers available during restart. But we still need to note that the restart of fuse manager itself triggers remount, so it's recommended to keep fuse manager running in good state.

You can enable fuse manager by adding flag `--detach-fuse-manager=true` to stargz snapshotter.

## Registry-related configuration

You can configure stargz snapshotter for accessing registries with custom configurations.
Expand Down
21 changes: 15 additions & 6 deletions fs/fs.go
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,13 @@ const (
fusermountBin = "fusermount"
)

var (
nsLock = sync.Mutex{}

ns *metrics.Namespace
metricsCtr *layermetrics.Controller
)

type Option func(*options)

type options struct {
Expand Down Expand Up @@ -114,14 +121,16 @@ func NewFilesystem(root string, cfg config.Config, opts ...Option) (_ snapshot.F
return nil, errors.Wrapf(err, "failed to setup resolver")
}

var ns *metrics.Namespace
if !cfg.NoPrometheus {
nsLock.Lock()
defer nsLock.Unlock()

if !cfg.NoPrometheus && ns == nil {
ns = metrics.NewNamespace("stargz", "fs", nil)
commonmetrics.Register() // Register common metrics. This will happen only once.
metrics.Register(ns) // Register layer metrics.
}
c := layermetrics.NewLayerMetrics(ns)
if ns != nil {
metrics.Register(ns) // Register layer metrics.
if metricsCtr == nil {
metricsCtr = layermetrics.NewLayerMetrics(ns)
}

return &filesystem{
Expand All @@ -135,7 +144,7 @@ func NewFilesystem(root string, cfg config.Config, opts ...Option) (_ snapshot.F
backgroundTaskManager: tm,
allowNoVerification: cfg.AllowNoVerification,
disableVerification: cfg.DisableVerification,
metricsController: c,
metricsController: metricsCtr,
attrTimeout: attrTimeout,
entryTimeout: entryTimeout,
}, nil
Expand Down
Loading

0 comments on commit 0cdde0e

Please sign in to comment.