Skip to content

Instantly share code, notes, and snippets.

@proppy
Forked from crosbymichael/pod.go
Last active August 29, 2015 14:21
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save proppy/9597b6ecd1dc39ca6613 to your computer and use it in GitHub Desktop.
Save proppy/9597b6ecd1dc39ca6613 to your computer and use it in GitHub Desktop.
package main
import (
"encoding/json"
"fmt"
"log"
"os"
"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()
log.Println("done")
}
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
}
pod := &Pod{
spec: spec,
factory: factory,
}
for _, c := range spec.Spec.Containers {
log.Printf("container: #%v", c)
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, 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.
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 {
log.Printf("%#v", cp.process)
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() {
log.Println(p.containers)
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.Sys().(syscall.WaitStatus)))
}
}
func getTemplate() *configs.Config {
const defaultMountFlags = syscall.MS_NOEXEC | syscall.MS_NOSUID | syscall.MS_NODEV
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{
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,
},
},
}
}
{
"spec": {
"containers": [{
"name": "foo",
"image": "/images/busybox",
"command": ["/bin/echo"],
"args": ["foo"]
},{
"name": "bar",
"image": "/images/busybox",
"command": ["/bin/echo"],
"args": ["bar"]
}]
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment