-
Notifications
You must be signed in to change notification settings - Fork 8
/
Copy pathmain.go
315 lines (277 loc) · 10.4 KB
/
main.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
//
// Copyright 2019-2020 Nestybox, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
package main
import (
"fmt"
"os"
"os/signal"
"strings"
"syscall"
"github.com/pkg/profile"
"github.com/sirupsen/logrus"
"github.com/urfave/cli"
)
var (
sysboxRunDir string = "/run/sysbox"
sysboxLibDirDefault string = "/var/lib/sysbox"
sysboxMgrPidFile string = sysboxRunDir + "/sysmgr.pid"
subidRangeSize uint64 = 65536
)
const (
usage = `Sysbox manager daemon
The Sysbox manager daemon's main job is to provide services to other
Sysbox components (e.g., sysbox-runc).`
)
// Globals to be populated at build time during Makefile processing.
var (
edition string // Sysbox Edition: CE or EE
version string // extracted from VERSION file
commitId string // latest sysbox-mgr's git commit-id
builtAt string // build time
builtBy string // build owner
)
func main() {
app := cli.NewApp()
app.Name = "sysbox-mgr"
app.Usage = usage
app.Version = version
var v []string
if version != "" {
v = append(v, version)
}
app.Version = strings.Join(v, "\n")
app.Flags = []cli.Flag{
cli.StringFlag{
Name: "log, l",
Value: "",
Usage: "log file path or empty string for stderr output (default: \"\")",
},
cli.StringFlag{
Name: "log-level",
Value: "info",
Usage: "log categories to include (debug, info, warning, error, fatal)",
},
cli.StringFlag{
Name: "log-format",
Value: "text",
Usage: "log format; must be json or text (default = text)",
},
cli.BoolTFlag{
Name: "alias-dns",
Usage: "aliases the DNS IP inside the system container to ensure it never has a localhost address; required for system containers on user-defined Docker bridge networks (default = true)",
},
cli.BoolFlag{
Name: "cpu-profiling",
Usage: "enable cpu-profiling data collection",
Hidden: true,
},
cli.BoolFlag{
Name: "memory-profiling",
Usage: "enable memory-profiling data collection",
Hidden: true,
},
cli.StringFlag{
Name: "data-root",
Value: "/var/lib/sysbox",
Usage: "root directory for sysbox data store",
},
cli.BoolFlag{
Name: "disable-shiftfs",
Usage: "Disables Sysbox's use of the kernel's shiftfs module (present in Ubuntu/Debian); files may show with nobody:nogroup ownership inside the container; meant for testing. (default = false)",
},
cli.BoolFlag{
Name: "disable-shiftfs-on-fuse",
Usage: "Disables shiftfs on top of FUSE-based filesystems (which don't always work with shiftfs); FUSE-backed files mounted into the Sysbox container may show with nobody:nogroup ownership inside the container. (default = false)",
},
cli.BoolFlag{
Name: "disable-shiftfs-precheck",
Usage: "Disables Sysbox's preflight functional check of shiftfs; use this only if you want Sysbox to use shiftfs (e.g., kernel < 5.12) and you know it works properly (default = false).",
},
cli.BoolFlag{
Name: "disable-idmapped-mount",
Usage: "Disables Sysbox's use of the kernel's ID-mapped-mount feature; files may show with nobody:nogroup ownership inside the container; meant for testing (default = false)",
},
cli.BoolFlag{
Name: "disable-rootfs-cloning",
Usage: "Disables Sysbox's rootfs cloning feature (used for fast chown of the container's rootfs in hosts without shiftfs); this option will significantly slow down container startup time in hosts without shiftfs (default = false)",
},
cli.BoolFlag{
Name: "disable-ovfs-on-idmapped-mount",
Usage: "Disables ID-mapping of overlayfs (available in Linux kernel 5.19+); when set to true, forces Sysbox to use either shiftfs (if available on the host) or otherwise chown the container's rootfs, slowing container start/stop time; meant for testing (default = false)",
},
cli.BoolFlag{
Name: "disable-inner-image-preload",
Usage: "Disables the Sysbox feature that allows users to preload inner container images into system container images (e.g., via Docker commit or build); this makes container stop faster; running system container images that come preloaded with inner container images continue to work fine; (default = false)",
},
cli.BoolFlag{
Name: "ignore-sysfs-chown",
Usage: "Ignore chown of /sys inside all Sysbox containers; may be needed to run a few apps that chown /sys inside the container (e.g,. rpm). Causes Sysbox to trap the chown syscall inside the container, slowing it down (default = false).",
},
cli.BoolFlag{
Name: "allow-trusted-xattr",
Usage: "Allows the overlayfs trusted.overlay.opaque xattr to be set inside all Sysbox containers; needed when running Docker inside Sysbox on hosts with kernel < 5.11. Causes Sysbox to trap the *xattr syscalls inside the container, slowing it down (default = false).",
},
cli.BoolFlag{
Name: "honor-caps",
Usage: "Honor the container's process capabilities passed to Sysbox by the higher level container manager (e.g., Docker/containerd). When set to false, Sysbox always gives the container's root user full capabilities and other users no capabilities to mimic a VM-like environment. Note that the container's capabilities are isolated from the host via the Linux user-namespace. (default = false).",
},
cli.BoolTFlag{
Name: "syscont-mode",
Usage: "Causes Sysbox to run in \"system container\" mode. In this mode, it sets up the container to run system workloads (e.g., systemd, Docker, Kubernetes, etc.) seamlessly and securely. When set to false, Sysbox operates in \"regular container\" mode where it sets up the container strictly per its OCI spec (usually for microservices), with the exception of the Linux 'user' and 'cgroup' namespaces which Sysbox always enables for extra container isolation. (default = true)",
},
cli.BoolFlag{
Name: "relaxed-read-only",
Usage: "Allows Sysbox to create read-only containers while enabling read-write operations in certain mountpoints within the container. (default = false)",
},
cli.BoolFlag{
Name: "fsuid-map-fail-on-error",
Usage: "When set to true, fail to launch a container whenever filesystem uid-mapping (needed for files to show proper ownership inside the container's user-namespace) hits an error; when set to false, launch the container anyway (files may show up owned by nobody:nogroup) (default = false).",
},
}
// show-version specialization.
cli.VersionPrinter = func(c *cli.Context) {
fmt.Printf("sysbox-mgr\n"+
"\tedition: \t%s\n"+
"\tversion: \t%s\n"+
"\tcommit: \t%s\n"+
"\tbuilt at: \t%s\n"+
"\tbuilt by: \t%s\n",
edition, c.App.Version, commitId, builtAt, builtBy)
}
app.Before = func(ctx *cli.Context) error {
if path := ctx.GlobalString("log"); path != "" {
f, err := os.OpenFile(path, os.O_CREATE|os.O_WRONLY|os.O_APPEND|os.O_SYNC, 0666)
if err != nil {
return err
}
logrus.SetOutput(f)
} else {
logrus.SetOutput(os.Stderr)
}
if logFormat := ctx.GlobalString("log-format"); logFormat == "json" {
logrus.SetFormatter(&logrus.JSONFormatter{
TimestampFormat: "2006-01-02 15:04:05",
})
} else {
logrus.SetFormatter(&logrus.TextFormatter{
TimestampFormat: "2006-01-02 15:04:05",
FullTimestamp: true,
})
}
// Set desired log-level.
if logLevel := ctx.GlobalString("log-level"); logLevel != "" {
switch logLevel {
case "debug":
logrus.SetLevel(logrus.DebugLevel)
case "info":
logrus.SetLevel(logrus.InfoLevel)
case "warning":
logrus.SetLevel(logrus.WarnLevel)
case "error":
logrus.SetLevel(logrus.ErrorLevel)
case "fatal":
logrus.SetLevel(logrus.FatalLevel)
default:
logrus.Fatalf("'%v' log-level option not recognized", logLevel)
}
} else {
// Set 'info' as our default log-level.
logrus.SetLevel(logrus.InfoLevel)
}
return nil
}
app.Action = func(ctx *cli.Context) error {
logrus.Info("Starting ...")
// If requested, launch cpu/mem profiling data collection.
profile, err := runProfiler(ctx)
if err != nil {
return err
}
mgr, err := newSysboxMgr(ctx)
if err != nil {
return fmt.Errorf("failed to create sysbox-mgr: %v", err)
}
var signalChan = make(chan os.Signal, 1)
signal.Notify(
signalChan,
syscall.SIGHUP,
syscall.SIGINT,
syscall.SIGTERM,
syscall.SIGQUIT)
go signalHandler(signalChan, mgr, profile)
logrus.Infof("Listening on %v", mgr.grpcServer.GetAddr())
if err := mgr.Start(); err != nil {
return fmt.Errorf("failed to start sysbox-mgr: %v", err)
}
mgr.Stop()
logrus.Info("Done.")
return nil
}
if err := app.Run(os.Args); err != nil {
logrus.Fatal(err)
}
}
// Run cpu / memory profiling collection.
func runProfiler(ctx *cli.Context) (interface{ Stop() }, error) {
var prof interface{ Stop() }
cpuProfOn := ctx.Bool("cpu-profiling")
memProfOn := ctx.Bool("memory-profiling")
// Cpu and Memory profiling options seem to be mutually exclused in pprof.
if cpuProfOn && memProfOn {
return nil, fmt.Errorf("Unsupported parameter combination: cpu and memory profiling")
}
// Typical / non-profiling case.
if !(cpuProfOn || memProfOn) {
return nil, nil
}
// Notice that 'NoShutdownHook' option is passed to profiler constructor to
// avoid this one reacting to 'sigterm' signal arrival. IOW, we want
// sysbox-mgr signal handler to be the one stopping all profiling tasks.
if cpuProfOn {
prof = profile.Start(
profile.CPUProfile,
profile.ProfilePath("."),
profile.NoShutdownHook,
)
logrus.Info("Initiated cpu-profiling data collection.")
}
if memProfOn {
prof = profile.Start(
profile.MemProfile,
profile.ProfilePath("."),
profile.NoShutdownHook,
)
logrus.Info("Initiated memory-profiling data collection.")
}
return prof, nil
}
// sysbox-mgr signal handler goroutine.
func signalHandler(
signalChan chan os.Signal,
mgr *SysboxMgr,
profile interface{ Stop() }) {
s := <-signalChan
logrus.Infof("Caught OS signal: %s", s)
if err := mgr.Stop(); err != nil {
logrus.Warnf("Failed to terminate sysbox-mgr gracefully: %s", err)
}
// Stop cpu/mem profiling tasks.
if profile != nil {
profile.Stop()
}
logrus.Info("Exiting.")
os.Exit(0)
}