pkg/init support for volumes

Signed-off-by: Avi Deitcher <avi@deitcher.net>
This commit is contained in:
Avi Deitcher
2024-07-18 17:54:25 +03:00
parent b953d1781c
commit a5085fc9ea
187 changed files with 290 additions and 187 deletions

View File

@@ -24,6 +24,9 @@ COPY --from=containerd-dev /go/src/github.com/containerd/containerd $GOPATH/src/
RUN cd /go/src/cmd/service && ./skanky-vendor.sh $GOPATH/src/github.com/containerd/containerd
RUN go-compile.sh /go/src/cmd/service
# volumes link to start
RUN mkdir -p /etc/init.d && ln -s /usr/bin/service /etc/init.d/005-volumes
FROM linuxkit/alpine:146f540f25cd92ec8ff0c5b0c98342a9a95e479e AS mirror
RUN mkdir -p /out/etc/apk && cp -r /etc/apk/* /out/etc/apk/
RUN apk add --no-cache --initdb -p /out alpine-baselayout busybox musl
@@ -34,6 +37,7 @@ RUN mkdir -p /out/etc/ssl/certs
# Remove cache residuals. We retain apk for SBOM tools
RUN rm -rf /out/var/cache
FROM scratch
ENTRYPOINT []
CMD []
@@ -42,5 +46,6 @@ COPY --from=build /go/bin/init /
COPY --from=build /tmp/bin /bin/
COPY --from=build /go/bin/service /usr/bin/
COPY --from=build usermode-helper /sbin/
COPY --from=build /etc/init.d/ /etc/init.d/
COPY --from=mirror /out/ /
COPY etc etc/

View File

@@ -25,7 +25,7 @@ func parseCmd(ctx context.Context, command string, args []string) (*log.Entry, s
}
sock := flags.String("sock", defaultSocket, "Path to containerd socket")
path := flags.String("path", defaultPath, "Path to service configs")
path := flags.String("path", defaultServicesPath, "Path to service configs")
dumpSpec := flags.String("dump-spec", "", "Dump container spec to file before start")

View File

@@ -14,7 +14,8 @@ import (
const (
defaultSocket = "/run/containerd/containerd.sock"
defaultPath = "/containers/services"
defaultServicesPath = "/containers/services"
defaultVolumesPath = "/containers/volumes"
defaultContainerd = "/usr/bin/containerd"
installPath = "/usr/bin/service"
onbootPath = "/containers/onboot"
@@ -84,6 +85,8 @@ func main() {
// check if called form startup scripts
command := os.Args[0]
switch {
case strings.Contains(command, "volumes"):
os.Exit(volumeInitCmd(ctx))
case strings.Contains(command, "onboot"):
os.Exit(runcInit(onbootPath, "onboot"))
case strings.Contains(command, "onshutdown"):

View File

@@ -67,7 +67,7 @@ func systemInitCmd(ctx context.Context, args []string) {
}
sock := flags.String("sock", defaultSocket, "Path to containerd socket")
path := flags.String("path", defaultPath, "Path to service configs")
path := flags.String("path", defaultServicesPath, "Path to service configs")
binary := flags.String("containerd", defaultContainerd, "Path to containerd")
if err := flags.Parse(args); err != nil {

View File

@@ -0,0 +1,95 @@
package main
import (
"context"
"flag"
"fmt"
"os"
"path/filepath"
log "github.com/sirupsen/logrus"
"golang.org/x/sys/unix"
)
func volumeInitCmd(ctx context.Context) int {
invoked := filepath.Base(os.Args[0])
flags := flag.NewFlagSet("volume", flag.ExitOnError)
flags.Usage = func() {
fmt.Printf("USAGE: %s volume\n\n", invoked)
fmt.Printf("Options:\n")
flags.PrintDefaults()
}
path := flags.String("path", defaultVolumesPath, "Path to volume configs")
// Set up volumes
vols, err := os.ReadDir(*path)
// just skip if there is an error, eg no such path
if err != nil {
return 1
}
// go through each volume, ensure that the volPath/merged exists as a directory,
// and is one of:
// - read-only: i.e. no tmp exists, merged bindmounted to lower
// - read-write: i.e. tmp exists, overlayfs lower/upper/merged
for _, vol := range vols {
subs, err := os.ReadDir(filepath.Join(*path, vol.Name()))
if err != nil {
log.WithError(err).Errorf("Error reading volume %s", vol.Name())
return 1
}
var hasLower, hasMerged, readWrite bool
for _, sub := range subs {
switch sub.Name() {
case "lower":
hasLower = true
case "tmp":
readWrite = true
case "merged":
hasMerged = true
}
}
if !hasMerged {
log.Errorf("Volume %s does not have a merged directory", vol.Name())
return 1
}
if !hasLower {
log.Errorf("Volume %s does not have a lower directory", vol.Name())
return 1
}
lowerDir := filepath.Join(*path, vol.Name(), "lower")
mergedDir := filepath.Join(*path, vol.Name(), "merged")
if !readWrite {
log.Infof("Volume %s is read-only, bind-mounting read-only", vol.Name())
if err := unix.Mount(lowerDir, mergedDir, "bind", unix.MS_RDONLY, ""); err != nil {
log.WithError(err).Errorf("Error bind-mounting volume %s", vol.Name())
return 1
}
} else {
log.Infof("Volume %s is read-write, overlay mounting", vol.Name())
// need a tmpfs to create the workdir and upper
tmpDir := filepath.Join(*path, vol.Name(), "tmp")
if err := unix.Mount("tmpfs", tmpDir, "tmpfs", unix.MS_RELATIME, ""); err != nil {
log.WithError(err).Errorf("Error creating tmpDir for volume %s", vol.Name())
return 1
}
workDir := filepath.Join(tmpDir, "work")
upperDir := filepath.Join(tmpDir, "upper")
if err := os.Mkdir(upperDir, 0755); err != nil {
log.WithError(err).Errorf("Error creating upper dir for volume %s", vol.Name())
return 1
}
if err := os.Mkdir(workDir, 0755); err != nil {
log.WithError(err).Errorf("Error creating work dir for volume %s", vol.Name())
return 1
}
// and let's mount the actual dir
data := fmt.Sprintf("lowerdir=%s,upperdir=%s,workdir=%s", lowerDir, upperDir, workDir)
if err := unix.Mount("overlay", mergedDir, "overlay", unix.MS_RELATIME, data); err != nil {
log.WithError(err).Errorf("Error overlay-mounting volume %s", vol.Name())
return 1
}
}
}
return 0
}