Skip to content

Commit 79088e6

Browse files
authored
Merge pull request #8581 from afbjorklund/preload-crio
Generate cri-o container runtime preload tarball
2 parents 2086bcb + b0b3a1a commit 79088e6

File tree

6 files changed

+176
-28
lines changed

6 files changed

+176
-28
lines changed

hack/preload-images/generate.go

+26
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,10 @@ func generateTarball(kubernetesVersion, containerRuntime, tarballFilename string
6060
return errors.Wrap(err, "creating kic driver")
6161
}
6262

63+
if err := verifyStorage(containerRuntime); err != nil {
64+
return errors.Wrap(err, "verifying storage")
65+
}
66+
6367
// Now, get images to pull
6468
imgs, err := images.Kubeadm("", kubernetesVersion)
6569
if err != nil {
@@ -128,6 +132,20 @@ func generateTarball(kubernetesVersion, containerRuntime, tarballFilename string
128132
return copyTarballToHost(tarballFilename)
129133
}
130134

135+
func verifyStorage(containerRuntime string) error {
136+
if containerRuntime == "docker" || containerRuntime == "containerd" {
137+
if err := verifyDockerStorage(); err != nil {
138+
return errors.Wrap(err, "Docker storage type is incompatible")
139+
}
140+
}
141+
if containerRuntime == "cri-o" {
142+
if err := verifyPodmanStorage(); err != nil {
143+
return errors.Wrap(err, "Podman storage type is incompatible")
144+
}
145+
}
146+
return nil
147+
}
148+
131149
// returns the right command to pull image for a specific runtime
132150
func imagePullCommand(containerRuntime, img string) *exec.Cmd {
133151
if containerRuntime == "docker" {
@@ -137,6 +155,10 @@ func imagePullCommand(containerRuntime, img string) *exec.Cmd {
137155
if containerRuntime == "containerd" {
138156
return exec.Command("docker", "exec", profile, "sudo", "crictl", "pull", img)
139157
}
158+
159+
if containerRuntime == "cri-o" {
160+
return exec.Command("docker", "exec", profile, "sudo", "crictl", "pull", img)
161+
}
140162
return nil
141163
}
142164

@@ -154,6 +176,10 @@ func createImageTarball(tarballFilename, containerRuntime string) error {
154176
dirs = append(dirs, fmt.Sprintf("./lib/containerd"))
155177
}
156178

179+
if containerRuntime == "cri-o" {
180+
dirs = append(dirs, fmt.Sprintf("./lib/containers"))
181+
}
182+
157183
args := []string{"exec", profile, "sudo", "tar", "-I", "lz4", "-C", "/var", "-cvf", tarballFilename}
158184
args = append(args, dirs...)
159185
cmd := exec.Command("docker", args...)

hack/preload-images/preload_images.go

+24-5
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ package main
1818

1919
import (
2020
"bytes"
21+
"encoding/json"
2122
"flag"
2223
"fmt"
2324
"os"
@@ -37,7 +38,8 @@ const (
3738

3839
var (
3940
dockerStorageDriver = "overlay2"
40-
containerRuntimes = []string{"docker", "containerd"}
41+
podmanStorageDriver = "overlay"
42+
containerRuntimes = []string{"docker", "containerd", "cri-o"}
4143
k8sVersion string
4244
k8sVersions []string
4345
)
@@ -62,9 +64,6 @@ func main() {
6264
fmt.Printf("error cleaning up minikube at start up: %v \n", err)
6365
}
6466

65-
if err := verifyDockerStorage(); err != nil {
66-
exit("Docker storage type is incompatible: %v \n", err)
67-
}
6867
if k8sVersions == nil {
6968
var err error
7069
k8sVersions, err = RecentK8sVersions()
@@ -99,7 +98,7 @@ func main() {
9998
}
10099

101100
func verifyDockerStorage() error {
102-
cmd := exec.Command("docker", "info", "-f", "{{.Info.Driver}}")
101+
cmd := exec.Command("docker", "exec", profile, "docker", "info", "-f", "{{.Info.Driver}}")
103102
var stderr bytes.Buffer
104103
cmd.Stderr = &stderr
105104
output, err := cmd.Output()
@@ -113,6 +112,26 @@ func verifyDockerStorage() error {
113112
return nil
114113
}
115114

115+
func verifyPodmanStorage() error {
116+
cmd := exec.Command("docker", "exec", profile, "sudo", "podman", "info", "-f", "json")
117+
var stderr bytes.Buffer
118+
cmd.Stderr = &stderr
119+
output, err := cmd.Output()
120+
if err != nil {
121+
return fmt.Errorf("%v: %v:\n%s", cmd.Args, err, stderr.String())
122+
}
123+
var info map[string]map[string]interface{}
124+
err = json.Unmarshal(output, &info)
125+
if err != nil {
126+
return err
127+
}
128+
driver := info["store"]["graphDriverName"]
129+
if driver != podmanStorageDriver {
130+
return fmt.Errorf("podman storage driver %s does not match requested %s", driver, podmanStorageDriver)
131+
}
132+
return nil
133+
}
134+
116135
// exit will exit and clean up minikube
117136
func exit(msg string, err error) {
118137
fmt.Printf("WithError(%s)=%v called from:\n%s", msg, err, debug.Stack())

pkg/minikube/cruntime/containerd.go

+2-14
Original file line numberDiff line numberDiff line change
@@ -370,7 +370,7 @@ func containerdImagesPreloaded(runner command.Runner, images []string) bool {
370370
if err != nil {
371371
return false
372372
}
373-
type containerdImages struct {
373+
type criImages struct {
374374
Images []struct {
375375
ID string `json:"id"`
376376
RepoTags []string `json:"repoTags"`
@@ -381,7 +381,7 @@ func containerdImagesPreloaded(runner command.Runner, images []string) bool {
381381
} `json:"images"`
382382
}
383383

384-
var jsonImages containerdImages
384+
var jsonImages criImages
385385
err = json.Unmarshal(rr.Stdout.Bytes(), &jsonImages)
386386
if err != nil {
387387
glog.Errorf("failed to unmarshal images, will assume images are not preloaded")
@@ -412,15 +412,3 @@ func containerdImagesPreloaded(runner command.Runner, images []string) bool {
412412
glog.Infof("all images are preloaded for containerd runtime.")
413413
return true
414414
}
415-
416-
// addRepoTagToImageName makes sure the image name has a repo tag in it.
417-
// in crictl images list have the repo tag prepended to them
418-
// for example "kubernetesui/dashboard:v2.0.0 will show up as "docker.io/kubernetesui/dashboard:v2.0.0"
419-
// warning this is only meant for kuberentes images where we know the GCR addreses have .io in them
420-
// not mean to be used for public images
421-
func addRepoTagToImageName(imgName string) string {
422-
if !strings.Contains(imgName, ".io/") {
423-
return "docker.io/" + imgName
424-
} // else it already has repo name dont add anything
425-
return imgName
426-
}

pkg/minikube/cruntime/cri.go

+12
Original file line numberDiff line numberDiff line change
@@ -259,3 +259,15 @@ func criContainerLogCmd(cr CommandRunner, id string, len int, follow bool) strin
259259
cmd.WriteString(id)
260260
return cmd.String()
261261
}
262+
263+
// addRepoTagToImageName makes sure the image name has a repo tag in it.
264+
// in crictl images list have the repo tag prepended to them
265+
// for example "kubernetesui/dashboard:v2.0.0 will show up as "docker.io/kubernetesui/dashboard:v2.0.0"
266+
// warning this is only meant for kuberentes images where we know the GCR addreses have .io in them
267+
// not mean to be used for public images
268+
func addRepoTagToImageName(imgName string) string {
269+
if !strings.Contains(imgName, ".io/") {
270+
return "docker.io/" + imgName
271+
} // else it already has repo name dont add anything
272+
return imgName
273+
}

pkg/minikube/cruntime/crio.go

+102-1
Original file line numberDiff line numberDiff line change
@@ -17,15 +17,20 @@ limitations under the License.
1717
package cruntime
1818

1919
import (
20+
"encoding/json"
2021
"fmt"
2122
"net"
2223
"os/exec"
24+
"path"
2325
"strings"
26+
"time"
2427

2528
"github.com/blang/semver"
2629
"github.com/golang/glog"
2730
"github.com/pkg/errors"
31+
"k8s.io/minikube/pkg/minikube/assets"
2832
"k8s.io/minikube/pkg/minikube/bootstrapper/images"
33+
"k8s.io/minikube/pkg/minikube/command"
2934
"k8s.io/minikube/pkg/minikube/config"
3035
"k8s.io/minikube/pkg/minikube/download"
3136
"k8s.io/minikube/pkg/minikube/out"
@@ -222,7 +227,103 @@ func (r *CRIO) Preload(cfg config.KubernetesConfig) error {
222227
if !download.PreloadExists(cfg.KubernetesVersion, cfg.ContainerRuntime) {
223228
return nil
224229
}
225-
return fmt.Errorf("not yet implemented for %s", r.Name())
230+
231+
k8sVersion := cfg.KubernetesVersion
232+
cRuntime := cfg.ContainerRuntime
233+
234+
// If images already exist, return
235+
images, err := images.Kubeadm(cfg.ImageRepository, k8sVersion)
236+
if err != nil {
237+
return errors.Wrap(err, "getting images")
238+
}
239+
if crioImagesPreloaded(r.Runner, images) {
240+
glog.Info("Images already preloaded, skipping extraction")
241+
return nil
242+
}
243+
244+
tarballPath := download.TarballPath(k8sVersion, cRuntime)
245+
targetDir := "/"
246+
targetName := "preloaded.tar.lz4"
247+
dest := path.Join(targetDir, targetName)
248+
249+
c := exec.Command("which", "lz4")
250+
if _, err := r.Runner.RunCmd(c); err != nil {
251+
return NewErrISOFeature("lz4")
252+
}
253+
254+
// Copy over tarball into host
255+
fa, err := assets.NewFileAsset(tarballPath, targetDir, targetName, "0644")
256+
if err != nil {
257+
return errors.Wrap(err, "getting file asset")
258+
}
259+
t := time.Now()
260+
if err := r.Runner.Copy(fa); err != nil {
261+
return errors.Wrap(err, "copying file")
262+
}
263+
glog.Infof("Took %f seconds to copy over tarball", time.Since(t).Seconds())
264+
265+
t = time.Now()
266+
// extract the tarball to /var in the VM
267+
if rr, err := r.Runner.RunCmd(exec.Command("sudo", "tar", "-I", "lz4", "-C", "/var", "-xvf", dest)); err != nil {
268+
return errors.Wrapf(err, "extracting tarball: %s", rr.Output())
269+
}
270+
glog.Infof("Took %f seconds t extract the tarball", time.Since(t).Seconds())
271+
272+
// remove the tarball in the VM
273+
if err := r.Runner.Remove(fa); err != nil {
274+
glog.Infof("error removing tarball: %v", err)
275+
}
276+
277+
return nil
278+
}
279+
280+
// crioImagesPreloaded returns true if all images have been preloaded
281+
func crioImagesPreloaded(runner command.Runner, images []string) bool {
282+
rr, err := runner.RunCmd(exec.Command("sudo", "crictl", "images", "--output", "json"))
283+
if err != nil {
284+
return false
285+
}
286+
type criImages struct {
287+
Images []struct {
288+
ID string `json:"id"`
289+
RepoTags []string `json:"repoTags"`
290+
RepoDigests []string `json:"repoDigests"`
291+
Size string `json:"size"`
292+
UID interface{} `json:"uid"`
293+
Username string `json:"username"`
294+
} `json:"images"`
295+
}
296+
297+
var jsonImages criImages
298+
err = json.Unmarshal(rr.Stdout.Bytes(), &jsonImages)
299+
if err != nil {
300+
glog.Errorf("failed to unmarshal images, will assume images are not preloaded")
301+
return false
302+
}
303+
304+
// Make sure images == imgs
305+
for _, i := range images {
306+
found := false
307+
for _, ji := range jsonImages.Images {
308+
for _, rt := range ji.RepoTags {
309+
i = addRepoTagToImageName(i)
310+
if i == rt {
311+
found = true
312+
break
313+
}
314+
}
315+
if found {
316+
break
317+
}
318+
319+
}
320+
if !found {
321+
glog.Infof("couldn't find preloaded image for %q. assuming images are not preloaded.", i)
322+
return false
323+
}
324+
}
325+
glog.Infof("all images are preloaded for crio runtime.")
326+
return true
226327
}
227328

228329
// UpdateCRIONet updates CRIO CNI network configuration and restarts it

pkg/minikube/download/preload.go

+10-8
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,16 @@ const (
4747

4848
// TarballName returns name of the tarball
4949
func TarballName(k8sVersion, containerRuntime string) string {
50-
return fmt.Sprintf("preloaded-images-k8s-%s-%s-%s-overlay2-%s.tar.lz4", PreloadVersion, k8sVersion, containerRuntime, runtime.GOARCH)
50+
if containerRuntime == "crio" {
51+
containerRuntime = "cri-o"
52+
}
53+
var storageDriver string
54+
if containerRuntime == "cri-o" {
55+
storageDriver = "overlay"
56+
} else {
57+
storageDriver = "overlay2"
58+
}
59+
return fmt.Sprintf("preloaded-images-k8s-%s-%s-%s-%s-%s.tar.lz4", PreloadVersion, k8sVersion, containerRuntime, storageDriver, runtime.GOARCH)
5160
}
5261

5362
// returns the name of the checksum file
@@ -78,13 +87,6 @@ func remoteTarballURL(k8sVersion, containerRuntime string) string {
7887
// PreloadExists returns true if there is a preloaded tarball that can be used
7988
func PreloadExists(k8sVersion, containerRuntime string, forcePreload ...bool) bool {
8089

81-
// and https://github.com/kubernetes/minikube/issues/6934
82-
// to track status of adding crio
83-
if containerRuntime == "crio" {
84-
glog.Info("crio is not supported yet, skipping preload")
85-
return false
86-
}
87-
8890
// TODO (#8166): Get rid of the need for this and viper at all
8991
force := false
9092
if len(forcePreload) > 0 {

0 commit comments

Comments
 (0)