Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Experiment] Explore running multiple containers in a shared VM #3658

Draft
wants to merge 18 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 26 additions & 12 deletions pkg/pillar/cmd/domainmgr/domainmgr.go
Original file line number Diff line number Diff line change
Expand Up @@ -1901,7 +1901,8 @@
config.UUIDandVersion, config.DisplayName)
status.DiskStatusList = make([]types.DiskStatus,
len(config.DiskConfigList))
need9P := false
var addDiskStatus []types.DiskStatus
status.ContainerList = nil

Check warning on line 1905 in pkg/pillar/cmd/domainmgr/domainmgr.go

View check run for this annotation

Codecov / codecov/patch

pkg/pillar/cmd/domainmgr/domainmgr.go#L1904-L1905

Added lines #L1904 - L1905 were not covered by tests
for i, dc := range config.DiskConfigList {
ds := &status.DiskStatusList[i]
ds.VolumeKey = dc.VolumeKey
Expand All @@ -1917,12 +1918,31 @@
if dc.Target == zconfig.Target_AppCustom {
ds.Devtype = "AppCustom"
} else if dc.Format == zconfig.Format_CONTAINER {
if i == 0 {
if i == 0 || ds.MountDir == "" {

Check warning on line 1921 in pkg/pillar/cmd/domainmgr/domainmgr.go

View check run for this annotation

Codecov / codecov/patch

pkg/pillar/cmd/domainmgr/domainmgr.go#L1921

Added line #L1921 was not covered by tests
ds.MountDir = "/"
status.OCIConfigDir = ds.FileLocation
suffix := ""
if i != 0 {
suffix = strconv.Itoa(i)
}
fileLocation := "/mnt" + suffix
dcs := types.DomainContainerStatus{
ContainerIndex: i,
FileLocation: fileLocation,
OCIConfigDir: ds.FileLocation,
}
status.ContainerList = append(status.ContainerList, dcs)
// Add information about the 9P export to
// DiskStatus.
// XXX Why do we/did we reuse DIskStatus here?
// Note that Format can not be set to CONTAINER
addDiskStatus = append(addDiskStatus,
types.DiskStatus{
FileLocation: ds.FileLocation,
Devtype: "9P",
ReadOnly: false,
})

Check warning on line 1943 in pkg/pillar/cmd/domainmgr/domainmgr.go

View check run for this annotation

Codecov / codecov/patch

pkg/pillar/cmd/domainmgr/domainmgr.go#L1923-L1943

Added lines #L1923 - L1943 were not covered by tests
}
ds.Devtype = ""
need9P = true
} else {
ds.Devtype = "hdd"
if dc.Format == zconfig.Format_ISO {
Expand All @@ -1948,7 +1968,7 @@
return fmt.Errorf("failed to fetch cloud-init userdata: %s",
err)
}
if status.OCIConfigDir != "" { // If AppInstance is a container, we need to parse cloud-init config and apply the supported parts
if len(status.ContainerList) != 0 { // AppInstance is a container, we need to parse cloud-init config and apply the supported parts

Check warning on line 1971 in pkg/pillar/cmd/domainmgr/domainmgr.go

View check run for this annotation

Codecov / codecov/patch

pkg/pillar/cmd/domainmgr/domainmgr.go#L1971

Added line #L1971 was not covered by tests
if cloudconfig.IsCloudConfig(ciStr) { // treat like the cloud-init config
cc, err := cloudconfig.ParseCloudConfig(ciStr)
if err != nil {
Expand Down Expand Up @@ -1984,13 +2004,7 @@
}
}

if need9P {
status.DiskStatusList = append(status.DiskStatusList, types.DiskStatus{
FileLocation: "/mnt",
Devtype: "9P",
ReadOnly: false,
})
}
status.DiskStatusList = append(status.DiskStatusList, addDiskStatus...)

Check warning on line 2007 in pkg/pillar/cmd/domainmgr/domainmgr.go

View check run for this annotation

Codecov / codecov/patch

pkg/pillar/cmd/domainmgr/domainmgr.go#L2007

Added line #L2007 was not covered by tests
return nil
}

Expand Down
15 changes: 14 additions & 1 deletion pkg/pillar/containerd/oci.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@
"github.com/linuxkit/linuxkit/src/cmd/linuxkit/moby"
v1 "github.com/opencontainers/image-spec/specs-go/v1"
"github.com/opencontainers/runtime-spec/specs-go"

"github.com/sirupsen/logrus"
)

const eveScript = "/bin/eve"
Expand Down Expand Up @@ -210,6 +212,7 @@
// finally do a switcheroo
s.Spec = spec.Spec

logrus.Infof("XXX AddLoader result %+v", s.Spec)
return nil
}

Expand Down Expand Up @@ -440,6 +443,7 @@
blkMountPoints := ""

for id, disk := range disks {
// XXX here we use MountDir and FileLocation
dst := disk.MountDir
src := disk.FileLocation
opts := []string{"rbind"}
Expand All @@ -453,14 +457,20 @@
// we can bind mount anything aside from FmtUnknown
switch disk.Format {
case zconfig.Format_FmtUnknown:
logrus.Infof("XXX FmtUnknown %d", id)

Check warning on line 460 in pkg/pillar/containerd/oci.go

View check run for this annotation

Codecov / codecov/patch

pkg/pillar/containerd/oci.go#L460

Added line #L460 was not covered by tests
continue
case zconfig.Format_CONTAINER:
logrus.Infof("XXX container %d MountDir %s",
id, disk.MountDir)
if path.Clean(disk.MountDir) == "/" {
// skipping root volumes for now
continue
} else {
src = path.Join(src, ociVolumeData)
}
default:
logrus.Infof("XXX format %s %d", disk.Format, id)

}

dests := []string{fmt.Sprintf("/dev/eve/volumes/by-id/%d", id)}
Expand All @@ -481,7 +491,10 @@
dests = append(dests, dst)
}

for _, dest := range dests {
for i, dest := range dests {
// XXX here we create bind mounts from FileLocation to MountDir
logrus.Infof("XXX Adding mount %d/%d from %s to %s",
id, i, src, dest)
s.Mounts = append(s.Mounts, specs.Mount{
Type: "bind",
Source: src,
Expand Down
11 changes: 8 additions & 3 deletions pkg/pillar/hypervisor/containerd.go
Original file line number Diff line number Diff line change
Expand Up @@ -95,15 +95,20 @@

func (ctx ctrdContext) Setup(status types.DomainStatus, config types.DomainConfig,
aa *types.AssignableAdapters, globalConfig *types.ConfigItemValueMap, file *os.File) error {
if status.OCIConfigDir == "" {
if len(status.ContainerList) == 0 {

Check warning on line 98 in pkg/pillar/hypervisor/containerd.go

View check run for this annotation

Codecov / codecov/patch

pkg/pillar/hypervisor/containerd.go#L98

Added line #L98 was not covered by tests
return logError("failed to run domain %s: not based on an OCI image", status.DomainName)
}

spec, err := ctx.setupSpec(&status, &config, status.OCIConfigDir)
// We assume a single container in the case of NOHYPER
if len(status.ContainerList) != 1 {
return logError("failed to run domain %s: more than one OCI image", status.DomainName)
}

Check warning on line 105 in pkg/pillar/hypervisor/containerd.go

View check run for this annotation

Codecov / codecov/patch

pkg/pillar/hypervisor/containerd.go#L103-L105

Added lines #L103 - L105 were not covered by tests

ociConfigDir := status.ContainerList[0].OCIConfigDir
spec, err := ctx.setupSpec(&status, &config, ociConfigDir)

Check warning on line 108 in pkg/pillar/hypervisor/containerd.go

View check run for this annotation

Codecov / codecov/patch

pkg/pillar/hypervisor/containerd.go#L107-L108

Added lines #L107 - L108 were not covered by tests
if err != nil {
return logError("setting up OCI spec for domain %s failed %v", status.DomainName, err)
}

// we use patched version of dhcpcd with /etc/resolv.conf.new
vifsTaskResolv := filepath.Join(vifsDir, status.DomainName, "etc", "resolv.conf.new")
err = os.MkdirAll(filepath.Dir(vifsTaskResolv), 0755)
Expand Down
61 changes: 52 additions & 9 deletions pkg/pillar/hypervisor/kvm.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
"os"
"path/filepath"
"runtime"
"strconv"
"strings"
"text/template"
"time"
Expand Down Expand Up @@ -261,7 +262,7 @@
[device "fs{{.DiskID}}"]
driver = "virtio-9p-pci"
fsdev = "fsdev{{.DiskID}}"
mount_tag = "share_dir"
mount_tag = "{{.Tag9P}}"
addr = "{{printf "0x%x" .PCIId}}"
{{else}}
[device "pci.{{.PCIId}}"]
Expand Down Expand Up @@ -673,24 +674,50 @@
"-readconfig", file.Name(),
"-pidfile", kvmStateDir+domainName+"/pid")

spec, err := ctx.setupSpec(&status, &config, status.OCIConfigDir)
if err != nil {
return logError("failed to load OCI spec for domain %s: %v", status.DomainName, err)
var spec0 containerd.OCISpec // The main container for the app instance
for _, dcs := range status.ContainerList {
ociConfigDir := dcs.OCIConfigDir
logrus.Infof("XXX processing %d dir %s", dcs.ContainerIndex, ociConfigDir)
spec, err := ctx.setupSpec(&status, &config, ociConfigDir)
if err != nil {
return logError("failed to load OCI spec for domain %s oci %d %s: %v",
status.DomainName, dcs.ContainerIndex, ociConfigDir, err)
}
if dcs.ContainerIndex == 0 {
spec0 = spec
}
if err = spec.AddLoader("/containers/services/xen-tools"); err != nil {
return logError("failed to add kvm hypervisor loader to domain %s oci %d %s: %v",
status.DomainName, dcs.ContainerIndex, ociConfigDir, err)
}

Check warning on line 692 in pkg/pillar/hypervisor/kvm.go

View check run for this annotation

Codecov / codecov/patch

pkg/pillar/hypervisor/kvm.go#L677-L692

Added lines #L677 - L692 were not covered by tests
}
if err = spec.AddLoader("/containers/services/xen-tools"); err != nil {
return logError("failed to add kvm hypervisor loader to domain %s: %v", status.DomainName, err)
// XXX find better code structure
if spec0 == nil {
// Not a container
var err error
spec0, err = ctx.setupSpec(&status, &config, "")
if err != nil {
return logError("failed to load OCI spec for domain %s: %v",
status.DomainName, err)
}
if err = spec0.AddLoader("/containers/services/xen-tools"); err != nil {
return logError("failed to add kvm hypervisor loader to domain %s: %v",
status.DomainName, err)
}

Check warning on line 706 in pkg/pillar/hypervisor/kvm.go

View check run for this annotation

Codecov / codecov/patch

pkg/pillar/hypervisor/kvm.go#L695-L706

Added lines #L695 - L706 were not covered by tests
}

// XXX potentially IoAdpaters per OCI? Would require different EVE API
overhead, err := vmmOverhead(domainName, domainUUID, int64(config.Memory), int64(config.VMMMaxMem), int64(config.MaxCpus), int64(config.VCpus), config.IoAdapterList, aa, globalConfig)
if err != nil {
return logError("vmmOverhead() failed for domain %s: %v",
status.DomainName, err)
}
logrus.Debugf("Qemu overhead for domain %s is %d bytes", status.DomainName, overhead)
spec.AdjustMemLimit(config, overhead)
spec.Get().Process.Args = args
spec0.AdjustMemLimit(config, overhead)
spec0.Get().Process.Args = args

Check warning on line 717 in pkg/pillar/hypervisor/kvm.go

View check run for this annotation

Codecov / codecov/patch

pkg/pillar/hypervisor/kvm.go#L716-L717

Added lines #L716 - L717 were not covered by tests
logrus.Infof("Hypervisor args: %v", args)

if err := spec.CreateContainer(true); err != nil {
if err := spec0.CreateContainer(true); err != nil {

Check warning on line 720 in pkg/pillar/hypervisor/kvm.go

View check run for this annotation

Codecov / codecov/patch

pkg/pillar/hypervisor/kvm.go#L720

Added line #L720 was not covered by tests
return logError("Failed to create container for task %s from %v: %v", status.DomainName, config, err)
}

Expand All @@ -700,13 +727,19 @@
// CreateDomConfig creates a domain config (a qemu config file, typically named something like xen-%d.cfg)
func (ctx KvmContext) CreateDomConfig(domainName string, config types.DomainConfig, status types.DomainStatus,
diskStatusList []types.DiskStatus, aa *types.AssignableAdapters, file *os.File) error {
var extra string
numOCI := len(status.ContainerList)
if numOCI > 1 {
extra = fmt.Sprintf(" max_oci=%d", numOCI-1)
}
tmplCtx := struct {
Machine string
types.DomainConfig
types.DomainStatus
}{ctx.devicemodel, config, status}
tmplCtx.DomainConfig.Memory = (config.Memory + 1023) / 1024
tmplCtx.DomainConfig.DisplayName = domainName
tmplCtx.DomainConfig.ExtraArgs += extra

// render global device model settings
t, _ := template.New("qemu").Parse(qemuConfTemplate)
Expand All @@ -719,6 +752,7 @@
Machine string
PCIId, DiskID, SATAId, NumQueues int
AioType string
Tag9P string
types.DiskStatus
}{Machine: ctx.devicemodel, PCIId: 4, DiskID: 0, SATAId: 0, AioType: "io_uring", NumQueues: config.VCpus}

Expand All @@ -727,14 +761,23 @@
Parse(qemuDiskTemplate)
for _, ds := range diskStatusList {
if ds.Devtype == "" {
// XXX doesn't all 9p fall in here?
logrus.Infof("XXX skipping DiskStatus: %+v", ds)
continue
}
if ds.Devtype == "AppCustom" {
// This is application custom data. It is forwarded to the VM
// differently - as a download url in zedrouter
continue
}
tag := "share_dir"
if diskContext.DiskID != 0 {
tag += strconv.Itoa(diskContext.DiskID)
}
diskContext.Tag9P = tag
diskContext.DiskStatus = ds
logrus.Infof("XXX tag %s DiskStatus %d: %+v",
tag, diskContext.DiskID, ds)
if err := t.Execute(file, diskContext); err != nil {
return logError("can't write to config file %s (%v)", file.Name(), err)
}
Expand Down
Loading
Loading