Sending build context to Docker daemon 220 MB Step 1 : FROM warpdrive:tos-release-1-5 ---> 769306738d96 Step 2 : COPY . /go/src/github.com/transwarp/warpdrive/ ---> 07c99697b16e Removing intermediate container 127c0e71a84b Successfully built 07c99697b16e /usr/bin/docker: Error response from daemon: invalid header field value "oci runtime error: container_linux.go:247: starting container process caused \"process_linux.go:245: running exec setns process for init caused \\\"exit status 6\\\"\"\n". FATA[0301] exit status 125 make: *** [build] Error 1
尝试run 07c99697b16e报同样的错, 查看docker日志, 出现"oci runtime error: container_linux.go:247: starting container process caused \"process_linux .go:245: running exec setns process for init caused \\\"exit status 6\\\"\"\n"
1 2 3 4 5 6
8月 21 15:29:01 zhenghc-tos dockerd[2517]: time="2018-08-21T15:29:01.778212288+08:00" level=error msg="Handler for POST /v1.24/containers/79a0906242e0180dfd7aeff30e9fb179f7b7c37f0ba20533f83b4cd40b409d2a/start returned error: invali d header field value \"oci runtime error: container_linux.go:247: starting container process caused \\\"process_linux.go:245: running exec setns process for init caused \\\\\\\"exit status 6\\\\\\\"\\\"\\n\"" 8月 21 15:51:08 zhenghc-tos dockerd[2517]: time="2018-08-21T15:51:08.075631868+08:00" level=error msg="containerd: start container" error="oci runtime error: container_linux.go:247: starting container process caused \"process_linux .go:245: running exec setns process for init caused \\\"exit status 6\\\"\"\n" id=b93539a02f27cc1ad0114552643d8e0c942fba053dc8cd3980cb8f24cf61ff25 8月 21 15:51:08 zhenghc-tos dockerd[2517]: time="2018-08-21T15:51:08.092002257+08:00" level=error msg="Create container failed with error: invalid header field value \"oci runtime error: container_linux.go:247: starting container p rocess caused \\\"process_linux.go:245: running exec setns process for init caused \\\\\\\"exit status 6\\\\\\\"\\\"\\n\""
func Sort(data Interface) { n := data.Len() if fs, ok := data.(*funcs); ok { quickSort_func(fs.lessSwap, 0, n, maxDepth(n)) } else { quickSort(data, 0, n, maxDepth(n)) } }
func quickSort(data Interface, a, b, maxDepth int) { for b-a > 12 { // Use ShellSort for slices <= 12 elements if maxDepth == 0 { heapSort(data, a, b) return } maxDepth-- mlo, mhi := doPivot(data, a, b) // Avoiding recursion on the larger subproblem guarantees // a stack depth of at most lg(b-a). if mlo-a < b-mhi { quickSort(data, a, mlo, maxDepth) a = mhi // i.e., quickSort(data, mhi, b) } else { quickSort(data, mhi, b, maxDepth) b = mlo // i.e., quickSort(data, a, mlo) } } if b-a > 1 { // Do ShellSort pass with gap 6 // It could be written in this simplified form cause b-a <= 12 for i := a + 6; i < b; i++ { if data.Less(i, i-6) { data.Swap(i, i-6) } } insertionSort(data, a, b) } } // Insertion sort func insertionSort(data Interface, a, b int) { for i := a + 1; i < b; i++ { for j := i; j > a && data.Less(j, j-1); j-- { data.Swap(j, j-1) } } }
// maxDepth returns a threshold at which quicksort should switch // to heapsort. It returns 2*ceil(lg(n+1)). func maxDepth(n int) int { var depth int for i := n; i > 0; i >>= 1 { depth++ } return depth * 2 }
funcdoPivot(data Interface, lo, hi int) (midlo, midhi int) { m := lo + (hi-lo)/2// 避免整数溢出 if hi-lo > 40 { 如果长度大于40, 使用Tukey ninther法 // Tukey's ``Ninther,'' median of three medians of three. s := (hi - lo) / 8 medianOfThree(data, lo, lo+s, lo+2*s) medianOfThree(data, m, m-s, m+s) medianOfThree(data, hi-1, hi-1-s, hi-1-2*s) } // medianOfThree 保证lo, m hi-1三个值是从小到大的 medianOfThree(data, lo, m, hi-1)
// Invariants are: // data[lo] = pivot (set up by ChoosePivot) // data[lo < i < a] < pivot // data[a <= i < b] <= pivot // data[b <= i < c] unexamined // data[c <= i < hi-1] > pivot // data[hi-1] >= pivot pivot := lo a, c := lo+1, hi-1
// 找到第一个比起始值点大的Index for ; a < c && data.Less(a, pivot); a++ { } b := a for { for ; b < c && !data.Less(pivot, b); b++ { // data[b] <= pivot } for ; b < c && data.Less(pivot, c-1); c-- { // data[c-1] > pivot } if b >= c { break } // data[b] > pivot; data[c-1] <= pivot data.Swap(b, c-1) b++ c-- } // If hi-c<3 then there are duplicates (by property of median of nine). // Let be a bit more conservative, and set border to 5. protect := hi-c < 5 if !protect && hi-c < (hi-lo)/4 { // Lets test some points for equality to pivot dups := 0 if !data.Less(pivot, hi-1) { // data[hi-1] = pivot data.Swap(c, hi-1) c++ dups++ } if !data.Less(b-1, pivot) { // data[b-1] = pivot b-- dups++ } // m-lo = (hi-lo)/2 > 6 // b-lo > (hi-lo)*3/4-1 > 8 // ==> m < b ==> data[m] <= pivot if !data.Less(m, pivot) { // data[m] = pivot data.Swap(m, b-1) b-- dups++ } // if at least 2 points are equal to pivot, assume skewed distribution protect = dups > 1 } if protect { // Protect against a lot of duplicates // Add invariant: // data[a <= i < b] unexamined // data[b <= i < c] = pivot for { for ; a < b && !data.Less(b-1, pivot); b-- { // data[b] == pivot } for ; a < b && data.Less(a, pivot); a++ { // data[a] < pivot } if a >= b { break } // data[a] == pivot; data[b-1] < pivot data.Swap(a, b-1) a++ b-- } } // Swap pivot into middle data.Swap(pivot, b-1) return b - 1, c } // medianOfThree moves the median of the three values data[m0], data[m1], data[m2] into data[m1]. funcmedianOfThree(data Interface, m1, m0, m2 int) { // sort 3 elements if data.Less(m1, m0) { data.Swap(m1, m0) } // data[m0] <= data[m1] if data.Less(m2, m1) { data.Swap(m2, m1) // data[m0] <= data[m2] && data[m1] < data[m2] if data.Less(m1, m0) { data.Swap(m1, m0) } } // 保证 data[m0] <= data[m1] <= data[m2] }
#从这里的输出可以看到,cpuset被挂载在了/sys/fs/cgroup/cpuset, #而cpu和cpuacct一起挂载到了/sys/fs/cgroup/cpu,cpuacct下面 dev@ubuntu:~$ mount|grep cpu cgroup on /sys/fs/cgroup/cpuset type cgroup (rw,nosuid,nodev,noexec,relatime,cpuset) cgroup on /sys/fs/cgroup/cpu,cpuacct type cgroup (rw,nosuid,nodev,noexec,relatime,cpu,cpuacct)
#进入/sys/fs/cgroup/cpu,cpuacct并创建子cgroup dev@ubuntu:~$ cd /sys/fs/cgroup/cpu,cpuacct dev@ubuntu:/sys/fs/cgroup/cpu,cpuacct$ sudo mkdir test dev@ubuntu:/sys/fs/cgroup/cpu,cpuacct$ cd test dev@ubuntu:/sys/fs/cgroup/cpu,cpuacct/test$ ls cgroup.clone_children cpuacct.stat cpuacct.usage_percpu cpu.cfs_quota_us cpu.stat tasks cgroup.procs cpuacct.usage cpu.cfs_period_us cpu.shares notify_on_release
func (s *MemoryGroup) Apply(d *cgroupData) (err error) { path, err := d.path("memory") if err != nil && !cgroups.IsNotFound(err) { return err } else if path == "" { return nil } if memoryAssigned(d.config) { if _, err := os.Stat(path); os.IsNotExist(err) { if err := os.MkdirAll(path, 0755); err != nil { return err } // 只有内核内存可以动态设置 if err := EnableKernelMemoryAccounting(path); err != nil { return err } } } ... }
func EnableKernelMemoryAccounting(path string) error { // Check if kernel memory is enabled // We have to limit the kernel memory here as it won't be accounted at all // until a limit is set on the cgroup and limit cannot be set once the // cgroup has children, or if there are already tasks in the cgroup. for _, i := range []int64{1, -1} { if err := setKernelMemory(path, i); err != nil { return err } } return nil }
func (s *CpuGroup) Apply(d *cgroupData) error { // We always want to join the cpu group, to allow fair cpu scheduling // on a container basis path, err := d.path("cpu") if err != nil && !cgroups.IsNotFound(err) { return err } return s.ApplyDir(path, d.config, d.pid) }
func (s *CpuGroup) ApplyDir(path string, cgroup *configs.Cgroup, pid int) error { // This might happen if we have no cpu cgroup mounted. // Just do nothing and don't fail. if path == "" { return nil } if err := os.MkdirAll(path, 0755); err != nil { return err } // We should set the real-Time group scheduling settings before moving // in the process because if the process is already in SCHED_RR mode // and no RT bandwidth is set, adding it will fail. if err := s.SetRtSched(path, cgroup); err != nil { return err } // because we are not using d.join we need to place the pid into the procs file // unlike the other subsystems if err := cgroups.WriteCgroupProc(path, pid); err != nil { return err }
// cgroupManagerImpl implements the CgroupManager interface. // Its a stateless object which can be used to // update,create or delete any number of cgroups // It uses the Libcontainer raw fs cgroup manager for cgroup management. type cgroupManagerImpl struct { // subsystems holds information about all the // mounted cgroup subsystems on the node subsystems *CgroupSubsystems // simplifies interaction with libcontainer and its cgroup managers adapter *libcontainerAdapter }
// ResourceConfigForPod takes the input pod and outputs the cgroup resource config. func ResourceConfigForPod(pod *v1.Pod) *ResourceConfig { // sum requests and limits. reqs, limits := resource.PodRequestsAndLimits(pod)
cpuRequests := int64(0) cpuLimits := int64(0) memoryLimits := int64(0) if request, found := reqs[v1.ResourceCPU]; found { cpuRequests = request.MilliValue() } if limit, found := limits[v1.ResourceCPU]; found { cpuLimits = limit.MilliValue() } if limit, found := limits[v1.ResourceMemory]; found { memoryLimits = limit.Value() }
// MilliCPUToShares converts the milliCPU to CFS shares. func MilliCPUToShares(milliCPU int64) uint64 { if milliCPU == 0 { // Docker converts zero milliCPU to unset, which maps to kernel default // for unset: 1024. Return 2 here to really match kernel default for // zero milliCPU. return MinShares } // Conceptually (milliCPU / milliCPUToCPU) * sharesPerCPU, but factored to improve rounding. shares := (milliCPU * SharesPerCPU) / MilliCPUToCPU if shares < MinShares { return MinShares } return uint64(shares) }
// MilliCPUToQuota converts milliCPU to CFS quota and period values. func MilliCPUToQuota(milliCPU int64) (quota int64, period uint64) { // CFS quota is measured in two values: // - cfs_period_us=100ms (the amount of time to measure usage across) // - cfs_quota=20ms (the amount of cpu time allowed to be used across a period) // so in the above example, you are limited to 20% of a single CPU // for multi-cpu environments, you just scale equivalent amounts
if milliCPU == 0 { return }
// we set the period to 100ms by default period = QuotaPeriod
// we then convert your milliCPU to a value normalized over a period quota = (milliCPU * QuotaPeriod) / MilliCPUToCPU
// quota needs to be a minimum of 1ms. if quota < MinQuotaPeriod { quota = MinQuotaPeriod }
return }
const ( // Taken from lmctfy https://github.com/google/lmctfy/blob/master/lmctfy/controllers/cpu_controller.cc MinShares = 2 SharesPerCPU = 1024 MilliCPUToCPU = 1000
// 100000 is equivalent to 100ms QuotaPeriod = 100000 MinQuotaPeriod = 1000 )
设置的代码:
1 2 3 4 5 6 7 8 9 10 11 12
func setSupportedSubsystems(cgroupConfig *libcontainerconfigs.Cgroup) error { for _, sys := range getSupportedSubsystems() { if _, ok := cgroupConfig.Paths[sys.Name()]; !ok { return fmt.Errorf("Failed to find subsystem mount for subsystem: %v", sys.Name()) } // 调用前面的cgroup.Set()方法 if err := sys.Set(cgroupConfig.Paths[sys.Name()], cgroupConfig); err != nil { return fmt.Errorf("Failed to set config for supported subsystems : %v", err) } } return nil }
type maptype struct { typ _type key *_type elem *_type bucket *_type // internal type representing a hash bucket hmap *_type // internal type representing a hmap keysize uint8// size of key slot indirectkey bool// store ptr to key instead of key itself valuesize uint8// size of value slot indirectvalue bool// store ptr to value instead of value itself bucketsize uint16// size of bucket reflexivekey bool// true if k==k for all keys needkeyupdate bool// true if we need to update key on an overwrite }
// A header for a Go map. type hmap struct { count int// len()返回的map的大小 即有多少kv对 flags uint8 B uint8// 表示hash table总共有2^B个buckets hash0 uint32// hash seed
// A bucket for a Go map. type bmap struct { tophash [bucketCnt]uint8 // Followed by bucketCnt keys and then bucketCnt values. // NOTE: packing all the keys together and then all the values together makes the // code a bit more complicated than alternating key/value/key/value/... but it allows // us to eliminate padding which would be needed for, e.g., map[int64]int8. // Followed by an overflow pointer. }
// makemap implements a Go map creation make(map[k]v, hint) // If the compiler has determined that the map or the first bucket // can be created on the stack, h and/or bucket may be non-nil. // If h != nil, the map can be created directly in h. // If bucket != nil, bucket can be used as the first bucket. // hint是map大小, h过不等于空就直接使用这个hmap, bucket不为空就当做第一个bucket. funcmakemap(t *maptype, hint int64, h *hmap, bucket unsafe.Pointer) *hmap { if sz := unsafe.Sizeof(hmap{}); sz > 48 || sz != t.hmap.size { println("runtime: sizeof(hmap) =", sz, ", t.hmap.size =", t.hmap.size) throw("bad hmap size") }
// hint值不符合规范, 置0 if hint < 0 || hint > int64(maxSliceCap(t.bucket.size)) { hint = 0 } // 按照是否实现hash()来判断是否支持map类型 if !ismapkey(t.key) { throw("runtime.makemap: unsupported map key type") }
// 检查key和value大小 if t.key.size > maxKeySize && (!t.indirectkey || t.keysize != uint8(sys.PtrSize)) || t.key.size <= maxKeySize && (t.indirectkey || t.keysize != uint8(t.key.size)) { throw("key size wrong") } if t.elem.size > maxValueSize && (!t.indirectvalue || t.valuesize != uint8(sys.PtrSize)) || t.elem.size <= maxValueSize && (t.indirectvalue || t.valuesize != uint8(t.elem.size)) { throw("value size wrong") } // 检查各种编译的规范, 跳过 // invariants we depend on. We should probably check these at compile time // somewhere, but for now we'll do it here. if t.key.align > bucketCnt { throw("key align too big") } if t.elem.align > bucketCnt { throw("value align too big") } if t.key.size%uintptr(t.key.align) != 0 { throw("key size not a multiple of key align") } if t.elem.size%uintptr(t.elem.align) != 0 { throw("value size not a multiple of value align") } if bucketCnt < 8 { throw("bucketsize too small for proper alignment") } if dataOffset%uintptr(t.key.align) != 0 { throw("need padding in bucket (key)") } if dataOffset%uintptr(t.elem.align) != 0 { throw("need padding in bucket (value)") }
// 把hint参数对应成2进制的上确界那个数. 例如size=6, B就是3, 因为2^2 < 6 < 2^3 B := uint8(0) for ; overLoadFactor(hint, B); B++ { }
// 使用malloc分配2^B个buckets给h. // allocate initial hash table // if B == 0, the buckets field is allocated lazily later (in mapassign) // If hint is large zeroing this memory could take a while. buckets := bucket var extra *mapextra if B != 0 { var nextOverflow *bmap buckets, nextOverflow = makeBucketArray(t, B) if nextOverflow != nil { extra = new(mapextra) extra.nextOverflow = nextOverflow } }
// initialize Hmap if h == nil { h = (*hmap)(newobject(t.hmap)) } h.count = 0 h.B = B h.extra = extra h.flags = 0 h.hash0 = fastrand() h.buckets = buckets h.oldbuckets = nil h.nevacuate = 0 h.noverflow = 0
// Like mapaccess, but allocates a slot for the key if it is not present in the map. funcmapassign(t *maptype, h *hmap, key unsafe.Pointer) unsafe.Pointer { if h == nil { panic(plainError("assignment to entry in nil map")) } if raceenabled { callerpc := getcallerpc(unsafe.Pointer(&t)) pc := funcPC(mapassign) racewritepc(unsafe.Pointer(h), callerpc, pc) raceReadObjectPC(t.key, key, callerpc, pc) } if msanenabled { msanread(key, t.key.size) } if h.flags&hashWriting != 0 { throw("concurrent map writes") } alg := t.key.alg hash := alg.hash(key, uintptr(h.hash0))
// Set hashWriting after calling alg.hash, since alg.hash may panic, // in which case we have not actually done a write. h.flags |= hashWriting
if h.buckets == nil { h.buckets = newarray(t.bucket, 1) }
again: // 用hash值的低八位找到bucket bucket := hash & (uintptr(1)<<h.B - 1) if h.growing() { growWork(t, h, bucket) } b := (*bmap)(unsafe.Pointer(uintptr(h.buckets) + bucket*uintptr(t.bucketsize))) // 拿到高八位的hash值用于比对tophash top := uint8(hash >> (sys.PtrSize*8 - 8)) if top < minTopHash { top += minTopHash }
var inserti *uint8 var insertk unsafe.Pointer var val unsafe.Pointer for { for i := uintptr(0); i < bucketCnt; i++ { // 遍历tophash, 找到对应的key if b.tophash[i] != top { // 如果没有找到key, 说明是第一次, 将这个key插入到insertk(第i+1个key所在的)的位置, 将value插入到val(第i+1个value所在)的位置, 并且将tophash的当前地址赋值给inserti, 用于记录是否插入以及插入的位置. if b.tophash[i] == empty && inserti == nil { inserti = &b.tophash[i] insertk = add(unsafe.Pointer(b), dataOffset+i*uintptr(t.keysize)) val = add(unsafe.Pointer(b), dataOffset+bucketCnt*uintptr(t.keysize)+i*uintptr(t.valuesize)) } continue } // 如果找到了key的tophash, 就将拿对应的key跟现在的key对比, 看是否相等, 如果不相等就跳过继续找key, 如果相等就更新它的value的值. k := add(unsafe.Pointer(b), dataOffset+i*uintptr(t.keysize)) if t.indirectkey { k = *((*unsafe.Pointer)(k)) } if !alg.equal(key, k) { continue } // 如果需要更新key, 就覆盖key的值. if t.needkeyupdate { typedmemmove(t.key, k, key) } // 返回val的地址, 这个函数并不真正更新value, 只是找到value所在的地址. val = add(unsafe.Pointer(b), dataOffset+bucketCnt*uintptr(t.keysize)+i*uintptr(t.valuesize)) goto done } // 如这个bucket没找到, 找他的overflow链表, 拿下一个bucket循环操作. ovf := b.overflow(t) if ovf == nil { break } b = ovf }
// 如果都没有找到对应的值, 就可能做两件事: // 1) 建立新的overflow, 然后把值加到这个overflow的bucket中. // 2) 如果此时map的len()超过了overLoadFactor(6.5默认值)*桶的数量(2^B, 每个桶最多8个kv), 或者overflow的bucket太多了, golang就会扩大map的容量. // Did not find mapping for key. Allocate new cell & add entry.
// If we hit the max load factor or we have too many overflow buckets, // and we're not already in the middle of growing, start growing. if !h.growing() && (overLoadFactor(int64(h.count), h.B) || tooManyOverflowBuckets(h.noverflow, h.B)) { hashGrow(t, h) goto again // Growing the table invalidates everything, so try again }
if inserti == nil { // all current buckets are full, allocate a new one. newb := h.newoverflow(t, b) inserti = &newb.tophash[0] insertk = add(unsafe.Pointer(newb), dataOffset) val = add(insertk, bucketCnt*uintptr(t.keysize)) }
// store new key/value at insert position if t.indirectkey { kmem := newobject(t.key) *(*unsafe.Pointer)(insertk) = kmem insertk = kmem } if t.indirectvalue { vmem := newobject(t.elem) *(*unsafe.Pointer)(val) = vmem } typedmemmove(t.key, insertk, key) *inserti = top h.count++
done: // 不支持并发map的写. if h.flags&hashWriting == 0 { throw("concurrent map writes") } h.flags &^= hashWriting if t.indirectvalue { val = *((*unsafe.Pointer)(val)) } return val }
OSD map: 包含集群fsid. a list of pools, replica sizes, PG numbers, a list of OSDs and their status (e.g., up, in).
The PG map: 包含PG version, its time stamp, the last OSD map epoch, the full ratios, and details on each placement group such as the PG ID, the Up Set, the Acting Set, the state of the PG (e.g., active + clean), and data usage statistics for each pool
The CRUSH map: 存储设备列表, 失败的Domain, 已经写入数据的水平路由规则.
The MDS Map: Contains the current MDS map epoch, when the map was created, and the last time it changed
node.kubernetes.io/not-ready: notready. node.alpha.kubernetes.io/unreachable: Unknown node.kubernetes.io/out-of-disk: Node becomes out of disk. node.kubernetes.io/memory-pressure: Node has memory pressure. node.kubernetes.io/disk-pressure: Node has disk pressure. node.kubernetes.io/network-unavailable: Node’s network is unavailable. node.cloudprovider.kubernetes.io/uninitialized: When kubelet is started with “external” cloud provider, it sets this taint on a node to mark it as unusable. When a controller from the cloud-controller-manager initializes this node, kubelet removes this taint.
/usr/bin/docker: Error response from daemon: OCI runtime create failed: container_linux.go:348: starting container process caused "process_linux.go:402: container init caused \"open /dev/console: input/output error\"": unknown. FATA[0007] exit status 125
网上查有如下回复:
1
I met this problem while I suspend my computer, then I restart my computer, this error was solved. I guess it was because the docker daemon missed driver library path.
// os.Rename call fails on windows (https://github.com/golang/go/issues/14527) // Replacing with copyFolder to the newPath and deleting the oldPath directory if runtime.GOOS == "windows" { err = copyFolder(oldPath, newPath) if err != nil { glog.Errorf("Error copying folder from: %s to: %s with error: %v", oldPath, newPath, err) return"", err } os.RemoveAll(oldPath) return newPath, nil }
funcrename(oldname, newname string)error { fi, err := Lstat(newname) if err == nil && fi.IsDir() { // There are two independent errors this function can return: // one for a bad oldname, and one for a bad newname. // At this point we've determined the newname is bad. // But just in case oldname is also bad, prioritize returning // the oldname error because that's what we did historically. if _, err := Lstat(oldname); err != nil { if pe, ok := err.(*PathError); ok { err = pe.Err } return &LinkError{"rename", oldname, newname, err} } return &LinkError{"rename", oldname, newname, syscall.EEXIST} } //------------------------版本分割线1.8 err = syscall.Rename(oldname, newname) if err != nil { return &LinkError{"rename", oldname, newname, err} } returnnil }
在虚线以上是go1.8之后新加的内容, 如果rename之后的目录存在, 就会打印”File Exits”错误, 这样就会创建大量的”deleting~”目录. 相关修改和讨论在Bugs in EmptyDir Teardown path.