debugging
Signed-off-by: Jess Frazelle <jess@mesosphere.com>
This commit is contained in:
parent
0ae930df26
commit
b92f1bdae4
8 changed files with 51 additions and 14 deletions
3
Makefile
3
Makefile
|
@ -49,7 +49,7 @@ image.tar:
|
||||||
docker export $(shell docker create $(DOCKER_ROOTFS_IMAGE) sh) > $@
|
docker export $(shell docker create $(DOCKER_ROOTFS_IMAGE) sh) > $@
|
||||||
|
|
||||||
rootfs.go: image.tar
|
rootfs.go: image.tar
|
||||||
go generate
|
GOMAXPROCS=1 go generate
|
||||||
|
|
||||||
fmt:
|
fmt:
|
||||||
@echo "+ $@"
|
@echo "+ $@"
|
||||||
|
@ -76,6 +76,7 @@ clean: clean-rootfs
|
||||||
@$(RM) *.tar
|
@$(RM) *.tar
|
||||||
@$(RM) rootfs.go
|
@$(RM) rootfs.go
|
||||||
@$(RM) -r $(BINDIR)
|
@$(RM) -r $(BINDIR)
|
||||||
|
-@docker rm $(shell docker ps -aq) /dev/null 2>&1
|
||||||
|
|
||||||
install:
|
install:
|
||||||
@echo "+ $@"
|
@echo "+ $@"
|
||||||
|
|
24
README.md
24
README.md
|
@ -8,13 +8,19 @@ This is based off a crazy idea from [@crosbymichael](https://github.com/crosbymi
|
||||||
**NOTE**
|
**NOTE**
|
||||||
|
|
||||||
You may have noticed you can't file an issue. That's because this is using a crazy
|
You may have noticed you can't file an issue. That's because this is using a crazy
|
||||||
person's (aka my) fork of libcontainer
|
person's (aka my) fork of libcontainer and until I get the patches into upstream
|
||||||
and until I get the patches into upstream there's no
|
there's no way in hell I'm fielding issues from whoever is crazy enough to try this.
|
||||||
way in hell I'm fielding issues from whoever is crazy
|
|
||||||
enough to try this.
|
|
||||||
|
|
||||||
### Building
|
### Building
|
||||||
|
|
||||||
|
This uses the new Golang vendoring so you need go 1.6 or
|
||||||
|
`GO15VENDOREXPERIMENT=1` in your env.
|
||||||
|
|
||||||
|
You will also need `libapparmor-dev` and `libseccomp-dev`.
|
||||||
|
|
||||||
|
Most importantly you need userns in your kernel (`CONFIG_USER_NS=y`)
|
||||||
|
or else this won't even work.
|
||||||
|
|
||||||
```console
|
```console
|
||||||
$ make static
|
$ make static
|
||||||
Static container created at: ./bin/alpine
|
Static container created at: ./bin/alpine
|
||||||
|
@ -97,12 +103,18 @@ $ ./bin/alpine -h
|
||||||
## Cool things
|
## Cool things
|
||||||
|
|
||||||
The binary spawned does NOT need to oversee the container process if you
|
The binary spawned does NOT need to oversee the container process if you
|
||||||
run in detached mode with a PID file. You can have it watched by the user mode
|
run in detached mode with a PID file. You can have it watched by the user mode
|
||||||
systemd so that this binary is really just the launcher :)
|
systemd so that this binary is really just the launcher :)
|
||||||
|
|
||||||
|
## Example
|
||||||
|
|
||||||
|
Nginx running with my user "jessie".
|
||||||
|
|
||||||
|
![nginx.png](nginx.png)
|
||||||
|
|
||||||
## Caveats
|
## Caveats
|
||||||
|
|
||||||
**Caps the binary needs to unpack and set
|
**Caps the binary needs to unpack and set
|
||||||
the right perms on the roofs for the userns user**
|
the right perms on the roofs for the userns user**
|
||||||
|
|
||||||
- **CAP_CHOWN**: chown the rootfs to the userns user
|
- **CAP_CHOWN**: chown the rootfs to the userns user
|
||||||
|
|
13
main.go
13
main.go
|
@ -12,6 +12,7 @@ import (
|
||||||
aaprofile "github.com/docker/docker/profiles/apparmor"
|
aaprofile "github.com/docker/docker/profiles/apparmor"
|
||||||
"github.com/opencontainers/runc/libcontainer"
|
"github.com/opencontainers/runc/libcontainer"
|
||||||
"github.com/opencontainers/runc/libcontainer/apparmor"
|
"github.com/opencontainers/runc/libcontainer/apparmor"
|
||||||
|
"github.com/opencontainers/runc/libcontainer/user"
|
||||||
"github.com/opencontainers/runtime-spec/specs-go"
|
"github.com/opencontainers/runtime-spec/specs-go"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -180,13 +181,21 @@ func main() {
|
||||||
|
|
||||||
// install the default apparmor profile
|
// install the default apparmor profile
|
||||||
if apparmor.IsEnabled() {
|
if apparmor.IsEnabled() {
|
||||||
if err := aaprofile.InstallDefault(defaultApparmorProfile); err != nil {
|
// check if we have the docker-default apparmor profile loaded
|
||||||
logrus.Warnf("AppArmor is enabled on the the system, but the profile (%s) could not be loaded", defaultApparmorProfile)
|
if err := aaprofile.IsLoaded(defaultApparmorProfile); err != nil {
|
||||||
|
logrus.Warnf("AppArmor enabled on system but the %s profile is not loaded. apparmor_parser needs root to load a profile so we can't do it for you.", defaultApparmorProfile)
|
||||||
} else {
|
} else {
|
||||||
spec.Process.ApparmorProfile = defaultApparmorProfile
|
spec.Process.ApparmorProfile = defaultApparmorProfile
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// set the CgroupsPath as this user
|
||||||
|
user, err := user.CurrentUser()
|
||||||
|
if err != nil {
|
||||||
|
logrus.Fatal(err)
|
||||||
|
}
|
||||||
|
spec.Linux.CgroupsPath = sPtr(user.Name)
|
||||||
|
|
||||||
if err := unpackRootfs(spec); err != nil {
|
if err := unpackRootfs(spec); err != nil {
|
||||||
logrus.Fatal(err)
|
logrus.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
BIN
nginx.png
Normal file
BIN
nginx.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 16 MiB |
17
vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/apply_raw.go
generated
vendored
17
vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/apply_raw.go
generated
vendored
|
@ -111,11 +111,14 @@ func (m *Manager) Apply(pid int) (err error) {
|
||||||
|
|
||||||
var c = m.Cgroups
|
var c = m.Cgroups
|
||||||
|
|
||||||
|
logrus.Debugf("pre get cgroups data: %#v", c)
|
||||||
d, err := getCgroupData(m.Cgroups, pid)
|
d, err := getCgroupData(m.Cgroups, pid)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
logrus.Debugf("cgroups data: %#v, config: %#v", d, d.config)
|
||||||
|
|
||||||
if c.Paths != nil {
|
if c.Paths != nil {
|
||||||
paths := make(map[string]string)
|
paths := make(map[string]string)
|
||||||
for name, path := range c.Paths {
|
for name, path := range c.Paths {
|
||||||
|
@ -129,6 +132,7 @@ func (m *Manager) Apply(pid int) (err error) {
|
||||||
paths[name] = path
|
paths[name] = path
|
||||||
}
|
}
|
||||||
m.Paths = paths
|
m.Paths = paths
|
||||||
|
logrus.Debugf("cgroups apply paths: %#v", m.Paths)
|
||||||
return cgroups.EnterPid(m.Paths, pid)
|
return cgroups.EnterPid(m.Paths, pid)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -136,6 +140,7 @@ func (m *Manager) Apply(pid int) (err error) {
|
||||||
defer m.mu.Unlock()
|
defer m.mu.Unlock()
|
||||||
paths := make(map[string]string)
|
paths := make(map[string]string)
|
||||||
for _, sys := range subsystems {
|
for _, sys := range subsystems {
|
||||||
|
logrus.Debugf("applying cgroups to subsystem %#v", sys)
|
||||||
if err := sys.Apply(d); err != nil {
|
if err := sys.Apply(d); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -353,23 +358,25 @@ func writeFile(dir, file, data string) error {
|
||||||
if dir == "" {
|
if dir == "" {
|
||||||
return fmt.Errorf("no such directory for %s", file)
|
return fmt.Errorf("no such directory for %s", file)
|
||||||
}
|
}
|
||||||
|
|
||||||
// get the current user
|
// get the current user
|
||||||
u, err := user.CurrentUser()
|
u, err := user.CurrentUser()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := os.Chown(dir, u.Uid, u.Gid); err != nil {
|
if err := os.Lchown(dir, u.Uid, u.Gid); err != nil {
|
||||||
return fmt.Errorf("failed to chown %s to %d:%d -> %v", dir, u.Uid, u.Gid, err)
|
return fmt.Errorf("failed to chown to %d:%d -> %v", u.Uid, u.Gid, err)
|
||||||
}
|
}
|
||||||
|
logrus.Debugf("chown dir %s to %d:%d", dir, u.Uid, u.Gid)
|
||||||
|
|
||||||
if err := os.Chown(filepath.Join(dir, "tasks"), u.Uid, u.Gid); err != nil {
|
if err := os.Lchown(filepath.Join(dir, file), u.Uid, u.Gid); err != nil {
|
||||||
return fmt.Errorf("failed to chown %s/tasks to %d:%d -> %v", dir, u.Uid, u.Gid, err)
|
return fmt.Errorf("failed to chown to %d:%d -> %v", u.Uid, u.Gid, err)
|
||||||
}
|
}
|
||||||
|
logrus.Debugf("chown %s to %d:%d", filepath.Join(dir, file), u.Uid, u.Gid)
|
||||||
|
|
||||||
if err := ioutil.WriteFile(filepath.Join(dir, file), []byte(data), 0700); err != nil {
|
if err := ioutil.WriteFile(filepath.Join(dir, file), []byte(data), 0700); err != nil {
|
||||||
logrus.Debugf("failed to write %v to %v: %v", data, file, err)
|
logrus.Debugf("failed to write %v to %v: %v", data, file, err)
|
||||||
|
//return err
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
2
vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/cpuset.go
generated
vendored
2
vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/cpuset.go
generated
vendored
|
@ -10,6 +10,7 @@ import (
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
|
"github.com/Sirupsen/logrus"
|
||||||
"github.com/opencontainers/runc/libcontainer/cgroups"
|
"github.com/opencontainers/runc/libcontainer/cgroups"
|
||||||
"github.com/opencontainers/runc/libcontainer/configs"
|
"github.com/opencontainers/runc/libcontainer/configs"
|
||||||
libcontainerUtils "github.com/opencontainers/runc/libcontainer/utils"
|
libcontainerUtils "github.com/opencontainers/runc/libcontainer/utils"
|
||||||
|
@ -27,6 +28,7 @@ func (s *CpusetGroup) Apply(d *cgroupData) error {
|
||||||
if err != nil && !cgroups.IsNotFound(err) {
|
if err != nil && !cgroups.IsNotFound(err) {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
logrus.Debugf("apply cpuset dir is %s", dir)
|
||||||
return s.ApplyDir(dir, d.config, d.pid)
|
return s.ApplyDir(dir, d.config, d.pid)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
2
vendor/github.com/opencontainers/runc/libcontainer/container_linux.go
generated
vendored
2
vendor/github.com/opencontainers/runc/libcontainer/container_linux.go
generated
vendored
|
@ -171,6 +171,7 @@ func (c *linuxContainer) Set(config configs.Config) error {
|
||||||
c.m.Lock()
|
c.m.Lock()
|
||||||
defer c.m.Unlock()
|
defer c.m.Unlock()
|
||||||
c.config = &config
|
c.config = &config
|
||||||
|
logrus.Debugf("setting cgroups")
|
||||||
return c.cgroupManager.Set(c.config)
|
return c.cgroupManager.Set(c.config)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -741,6 +742,7 @@ func (c *linuxContainer) Restore(process *Process, criuOpts *CriuOpts) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *linuxContainer) criuApplyCgroups(pid int, req *criurpc.CriuReq) error {
|
func (c *linuxContainer) criuApplyCgroups(pid int, req *criurpc.CriuReq) error {
|
||||||
|
logrus.Debugf("criu apply cgroups")
|
||||||
if err := c.cgroupManager.Apply(pid); err != nil {
|
if err := c.cgroupManager.Apply(pid); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
4
vendor/github.com/opencontainers/runc/libcontainer/process_linux.go
generated
vendored
4
vendor/github.com/opencontainers/runc/libcontainer/process_linux.go
generated
vendored
|
@ -13,6 +13,7 @@ import (
|
||||||
"strconv"
|
"strconv"
|
||||||
"syscall"
|
"syscall"
|
||||||
|
|
||||||
|
"github.com/Sirupsen/logrus"
|
||||||
"github.com/opencontainers/runc/libcontainer/cgroups"
|
"github.com/opencontainers/runc/libcontainer/cgroups"
|
||||||
"github.com/opencontainers/runc/libcontainer/configs"
|
"github.com/opencontainers/runc/libcontainer/configs"
|
||||||
"github.com/opencontainers/runc/libcontainer/system"
|
"github.com/opencontainers/runc/libcontainer/system"
|
||||||
|
@ -247,6 +248,9 @@ func (p *initProcess) start() error {
|
||||||
return newSystemError(err)
|
return newSystemError(err)
|
||||||
}
|
}
|
||||||
p.setExternalDescriptors(fds)
|
p.setExternalDescriptors(fds)
|
||||||
|
|
||||||
|
logrus.Debugf("starting process apply cgroups")
|
||||||
|
|
||||||
// Do this before syncing with child so that no children
|
// Do this before syncing with child so that no children
|
||||||
// can escape the cgroup
|
// can escape the cgroup
|
||||||
if err := p.manager.Apply(p.pid()); err != nil {
|
if err := p.manager.Apply(p.pid()); err != nil {
|
||||||
|
|
Loading…
Reference in a new issue