зеркало из 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_STATUS = $(shell test -n "`git status --porcelain`" && echo "+CHANGES")
|
||||
|
||||
NO_MEMORY_LIMIT ?= 0
|
||||
export NO_MEMORY_LIMIT
|
||||
|
||||
BUILD_OPTIONS = -ldflags "-X main.GIT_COMMIT $(GIT_COMMIT)$(GIT_STATUS) -X main.NO_MEMORY_LIMIT $(NO_MEMORY_LIMIT)"
|
||||
BUILD_OPTIONS = -ldflags "-X main.GIT_COMMIT $(GIT_COMMIT)$(GIT_STATUS)"
|
||||
|
||||
SRC_DIR := $(GOPATH)/src
|
||||
|
||||
|
|
11
commands.go
11
commands.go
|
@ -22,7 +22,6 @@ const VERSION = "0.1.7"
|
|||
|
||||
var (
|
||||
GIT_COMMIT string
|
||||
NO_MEMORY_LIMIT bool
|
||||
)
|
||||
|
||||
func (srv *Server) Name() string {
|
||||
|
@ -186,8 +185,12 @@ func (srv *Server) CmdWait(stdin io.ReadCloser, stdout io.Writer, args ...string
|
|||
func (srv *Server) CmdVersion(stdin io.ReadCloser, stdout io.Writer, args ...string) error {
|
||||
fmt.Fprintf(stdout, "Version: %s\n", VERSION)
|
||||
fmt.Fprintf(stdout, "Git Commit: %s\n", GIT_COMMIT)
|
||||
if NO_MEMORY_LIMIT {
|
||||
fmt.Fprintf(stdout, "Memory limit disabled\n")
|
||||
fmt.Fprintf(stdout, "Kernel: %s\n", srv.runtime.kernelVersion)
|
||||
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
|
||||
}
|
||||
|
@ -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 {
|
||||
config, err := ParseRun(args, stdout)
|
||||
config, err := ParseRun(args, stdout, srv.runtime.capabilities)
|
||||
if err != nil {
|
||||
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)
|
||||
}
|
||||
|
||||
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")
|
||||
if len(args) > 0 && args[0] != "--help" {
|
||||
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")
|
||||
flMemory := cmd.Int64("m", 0, "Memory limit (in bytes)")
|
||||
|
||||
if *flMemory > 0 && NO_MEMORY_LIMIT {
|
||||
fmt.Fprintf(stdout, "WARNING: This version of docker has been compiled without memory limit support. Discarding -m.")
|
||||
if *flMemory > 0 && !capabilities.MemoryLimit {
|
||||
fmt.Fprintf(stdout, "WARNING: Your kernel does not support memory limit capabilities. Limitation discarded.\n")
|
||||
*flMemory = 0
|
||||
}
|
||||
|
||||
|
@ -137,6 +137,12 @@ func ParseRun(args []string, stdout io.Writer) (*Config, error) {
|
|||
Dns: flDns,
|
||||
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
|
||||
if config.OpenStdin && config.AttachStdin {
|
||||
config.StdinOnce = true
|
||||
|
@ -379,10 +385,15 @@ func (container *Container) Start() error {
|
|||
return err
|
||||
}
|
||||
|
||||
if container.Config.Memory > 0 && NO_MEMORY_LIMIT {
|
||||
log.Printf("WARNING: This version of docker has been compiled without memory limit support. Discarding the limit.")
|
||||
// Make sure the config is compatible with the current kernel
|
||||
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
|
||||
}
|
||||
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 {
|
||||
return err
|
||||
|
|
|
@ -15,7 +15,6 @@ import (
|
|||
|
||||
var (
|
||||
GIT_COMMIT string
|
||||
NO_MEMORY_LIMIT string
|
||||
)
|
||||
|
||||
func main() {
|
||||
|
@ -39,15 +38,11 @@ func main() {
|
|||
os.Setenv("DEBUG", "1")
|
||||
}
|
||||
docker.GIT_COMMIT = GIT_COMMIT
|
||||
docker.NO_MEMORY_LIMIT = NO_MEMORY_LIMIT == "1"
|
||||
if *flDaemon {
|
||||
if flag.NArg() != 0 {
|
||||
flag.Usage()
|
||||
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 {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
|
38
runtime.go
38
runtime.go
|
@ -6,6 +6,7 @@ import (
|
|||
"github.com/dotcloud/docker/auth"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path"
|
||||
|
@ -14,6 +15,11 @@ import (
|
|||
"time"
|
||||
)
|
||||
|
||||
type Capabilities struct {
|
||||
MemoryLimit bool
|
||||
SwapLimit bool
|
||||
}
|
||||
|
||||
type Runtime struct {
|
||||
root string
|
||||
repository string
|
||||
|
@ -23,6 +29,8 @@ type Runtime struct {
|
|||
repositories *TagStore
|
||||
authConfig *auth.AuthConfig
|
||||
idIndex *TruncIndex
|
||||
capabilities *Capabilities
|
||||
kernelVersion *KernelVersionInfo
|
||||
}
|
||||
|
||||
var sysInitPath string
|
||||
|
@ -282,7 +290,34 @@ func (runtime *Runtime) restore() error {
|
|||
|
||||
// FIXME: harmonize with NewGraph()
|
||||
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) {
|
||||
|
@ -321,6 +356,7 @@ func NewRuntimeFromDirectory(root string) (*Runtime, error) {
|
|||
repositories: repositories,
|
||||
authConfig: authConfig,
|
||||
idIndex: NewTruncIndex(),
|
||||
capabilities: &Capabilities{},
|
||||
}
|
||||
|
||||
if err := runtime.restore(); err != nil {
|
||||
|
|
|
@ -48,8 +48,6 @@ func layerArchive(tarfile string) (io.Reader, error) {
|
|||
}
|
||||
|
||||
func init() {
|
||||
NO_MEMORY_LIMIT = os.Getenv("NO_MEMORY_LIMIT") == "1"
|
||||
|
||||
// Hack to run sys init during unit testing
|
||||
if SelfPath() == "/sbin/init" {
|
||||
SysInit()
|
||||
|
|
112
utils.go
112
utils.go
|
@ -12,9 +12,12 @@ import (
|
|||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"runtime"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"syscall"
|
||||
"time"
|
||||
)
|
||||
|
||||
|
@ -384,3 +387,112 @@ func CopyEscapable(dst io.Writer, src io.ReadCloser) (written int64, err error)
|
|||
}
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче