Skip to content

Commit

Permalink
pod create: remove need for pause image
Browse files Browse the repository at this point in the history
So far, the infra containers of pods required pulling down an image
rendering pods not usable in disconnected environments.  Instead, build
an image locally which uses local pause binary.

Fixes: #10354
Signed-off-by: Valentin Rothberg <[email protected]>
  • Loading branch information
vrothberg committed Oct 26, 2021
1 parent 9d2b8d2 commit 75f478c
Show file tree
Hide file tree
Showing 9 changed files with 135 additions and 66 deletions.
9 changes: 2 additions & 7 deletions cmd/podman/containers/create.go
Original file line number Diff line number Diff line change
Expand Up @@ -372,15 +372,10 @@ func createPodIfNecessary(s *specgen.SpecGenerator, netOpts *entities.NetOptions
}

infraOpts := entities.ContainerCreateOptions{ImageVolume: "bind", Net: netOpts, Quiet: true}
rawImageName := config.DefaultInfraImage
name, err := PullImage(rawImageName, infraOpts)
if err != nil {
fmt.Println(err)
}
imageName := name
imageName := config.DefaultInfraImage
podGen.InfraImage = imageName
podGen.InfraContainerSpec = specgen.NewSpecGenerator(imageName, false)
podGen.InfraContainerSpec.RawImageName = rawImageName
podGen.InfraContainerSpec.RawImageName = imageName
podGen.InfraContainerSpec.NetworkOptions = podGen.NetworkOptions
err = specgenutil.FillOutSpecGen(podGen.InfraContainerSpec, &infraOpts, []string{})
if err != nil {
Expand Down
10 changes: 0 additions & 10 deletions cmd/podman/pods/create.go
Original file line number Diff line number Diff line change
Expand Up @@ -242,16 +242,6 @@ func create(cmd *cobra.Command, args []string) error {
}
if createOptions.Infra {
rawImageName = img
if !infraOptions.RootFS {
curr := infraOptions.Quiet
infraOptions.Quiet = true
name, err := containers.PullImage(imageName, infraOptions)
if err != nil {
fmt.Println(err)
}
imageName = name
infraOptions.Quiet = curr
}
podSpec.InfraImage = imageName
if infraOptions.Entrypoint != nil {
createOptions.InfraCommand = infraOptions.Entrypoint
Expand Down
2 changes: 1 addition & 1 deletion cmd/podman/system/version.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ func version(cmd *cobra.Command, args []string) error {
}
if err := tmpl.Execute(w, versions); err != nil {
// On Failure, assume user is using older version of podman version --format and check client
row = strings.Replace(row, ".Server.", ".", 1)
row = strings.ReplaceAll(row, ".Server.", ".")
tmpl, err := report.NewTemplate("version 1.0.0").Parse(row)
if err != nil {
return err
Expand Down
2 changes: 1 addition & 1 deletion docs/source/markdown/podman-pod-create.1.md
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ The command that will be run to start the infra container. Default: "/pause".

#### **--infra-image**=*image*

The image that will be created for the infra container. Default: "k8s.gcr.io/pause:3.1".
The custom image that will be used for the infra container. Unless specified, Podman builds a custom local image which does not require pulling down an image.

#### **--infra-name**=*name*

Expand Down
15 changes: 14 additions & 1 deletion libpod/kube.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (
"strings"
"time"

"github.com/containers/common/pkg/config"
"github.com/containers/podman/v3/libpod/define"
"github.com/containers/podman/v3/libpod/network/types"
"github.com/containers/podman/v3/pkg/env"
Expand Down Expand Up @@ -468,11 +469,23 @@ func containerToV1Container(ctx context.Context, c *Container) (v1.Container, []

kubeContainer.Name = removeUnderscores(c.Name())
_, image := c.Image()

// The infra container may have been created with an overlay root FS
// instead of an infra image. If so, set the imageto the default K8s
// pause one and make sure it's in the storage by pulling it down if
// missing.
if image == "" && c.IsInfra() {
image = config.DefaultInfraImage
if _, err := c.runtime.libimageRuntime.Pull(ctx, image, config.PullPolicyMissing, nil); err != nil {
return kubeContainer, nil, nil, nil, err
}
}

kubeContainer.Image = image
kubeContainer.Stdin = c.Stdin()
img, _, err := c.runtime.libimageRuntime.LookupImage(image, nil)
if err != nil {
return kubeContainer, kubeVolumes, nil, annotations, err
return kubeContainer, kubeVolumes, nil, annotations, fmt.Errorf("looking up image %q of container %q: %w", image, c.ID(), err)
}
imgData, err := img.Inspect(ctx, nil)
if err != nil {
Expand Down
17 changes: 0 additions & 17 deletions pkg/api/handlers/libpod/pods.go
Original file line number Diff line number Diff line change
@@ -1,15 +1,12 @@
package libpod

import (
"context"
"encoding/json"
"fmt"
"net/http"
"strings"

"github.com/containers/common/libimage"
"github.com/containers/common/pkg/config"
"github.com/containers/image/v5/transports/alltransports"
"github.com/containers/podman/v3/libpod"
"github.com/containers/podman/v3/libpod/define"
"github.com/containers/podman/v3/pkg/api/handlers"
Expand Down Expand Up @@ -67,20 +64,6 @@ func PodCreate(w http.ResponseWriter, r *http.Request) {
imageName = config.DefaultInfraImage
rawImageName = config.DefaultInfraImage
}
curr := infraOptions.Quiet
infraOptions.Quiet = true
pullOptions := &libimage.PullOptions{}
pulledImages, err := runtime.LibimageRuntime().Pull(context.Background(), imageName, config.PullPolicyMissing, pullOptions)
if err != nil {
utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrap(err, "could not pull image"))
return
}
if _, err := alltransports.ParseImageName(imageName); err == nil {
if len(pulledImages) != 0 {
imageName = pulledImages[0].ID()
}
}
infraOptions.Quiet = curr
psg.InfraImage = imageName
psg.InfraContainerSpec.Image = imageName
psg.InfraContainerSpec.RawImageName = rawImageName
Expand Down
97 changes: 96 additions & 1 deletion pkg/specgen/generate/pod_create.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,12 @@ package generate

import (
"context"
"fmt"
"io/ioutil"
"net"
"os"

buildahDefine "github.com/containers/buildah/define"
"github.com/containers/common/pkg/config"
"github.com/containers/podman/v3/libpod"
"github.com/containers/podman/v3/libpod/define"
Expand All @@ -14,10 +18,102 @@ import (
"github.com/sirupsen/logrus"
)

func buildPauseImage(rt *libpod.Runtime, rtConfig *config.Config) (string, error) {
version, err := define.GetVersion()
if err != nil {
return "", err
}
imageName := fmt.Sprintf("localhost/podman-pause:%s-%d", version.Version, version.Built)

// First check if the image has already been built.
if _, _, err := rt.LibimageRuntime().LookupImage(imageName, nil); err == nil {
return imageName, nil
}

// NOTE: Having the pause binary in its own directory keeps the door
// open for replacing the image building with using an overlay root FS.
// The latter turned out to be complex and error prone (see #11956) but
// we may be able to come up with a proper solution at a later point in
// time.
pausePath, err := rtConfig.FindHelperBinary("pause/pause", false)
if err != nil {
return "", fmt.Errorf("finding pause binary: %w", err)
}

buildContent := fmt.Sprintf(`FROM scratch
COPY %s /pause
ENTRYPOINT ["/pause"]`, pausePath)

tmpF, err := ioutil.TempFile("", "pause.containerfile")
if err != nil {
return "", err
}
if _, err := tmpF.WriteString(buildContent); err != nil {
return "", err
}
if err := tmpF.Close(); err != nil {
return "", err
}
defer os.Remove(tmpF.Name())

buildOptions := buildahDefine.BuildOptions{
CommonBuildOpts: &buildahDefine.CommonBuildOptions{},
Output: imageName,
Quiet: true,
IIDFile: "/dev/null", // prevents Buildah from writing the ID on stdout
}
if _, _, err := rt.Build(context.Background(), buildOptions, tmpF.Name()); err != nil {
return "", err
}

return imageName, nil
}

func pullOrBuildInfraImage(p *entities.PodSpec, rt *libpod.Runtime) error {
if p.PodSpecGen.NoInfra {
return nil
}

rtConfig, err := rt.GetConfigNoCopy()
if err != nil {
return err
}

// NOTE: we need pull down the infra image if it was explicitly set by
// the user (or containers.conf) to the non-default one.
imageName := p.PodSpecGen.InfraImage
if imageName == "" {
imageName = rtConfig.Engine.InfraImage
}

if imageName != config.DefaultInfraImage {
_, err := rt.LibimageRuntime().Pull(context.Background(), imageName, config.PullPolicyMissing, nil)
if err != nil {
return err
}
} else {
name, err := buildPauseImage(rt, rtConfig)
if err != nil {
return fmt.Errorf("building local pause image: %w", err)
}
imageName = name
}

p.PodSpecGen.InfraImage = imageName
p.PodSpecGen.InfraContainerSpec.RawImageName = imageName

return nil
}

func MakePod(p *entities.PodSpec, rt *libpod.Runtime) (*libpod.Pod, error) {
if err := p.PodSpecGen.Validate(); err != nil {
return nil, err
}

if err := pullOrBuildInfraImage(p, rt); err != nil {
return nil, err
}

if !p.PodSpecGen.NoInfra && p.PodSpecGen.InfraContainerSpec != nil {
var err error
p.PodSpecGen.InfraContainerSpec, err = MapSpec(&p.PodSpecGen)
Expand All @@ -35,7 +131,6 @@ func MakePod(p *entities.PodSpec, rt *libpod.Runtime) (*libpod.Pod, error) {
return nil, err
}
if !p.PodSpecGen.NoInfra && p.PodSpecGen.InfraContainerSpec != nil {
p.PodSpecGen.InfraContainerSpec.ContainerCreateCommand = []string{} // we do NOT want os.Args as the command, will display the pod create cmd
if p.PodSpecGen.InfraContainerSpec.Name == "" {
p.PodSpecGen.InfraContainerSpec.Name = pod.ID()[:12] + "-infra"
}
Expand Down
19 changes: 0 additions & 19 deletions test/e2e/play_kube_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ import (
"text/template"
"time"

"github.com/containers/common/pkg/config"
"github.com/containers/podman/v3/libpod/define"
"github.com/containers/podman/v3/pkg/util"
. "github.com/containers/podman/v3/test/utils"
Expand Down Expand Up @@ -1120,24 +1119,6 @@ var _ = Describe("Podman play kube", func() {
Expect(label).To(ContainSubstring("unconfined_u:system_r:spc_t:s0"))
})

It("podman play kube should use default infra_image", func() {
err := writeYaml(checkInfraImagePodYaml, kubeYaml)
Expect(err).To(BeNil())

kube := podmanTest.Podman([]string{"play", "kube", kubeYaml})
kube.WaitWithDefaultTimeout()
Expect(kube).Should(Exit(0))

podInspect := podmanTest.Podman([]string{"inspect", "check-infra-image", "--format", "{{ .InfraContainerID }}"})
podInspect.WaitWithDefaultTimeout()
infraContainerID := podInspect.OutputToString()

conInspect := podmanTest.Podman([]string{"inspect", infraContainerID, "--format", "{{ .ImageName }}"})
conInspect.WaitWithDefaultTimeout()
infraContainerImage := conInspect.OutputToString()
Expect(infraContainerImage).To(Equal(config.DefaultInfraImage))
})

It("podman play kube --no-host", func() {
err := writeYaml(checkInfraImagePodYaml, kubeYaml)
Expect(err).To(BeNil())
Expand Down
30 changes: 21 additions & 9 deletions test/system/200-pod.bats
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,10 @@ function teardown() {
run_podman pod rm -f -t 0 $podid
}

function rm_podman_pause_image() {
run_podman version --format "{{.Server.Version}}-{{.Server.Built}}"
run_podman rmi -f "localhost/podman-pause:$output"
}

@test "podman pod - communicating between pods" {
podname=pod$(random_string)
Expand Down Expand Up @@ -100,19 +104,14 @@ function teardown() {
# Clean up. First the nc -l container...
run_podman rm $cid1

# ...then, from pause container, find the image ID of the pause image...
run_podman pod inspect --format '{{(index .Containers 0).ID}}' $podname
pause_cid="$output"
run_podman container inspect --format '{{.Image}}' $pause_cid
pause_iid="$output"

# ...then rm the pod, then rmi the pause image so we don't leave strays.
run_podman pod rm $podname
run_podman rmi $pause_iid

# Pod no longer exists
run_podman 1 pod exists $podid
run_podman 1 pod exists $podname

rm_podman_pause_image
}

@test "podman pod - communicating via /dev/shm " {
Expand All @@ -133,6 +132,10 @@ function teardown() {
# Pod no longer exists
run_podman 1 pod exists $podid
run_podman 1 pod exists $podname

# Pause image hasn't been pulled
run_podman 1 image exists k8s.gcr.io/pause:3.5
rm_podman_pause_image
}

# Random byte
Expand Down Expand Up @@ -303,16 +306,25 @@ EOF
run_podman rm $cid
run_podman pod rm -t 0 -f mypod
run_podman rmi $infra_image

}

@test "podman pod create should fail when infra-name is already in use" {
local infra_name="infra_container_$(random_string 10 | tr A-Z a-z)"
run_podman pod create --infra-name "$infra_name"
local pod_name="$(random_string 10 | tr A-Z a-z)"

# Note that the internal pause image is built even when --infra-image is
# set to the K8s one.
run_podman pod create --name $pod_name --infra-name "$infra_name" --infra-image "k8s.gcr.io/pause:3.5"
run_podman '?' pod create --infra-name "$infra_name"
if [ $status -eq 0 ]; then
die "Podman should fail when user try to create two pods with the same infra-name value"
fi
run_podman pod rm -f $pod_name
run_podman images -a

# Pause image hasn't been pulled
run_podman 1 image exists k8s.gcr.io/pause:3.5
rm_podman_pause_image
}

# vim: filetype=sh

0 comments on commit 75f478c

Please sign in to comment.