зеркало из https://github.com/microsoft/docker.git
Merge remote-tracking branch 'origin/check_kernel_capabilities'
This commit is contained in:
Коммит
76b40ad6c9
5
Makefile
5
Makefile
|
@ -13,10 +13,7 @@ endif
|
||||||
GIT_COMMIT = $(shell git rev-parse --short HEAD)
|
GIT_COMMIT = $(shell git rev-parse --short HEAD)
|
||||||
GIT_STATUS = $(shell test -n "`git status --porcelain`" && echo "+CHANGES")
|
GIT_STATUS = $(shell test -n "`git status --porcelain`" && echo "+CHANGES")
|
||||||
|
|
||||||
NO_MEMORY_LIMIT ?= 0
|
BUILD_OPTIONS = -ldflags "-X main.GIT_COMMIT $(GIT_COMMIT)$(GIT_STATUS)"
|
||||||
export NO_MEMORY_LIMIT
|
|
||||||
|
|
||||||
BUILD_OPTIONS = -ldflags "-X main.GIT_COMMIT $(GIT_COMMIT)$(GIT_STATUS) -X main.NO_MEMORY_LIMIT $(NO_MEMORY_LIMIT)"
|
|
||||||
|
|
||||||
SRC_DIR := $(GOPATH)/src
|
SRC_DIR := $(GOPATH)/src
|
||||||
|
|
||||||
|
|
15
commands.go
15
commands.go
|
@ -22,7 +22,6 @@ const VERSION = "0.1.7"
|
||||||
|
|
||||||
var (
|
var (
|
||||||
GIT_COMMIT string
|
GIT_COMMIT string
|
||||||
NO_MEMORY_LIMIT bool
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func (srv *Server) Name() string {
|
func (srv *Server) Name() string {
|
||||||
|
@ -184,10 +183,14 @@ func (srv *Server) CmdWait(stdin io.ReadCloser, stdout io.Writer, args ...string
|
||||||
|
|
||||||
// 'docker version': show version information
|
// 'docker version': show version information
|
||||||
func (srv *Server) CmdVersion(stdin io.ReadCloser, stdout io.Writer, args ...string) error {
|
func (srv *Server) CmdVersion(stdin io.ReadCloser, stdout io.Writer, args ...string) error {
|
||||||
fmt.Fprintf(stdout, "Version:%s\n", VERSION)
|
fmt.Fprintf(stdout, "Version: %s\n", VERSION)
|
||||||
fmt.Fprintf(stdout, "Git Commit:%s\n", GIT_COMMIT)
|
fmt.Fprintf(stdout, "Git Commit: %s\n", GIT_COMMIT)
|
||||||
if NO_MEMORY_LIMIT {
|
fmt.Fprintf(stdout, "Kernel: %s\n", srv.runtime.kernelVersion)
|
||||||
fmt.Fprintf(stdout, "Memory limit disabled\n")
|
if !srv.runtime.capabilities.MemoryLimit {
|
||||||
|
fmt.Fprintf(stdout, "WARNING: No memory limit support\n")
|
||||||
|
}
|
||||||
|
if !srv.runtime.capabilities.SwapLimit {
|
||||||
|
fmt.Fprintf(stdout, "WARNING: No swap limit support\n")
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -910,7 +913,7 @@ func (srv *Server) CmdTag(stdin io.ReadCloser, stdout io.Writer, args ...string)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (srv *Server) CmdRun(stdin io.ReadCloser, stdout rcli.DockerConn, args ...string) error {
|
func (srv *Server) CmdRun(stdin io.ReadCloser, stdout rcli.DockerConn, args ...string) error {
|
||||||
config, err := ParseRun(args, stdout)
|
config, err := ParseRun(args, stdout, srv.runtime.capabilities)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
21
container.go
21
container.go
|
@ -68,7 +68,7 @@ type Config struct {
|
||||||
Image string // Name of the image as it was passed by the operator (eg. could be symbolic)
|
Image string // Name of the image as it was passed by the operator (eg. could be symbolic)
|
||||||
}
|
}
|
||||||
|
|
||||||
func ParseRun(args []string, stdout io.Writer) (*Config, error) {
|
func ParseRun(args []string, stdout io.Writer, capabilities *Capabilities) (*Config, error) {
|
||||||
cmd := rcli.Subcmd(stdout, "run", "[OPTIONS] IMAGE COMMAND [ARG...]", "Run a command in a new container")
|
cmd := rcli.Subcmd(stdout, "run", "[OPTIONS] IMAGE COMMAND [ARG...]", "Run a command in a new container")
|
||||||
if len(args) > 0 && args[0] != "--help" {
|
if len(args) > 0 && args[0] != "--help" {
|
||||||
cmd.SetOutput(ioutil.Discard)
|
cmd.SetOutput(ioutil.Discard)
|
||||||
|
@ -83,8 +83,8 @@ func ParseRun(args []string, stdout io.Writer) (*Config, error) {
|
||||||
flTty := cmd.Bool("t", false, "Allocate a pseudo-tty")
|
flTty := cmd.Bool("t", false, "Allocate a pseudo-tty")
|
||||||
flMemory := cmd.Int64("m", 0, "Memory limit (in bytes)")
|
flMemory := cmd.Int64("m", 0, "Memory limit (in bytes)")
|
||||||
|
|
||||||
if *flMemory > 0 && NO_MEMORY_LIMIT {
|
if *flMemory > 0 && !capabilities.MemoryLimit {
|
||||||
fmt.Fprintf(stdout, "WARNING: This version of docker has been compiled without memory limit support. Discarding -m.")
|
fmt.Fprintf(stdout, "WARNING: Your kernel does not support memory limit capabilities. Limitation discarded.\n")
|
||||||
*flMemory = 0
|
*flMemory = 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -137,6 +137,12 @@ func ParseRun(args []string, stdout io.Writer) (*Config, error) {
|
||||||
Dns: flDns,
|
Dns: flDns,
|
||||||
Image: image,
|
Image: image,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if *flMemory > 0 && !capabilities.SwapLimit {
|
||||||
|
fmt.Fprintf(stdout, "WARNING: Your kernel does not support swap limit capabilities. Limitation discarded.\n")
|
||||||
|
config.MemorySwap = -1
|
||||||
|
}
|
||||||
|
|
||||||
// When allocating stdin in attached mode, close stdin at client disconnect
|
// When allocating stdin in attached mode, close stdin at client disconnect
|
||||||
if config.OpenStdin && config.AttachStdin {
|
if config.OpenStdin && config.AttachStdin {
|
||||||
config.StdinOnce = true
|
config.StdinOnce = true
|
||||||
|
@ -379,10 +385,15 @@ func (container *Container) Start() error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if container.Config.Memory > 0 && NO_MEMORY_LIMIT {
|
// Make sure the config is compatible with the current kernel
|
||||||
log.Printf("WARNING: This version of docker has been compiled without memory limit support. Discarding the limit.")
|
if container.Config.Memory > 0 && !container.runtime.capabilities.MemoryLimit {
|
||||||
|
log.Printf("WARNING: Your kernel does not support memory limit capabilities. Limitation discarded.\n")
|
||||||
container.Config.Memory = 0
|
container.Config.Memory = 0
|
||||||
}
|
}
|
||||||
|
if container.Config.Memory > 0 && !container.runtime.capabilities.SwapLimit {
|
||||||
|
log.Printf("WARNING: Your kernel does not support swap limit capabilities. Limitation discarded.\n")
|
||||||
|
container.Config.MemorySwap = -1
|
||||||
|
}
|
||||||
|
|
||||||
if err := container.generateLXCConfig(); err != nil {
|
if err := container.generateLXCConfig(); err != nil {
|
||||||
return err
|
return err
|
||||||
|
|
|
@ -15,7 +15,6 @@ import (
|
||||||
|
|
||||||
var (
|
var (
|
||||||
GIT_COMMIT string
|
GIT_COMMIT string
|
||||||
NO_MEMORY_LIMIT string
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
@ -39,15 +38,11 @@ func main() {
|
||||||
os.Setenv("DEBUG", "1")
|
os.Setenv("DEBUG", "1")
|
||||||
}
|
}
|
||||||
docker.GIT_COMMIT = GIT_COMMIT
|
docker.GIT_COMMIT = GIT_COMMIT
|
||||||
docker.NO_MEMORY_LIMIT = NO_MEMORY_LIMIT == "1"
|
|
||||||
if *flDaemon {
|
if *flDaemon {
|
||||||
if flag.NArg() != 0 {
|
if flag.NArg() != 0 {
|
||||||
flag.Usage()
|
flag.Usage()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if NO_MEMORY_LIMIT == "1" {
|
|
||||||
log.Printf("WARNING: This version of docker has been compiled without memory limit support.")
|
|
||||||
}
|
|
||||||
if err := daemon(*pidfile); err != nil {
|
if err := daemon(*pidfile); err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
38
runtime.go
38
runtime.go
|
@ -6,6 +6,7 @@ import (
|
||||||
"github.com/dotcloud/docker/auth"
|
"github.com/dotcloud/docker/auth"
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
|
"log"
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"path"
|
"path"
|
||||||
|
@ -14,6 +15,11 @@ import (
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type Capabilities struct {
|
||||||
|
MemoryLimit bool
|
||||||
|
SwapLimit bool
|
||||||
|
}
|
||||||
|
|
||||||
type Runtime struct {
|
type Runtime struct {
|
||||||
root string
|
root string
|
||||||
repository string
|
repository string
|
||||||
|
@ -23,6 +29,8 @@ type Runtime struct {
|
||||||
repositories *TagStore
|
repositories *TagStore
|
||||||
authConfig *auth.AuthConfig
|
authConfig *auth.AuthConfig
|
||||||
idIndex *TruncIndex
|
idIndex *TruncIndex
|
||||||
|
capabilities *Capabilities
|
||||||
|
kernelVersion *KernelVersionInfo
|
||||||
}
|
}
|
||||||
|
|
||||||
var sysInitPath string
|
var sysInitPath string
|
||||||
|
@ -282,7 +290,34 @@ func (runtime *Runtime) restore() error {
|
||||||
|
|
||||||
// FIXME: harmonize with NewGraph()
|
// FIXME: harmonize with NewGraph()
|
||||||
func NewRuntime() (*Runtime, error) {
|
func NewRuntime() (*Runtime, error) {
|
||||||
return NewRuntimeFromDirectory("/var/lib/docker")
|
runtime, err := NewRuntimeFromDirectory("/var/lib/docker")
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
k, err := GetKernelVersion()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
runtime.kernelVersion = k
|
||||||
|
|
||||||
|
if CompareKernelVersion(k, &KernelVersionInfo{Kernel: 3, Major: 8, Minor: 0}) < 0 {
|
||||||
|
log.Printf("WARNING: You are running linux kernel version %s, which might be unstable running docker. Please upgrade your kernel to 3.8.0.", k.String())
|
||||||
|
}
|
||||||
|
|
||||||
|
cgroupMemoryMountpoint, err := FindCgroupMountpoint("memory")
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err1 := ioutil.ReadFile(path.Join(cgroupMemoryMountpoint, "/memory.limit_in_bytes"))
|
||||||
|
_, err2 := ioutil.ReadFile(path.Join(cgroupMemoryMountpoint, "memory.soft_limit_in_bytes"))
|
||||||
|
runtime.capabilities.MemoryLimit = err1 == nil && err2 == nil
|
||||||
|
|
||||||
|
_, err = ioutil.ReadFile(path.Join(cgroupMemoryMountpoint, "memeory.memsw.limit_in_bytes"))
|
||||||
|
runtime.capabilities.SwapLimit = err == nil
|
||||||
|
|
||||||
|
return runtime, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewRuntimeFromDirectory(root string) (*Runtime, error) {
|
func NewRuntimeFromDirectory(root string) (*Runtime, error) {
|
||||||
|
@ -321,6 +356,7 @@ func NewRuntimeFromDirectory(root string) (*Runtime, error) {
|
||||||
repositories: repositories,
|
repositories: repositories,
|
||||||
authConfig: authConfig,
|
authConfig: authConfig,
|
||||||
idIndex: NewTruncIndex(),
|
idIndex: NewTruncIndex(),
|
||||||
|
capabilities: &Capabilities{},
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := runtime.restore(); err != nil {
|
if err := runtime.restore(); err != nil {
|
||||||
|
|
|
@ -48,8 +48,6 @@ func layerArchive(tarfile string) (io.Reader, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
NO_MEMORY_LIMIT = os.Getenv("NO_MEMORY_LIMIT") == "1"
|
|
||||||
|
|
||||||
// Hack to run sys init during unit testing
|
// Hack to run sys init during unit testing
|
||||||
if SelfPath() == "/sbin/init" {
|
if SelfPath() == "/sbin/init" {
|
||||||
SysInit()
|
SysInit()
|
||||||
|
|
112
utils.go
112
utils.go
|
@ -12,9 +12,12 @@ import (
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
"regexp"
|
||||||
"runtime"
|
"runtime"
|
||||||
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
|
"syscall"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -384,3 +387,112 @@ func CopyEscapable(dst io.Writer, src io.ReadCloser) (written int64, err error)
|
||||||
}
|
}
|
||||||
return written, err
|
return written, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type KernelVersionInfo struct {
|
||||||
|
Kernel int
|
||||||
|
Major int
|
||||||
|
Minor int
|
||||||
|
Specific int
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetKernelVersion() (*KernelVersionInfo, error) {
|
||||||
|
var uts syscall.Utsname
|
||||||
|
|
||||||
|
if err := syscall.Uname(&uts); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
release := make([]byte, len(uts.Release))
|
||||||
|
|
||||||
|
i := 0
|
||||||
|
for _, c := range uts.Release {
|
||||||
|
release[i] = byte(c)
|
||||||
|
i++
|
||||||
|
}
|
||||||
|
|
||||||
|
tmp := strings.SplitN(string(release), "-", 2)
|
||||||
|
if len(tmp) != 2 {
|
||||||
|
return nil, fmt.Errorf("Unrecognized kernel version")
|
||||||
|
}
|
||||||
|
tmp2 := strings.SplitN(tmp[0], ".", 3)
|
||||||
|
if len(tmp2) != 3 {
|
||||||
|
return nil, fmt.Errorf("Unrecognized kernel version")
|
||||||
|
}
|
||||||
|
|
||||||
|
kernel, err := strconv.Atoi(tmp2[0])
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
major, err := strconv.Atoi(tmp2[1])
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
minor, err := strconv.Atoi(tmp2[2])
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
specific, err := strconv.Atoi(strings.Split(tmp[1], "-")[0])
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &KernelVersionInfo{
|
||||||
|
Kernel: kernel,
|
||||||
|
Major: major,
|
||||||
|
Minor: minor,
|
||||||
|
Specific: specific,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (k *KernelVersionInfo) String() string {
|
||||||
|
return fmt.Sprintf("%d.%d.%d-%d", k.Kernel, k.Major, k.Minor, k.Specific)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compare two KernelVersionInfo struct.
|
||||||
|
// Returns -1 if a < b, = if a == b, 1 it a > b
|
||||||
|
func CompareKernelVersion(a, b *KernelVersionInfo) int {
|
||||||
|
if a.Kernel < b.Kernel {
|
||||||
|
return -1
|
||||||
|
} else if a.Kernel > b.Kernel {
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
if a.Major < b.Major {
|
||||||
|
return -1
|
||||||
|
} else if a.Major > b.Major {
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
if a.Minor < b.Minor {
|
||||||
|
return -1
|
||||||
|
} else if a.Minor > b.Minor {
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
if a.Specific < b.Specific {
|
||||||
|
return -1
|
||||||
|
} else if a.Specific > b.Specific {
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func FindCgroupMountpoint(cgroupType string) (string, error) {
|
||||||
|
output, err := exec.Command("mount").CombinedOutput()
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
reg := regexp.MustCompile(`^cgroup on (.*) type cgroup \(.*` + cgroupType + `[,\)]`)
|
||||||
|
for _, line := range strings.Split(string(output), "\n") {
|
||||||
|
r := reg.FindStringSubmatch(line)
|
||||||
|
if len(r) == 2 {
|
||||||
|
return r[1], nil
|
||||||
|
}
|
||||||
|
fmt.Printf("line: %s (%d)\n", line, len(r))
|
||||||
|
}
|
||||||
|
return "", fmt.Errorf("cgroup mountpoint not found")
|
||||||
|
}
|
||||||
|
|
|
@ -228,3 +228,36 @@ func assertIndexGet(t *testing.T, index *TruncIndex, input, expectedResult strin
|
||||||
t.Fatalf("Getting '%s' returned '%s' instead of '%s'", input, result, expectedResult)
|
t.Fatalf("Getting '%s' returned '%s' instead of '%s'", input, result, expectedResult)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func assertKernelVersion(t *testing.T, a, b *KernelVersionInfo, result int) {
|
||||||
|
if r := CompareKernelVersion(a, b); r != result {
|
||||||
|
t.Fatalf("Unepected kernel version comparaison result. Found %d, expected %d", r, result)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCompareKernelVersion(t *testing.T) {
|
||||||
|
assertKernelVersion(t,
|
||||||
|
&KernelVersionInfo{Kernel: 3, Major: 8, Minor: 0, Specific: 0},
|
||||||
|
&KernelVersionInfo{Kernel: 3, Major: 8, Minor: 0, Specific: 0},
|
||||||
|
0)
|
||||||
|
assertKernelVersion(t,
|
||||||
|
&KernelVersionInfo{Kernel: 2, Major: 6, Minor: 0, Specific: 0},
|
||||||
|
&KernelVersionInfo{Kernel: 3, Major: 8, Minor: 0, Specific: 0},
|
||||||
|
-1)
|
||||||
|
assertKernelVersion(t,
|
||||||
|
&KernelVersionInfo{Kernel: 3, Major: 8, Minor: 0, Specific: 0},
|
||||||
|
&KernelVersionInfo{Kernel: 2, Major: 6, Minor: 0, Specific: 0},
|
||||||
|
1)
|
||||||
|
assertKernelVersion(t,
|
||||||
|
&KernelVersionInfo{Kernel: 3, Major: 8, Minor: 0, Specific: 0},
|
||||||
|
&KernelVersionInfo{Kernel: 3, Major: 8, Minor: 0, Specific: 16},
|
||||||
|
-1)
|
||||||
|
assertKernelVersion(t,
|
||||||
|
&KernelVersionInfo{Kernel: 3, Major: 8, Minor: 5, Specific: 0},
|
||||||
|
&KernelVersionInfo{Kernel: 3, Major: 8, Minor: 0, Specific: 0},
|
||||||
|
1)
|
||||||
|
assertKernelVersion(t,
|
||||||
|
&KernelVersionInfo{Kernel: 3, Major: 0, Minor: 20, Specific: 25},
|
||||||
|
&KernelVersionInfo{Kernel: 3, Major: 8, Minor: 0, Specific: 0},
|
||||||
|
-1)
|
||||||
|
}
|
||||||
|
|
Загрузка…
Ссылка в новой задаче