From ca56714aa47f52e145e7181fe62a2461ebd57768 Mon Sep 17 00:00:00 2001 From: Achilleas Koutsou Date: Tue, 27 Jul 2021 13:26:46 +0200 Subject: [PATCH] rhel85: use nginx with custom config for container Running the container on Openshift requires that the process inside the container run without special permissions. Switching to nginx and setting the following options that don't require root privileges: - Port 8080 (> 1024) - pid file in '/tmp' instead of the default '/run' path Also, the log file is chmod-ed to be world writable. Nginx always writes to the default log file on startup, even if a different log file path is specified in the configuration. See rhbz#1945238 Signed-off-by: Achilleas Koutsou --- internal/distro/rhel85/distro.go | 4 ++-- internal/distro/rhel85/pipelines.go | 29 ++++++++++++++++++------- internal/distro/rhel85/stage_options.go | 23 ++++++++++++++++++++ 3 files changed, 46 insertions(+), 10 deletions(-) diff --git a/internal/distro/rhel85/distro.go b/internal/distro/rhel85/distro.go index 255ec3f96..d1cc3a54f 100644 --- a/internal/distro/rhel85/distro.go +++ b/internal/distro/rhel85/distro.go @@ -574,13 +574,13 @@ func newDistro(name, modulePlatformID, ostreeRef string) distro.Distro { packageSets: map[string]rpmmd.PackageSet{ buildPkgsKey: edgeBuildPackageSet(), osPkgsKey: edgeCommitPackageSet(), - containerPkgsKey: {Include: []string{"httpd"}}, + containerPkgsKey: {Include: []string{"nginx"}}, }, enabledServices: edgeServices, rpmOstree: true, bootISO: false, pipelines: edgeContainerPipelines, - exports: []string{containerPkgsKey}, + exports: []string{"container"}, } edgeInstallerImgType := imageType{ name: "edge-installer", diff --git a/internal/distro/rhel85/pipelines.go b/internal/distro/rhel85/pipelines.go index 3452f1079..ceeb2aad7 100644 --- a/internal/distro/rhel85/pipelines.go +++ b/internal/distro/rhel85/pipelines.go @@ -3,6 +3,7 @@ package rhel85 import ( "fmt" "math/rand" + "path/filepath" "strings" "github.com/osbuild/osbuild-composer/internal/blueprint" @@ -559,8 +560,11 @@ func edgeContainerPipelines(t *imageType, customizations *blueprint.Customizatio if err != nil { return nil, err } - pipelines = append(pipelines, *containerTreePipeline(repos, packageSetSpecs[containerPkgsKey], options, customizations)) - pipelines = append(pipelines, *containerPipeline(t)) + + nginxConfigPath := "/etc/nginx.conf" + httpPort := "8080" + pipelines = append(pipelines, *containerTreePipeline(repos, packageSetSpecs[containerPkgsKey], options, customizations, nginxConfigPath, httpPort)) + pipelines = append(pipelines, *containerPipeline(t, nginxConfigPath, httpPort)) return pipelines, nil } @@ -772,7 +776,7 @@ func tarStage(source, filename string) *osbuild.Stage { return osbuild.NewTarStage(&osbuild.TarStageOptions{Filename: filename}, &osbuild.TarStageInputs{Tree: tree}) } -func containerTreePipeline(repos []rpmmd.RepoConfig, packages []rpmmd.PackageSpec, options distro.ImageOptions, c *blueprint.Customizations) *osbuild.Pipeline { +func containerTreePipeline(repos []rpmmd.RepoConfig, packages []rpmmd.PackageSpec, options distro.ImageOptions, c *blueprint.Customizations, nginxConfigPath, listenPort string) *osbuild.Pipeline { p := new(osbuild.Pipeline) p.Name = "container-tree" p.Build = "name:build" @@ -783,16 +787,25 @@ func containerTreePipeline(repos []rpmmd.RepoConfig, packages []rpmmd.PackageSpe } else { p.AddStage(osbuild.NewLocaleStage(&osbuild.LocaleStageOptions{Language: "en_US"})) } - p.AddStage(osbuild.NewOSTreeInitStage(&osbuild.OSTreeInitStageOptions{Path: "/var/www/html/repo"})) + + htmlRoot := "/usr/share/nginx/html" + repoPath := filepath.Join(htmlRoot, "repo") + p.AddStage(osbuild.NewOSTreeInitStage(&osbuild.OSTreeInitStageOptions{Path: repoPath})) p.AddStage(osbuild.NewOSTreePullStage( - &osbuild.OSTreePullStageOptions{Repo: "/var/www/html/repo"}, + &osbuild.OSTreePullStageOptions{Repo: repoPath}, ostreePullStageInputs("org.osbuild.pipeline", "name:ostree-commit", options.OSTree.Ref), )) + + // make nginx log directory world writeable, otherwise nginx can't start in + // an unprivileged container + p.AddStage(osbuild.NewChmodStage(chmodStageOptions("/var/log/nginx", "o+w", true))) + + p.AddStage(osbuild.NewNginxConfigStage(nginxConfigStageOptions(nginxConfigPath, htmlRoot, listenPort))) return p } -func containerPipeline(t *imageType) *osbuild.Pipeline { +func containerPipeline(t *imageType, nginxConfigPath, listenPort string) *osbuild.Pipeline { p := new(osbuild.Pipeline) p.Name = "container" p.Build = "name:build" @@ -800,8 +813,8 @@ func containerPipeline(t *imageType) *osbuild.Pipeline { Architecture: t.arch.Name(), Filename: t.Filename(), Config: &osbuild.OCIArchiveConfig{ - Cmd: []string{"httpd", "-D", "FOREGROUND"}, - ExposedPorts: []string{"80"}, + Cmd: []string{"nginx", "-c", nginxConfigPath}, + ExposedPorts: []string{listenPort}, }, } baseInput := new(osbuild.OCIArchiveStageInput) diff --git a/internal/distro/rhel85/stage_options.go b/internal/distro/rhel85/stage_options.go index 1b70b0891..74267d06c 100644 --- a/internal/distro/rhel85/stage_options.go +++ b/internal/distro/rhel85/stage_options.go @@ -8,6 +8,7 @@ import ( "github.com/google/uuid" "github.com/osbuild/osbuild-composer/internal/blueprint" + "github.com/osbuild/osbuild-composer/internal/common" "github.com/osbuild/osbuild-composer/internal/crypt" "github.com/osbuild/osbuild-composer/internal/disk" osbuild "github.com/osbuild/osbuild-composer/internal/osbuild2" @@ -515,3 +516,25 @@ func kernelCmdlineStageOptions(rootUUID string, kernelOptions string) *osbuild.K KernelOpts: kernelOptions, } } + +func nginxConfigStageOptions(path, htmlRoot, listen string) *osbuild.NginxConfigStageOptions { + // configure nginx to work in an unprivileged container + cfg := &osbuild.NginxConfig{ + Listen: listen, + Root: htmlRoot, + Daemon: common.BoolToPtr(false), + PID: "/tmp/nginx.pid", + } + return &osbuild.NginxConfigStageOptions{ + Path: path, + Config: cfg, + } +} + +func chmodStageOptions(path, mode string, recursive bool) *osbuild.ChmodStageOptions { + return &osbuild.ChmodStageOptions{ + Items: map[string]osbuild.ChmodStagePathOptions{ + path: {Mode: mode, Recursive: recursive}, + }, + } +}