Merge pull request #8581 from afbjorklund/preload-crio
Generate cri-o container runtime preload tarballpull/8787/head
commit
79088e6ed2
|
@ -60,6 +60,10 @@ func generateTarball(kubernetesVersion, containerRuntime, tarballFilename string
|
||||||
return errors.Wrap(err, "creating kic driver")
|
return errors.Wrap(err, "creating kic driver")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if err := verifyStorage(containerRuntime); err != nil {
|
||||||
|
return errors.Wrap(err, "verifying storage")
|
||||||
|
}
|
||||||
|
|
||||||
// Now, get images to pull
|
// Now, get images to pull
|
||||||
imgs, err := images.Kubeadm("", kubernetesVersion)
|
imgs, err := images.Kubeadm("", kubernetesVersion)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -128,6 +132,20 @@ func generateTarball(kubernetesVersion, containerRuntime, tarballFilename string
|
||||||
return copyTarballToHost(tarballFilename)
|
return copyTarballToHost(tarballFilename)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func verifyStorage(containerRuntime string) error {
|
||||||
|
if containerRuntime == "docker" || containerRuntime == "containerd" {
|
||||||
|
if err := verifyDockerStorage(); err != nil {
|
||||||
|
return errors.Wrap(err, "Docker storage type is incompatible")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if containerRuntime == "cri-o" {
|
||||||
|
if err := verifyPodmanStorage(); err != nil {
|
||||||
|
return errors.Wrap(err, "Podman storage type is incompatible")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// returns the right command to pull image for a specific runtime
|
// returns the right command to pull image for a specific runtime
|
||||||
func imagePullCommand(containerRuntime, img string) *exec.Cmd {
|
func imagePullCommand(containerRuntime, img string) *exec.Cmd {
|
||||||
if containerRuntime == "docker" {
|
if containerRuntime == "docker" {
|
||||||
|
@ -137,6 +155,10 @@ func imagePullCommand(containerRuntime, img string) *exec.Cmd {
|
||||||
if containerRuntime == "containerd" {
|
if containerRuntime == "containerd" {
|
||||||
return exec.Command("docker", "exec", profile, "sudo", "crictl", "pull", img)
|
return exec.Command("docker", "exec", profile, "sudo", "crictl", "pull", img)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if containerRuntime == "cri-o" {
|
||||||
|
return exec.Command("docker", "exec", profile, "sudo", "crictl", "pull", img)
|
||||||
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -154,6 +176,10 @@ func createImageTarball(tarballFilename, containerRuntime string) error {
|
||||||
dirs = append(dirs, fmt.Sprintf("./lib/containerd"))
|
dirs = append(dirs, fmt.Sprintf("./lib/containerd"))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if containerRuntime == "cri-o" {
|
||||||
|
dirs = append(dirs, fmt.Sprintf("./lib/containers"))
|
||||||
|
}
|
||||||
|
|
||||||
args := []string{"exec", profile, "sudo", "tar", "-I", "lz4", "-C", "/var", "-cvf", tarballFilename}
|
args := []string{"exec", profile, "sudo", "tar", "-I", "lz4", "-C", "/var", "-cvf", tarballFilename}
|
||||||
args = append(args, dirs...)
|
args = append(args, dirs...)
|
||||||
cmd := exec.Command("docker", args...)
|
cmd := exec.Command("docker", args...)
|
||||||
|
|
|
@ -18,6 +18,7 @@ package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"encoding/json"
|
||||||
"flag"
|
"flag"
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
|
@ -37,7 +38,8 @@ const (
|
||||||
|
|
||||||
var (
|
var (
|
||||||
dockerStorageDriver = "overlay2"
|
dockerStorageDriver = "overlay2"
|
||||||
containerRuntimes = []string{"docker", "containerd"}
|
podmanStorageDriver = "overlay"
|
||||||
|
containerRuntimes = []string{"docker", "containerd", "cri-o"}
|
||||||
k8sVersion string
|
k8sVersion string
|
||||||
k8sVersions []string
|
k8sVersions []string
|
||||||
)
|
)
|
||||||
|
@ -62,9 +64,6 @@ func main() {
|
||||||
fmt.Printf("error cleaning up minikube at start up: %v \n", err)
|
fmt.Printf("error cleaning up minikube at start up: %v \n", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := verifyDockerStorage(); err != nil {
|
|
||||||
exit("Docker storage type is incompatible: %v \n", err)
|
|
||||||
}
|
|
||||||
if k8sVersions == nil {
|
if k8sVersions == nil {
|
||||||
var err error
|
var err error
|
||||||
k8sVersions, err = RecentK8sVersions()
|
k8sVersions, err = RecentK8sVersions()
|
||||||
|
@ -99,7 +98,7 @@ func main() {
|
||||||
}
|
}
|
||||||
|
|
||||||
func verifyDockerStorage() error {
|
func verifyDockerStorage() error {
|
||||||
cmd := exec.Command("docker", "info", "-f", "{{.Info.Driver}}")
|
cmd := exec.Command("docker", "exec", profile, "docker", "info", "-f", "{{.Info.Driver}}")
|
||||||
var stderr bytes.Buffer
|
var stderr bytes.Buffer
|
||||||
cmd.Stderr = &stderr
|
cmd.Stderr = &stderr
|
||||||
output, err := cmd.Output()
|
output, err := cmd.Output()
|
||||||
|
@ -113,6 +112,26 @@ func verifyDockerStorage() error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func verifyPodmanStorage() error {
|
||||||
|
cmd := exec.Command("docker", "exec", profile, "sudo", "podman", "info", "-f", "json")
|
||||||
|
var stderr bytes.Buffer
|
||||||
|
cmd.Stderr = &stderr
|
||||||
|
output, err := cmd.Output()
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("%v: %v:\n%s", cmd.Args, err, stderr.String())
|
||||||
|
}
|
||||||
|
var info map[string]map[string]interface{}
|
||||||
|
err = json.Unmarshal(output, &info)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
driver := info["store"]["graphDriverName"]
|
||||||
|
if driver != podmanStorageDriver {
|
||||||
|
return fmt.Errorf("podman storage driver %s does not match requested %s", driver, podmanStorageDriver)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// exit will exit and clean up minikube
|
// exit will exit and clean up minikube
|
||||||
func exit(msg string, err error) {
|
func exit(msg string, err error) {
|
||||||
fmt.Printf("WithError(%s)=%v called from:\n%s", msg, err, debug.Stack())
|
fmt.Printf("WithError(%s)=%v called from:\n%s", msg, err, debug.Stack())
|
||||||
|
|
|
@ -370,7 +370,7 @@ func containerdImagesPreloaded(runner command.Runner, images []string) bool {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
type containerdImages struct {
|
type criImages struct {
|
||||||
Images []struct {
|
Images []struct {
|
||||||
ID string `json:"id"`
|
ID string `json:"id"`
|
||||||
RepoTags []string `json:"repoTags"`
|
RepoTags []string `json:"repoTags"`
|
||||||
|
@ -381,7 +381,7 @@ func containerdImagesPreloaded(runner command.Runner, images []string) bool {
|
||||||
} `json:"images"`
|
} `json:"images"`
|
||||||
}
|
}
|
||||||
|
|
||||||
var jsonImages containerdImages
|
var jsonImages criImages
|
||||||
err = json.Unmarshal(rr.Stdout.Bytes(), &jsonImages)
|
err = json.Unmarshal(rr.Stdout.Bytes(), &jsonImages)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
glog.Errorf("failed to unmarshal images, will assume images are not preloaded")
|
glog.Errorf("failed to unmarshal images, will assume images are not preloaded")
|
||||||
|
@ -412,15 +412,3 @@ func containerdImagesPreloaded(runner command.Runner, images []string) bool {
|
||||||
glog.Infof("all images are preloaded for containerd runtime.")
|
glog.Infof("all images are preloaded for containerd runtime.")
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
// addRepoTagToImageName makes sure the image name has a repo tag in it.
|
|
||||||
// in crictl images list have the repo tag prepended to them
|
|
||||||
// for example "kubernetesui/dashboard:v2.0.0 will show up as "docker.io/kubernetesui/dashboard:v2.0.0"
|
|
||||||
// warning this is only meant for kuberentes images where we know the GCR addreses have .io in them
|
|
||||||
// not mean to be used for public images
|
|
||||||
func addRepoTagToImageName(imgName string) string {
|
|
||||||
if !strings.Contains(imgName, ".io/") {
|
|
||||||
return "docker.io/" + imgName
|
|
||||||
} // else it already has repo name dont add anything
|
|
||||||
return imgName
|
|
||||||
}
|
|
||||||
|
|
|
@ -259,3 +259,15 @@ func criContainerLogCmd(cr CommandRunner, id string, len int, follow bool) strin
|
||||||
cmd.WriteString(id)
|
cmd.WriteString(id)
|
||||||
return cmd.String()
|
return cmd.String()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// addRepoTagToImageName makes sure the image name has a repo tag in it.
|
||||||
|
// in crictl images list have the repo tag prepended to them
|
||||||
|
// for example "kubernetesui/dashboard:v2.0.0 will show up as "docker.io/kubernetesui/dashboard:v2.0.0"
|
||||||
|
// warning this is only meant for kuberentes images where we know the GCR addreses have .io in them
|
||||||
|
// not mean to be used for public images
|
||||||
|
func addRepoTagToImageName(imgName string) string {
|
||||||
|
if !strings.Contains(imgName, ".io/") {
|
||||||
|
return "docker.io/" + imgName
|
||||||
|
} // else it already has repo name dont add anything
|
||||||
|
return imgName
|
||||||
|
}
|
||||||
|
|
|
@ -17,15 +17,20 @@ limitations under the License.
|
||||||
package cruntime
|
package cruntime
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net"
|
"net"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
|
"path"
|
||||||
"strings"
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/blang/semver"
|
"github.com/blang/semver"
|
||||||
"github.com/golang/glog"
|
"github.com/golang/glog"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
|
"k8s.io/minikube/pkg/minikube/assets"
|
||||||
"k8s.io/minikube/pkg/minikube/bootstrapper/images"
|
"k8s.io/minikube/pkg/minikube/bootstrapper/images"
|
||||||
|
"k8s.io/minikube/pkg/minikube/command"
|
||||||
"k8s.io/minikube/pkg/minikube/config"
|
"k8s.io/minikube/pkg/minikube/config"
|
||||||
"k8s.io/minikube/pkg/minikube/download"
|
"k8s.io/minikube/pkg/minikube/download"
|
||||||
"k8s.io/minikube/pkg/minikube/out"
|
"k8s.io/minikube/pkg/minikube/out"
|
||||||
|
@ -222,7 +227,103 @@ func (r *CRIO) Preload(cfg config.KubernetesConfig) error {
|
||||||
if !download.PreloadExists(cfg.KubernetesVersion, cfg.ContainerRuntime) {
|
if !download.PreloadExists(cfg.KubernetesVersion, cfg.ContainerRuntime) {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
return fmt.Errorf("not yet implemented for %s", r.Name())
|
|
||||||
|
k8sVersion := cfg.KubernetesVersion
|
||||||
|
cRuntime := cfg.ContainerRuntime
|
||||||
|
|
||||||
|
// If images already exist, return
|
||||||
|
images, err := images.Kubeadm(cfg.ImageRepository, k8sVersion)
|
||||||
|
if err != nil {
|
||||||
|
return errors.Wrap(err, "getting images")
|
||||||
|
}
|
||||||
|
if crioImagesPreloaded(r.Runner, images) {
|
||||||
|
glog.Info("Images already preloaded, skipping extraction")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
tarballPath := download.TarballPath(k8sVersion, cRuntime)
|
||||||
|
targetDir := "/"
|
||||||
|
targetName := "preloaded.tar.lz4"
|
||||||
|
dest := path.Join(targetDir, targetName)
|
||||||
|
|
||||||
|
c := exec.Command("which", "lz4")
|
||||||
|
if _, err := r.Runner.RunCmd(c); err != nil {
|
||||||
|
return NewErrISOFeature("lz4")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copy over tarball into host
|
||||||
|
fa, err := assets.NewFileAsset(tarballPath, targetDir, targetName, "0644")
|
||||||
|
if err != nil {
|
||||||
|
return errors.Wrap(err, "getting file asset")
|
||||||
|
}
|
||||||
|
t := time.Now()
|
||||||
|
if err := r.Runner.Copy(fa); err != nil {
|
||||||
|
return errors.Wrap(err, "copying file")
|
||||||
|
}
|
||||||
|
glog.Infof("Took %f seconds to copy over tarball", time.Since(t).Seconds())
|
||||||
|
|
||||||
|
t = time.Now()
|
||||||
|
// extract the tarball to /var in the VM
|
||||||
|
if rr, err := r.Runner.RunCmd(exec.Command("sudo", "tar", "-I", "lz4", "-C", "/var", "-xvf", dest)); err != nil {
|
||||||
|
return errors.Wrapf(err, "extracting tarball: %s", rr.Output())
|
||||||
|
}
|
||||||
|
glog.Infof("Took %f seconds t extract the tarball", time.Since(t).Seconds())
|
||||||
|
|
||||||
|
// remove the tarball in the VM
|
||||||
|
if err := r.Runner.Remove(fa); err != nil {
|
||||||
|
glog.Infof("error removing tarball: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// crioImagesPreloaded returns true if all images have been preloaded
|
||||||
|
func crioImagesPreloaded(runner command.Runner, images []string) bool {
|
||||||
|
rr, err := runner.RunCmd(exec.Command("sudo", "crictl", "images", "--output", "json"))
|
||||||
|
if err != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
type criImages struct {
|
||||||
|
Images []struct {
|
||||||
|
ID string `json:"id"`
|
||||||
|
RepoTags []string `json:"repoTags"`
|
||||||
|
RepoDigests []string `json:"repoDigests"`
|
||||||
|
Size string `json:"size"`
|
||||||
|
UID interface{} `json:"uid"`
|
||||||
|
Username string `json:"username"`
|
||||||
|
} `json:"images"`
|
||||||
|
}
|
||||||
|
|
||||||
|
var jsonImages criImages
|
||||||
|
err = json.Unmarshal(rr.Stdout.Bytes(), &jsonImages)
|
||||||
|
if err != nil {
|
||||||
|
glog.Errorf("failed to unmarshal images, will assume images are not preloaded")
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make sure images == imgs
|
||||||
|
for _, i := range images {
|
||||||
|
found := false
|
||||||
|
for _, ji := range jsonImages.Images {
|
||||||
|
for _, rt := range ji.RepoTags {
|
||||||
|
i = addRepoTagToImageName(i)
|
||||||
|
if i == rt {
|
||||||
|
found = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if found {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
if !found {
|
||||||
|
glog.Infof("couldn't find preloaded image for %q. assuming images are not preloaded.", i)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
glog.Infof("all images are preloaded for crio runtime.")
|
||||||
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
// UpdateCRIONet updates CRIO CNI network configuration and restarts it
|
// UpdateCRIONet updates CRIO CNI network configuration and restarts it
|
||||||
|
|
|
@ -47,7 +47,16 @@ const (
|
||||||
|
|
||||||
// TarballName returns name of the tarball
|
// TarballName returns name of the tarball
|
||||||
func TarballName(k8sVersion, containerRuntime string) string {
|
func TarballName(k8sVersion, containerRuntime string) string {
|
||||||
return fmt.Sprintf("preloaded-images-k8s-%s-%s-%s-overlay2-%s.tar.lz4", PreloadVersion, k8sVersion, containerRuntime, runtime.GOARCH)
|
if containerRuntime == "crio" {
|
||||||
|
containerRuntime = "cri-o"
|
||||||
|
}
|
||||||
|
var storageDriver string
|
||||||
|
if containerRuntime == "cri-o" {
|
||||||
|
storageDriver = "overlay"
|
||||||
|
} else {
|
||||||
|
storageDriver = "overlay2"
|
||||||
|
}
|
||||||
|
return fmt.Sprintf("preloaded-images-k8s-%s-%s-%s-%s-%s.tar.lz4", PreloadVersion, k8sVersion, containerRuntime, storageDriver, runtime.GOARCH)
|
||||||
}
|
}
|
||||||
|
|
||||||
// returns the name of the checksum file
|
// returns the name of the checksum file
|
||||||
|
@ -78,13 +87,6 @@ func remoteTarballURL(k8sVersion, containerRuntime string) string {
|
||||||
// PreloadExists returns true if there is a preloaded tarball that can be used
|
// PreloadExists returns true if there is a preloaded tarball that can be used
|
||||||
func PreloadExists(k8sVersion, containerRuntime string, forcePreload ...bool) bool {
|
func PreloadExists(k8sVersion, containerRuntime string, forcePreload ...bool) bool {
|
||||||
|
|
||||||
// and https://github.com/kubernetes/minikube/issues/6934
|
|
||||||
// to track status of adding crio
|
|
||||||
if containerRuntime == "crio" {
|
|
||||||
glog.Info("crio is not supported yet, skipping preload")
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO (#8166): Get rid of the need for this and viper at all
|
// TODO (#8166): Get rid of the need for this and viper at all
|
||||||
force := false
|
force := false
|
||||||
if len(forcePreload) > 0 {
|
if len(forcePreload) > 0 {
|
||||||
|
|
Loading…
Reference in New Issue