Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
gitpod-io
GitHub Repository: gitpod-io/gitpod
Path: blob/main/components/docker-up/runc-facade/main.go
2496 views
1
// Copyright (c) 2020 Gitpod GmbH. All rights reserved.
2
// Licensed under the GNU Affero General Public License (AGPL).
3
// See License.AGPL.txt in the project root for license information.
4
5
package main
6
7
import (
8
"encoding/json"
9
"os"
10
"os/exec"
11
"syscall"
12
"time"
13
14
"github.com/opencontainers/runtime-spec/specs-go"
15
"github.com/sirupsen/logrus"
16
"golang.org/x/xerrors"
17
)
18
19
const RETRY = 10
20
21
var (
22
defaultOOMScoreAdj = 1000
23
)
24
25
func main() {
26
log := logrus.New()
27
log.SetLevel(logrus.DebugLevel)
28
29
var err error
30
runcPath, err := exec.LookPath("runc")
31
if err != nil {
32
log.WithError(err).Fatal("runc not found")
33
}
34
35
var useFacade bool
36
for _, arg := range os.Args {
37
if arg == "create" {
38
useFacade = true
39
break
40
}
41
}
42
43
if useFacade {
44
err = createAndRunc(runcPath, log)
45
} else {
46
err = syscall.Exec(runcPath, os.Args, os.Environ())
47
}
48
if err != nil {
49
log.WithError(err).Fatal("failed")
50
}
51
}
52
53
func createAndRunc(runcPath string, log *logrus.Logger) error {
54
fc, err := os.ReadFile("config.json")
55
if err != nil {
56
return xerrors.Errorf("cannot read config.json: %w", err)
57
}
58
59
var cfg specs.Spec
60
err = json.Unmarshal(fc, &cfg)
61
if err != nil {
62
return xerrors.Errorf("cannot decode config.json: %w", err)
63
}
64
65
cfg.Process.OOMScoreAdj = &defaultOOMScoreAdj
66
delete(cfg.Linux.Sysctl, "net.ipv4.ip_unprivileged_port_start")
67
// TODO(toru): Drop the `kernel.domainame`` setting as it currently fails in the rootless container.
68
// - https://github.com/opencontainers/runc/issues/2091
69
// - https://github.com/opencontainers/runtime-spec/issues/592
70
// Perhaps using OCI hooks can solve this problem, but it's a bit tricky and hard.
71
if _, ok := cfg.Linux.Sysctl["kernel.domainname"]; ok {
72
log.Warnln("Since the rootless container cannot use domainname yet, we ignored it.")
73
delete(cfg.Linux.Sysctl, "kernel.domainname")
74
}
75
cfg.Process.Capabilities.Ambient = append(cfg.Process.Capabilities.Ambient, "CAP_NET_BIND_SERVICE")
76
cfg.Process.Capabilities.Bounding = append(cfg.Process.Capabilities.Bounding, "CAP_NET_BIND_SERVICE")
77
cfg.Process.Capabilities.Effective = append(cfg.Process.Capabilities.Effective, "CAP_NET_BIND_SERVICE")
78
cfg.Process.Capabilities.Inheritable = append(cfg.Process.Capabilities.Inheritable, "CAP_NET_BIND_SERVICE")
79
cfg.Process.Capabilities.Permitted = append(cfg.Process.Capabilities.Permitted, "CAP_NET_BIND_SERVICE")
80
81
fc, err = json.Marshal(cfg)
82
if err != nil {
83
return xerrors.Errorf("cannot encode config.json: %w", err)
84
}
85
err = os.WriteFile("config.json", fc, 0644)
86
if err != nil {
87
return xerrors.Errorf("cannot encode config.json: %w", err)
88
}
89
90
// See here for more details on why retries are necessary.
91
// https://github.com/gitpod-io/gitpod/issues/12365
92
for i := 0; i <= RETRY; i++ {
93
94
cmd := exec.Command(runcPath, os.Args[1:]...)
95
cmd.Stdin = os.Stdin
96
cmd.Stderr = os.Stderr
97
cmd.Stdout = os.Stdout
98
err = cmd.Run()
99
100
if err != nil {
101
log.WithError(err).Warn("runc failed")
102
103
// runc creation failures can be caused by timing issues with workspacekit/seccomp notify under load.
104
// Easing of on the pressure here lowers the likelihood of that error.
105
// NOTE(cw): glossing over races with delays is bad style, but also pragmatic.
106
//
107
// Context: https://linear.app/gitpod/issue/ENG-797/docker-containers-sometimes-fail-to-start
108
time.Sleep(100 * time.Millisecond)
109
continue
110
}
111
return nil
112
}
113
return xerrors.Errorf("exec %s: %w", runcPath, err)
114
}
115
116