Skip to content

Instantly share code, notes, and snippets.

@hayajo
Last active December 5, 2018 01:03
  • Star 12 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
Star You must be signed in to star a gist
Save hayajo/ca9ba2b13154f260d4b00774e1f509e2 to your computer and use it in GitHub Desktop.
「GoでくつるLinuxコンテナ」 - 第10回 コンテナ型仮想化の情報交換会@東京 #lxcjp

Simple unprivileged container

Usage

Start minimal container.

$ echo $UID $$
1000 879
$ cd $(mktemp -d)
$ cp -a /bin /lib /lib64 .
$ go run /PATH/TO/main.go /bin/bash
# echo $UID $$
0 1

Using the docker container's filesystem

First, prepare the tar archive.

$ docker export $(docker create alpine /bin/sh) > alpine.tar

And start container.

$ cd $(mktemp -d)
$ tar xf /PATH/TO/nginx-alpine.tar
$ go run /PATH/TO/main.go /bin/sh
# apk update
# apk add perl
# perl -v
package main
import (
"io/ioutil"
golog "log"
"os"
"os/exec"
"path/filepath"
"runtime"
"syscall"
)
const INIT_CMD = "ctstudy-init"
var log = golog.New(os.Stderr, "", 0)
func init() {
if os.Args[0] == INIT_CMD {
runtime.GOMAXPROCS(1)
runtime.LockOSThread()
prepare()
path, err := exec.LookPath(os.Args[1])
if err != nil {
log.Fatal(err)
}
must(syscall.Exec(path, os.Args[1:], os.Environ()))
panic("this line should have never been reached.")
}
}
func main() {
if err := run(os.Args[1:]); err != nil {
log.Fatalf("ERROR: %v\n", err)
}
}
func run(args []string) error {
if len(args) == 0 {
args = []string{os.Getenv("SHELL")}
}
cmd := exec.Command("/proc/self/exe", args...)
cmd.Args[0] = INIT_CMD
cmd.Stdin = os.Stdin
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
cmd.SysProcAttr = &syscall.SysProcAttr{
Cloneflags: syscall.CLONE_NEWUTS | syscall.CLONE_NEWUSER | syscall.CLONE_NEWPID | syscall.CLONE_NEWNS,
UidMappings: []syscall.SysProcIDMap{
{
ContainerID: 0,
HostID: os.Getuid(),
Size: 1,
},
},
GidMappings: []syscall.SysProcIDMap{
{
ContainerID: 0,
HostID: os.Getgid(),
Size: 1,
},
},
}
return cmd.Run()
}
func prepare() {
root, _ := os.Getwd()
for _, v := range []string{"/proc", "/etc"} {
d := filepath.Join(root, v)
if _, err := os.Stat(d); os.IsNotExist(err) {
must(os.MkdirAll(d, 0755))
}
}
must(syscall.Mount("proc", filepath.Join(root, "/proc"), "proc", 0, ""))
for _, f := range []string{"/etc/resolv.conf", "/etc/hosts"} {
d, err := ioutil.ReadFile(f)
must(err)
must(ioutil.WriteFile(filepath.Join(root, f), d, 0644))
}
must(syscall.Chroot(root))
must(os.Chdir("/"))
os.Clearenv()
}
func must(err error) {
if err != nil {
panic(err)
}
}
# -*- mode: ruby -*-
# vi: set ft=ruby :
GO_VERSION="1.7.1"
Vagrant.configure("2") do |config|
config.vm.box = "boxcutter/ubuntu1604"
config.vm.provision "shell", inline: <<-SHELL
apt update
apt install -y git
if [ ! -e /usr/local/go ]; then
cd /tmp
curl -s -LO https://storage.googleapis.com/golang/go#{GO_VERSION}.linux-amd64.tar.gz
tar xzf go#{GO_VERSION}.linux-amd64.tar.gz
mv go /usr/local/
echo 'export GOPATH=$HOME/go' >> ~vagrant/.profile
echo 'export PATH=$HOME/go/bin:/usr/local/go/bin:$PATH' >> ~vagrant/.profile
fi
SHELL
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment