Skip to content

Commit

Permalink
Allow passing custom node level sysctls
Browse files Browse the repository at this point in the history
  • Loading branch information
streamer45 committed Dec 12, 2024
1 parent b961c40 commit d30e5b8
Show file tree
Hide file tree
Showing 4 changed files with 141 additions and 18 deletions.
5 changes: 5 additions & 0 deletions config/config.sample.toml
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,11 @@ image_registry = "mattermost"
#
# The Persistent Volume Claim name to use to store data produced by jobs (e.g. recording files).
#persistent_volume_claim_name = "my-pvc"
#
# A comma separated list of Sysctls to apply on the node through priviledged init container before starting jobs.
# For example, enabling the `kernel.unprivileged_userns_clone` at node level was necessary
# on Debian based systems (pre kernel 5.10) in order to run Chromium sandbox.
#node_sysctls = "kernel.unprivileged_userns_clone=1"

[logger]
# A boolean controlling whether to log to the console.
Expand Down
28 changes: 10 additions & 18 deletions service/kubernetes/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ type JobServiceConfig struct {
ImageRegistry string
JobsResourceRequirements JobsResourceRequirements `toml:"jobs_resource_requirements"`
PersistentVolumeClaimName string `toml:"persistent_volume_claim_name"`
NodeSysctls string `toml:"node_sysctls"`
}

func (c JobServiceConfig) IsValid() error {
Expand Down Expand Up @@ -153,37 +154,28 @@ func (s *JobService) CreateJob(cfg job.Config, onStopCb job.StopCb) (job.Job, er
var jobID string
var jobPrefix string
var env []corev1.EnvVar
var initContainers []corev1.Container
switch cfg.Type {
case job.TypeRecording:
cfg.InputData.SetSiteURL(getSiteURLForJob(cfg.InputData.GetSiteURL()))
jobPrefix = job.RecordingJobPrefix
jobID = jobPrefix + "-job-" + random.NewID()
env = append(env, getEnvFromJobInputData(cfg.InputData)...)
initContainers = []corev1.Container{
{
Name: jobID + "-init",
Image: k8sInitContainerImage,
ImagePullPolicy: corev1.PullIfNotPresent,
Command: []string{
// Enabling the `kernel.unprivileged_userns_clone` sysctl at node level is necessary in order to run Chromium sandbox.
// See https://developer.chrome.com/docs/puppeteer/troubleshooting/#recommended-enable-user-namespace-cloning for details.
"sysctl",
"-w",
"kernel.unprivileged_userns_clone=1",
},
SecurityContext: &corev1.SecurityContext{
Privileged: newBool(true),
},
},
}
case job.TypeTranscribing:
cfg.InputData.SetSiteURL(getSiteURLForJob(cfg.InputData.GetSiteURL()))
jobPrefix = job.TranscribingJobPrefix
jobID = jobPrefix + "-job-" + random.NewID()
env = append(env, getEnvFromJobInputData(cfg.InputData)...)
}

var initContainers []corev1.Container
if s.cfg.NodeSysctls != "" {
s.log.Info("generating init containers", mlog.String("sysctls", s.cfg.NodeSysctls))
initContainers, err = genInitContainers(jobID, k8sInitContainerImage, s.cfg.NodeSysctls)
if err != nil {
return job.Job{}, fmt.Errorf("failed to generate init containers: %w", err)
}
}

var hostNetwork bool
if devMode {
s.log.Info("DEV_MODE enabled, enabling host networking", mlog.String("hostIP", os.Getenv("HOST_IP")))
Expand Down
34 changes: 34 additions & 0 deletions service/kubernetes/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -114,3 +114,37 @@ func getSiteURLForJob(siteURL string) string {

return siteURL
}

func genInitContainers(jobID, image, sysctls string) ([]corev1.Container, error) {
if jobID == "" {
return nil, fmt.Errorf("invalid empty jobID")
}

if image == "" {
return nil, fmt.Errorf("invalid empty image")
}

if sysctls == "" {
return nil, fmt.Errorf("invalid empty sysctls")
}

ctls := strings.Split(sysctls, ",")
cnts := make([]corev1.Container, len(ctls))
for i, ctl := range ctls {
cnts[i] = corev1.Container{
Name: fmt.Sprintf("%s-init-%d", jobID, i),
Image: image,
ImagePullPolicy: corev1.PullIfNotPresent,
Command: []string{
"sysctl",
"-w",
ctl,
},
SecurityContext: &corev1.SecurityContext{
Privileged: newBool(true),
},
}
}

return cnts, nil
}
92 changes: 92 additions & 0 deletions service/kubernetes/utils_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -171,3 +171,95 @@ func TestGetJobPodTolerations(t *testing.T) {
require.EqualError(t, err, "failed to open file invalid: open invalid: no such file or directory")
})
}

func TestGenInitContainers(t *testing.T) {
for _, tc := range []struct {
name string
jobID string
image string
sysctls string
err string
cnts []corev1.Container
}{
{
name: "empty jobID",
err: "invalid empty jobID",
},
{
name: "empty image",
jobID: "jobID",
err: "invalid empty image",
},
{
name: "empty sysctls",
jobID: "jobID",
image: "image",
err: "invalid empty sysctls",
},
{
name: "single sysctl",
jobID: "jobID",
image: "image",
sysctls: "kernel.unprivileged_userns_clone=1",
cnts: []corev1.Container{
{
Name: "jobID-init-0",
Image: "image",
ImagePullPolicy: corev1.PullIfNotPresent,
Command: []string{
"sysctl",
"-w",
"kernel.unprivileged_userns_clone=1",
},
SecurityContext: &corev1.SecurityContext{
Privileged: newBool(true),
},
},
},
},
{
name: "multiple sysctls",
jobID: "jobID",
image: "image",
sysctls: "kernel.unprivileged_userns_clone=1,user.max_user_namespaces=4545",
cnts: []corev1.Container{
{
Name: "jobID-init-0",
Image: "image",
ImagePullPolicy: corev1.PullIfNotPresent,
Command: []string{
"sysctl",
"-w",
"kernel.unprivileged_userns_clone=1",
},
SecurityContext: &corev1.SecurityContext{
Privileged: newBool(true),
},
},
{
Name: "jobID-init-1",
Image: "image",
ImagePullPolicy: corev1.PullIfNotPresent,
Command: []string{
"sysctl",
"-w",
"user.max_user_namespaces=4545",
},
SecurityContext: &corev1.SecurityContext{
Privileged: newBool(true),
},
},
},
},
} {
t.Run(tc.name, func(t *testing.T) {
cnts, err := genInitContainers(tc.jobID, tc.image, tc.sysctls)
if tc.err != "" {
require.Empty(t, cnts)
require.EqualError(t, err, tc.err)
} else {
require.Equal(t, tc.cnts, cnts)
}
})
}
}

0 comments on commit d30e5b8

Please sign in to comment.