Created
May 16, 2015 01:00
-
-
Save crosbymichael/56610c9b3bc4296b8c69 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package main | |
import ( | |
"encoding/json" | |
"fmt" | |
"log" | |
"os" | |
"path/filepath" | |
"syscall" | |
"github.com/docker/libcontainer" | |
"github.com/docker/libcontainer/cgroups" | |
"github.com/docker/libcontainer/configs" | |
"github.com/docker/libcontainer/utils" | |
) | |
func main() { | |
var spec PodSpec | |
if err := json.NewDecoder(os.Stdin).Decode(&spec); err != nil { | |
log.Fatal(err) | |
} | |
pod, err := New("/var/run/pods", &spec) | |
if err != nil { | |
log.Fatal(err) | |
} | |
if err := pod.Start(); err != nil { | |
log.Fatal(err) | |
} | |
pod.Wait() | |
} | |
type PodSpec struct { | |
Kind string | |
ApiVersion string `json:"apiVersion"` | |
Metadata struct { | |
Name string | |
} | |
Spec struct { | |
Containers []struct { | |
Name string | |
Image string // path | |
Command []string | |
Args []string | |
Env []struct { | |
Name string | |
Value string | |
} | |
Ports []struct { | |
HostIP string `json:"hostIP"` | |
HostPort string `json:"hostPort"` | |
ContainerPort string `json:"containerPort"` | |
} | |
VolumeMounts []struct { | |
Name string | |
MountPath string `json:"mountPath"` | |
} `json:"volumeMounts"` | |
} | |
Volumes []struct { | |
Name string | |
HostPath struct { | |
Path string | |
} `json:"hostPath"` | |
} | |
} | |
Crap struct { | |
IP string | |
} | |
} | |
func New(root string, spec *PodSpec) (*Pod, error) { | |
factory, err := libcontainer.New(root) | |
if err != nil { | |
return nil, err | |
} | |
var pod Pod | |
for _, c := range spec.Spec.Containers { | |
config := getTemplate() | |
config.Rootfs = c.Image | |
config.Cgroups.Name = c.Name | |
cont, err := factory.Create(c.Name, config) | |
if err != nil { | |
return nil, fmt.Errorf("failed to create container %q: %v", c.Name, err) | |
} | |
var env []string | |
for _, e := range c.Env { | |
env = append(env, e.Name+"="+e.Value) | |
} | |
pod.containers = append(pod.containers, containerProcess{ | |
name: c.Name, | |
process: &libcontainer.Process{ | |
Args: append(c.Command, c.Args...), | |
Env: env, | |
Stdout: os.Stdout, | |
Stderr: os.Stderr, | |
}, | |
container: cont, | |
}) | |
} | |
return &Pod{ | |
spec: spec, | |
factory: factory, | |
}, nil | |
} | |
type containerProcess struct { | |
name string | |
process *libcontainer.Process | |
container libcontainer.Container | |
} | |
type Pod struct { | |
spec *PodSpec | |
factory libcontainer.Factory | |
// namespaces shares all the namespaces except the mount and pid namespace with the pod. | |
cgroups *configs.Cgroup | |
containers []containerProcess | |
} | |
func (p *Pod) Start() error { | |
if err := syscall.Unshare(syscall.CLONE_NEWNET | syscall.CLONE_NEWUTS | syscall.CLONE_NEWIPC); err != nil { | |
return fmt.Errorf("failed to unshare namespaces: %v", err) | |
} | |
for _, cp := range p.containers { | |
if err := cp.container.Start(cp.process); err != nil { | |
return fmt.Errorf("failed to start container %q: %v", cp.name, err) | |
} | |
} | |
return nil | |
} | |
func (p *Pod) Wait() { | |
for _, cp := range p.containers { | |
state, err := cp.process.Wait() | |
if err != nil { | |
log.Println(err) | |
continue | |
} | |
log.Printf("container exited with status %d\n", utils.ExitStatus(state)) | |
} | |
} | |
func getTemplate() *configs.Config { | |
cgroupRoot, err := cgroups.GetThisCgroupDir("devices") | |
if err != nil { | |
panic(err) | |
} | |
return &configs.Config{ | |
ParentDeathSignal: int(syscall.SIGKILL), | |
Capabilities: []string{ | |
"CHOWN", | |
"DAC_OVERRIDE", | |
"FSETID", | |
"FOWNER", | |
"MKNOD", | |
"NET_RAW", | |
"SETGID", | |
"SETUID", | |
"SETFCAP", | |
"SETPCAP", | |
"NET_BIND_SERVICE", | |
"SYS_CHROOT", | |
"KILL", | |
"AUDIT_WRITE", | |
}, | |
Namespaces: configs.Namespaces([]configs.Namespace{ | |
{Type: configs.NEWNS}, | |
{Type: configs.NEWPID}, | |
}), | |
Cgroups: &configs.Cgroup{ | |
Name: filepath.Base(cwd), | |
Parent: cgroupRoot, | |
AllowAllDevices: false, | |
AllowedDevices: configs.DefaultAllowedDevices, | |
}, | |
Devices: configs.DefaultAutoCreatedDevices, | |
MaskPaths: []string{ | |
"/proc/kcore", | |
}, | |
ReadonlyPaths: []string{ | |
"/proc/sys", "/proc/sysrq-trigger", "/proc/irq", "/proc/bus", | |
}, | |
Mounts: []*configs.Mount{ | |
{ | |
Source: "proc", | |
Destination: "/proc", | |
Device: "proc", | |
Flags: defaultMountFlags, | |
}, | |
{ | |
Source: "tmpfs", | |
Destination: "/dev", | |
Device: "tmpfs", | |
Flags: syscall.MS_NOSUID | syscall.MS_STRICTATIME, | |
Data: "mode=755", | |
}, | |
{ | |
Source: "devpts", | |
Destination: "/dev/pts", | |
Device: "devpts", | |
Flags: syscall.MS_NOSUID | syscall.MS_NOEXEC, | |
Data: "newinstance,ptmxmode=0666,mode=0620,gid=5", | |
}, | |
{ | |
Device: "tmpfs", | |
Source: "shm", | |
Destination: "/dev/shm", | |
Data: "mode=1777,size=65536k", | |
Flags: defaultMountFlags, | |
}, | |
{ | |
Source: "mqueue", | |
Destination: "/dev/mqueue", | |
Device: "mqueue", | |
Flags: defaultMountFlags, | |
}, | |
{ | |
Source: "sysfs", | |
Destination: "/sys", | |
Device: "sysfs", | |
Flags: defaultMountFlags | syscall.MS_RDONLY, | |
}, | |
}, | |
Rlimits: []configs.Rlimit{ | |
{ | |
Type: syscall.RLIMIT_NOFILE, | |
Hard: 1024, | |
Soft: 1024, | |
}, | |
}, | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment