pod create: remove need for pause image

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 <rothberg@redhat.com>
This commit is contained in:
Valentin Rothberg 2021-10-13 16:33:38 +02:00
parent 9d2b8d2791
commit 75f478c08b
9 changed files with 135 additions and 66 deletions

View file

@ -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 {

View file

@ -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

View file

@ -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

View file

@ -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*

View file

@ -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"
@ -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 {

View file

@ -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"
@ -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

View file

@ -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"
@ -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)
@ -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"
}

View file

@ -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"
@ -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())

View file

@ -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)
@ -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 " {
@ -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
@ -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