mirror of
https://github.com/moby/moby.git
synced 2022-11-09 12:21:53 -05:00
Implemented a self-injecting process wrapper that runs inside the container
- Before starting the container, docker injects itself inside the container by mount binding the dockerd binary into /sbin/init - Instead of running the user process directly inside the container, we run /sbin/init targetprocess [args...] - When docker is run as /sbin/init (e.g. argv[0] == "/sbin/init"), then its own sys init code kicks in - The sys init code will be responsible for setting up the process environment prior to its execution (setuid, networking, ...). - Finally, docker's sys init will exec() the container's process, thus replacing itself with the target binary (which will be running as pid 1)
This commit is contained in:
parent
0d46006269
commit
58a2294260
5 changed files with 53 additions and 0 deletions
|
@ -16,6 +16,12 @@ import (
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var sysInitPath string
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
sysInitPath = SelfPath()
|
||||||
|
}
|
||||||
|
|
||||||
type Container struct {
|
type Container struct {
|
||||||
Id string
|
Id string
|
||||||
Root string
|
Root string
|
||||||
|
@ -29,6 +35,7 @@ type Container struct {
|
||||||
Filesystem *Filesystem
|
Filesystem *Filesystem
|
||||||
State *State
|
State *State
|
||||||
|
|
||||||
|
SysInitPath string
|
||||||
lxcConfigPath string
|
lxcConfigPath string
|
||||||
cmd *exec.Cmd
|
cmd *exec.Cmd
|
||||||
stdout *writeBroadcaster
|
stdout *writeBroadcaster
|
||||||
|
@ -58,6 +65,7 @@ func createContainer(id string, root string, command string, args []string, laye
|
||||||
Filesystem: newFilesystem(path.Join(root, "rootfs"), path.Join(root, "rw"), layers),
|
Filesystem: newFilesystem(path.Join(root, "rootfs"), path.Join(root, "rw"), layers),
|
||||||
State: newState(),
|
State: newState(),
|
||||||
|
|
||||||
|
SysInitPath: sysInitPath,
|
||||||
lxcConfigPath: path.Join(root, "config.lxc"),
|
lxcConfigPath: path.Join(root, "config.lxc"),
|
||||||
stdout: newWriteBroadcaster(),
|
stdout: newWriteBroadcaster(),
|
||||||
stderr: newWriteBroadcaster(),
|
stderr: newWriteBroadcaster(),
|
||||||
|
@ -261,6 +269,7 @@ func (container *Container) Start() error {
|
||||||
"-n", container.Id,
|
"-n", container.Id,
|
||||||
"-f", container.lxcConfigPath,
|
"-f", container.lxcConfigPath,
|
||||||
"--",
|
"--",
|
||||||
|
"/sbin/init",
|
||||||
container.Path,
|
container.Path,
|
||||||
}
|
}
|
||||||
params = append(params, container.Args...)
|
params = append(params, container.Args...)
|
||||||
|
|
|
@ -6,6 +6,13 @@ import (
|
||||||
"testing"
|
"testing"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Hack to run sys init during unit testing
|
||||||
|
func init() {
|
||||||
|
if SelfPath() == "/sbin/init" {
|
||||||
|
SysInit()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func newTestDocker() (*Docker, error) {
|
func newTestDocker() (*Docker, error) {
|
||||||
root, err := ioutil.TempDir("", "docker-test")
|
root, err := ioutil.TempDir("", "docker-test")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -705,6 +705,11 @@ func (srv *Server) CmdRun(stdin io.ReadCloser, stdout io.Writer, args ...string)
|
||||||
}
|
}
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
if docker.SelfPath() == "/sbin/init" {
|
||||||
|
// Running in init mode
|
||||||
|
docker.SysInit()
|
||||||
|
return
|
||||||
|
}
|
||||||
future.Seed()
|
future.Seed()
|
||||||
flag.Parse()
|
flag.Parse()
|
||||||
d, err := New()
|
d, err := New()
|
||||||
|
|
|
@ -74,6 +74,9 @@ lxc.mount.entry = devpts {{$ROOTFS}}/dev/pts devpts newinstance,ptmxmode=0666,no
|
||||||
#lxc.mount.entry = varlock {{$ROOTFS}}/var/lock tmpfs size=1024k,nosuid,nodev,noexec 0 0
|
#lxc.mount.entry = varlock {{$ROOTFS}}/var/lock tmpfs size=1024k,nosuid,nodev,noexec 0 0
|
||||||
#lxc.mount.entry = shm {{$ROOTFS}}/dev/shm tmpfs size=65536k,nosuid,nodev,noexec 0 0
|
#lxc.mount.entry = shm {{$ROOTFS}}/dev/shm tmpfs size=65536k,nosuid,nodev,noexec 0 0
|
||||||
|
|
||||||
|
# Inject docker-init
|
||||||
|
lxc.mount.entry = {{.SysInitPath}} {{$ROOTFS}}/sbin/init none bind,ro 0 0
|
||||||
|
|
||||||
# In order to get a working DNS environment, mount bind (ro) the host's /etc/resolv.conf into the container
|
# In order to get a working DNS environment, mount bind (ro) the host's /etc/resolv.conf into the container
|
||||||
lxc.mount.entry = /etc/resolv.conf {{$ROOTFS}}/etc/resolv.conf none bind,ro 0 0
|
lxc.mount.entry = /etc/resolv.conf {{$ROOTFS}}/etc/resolv.conf none bind,ro 0 0
|
||||||
|
|
||||||
|
|
29
sysinit.go
Normal file
29
sysinit.go
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
package docker
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
"os/exec"
|
||||||
|
"syscall"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Sys Init code
|
||||||
|
// This code is run INSIDE the container and is responsible for setting
|
||||||
|
// up the environment before running the actual process
|
||||||
|
func SysInit() {
|
||||||
|
if len(os.Args) <= 1 {
|
||||||
|
fmt.Println("You should not invoke docker-init manually")
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
path, err := exec.LookPath(os.Args[1])
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("Unable to locate %v", os.Args[1])
|
||||||
|
os.Exit(127)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := syscall.Exec(path, os.Args[1:], os.Environ()); err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
}
|
Loading…
Add table
Reference in a new issue