cleanup
Signed-off-by: Jess Frazelle <acidburn@microsoft.com>
This commit is contained in:
parent
cdd93563f5
commit
99c2e615ee
8 changed files with 28 additions and 306 deletions
5
.gitignore
vendored
5
.gitignore
vendored
|
@ -49,7 +49,10 @@ cross/
|
|||
coverage.txt
|
||||
profile.out
|
||||
|
||||
*.tar
|
||||
rootfs
|
||||
config.json
|
||||
.ip
|
||||
*.tar
|
||||
|
||||
busybox
|
||||
alpine
|
||||
|
|
51
Makefile
51
Makefile
|
@ -1,45 +1,31 @@
|
|||
# Set an output prefix, which is the local directory if not specified
|
||||
PREFIX?=$(shell pwd)
|
||||
|
||||
# Setup name variables for the package/tool
|
||||
NAME := binctr
|
||||
PKG := github.com/genuinetools/$(NAME)
|
||||
|
||||
# Set any default go build tags
|
||||
BUILDTAGS := seccomp apparmor
|
||||
|
||||
# Set the build dir, where built cross-compiled binaries will be output
|
||||
BUILDDIR := ${PREFIX}/cross
|
||||
|
||||
IMAGE := alpine
|
||||
IMAGE_DATA_FILE := container/bindata.go
|
||||
|
||||
# Populate version variables
|
||||
# Add to compile time flags
|
||||
VERSION := $(shell cat VERSION.txt)
|
||||
GITCOMMIT := $(shell git rev-parse --short HEAD)
|
||||
GITUNTRACKEDCHANGES := $(shell git status --porcelain --untracked-files=no)
|
||||
ifneq ($(GITUNTRACKEDCHANGES),)
|
||||
GITCOMMIT := $(GITCOMMIT)-dirty
|
||||
endif
|
||||
CTIMEVAR=-X $(PKG)/version.GITCOMMIT=$(GITCOMMIT) -X $(PKG)/version.VERSION=$(VERSION)
|
||||
GO_LDFLAGS=-ldflags "-w $(CTIMEVAR)"
|
||||
GO_LDFLAGS_STATIC=-ldflags "-w $(CTIMEVAR) -extldflags -static"
|
||||
GO_LDFLAGS_STATIC=-ldflags "-w -extldflags -static"
|
||||
|
||||
all: clean build fmt lint test staticcheck vet ## Runs a clean, build, fmt, lint, test, staticcheck, and vet
|
||||
|
||||
.PHONY: build
|
||||
build: $(BUILDDIR)/$(notdir $(IMAGE)) ## Builds a static executable or package
|
||||
build: alpine busybox ## Builds a static executable or package
|
||||
|
||||
$(BUILDDIR):
|
||||
@mkdir -p $@
|
||||
|
||||
$(BUILDDIR)/$(notdir $(IMAGE)): $(BUILDDIR) $(IMAGE_DATA_FILE) *.go VERSION.txt
|
||||
.PHONY: alpine
|
||||
alpine: generate
|
||||
@echo "+ $@"
|
||||
CGO_ENABLED=1 go build \
|
||||
-tags "$(BUILDTAGS) static_build" \
|
||||
${GO_LDFLAGS_STATIC} -o $@ .
|
||||
@echo "Static container for $(IMAGE) created at: $@"
|
||||
${GO_LDFLAGS_STATIC} -o $@ ./examples/$@/...
|
||||
@echo "Static container for alpine created at: ./$@"
|
||||
|
||||
.PHONY: busybox
|
||||
busybox: generate
|
||||
@echo "+ $@"
|
||||
CGO_ENABLED=1 go build \
|
||||
-tags "$(BUILDTAGS) static_build" \
|
||||
${GO_LDFLAGS_STATIC} -o $@ ./examples/$@/...
|
||||
@echo "Static container for alpine created at: ./$@"
|
||||
|
||||
.PHONY: fmt
|
||||
fmt: ## Verifies all files have men `gofmt`ed
|
||||
|
@ -95,15 +81,14 @@ tag: ## Create a new git tag to prepare to build a release
|
|||
git tag -sa $(VERSION) -m "$(VERSION)"
|
||||
@echo "Run git push origin $(VERSION) to push your new tag to GitHub and trigger a travis build."
|
||||
|
||||
.PHONY: $(IMAGE_DATA_FILE)
|
||||
$(IMAGE_DATA_FILE):
|
||||
GOMAXPROCS=1 go generate
|
||||
.PHONY: generate
|
||||
generate:
|
||||
GOMAXPROCS=1 go generate ./...
|
||||
|
||||
.PHONY: clean
|
||||
clean: ## Cleanup any build binaries or packages
|
||||
@echo "+ $@"
|
||||
$(RM) $(NAME)
|
||||
$(RM) -r $(BUILDDIR)
|
||||
$(RM) alpine busybox
|
||||
@sudo $(RM) -r rootfs
|
||||
|
||||
.PHONY: help
|
||||
|
|
54
README.md
54
README.md
|
@ -17,11 +17,6 @@ got rootless containers into upstream! Woohoo!
|
|||
Check out the original thread on the
|
||||
[mailing list](https://groups.google.com/a/opencontainers.org/forum/#!topic/dev/yutVaSLcqWI).
|
||||
|
||||
**Nginx running with my user "jessie".**
|
||||
|
||||
![nginx.png](nginx.png)
|
||||
|
||||
|
||||
### Building
|
||||
|
||||
You will need `libapparmor-dev` and `libseccomp-dev`.
|
||||
|
@ -30,14 +25,13 @@ Most importantly you need userns in your kernel (`CONFIG_USER_NS=y`)
|
|||
or else this won't even work.
|
||||
|
||||
```console
|
||||
$ make build
|
||||
Static container created at: ./bin/alpine
|
||||
Run with ./bin/alpine
|
||||
# building the alpine example
|
||||
$ make alpine
|
||||
Static container created at: ./alpine
|
||||
|
||||
# building a different base image
|
||||
$ make build IMAGE=busybox
|
||||
Static container created at: ./bin/busybox
|
||||
Run with ./bin/busybox
|
||||
# building the busybox example
|
||||
$ make alpine
|
||||
Static container created at: ./busybox
|
||||
```
|
||||
|
||||
### Running
|
||||
|
@ -47,42 +41,6 @@ $ ./alpine
|
|||
$ ./busybox --read-only
|
||||
```
|
||||
|
||||
### Usage
|
||||
|
||||
```console
|
||||
_ _ _
|
||||
| |__ (_)_ __ ___| |_ _ __
|
||||
| '_ \| | '_ \ / __| __| '__|
|
||||
| |_) | | | | | (__| |_| |
|
||||
|_.__/|_|_| |_|\___|\__|_|
|
||||
|
||||
Fully static, self-contained container including the rootfs
|
||||
that can be run by an unprivileged user.
|
||||
|
||||
Embedded Image: alpine - sha256:3fd9065eaf02feaf94d68376da52541925650b81698c53c6824d92ff63f98353
|
||||
Version: 0.1.0
|
||||
Build: 91b3ab5-dirty
|
||||
|
||||
-D run in debug mode
|
||||
-console-socket string
|
||||
path to an AF_UNIX socket which will receive a file descriptor referencing the master end of the console's pseudoterminal
|
||||
-d detach from the container's process
|
||||
-hook value
|
||||
Hooks to prefill into spec file. (ex. --hook prestart:netns)
|
||||
-id string
|
||||
container ID
|
||||
-pid-file string
|
||||
specify the file to write the process id to
|
||||
-read-only
|
||||
make container filesystem readonly
|
||||
-root string
|
||||
root directory of container state, should be tmpfs (default "/tmp/binctr")
|
||||
-t allocate a tty for the container (default true)
|
||||
-v print version and exit (shorthand)
|
||||
-version
|
||||
print version and exit
|
||||
```
|
||||
|
||||
## Cool things
|
||||
|
||||
The binary spawned does NOT need to oversee the container process if you
|
||||
|
|
|
@ -1 +0,0 @@
|
|||
0.1.0
|
18
generate.go
18
generate.go
|
@ -1,18 +0,0 @@
|
|||
// +build ignore
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"github.com/genuinetools/binctr/container"
|
||||
)
|
||||
|
||||
// Pulls an image and saves the binary data in the container package bindata.go.
|
||||
func main() {
|
||||
if err := container.EmbedImage("alpine"); err != nil {
|
||||
fmt.Fprintf(os.Stderr, "embed image failed: %v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
198
main.go
198
main.go
|
@ -1,198 +0,0 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"os"
|
||||
"os/exec"
|
||||
"runtime"
|
||||
"strings"
|
||||
|
||||
"github.com/genuinetools/binctr/container"
|
||||
"github.com/genuinetools/binctr/version"
|
||||
"github.com/opencontainers/runc/libcontainer"
|
||||
_ "github.com/opencontainers/runc/libcontainer/nsenter"
|
||||
specs "github.com/opencontainers/runtime-spec/specs-go"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
const (
|
||||
// BANNER is what is printed for help/info output.
|
||||
BANNER = ` _ _ _
|
||||
| |__ (_)_ __ ___| |_ _ __
|
||||
| '_ \| | '_ \ / __| __| '__|
|
||||
| |_) | | | | | (__| |_| |
|
||||
|_.__/|_|_| |_|\___|\__|_|
|
||||
|
||||
Fully static, self-contained container including the rootfs
|
||||
that can be run by an unprivileged user.
|
||||
|
||||
Version: %s
|
||||
Build: %s
|
||||
|
||||
`
|
||||
|
||||
defaultRoot = "/tmp/binctr"
|
||||
defaultRootfsDir = "rootfs"
|
||||
)
|
||||
|
||||
var (
|
||||
containerID string
|
||||
pidFile string
|
||||
root string
|
||||
|
||||
allocateTty bool
|
||||
consoleSocket string
|
||||
detach bool
|
||||
readonly bool
|
||||
|
||||
hooks specs.Hooks
|
||||
hookflags stringSlice
|
||||
|
||||
debug bool
|
||||
vrsn bool
|
||||
)
|
||||
|
||||
// stringSlice is a slice of strings
|
||||
type stringSlice []string
|
||||
|
||||
// implement the flag interface for stringSlice
|
||||
func (s *stringSlice) String() string {
|
||||
return fmt.Sprintf("%s", *s)
|
||||
}
|
||||
func (s *stringSlice) Set(value string) error {
|
||||
*s = append(*s, value)
|
||||
return nil
|
||||
}
|
||||
func (s stringSlice) ParseHooks() (hooks specs.Hooks, err error) {
|
||||
for _, v := range s {
|
||||
parts := strings.SplitN(v, ":", 2)
|
||||
if len(parts) <= 1 {
|
||||
return hooks, fmt.Errorf("parsing %s as hook_name:exec failed", v)
|
||||
}
|
||||
cmd := strings.Split(parts[1], " ")
|
||||
exec, err := exec.LookPath(cmd[0])
|
||||
if err != nil {
|
||||
return hooks, fmt.Errorf("looking up exec path for %s failed: %v", cmd[0], err)
|
||||
}
|
||||
hook := specs.Hook{
|
||||
Path: exec,
|
||||
}
|
||||
if len(cmd) > 1 {
|
||||
hook.Args = cmd[:1]
|
||||
}
|
||||
switch parts[0] {
|
||||
case "prestart":
|
||||
hooks.Prestart = append(hooks.Prestart, hook)
|
||||
case "poststart":
|
||||
hooks.Poststart = append(hooks.Poststart, hook)
|
||||
case "poststop":
|
||||
hooks.Poststop = append(hooks.Poststop, hook)
|
||||
default:
|
||||
return hooks, fmt.Errorf("%s is not a valid hook, try 'prestart', 'poststart', or 'poststop'", parts[0])
|
||||
}
|
||||
}
|
||||
return hooks, nil
|
||||
}
|
||||
|
||||
func init() {
|
||||
// Parse flags
|
||||
flag.StringVar(&containerID, "id", "binctr", "container ID")
|
||||
flag.StringVar(&pidFile, "pid-file", "", "specify the file to write the process id to")
|
||||
flag.StringVar(&root, "root", defaultRoot, "root directory of container state, should be tmpfs")
|
||||
|
||||
flag.Var(&hookflags, "hook", "Hooks to prefill into spec file. (ex. --hook prestart:netns)")
|
||||
|
||||
flag.BoolVar(&allocateTty, "t", true, "allocate a tty for the container")
|
||||
flag.StringVar(&consoleSocket, "console-socket", "", "path to an AF_UNIX socket which will receive a file descriptor referencing the master end of the console's pseudoterminal")
|
||||
flag.BoolVar(&detach, "d", false, "detach from the container's process")
|
||||
flag.BoolVar(&readonly, "read-only", false, "make container filesystem readonly")
|
||||
|
||||
flag.BoolVar(&vrsn, "version", false, "print version and exit")
|
||||
flag.BoolVar(&vrsn, "v", false, "print version and exit (shorthand)")
|
||||
flag.BoolVar(&debug, "D", false, "run in debug mode")
|
||||
|
||||
flag.Usage = func() {
|
||||
fmt.Fprint(os.Stderr, fmt.Sprintf(BANNER, version.VERSION, version.GITCOMMIT))
|
||||
flag.PrintDefaults()
|
||||
}
|
||||
|
||||
flag.Parse()
|
||||
|
||||
if vrsn {
|
||||
fmt.Printf("%s, commit: %s", version.VERSION, version.GITCOMMIT)
|
||||
os.Exit(0)
|
||||
}
|
||||
|
||||
// Set log level.
|
||||
if debug {
|
||||
logrus.SetLevel(logrus.DebugLevel)
|
||||
}
|
||||
|
||||
// Parse the hook flags.
|
||||
var err error
|
||||
hooks, err = hookflags.ParseHooks()
|
||||
if err != nil {
|
||||
logrus.Fatal(err)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//go:generate go run generate.go
|
||||
func main() {
|
||||
if len(os.Args) > 1 && os.Args[1] == "init" {
|
||||
runInit()
|
||||
return
|
||||
}
|
||||
|
||||
// Create a new container spec with the following options.
|
||||
opts := container.SpecOpts{
|
||||
Rootless: true,
|
||||
Readonly: readonly,
|
||||
Terminal: allocateTty,
|
||||
Hooks: &hooks,
|
||||
}
|
||||
spec := container.Spec(opts)
|
||||
|
||||
// Initialize the container object.
|
||||
c := &container.Container{
|
||||
ID: containerID,
|
||||
Spec: spec,
|
||||
PIDFile: pidFile,
|
||||
ConsoleSocket: consoleSocket,
|
||||
Root: root,
|
||||
Detach: detach,
|
||||
Rootless: true,
|
||||
}
|
||||
|
||||
// Unpack the rootfs.
|
||||
if err := c.UnpackRootfs(defaultRootfsDir, Asset); err != nil {
|
||||
logrus.Fatal(err)
|
||||
}
|
||||
|
||||
// Run the container.
|
||||
status, err := c.Run()
|
||||
if err != nil {
|
||||
logrus.Fatal(err)
|
||||
}
|
||||
|
||||
// Remove the rootfs after the container has exited.
|
||||
if err := os.RemoveAll(defaultRootfsDir); err != nil {
|
||||
logrus.Warnf("removing rootfs failed: %v", err)
|
||||
}
|
||||
|
||||
// Exit with the container's exit status.
|
||||
os.Exit(status)
|
||||
}
|
||||
|
||||
func runInit() {
|
||||
runtime.GOMAXPROCS(1)
|
||||
runtime.LockOSThread()
|
||||
factory, _ := libcontainer.New("")
|
||||
if err := factory.StartInitialization(); err != nil {
|
||||
// as the error is sent back to the parent there is no need to log
|
||||
// or write it to stderr because the parent process will handle this
|
||||
os.Exit(1)
|
||||
}
|
||||
panic("libcontainer: container init failed to exec")
|
||||
}
|
BIN
nginx.png
BIN
nginx.png
Binary file not shown.
Before Width: | Height: | Size: 1.2 MiB |
|
@ -1,7 +0,0 @@
|
|||
package version
|
||||
|
||||
// VERSION indicates which version of the binary is running.
|
||||
var VERSION string
|
||||
|
||||
// GITCOMMIT indicates which git hash the binary was built off of
|
||||
var GITCOMMIT string
|
Loading…
Reference in a new issue