Skip to content

Commit 51c4df1

Browse files
Merge pull request #25789 from jankaluza/23292
Replace podman pause image with rootfs.
2 parents f22a0a9 + 224e791 commit 51c4df1

17 files changed

+174
-174
lines changed

libpod/container.go

+5
Original file line numberDiff line numberDiff line change
@@ -1266,6 +1266,11 @@ func (c *Container) IsInfra() bool {
12661266
return c.config.IsInfra
12671267
}
12681268

1269+
// IsDefaultInfra returns whether the container is a default infra container generated directly by podman
1270+
func (c *Container) IsDefaultInfra() bool {
1271+
return c.config.IsDefaultInfra
1272+
}
1273+
12691274
// IsInitCtr returns whether the container is an init container
12701275
func (c *Container) IsInitCtr() bool {
12711276
return len(c.config.InitContainerType) > 0

libpod/container_config.go

+3
Original file line numberDiff line numberDiff line change
@@ -404,6 +404,9 @@ type ContainerMiscConfig struct {
404404
// IsInfra is a bool indicating whether this container is an infra container used for
405405
// sharing kernel namespaces in a pod
406406
IsInfra bool `json:"pause"`
407+
// IsDefaultInfra is a bool indicating whether this container is a default infra container
408+
// using the default rootfs with catatonit bind-mounted into it.
409+
IsDefaultInfra bool `json:"defaultPause"`
407410
// IsService is a bool indicating whether this container is a service container used for
408411
// tracking the life cycle of K8s service.
409412
IsService bool `json:"isService"`

libpod/container_internal_common.go

+53
Original file line numberDiff line numberDiff line change
@@ -178,6 +178,51 @@ func getOverlayUpperAndWorkDir(options []string) (string, string, error) {
178178
return upperDir, workDir, nil
179179
}
180180

181+
// Internal only function which creates the Rootfs for default internal
182+
// pause image, configures the Rootfs in the Container and returns
183+
// the mount-point for the /catatonit. This mount-point should be added
184+
// to the Container spec.
185+
func (c *Container) prepareInitRootfs() (spec.Mount, error) {
186+
newMount := spec.Mount{
187+
Type: define.TypeBind,
188+
Source: "",
189+
Destination: "",
190+
Options: append(bindOptions, "ro", "nosuid", "nodev"),
191+
}
192+
193+
tmpDir, err := c.runtime.TmpDir()
194+
if err != nil {
195+
return newMount, fmt.Errorf("getting runtime temporary directory: %w", err)
196+
}
197+
tmpDir = filepath.Join(tmpDir, "infra-container")
198+
err = os.MkdirAll(tmpDir, 0755)
199+
if err != nil {
200+
return newMount, fmt.Errorf("creating infra container temporary directory: %w", err)
201+
}
202+
// Also look into the path as some distributions install catatonit in
203+
// /usr/bin.
204+
catatonitPath, err := c.runtime.config.FindInitBinary()
205+
if err != nil {
206+
return newMount, fmt.Errorf("finding catatonit binary: %w", err)
207+
}
208+
catatonitPath, err = filepath.EvalSymlinks(catatonitPath)
209+
if err != nil {
210+
return newMount, fmt.Errorf("follow symlink to catatonit binary: %w", err)
211+
}
212+
213+
newMount.Source = catatonitPath
214+
newMount.Destination = "/" + filepath.Base(catatonitPath)
215+
216+
c.config.Rootfs = tmpDir
217+
c.config.RootfsOverlay = true
218+
if len(c.config.Entrypoint) == 0 {
219+
c.config.Entrypoint = []string{"/" + filepath.Base(catatonitPath), "-P"}
220+
c.config.Spec.Process.Args = c.config.Entrypoint
221+
}
222+
223+
return newMount, nil
224+
}
225+
181226
// Generate spec for a container
182227
// Accepts a map of the container's dependencies
183228
func (c *Container) generateSpec(ctx context.Context) (s *spec.Spec, cleanupFuncRet func(), err error) {
@@ -380,6 +425,14 @@ func (c *Container) generateSpec(ctx context.Context) (s *spec.Spec, cleanupFunc
380425
c.setProcessLabel(&g)
381426
c.setMountLabel(&g)
382427

428+
if c.IsDefaultInfra() || c.IsService() {
429+
newMount, err := c.prepareInitRootfs()
430+
if err != nil {
431+
return nil, nil, err
432+
}
433+
g.AddMount(newMount)
434+
}
435+
383436
// Add bind mounts to container
384437
for dstPath, srcPath := range c.state.BindMounts {
385438
newMount := spec.Mount{

libpod/container_validate.go

+4
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,10 @@ func (c *Container) validate() error {
183183
}
184184
}
185185

186+
if c.config.IsDefaultInfra && !c.config.IsInfra {
187+
return fmt.Errorf("default rootfs-based infra container is set for non-infra container")
188+
}
189+
186190
return nil
187191
}
188192

libpod/kube.go

+36-41
Original file line numberDiff line numberDiff line change
@@ -925,6 +925,10 @@ func containerToV1Container(ctx context.Context, c *Container, getService bool)
925925
return kubeContainer, kubeVolumes, nil, annotations, fmt.Errorf("linux devices: %w", define.ErrNotImplemented)
926926
}
927927

928+
if !c.IsInfra() && len(c.config.Rootfs) > 0 {
929+
return kubeContainer, kubeVolumes, nil, annotations, fmt.Errorf("k8s does not support Rootfs")
930+
}
931+
928932
if len(c.config.UserVolumes) > 0 {
929933
volumeMounts, volumes, localAnnotations, err := libpodMountsToKubeVolumeMounts(c)
930934
if err != nil {
@@ -957,53 +961,44 @@ func containerToV1Container(ctx context.Context, c *Container, getService bool)
957961
kubeContainer.Name = removeUnderscores(c.Name())
958962
_, image := c.Image()
959963

960-
// The infra container may have been created with an overlay root FS
961-
// instead of an infra image. If so, set the imageto the default K8s
962-
// pause one and make sure it's in the storage by pulling it down if
963-
// missing.
964-
if image == "" && c.IsInfra() {
965-
image = c.runtime.config.Engine.InfraImage
966-
if _, err := c.runtime.libimageRuntime.Pull(ctx, image, config.PullPolicyMissing, nil); err != nil {
967-
return kubeContainer, nil, nil, nil, err
968-
}
969-
}
970-
971964
kubeContainer.Image = image
972965
kubeContainer.Stdin = c.Stdin()
973-
img, _, err := c.runtime.libimageRuntime.LookupImage(image, nil)
974-
if err != nil {
975-
return kubeContainer, kubeVolumes, nil, annotations, fmt.Errorf("looking up image %q of container %q: %w", image, c.ID(), err)
976-
}
977-
imgData, err := img.Inspect(ctx, nil)
978-
if err != nil {
979-
return kubeContainer, kubeVolumes, nil, annotations, err
980-
}
981-
// If the user doesn't set a command/entrypoint when creating the container with podman and
982-
// is using the image command or entrypoint from the image, don't add it to the generated kube yaml
983-
if reflect.DeepEqual(imgData.Config.Cmd, kubeContainer.Command) || reflect.DeepEqual(imgData.Config.Entrypoint, kubeContainer.Command) {
984-
kubeContainer.Command = nil
985-
}
966+
if len(image) > 0 {
967+
img, _, err := c.runtime.libimageRuntime.LookupImage(image, nil)
968+
if err != nil {
969+
return kubeContainer, kubeVolumes, nil, annotations, fmt.Errorf("looking up image %q of container %q: %w", image, c.ID(), err)
970+
}
971+
imgData, err := img.Inspect(ctx, nil)
972+
if err != nil {
973+
return kubeContainer, kubeVolumes, nil, annotations, err
974+
}
975+
// If the user doesn't set a command/entrypoint when creating the container with podman and
976+
// is using the image command or entrypoint from the image, don't add it to the generated kube yaml
977+
if reflect.DeepEqual(imgData.Config.Cmd, kubeContainer.Command) || reflect.DeepEqual(imgData.Config.Entrypoint, kubeContainer.Command) {
978+
kubeContainer.Command = nil
979+
}
986980

987-
if c.WorkingDir() != "/" && imgData.Config.WorkingDir != c.WorkingDir() {
988-
kubeContainer.WorkingDir = c.WorkingDir()
989-
}
981+
if c.WorkingDir() != "/" && imgData.Config.WorkingDir != c.WorkingDir() {
982+
kubeContainer.WorkingDir = c.WorkingDir()
983+
}
990984

991-
if imgData.User == c.User() && hasSecData {
992-
kubeSec.RunAsGroup, kubeSec.RunAsUser = nil, nil
993-
}
994-
// If the image has user set as a positive integer value, then set runAsNonRoot to true
995-
// in the kube yaml
996-
imgUserID, err := strconv.Atoi(imgData.User)
997-
if err == nil && imgUserID > 0 {
998-
trueBool := true
999-
kubeSec.RunAsNonRoot = &trueBool
1000-
}
985+
if imgData.User == c.User() && hasSecData {
986+
kubeSec.RunAsGroup, kubeSec.RunAsUser = nil, nil
987+
}
988+
// If the image has user set as a positive integer value, then set runAsNonRoot to true
989+
// in the kube yaml
990+
imgUserID, err := strconv.Atoi(imgData.User)
991+
if err == nil && imgUserID > 0 {
992+
trueBool := true
993+
kubeSec.RunAsNonRoot = &trueBool
994+
}
1001995

1002-
envVariables, err := libpodEnvVarsToKubeEnvVars(c.config.Spec.Process.Env, imgData.Config.Env)
1003-
if err != nil {
1004-
return kubeContainer, kubeVolumes, nil, annotations, err
996+
envVariables, err := libpodEnvVarsToKubeEnvVars(c.config.Spec.Process.Env, imgData.Config.Env)
997+
if err != nil {
998+
return kubeContainer, kubeVolumes, nil, annotations, err
999+
}
1000+
kubeContainer.Env = envVariables
10051001
}
1006-
kubeContainer.Env = envVariables
10071002

10081003
kubeContainer.Ports = ports
10091004
// This should not be applicable

libpod/options.go

+14
Original file line numberDiff line numberDiff line change
@@ -1648,6 +1648,20 @@ func withIsInfra() CtrCreateOption {
16481648
}
16491649
}
16501650

1651+
// withIsDefaultInfra allows us to differentiate between the default infra containers generated
1652+
// directly by podman and custom infra containers within the container config
1653+
func withIsDefaultInfra() CtrCreateOption {
1654+
return func(ctr *Container) error {
1655+
if ctr.valid {
1656+
return define.ErrCtrFinalized
1657+
}
1658+
1659+
ctr.config.IsDefaultInfra = true
1660+
1661+
return nil
1662+
}
1663+
}
1664+
16511665
// WithIsService allows us to differentiate between service containers and other container
16521666
// within the container config. It also sets the exit-code propagation of the
16531667
// service container.

libpod/runtime_ctr.go

+10-1
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,9 @@ func (r *Runtime) NewContainer(ctx context.Context, rSpec *spec.Spec, spec *spec
5151
}
5252
if infra {
5353
options = append(options, withIsInfra())
54+
if len(spec.RawImageName) == 0 {
55+
options = append(options, withIsDefaultInfra())
56+
}
5457
}
5558
return r.newContainer(ctx, rSpec, options...)
5659
}
@@ -246,6 +249,13 @@ func (r *Runtime) newContainer(ctx context.Context, rSpec *spec.Spec, options ..
246249
}
247250

248251
func (r *Runtime) setupContainer(ctx context.Context, ctr *Container) (_ *Container, retErr error) {
252+
if ctr.IsDefaultInfra() || ctr.IsService() {
253+
_, err := ctr.prepareInitRootfs()
254+
if err != nil {
255+
return nil, err
256+
}
257+
}
258+
249259
// normalize the networks to names
250260
// the db backend only knows about network names so we have to make
251261
// sure we do not use ids internally
@@ -422,7 +432,6 @@ func (r *Runtime) setupContainer(ctx context.Context, ctr *Container) (_ *Contai
422432
if ctr.restoreFromCheckpoint {
423433
// Remove information about bind mount
424434
// for new container from imported checkpoint
425-
426435
// NewFromSpec() is deprecated according to its comment
427436
// however the recommended replace just causes a nil map panic
428437
g := generate.NewFromSpec(ctr.config.Spec)

pkg/domain/infra/abi/play.go

+5-7
Original file line numberDiff line numberDiff line change
@@ -67,12 +67,6 @@ func (ic *ContainerEngine) createServiceContainer(ctx context.Context, name stri
6767
}
6868
}
6969

70-
// Similar to infra containers, a service container is using the pause image.
71-
image, err := generate.PullOrBuildInfraImage(ic.Libpod, "")
72-
if err != nil {
73-
return nil, fmt.Errorf("image for service container: %w", err)
74-
}
75-
7670
rtc, err := ic.Libpod.GetConfigNoCopy()
7771
if err != nil {
7872
return nil, err
@@ -92,7 +86,7 @@ func (ic *ContainerEngine) createServiceContainer(ctx context.Context, name stri
9286
}
9387

9488
// Create and fill out the runtime spec.
95-
s := specgen.NewSpecGenerator(image, false)
89+
s := specgen.NewSpecGenerator("", true)
9690
if err := specgenutil.FillOutSpecGen(s, &ctrOpts, []string{}); err != nil {
9791
return nil, fmt.Errorf("completing spec for service container: %w", err)
9892
}
@@ -1314,6 +1308,10 @@ func (ic *ContainerEngine) getImageAndLabelInfo(ctx context.Context, cwd string,
13141308
// Contains all labels obtained from kube
13151309
labels := make(map[string]string)
13161310

1311+
if len(container.Image) == 0 {
1312+
return nil, labels, nil
1313+
}
1314+
13171315
pulledImage, err := ic.buildOrPullImage(ctx, cwd, writer, container.Image, container.ImagePullPolicy, options)
13181316
if err != nil {
13191317
return nil, labels, err

pkg/specgen/generate/kube/kube.go

+7-3
Original file line numberDiff line numberDiff line change
@@ -301,9 +301,13 @@ func ToSpecGen(ctx context.Context, opts *CtrSpecGenOptions) (*specgen.SpecGener
301301

302302
// TODO: We don't understand why specgen does not take of this, but
303303
// integration tests clearly pointed out that it was required.
304-
imageData, err := opts.Image.Inspect(ctx, nil)
305-
if err != nil {
306-
return nil, err
304+
var imageData *libimage.ImageData
305+
if opts.Image != nil {
306+
var err error
307+
imageData, err = opts.Image.Inspect(ctx, nil)
308+
if err != nil {
309+
return nil, err
310+
}
307311
}
308312
s.WorkDir = "/"
309313
// Entrypoint/Command handling is based off of

pkg/specgen/generate/pause_image.go

+5-67
Original file line numberDiff line numberDiff line change
@@ -4,18 +4,15 @@ package generate
44

55
import (
66
"context"
7-
"fmt"
8-
"os"
97

10-
buildahDefine "github.com/containers/buildah/define"
118
"github.com/containers/common/pkg/config"
129
"github.com/containers/podman/v5/libpod"
13-
"github.com/containers/podman/v5/libpod/define"
1410
)
1511

16-
// PullOrBuildInfraImage pulls down the specified image or the one set in
17-
// containers.conf. If none is set, it builds a local pause image.
18-
func PullOrBuildInfraImage(rt *libpod.Runtime, imageName string) (string, error) {
12+
// PullInfraImage pulls down the specified image or the one set in
13+
// containers.conf. If none is set, it returns an empty string. In this
14+
// case, the rootfs-based pause image is used by libpod.
15+
func PullInfraImage(rt *libpod.Runtime, imageName string) (string, error) {
1916
rtConfig, err := rt.GetConfigNoCopy()
2017
if err != nil {
2118
return "", err
@@ -33,64 +30,5 @@ func PullOrBuildInfraImage(rt *libpod.Runtime, imageName string) (string, error)
3330
return imageName, nil
3431
}
3532

36-
name, err := buildPauseImage(rt, rtConfig)
37-
if err != nil {
38-
return "", fmt.Errorf("building local pause image: %w", err)
39-
}
40-
return name, nil
41-
}
42-
43-
func buildPauseImage(rt *libpod.Runtime, rtConfig *config.Config) (string, error) {
44-
version, err := define.GetVersion()
45-
if err != nil {
46-
return "", err
47-
}
48-
imageName := fmt.Sprintf("localhost/podman-pause:%s-%d", version.Version, version.Built)
49-
50-
// First check if the image has already been built.
51-
if _, _, err := rt.LibimageRuntime().LookupImage(imageName, nil); err == nil {
52-
return imageName, nil
53-
}
54-
55-
// Also look into the path as some distributions install catatonit in
56-
// /usr/bin.
57-
catatonitPath, err := rtConfig.FindInitBinary()
58-
if err != nil {
59-
return "", fmt.Errorf("finding pause binary: %w", err)
60-
}
61-
62-
buildContent := fmt.Sprintf(`FROM scratch
63-
COPY %s /catatonit
64-
ENTRYPOINT ["/catatonit", "-P"]`, catatonitPath)
65-
66-
tmpF, err := os.CreateTemp("", "pause.containerfile")
67-
if err != nil {
68-
return "", err
69-
}
70-
if _, err := tmpF.WriteString(buildContent); err != nil {
71-
return "", err
72-
}
73-
if err := tmpF.Close(); err != nil {
74-
return "", err
75-
}
76-
defer os.Remove(tmpF.Name())
77-
78-
buildOptions := buildahDefine.BuildOptions{
79-
CommonBuildOpts: &buildahDefine.CommonBuildOptions{},
80-
Output: imageName,
81-
Quiet: true,
82-
IgnoreFile: "/dev/null", // makes sure to not read a local .ignorefile (see #13529)
83-
IIDFile: "/dev/null", // prevents Buildah from writing the ID on stdout
84-
IDMappingOptions: &buildahDefine.IDMappingOptions{
85-
// Use the host UID/GID mappings for the build to avoid issues when
86-
// running with a custom mapping (BZ #2083997).
87-
HostUIDMapping: true,
88-
HostGIDMapping: true,
89-
},
90-
}
91-
if _, _, err := rt.Build(context.Background(), buildOptions, tmpF.Name()); err != nil {
92-
return "", err
93-
}
94-
95-
return imageName, nil
33+
return "", nil
9634
}

0 commit comments

Comments
 (0)