Rebased on master

pull/6863/head
Priya Wadhwa 2020-03-02 13:33:27 -08:00
commit 6b0e942e7e
43 changed files with 994 additions and 219 deletions

View File

@ -519,9 +519,10 @@ kic-base-image: ## builds the base image used for kic.
.PHONY: upload-preloaded-images-tar
upload-preloaded-images-tar: generate-preloaded-images-tar # Upload the preloaded images tar to the GCS bucket. Specify a specific kubernetes version to build via `KUBERNETES_VERSION=vx.y.z make upload-preloaded-images-tar`.
gsutil cp out/preloaded-images-k8s-${KUBERNETES_VERSION}.tar.lz4 gs://${PRELOADED_VOLUMES_GCS_BUCKET}
gsutil acl ch -u AllUsers:R gs://${PRELOADED_VOLUMES_GCS_BUCKET}/preloaded-images-k8s-${KUBERNETES_VERSION}.tar.lz4
.PHONY: generate-preloaded-images-tar
generate-preloaded-images-tar: out/minikube
generate-preloaded-images-tar:
go run ./hack/preload-images/preload_images.go -kubernetes-version ${KUBERNETES_VERSION}

View File

@ -65,7 +65,8 @@ var ProfileCmd = &cobra.Command{
}
if !pkgConfig.ProfileExists(profile) {
out.FailureT("if you want to create a profile you can by this command: minikube start -p {{.profile_name}}", out.V{"profile_name": profile})
out.ErrT(out.Tip, `if you want to create a profile you can by this command: minikube start -p {{.profile_name}}`, out.V{"profile_name": profile})
os.Exit(0)
}
err := Set(pkgConfig.MachineProfile, profile)

View File

@ -116,7 +116,7 @@ func runDelete(cmd *cobra.Command, args []string) {
exit.UsageT("usage: minikube delete --all")
}
delLabel := fmt.Sprintf("%s=%s", oci.CreatedByLabelKey, "true")
errs := oci.DeleteAllContainersByLabel(oci.Docker, delLabel)
errs := oci.DeleteContainersByLabel(oci.Docker, delLabel)
if len(errs) > 0 { // it will error if there is no container to delete
glog.Infof("error delete containers by label %q (might be okay): %+v", delLabel, err)
}
@ -194,7 +194,7 @@ func deleteProfile(profile *pkg_config.Profile) error {
viper.Set(pkg_config.MachineProfile, profile.Name)
delLabel := fmt.Sprintf("%s=%s", oci.ProfileLabelKey, profile.Name)
errs := oci.DeleteAllContainersByLabel(oci.Docker, delLabel)
errs := oci.DeleteContainersByLabel(oci.Docker, delLabel)
if errs != nil { // it will error if there is no container to delete
glog.Infof("error deleting containers for %s (might be okay):\n%v", profile.Name, errs)
}
@ -207,7 +207,6 @@ func deleteProfile(profile *pkg_config.Profile) error {
if len(errs) > 0 { // it will not error if there is nothing to delete
glog.Warningf("error pruning volume (might be okay):\n%v", errs)
}
api, err := machine.NewAPIClient()
if err != nil {
delErr := profileDeletionErr(profile.Name, fmt.Sprintf("error getting client %v", err))

View File

@ -20,18 +20,28 @@ import (
"fmt"
"net/url"
"os"
"os/signal"
"path/filepath"
"runtime"
"strconv"
"strings"
"text/template"
"time"
"github.com/golang/glog"
"github.com/pkg/browser"
"github.com/spf13/cobra"
"github.com/spf13/viper"
"k8s.io/minikube/pkg/drivers/kic/oci"
"k8s.io/minikube/pkg/minikube/config"
pkg_config "k8s.io/minikube/pkg/minikube/config"
"k8s.io/minikube/pkg/minikube/exit"
"k8s.io/minikube/pkg/minikube/localpath"
"k8s.io/minikube/pkg/minikube/machine"
"k8s.io/minikube/pkg/minikube/out"
"k8s.io/minikube/pkg/minikube/service"
"k8s.io/minikube/pkg/minikube/tunnel/kic"
)
const defaultServiceFormatTemplate = "http://{{.IP}}:{{.Port}}"
@ -77,28 +87,22 @@ var serviceCmd = &cobra.Command{
os.Exit(1)
}
cfg, err := config.Load(profileName)
if err != nil {
exit.WithError("Error getting config", err)
}
if runtime.GOOS == "darwin" && cfg.Driver == oci.Docker {
startKicServiceTunnel(svc, cfg.Name)
return
}
urls, err := service.WaitForService(api, namespace, svc, serviceURLTemplate, serviceURLMode, https, wait, interval)
if err != nil {
exit.WithError("Error opening service", err)
}
for _, u := range urls {
_, err := url.Parse(u)
if err != nil {
glog.Warningf("failed to parse url %q: %v (will not open)", u, err)
out.String(fmt.Sprintf("%s\n", u))
continue
}
if serviceURLMode {
out.String(fmt.Sprintf("%s\n", u))
continue
}
out.T(out.Celebrate, "Opening service {{.namespace_name}}/{{.service_name}} in default browser...", out.V{"namespace_name": namespace, "service_name": svc})
if err := browser.OpenURL(u); err != nil {
exit.WithError(fmt.Sprintf("open url failed: %s", u), err)
}
}
openURLs(svc, urls)
},
}
@ -112,3 +116,65 @@ func init() {
serviceCmd.PersistentFlags().StringVar(&serviceURLFormat, "format", defaultServiceFormatTemplate, "Format to output service URL in. This format will be applied to each url individually and they will be printed one at a time.")
}
func startKicServiceTunnel(svc, configName string) {
ctrlC := make(chan os.Signal, 1)
signal.Notify(ctrlC, os.Interrupt)
clientset, err := service.K8s.GetClientset(1 * time.Second)
if err != nil {
exit.WithError("error creating clientset", err)
}
port, err := oci.HostPortBinding(oci.Docker, configName, 22)
if err != nil {
exit.WithError("error getting ssh port", err)
}
sshPort := strconv.Itoa(port)
sshKey := filepath.Join(localpath.MiniPath(), "machines", configName, "id_rsa")
serviceTunnel := kic.NewServiceTunnel(sshPort, sshKey, clientset.CoreV1())
urls, err := serviceTunnel.Start(svc, namespace)
if err != nil {
exit.WithError("error starting tunnel", err)
}
// wait for tunnel to come up
time.Sleep(1 * time.Second)
data := [][]string{{namespace, svc, "", strings.Join(urls, "\n")}}
service.PrintServiceList(os.Stdout, data)
openURLs(svc, urls)
<-ctrlC
err = serviceTunnel.Stop()
if err != nil {
exit.WithError("error stopping tunnel", err)
}
}
func openURLs(svc string, urls []string) {
for _, u := range urls {
_, err := url.Parse(u)
if err != nil {
glog.Warningf("failed to parse url %q: %v (will not open)", u, err)
out.String(fmt.Sprintf("%s\n", u))
continue
}
if serviceURLMode {
out.String(fmt.Sprintf("%s\n", u))
continue
}
out.T(out.Celebrate, "Opening service {{.namespace_name}}/{{.service_name}} in default browser...", out.V{"namespace_name": namespace, "service_name": svc})
if err := browser.OpenURL(u); err != nil {
exit.WithError(fmt.Sprintf("open url failed: %s", u), err)
}
out.T(out.WarningType, "Because you are using docker driver on Mac, the terminal needs to be open to run it.")
}
}

View File

@ -18,10 +18,15 @@ package cmd
import (
"os"
"runtime"
"strings"
"github.com/spf13/cobra"
"github.com/spf13/viper"
core "k8s.io/api/core/v1"
"k8s.io/minikube/pkg/drivers/kic/oci"
"k8s.io/minikube/pkg/minikube/config"
pkg_config "k8s.io/minikube/pkg/minikube/config"
"k8s.io/minikube/pkg/minikube/exit"
"k8s.io/minikube/pkg/minikube/machine"
"k8s.io/minikube/pkg/minikube/out"
@ -41,21 +46,35 @@ var serviceListCmd = &cobra.Command{
exit.WithError("Error getting client", err)
}
defer api.Close()
profileName := viper.GetString(pkg_config.MachineProfile)
if !machine.IsHostRunning(api, profileName) {
exit.WithCodeT(exit.Unavailable, "profile {{.name}} is not running.", out.V{"name": profileName})
}
serviceURLs, err := service.GetServiceURLs(api, serviceListNamespace, serviceURLTemplate)
if err != nil {
out.FatalT("Failed to get service URL: {{.error}}", out.V{"error": err})
out.ErrT(out.Notice, "Check that minikube is running and that you have specified the correct namespace (-n flag) if required.")
os.Exit(exit.Unavailable)
}
cfg, err := config.Load(viper.GetString(config.MachineProfile))
if err != nil {
exit.WithError("Error getting config", err)
}
var data [][]string
for _, serviceURL := range serviceURLs {
if len(serviceURL.URLs) == 0 {
data = append(data, []string{serviceURL.Namespace, serviceURL.Name, "No node port"})
} else {
data = append(data, []string{serviceURL.Namespace, serviceURL.Name, strings.Join(serviceURL.URLs, "\n")})
}
serviceURLs := strings.Join(serviceURL.URLs, "\n")
// if we are running Docker on OSX we empty the internal service URLs
if runtime.GOOS == "darwin" && cfg.Driver == oci.Docker {
serviceURLs = ""
}
data = append(data, []string{serviceURL.Namespace, serviceURL.Name, "", serviceURLs})
}
}
service.PrintServiceList(os.Stdout, data)

View File

@ -436,12 +436,6 @@ func selectDriver(existing *config.ClusterConfig) registry.DriverState {
// Technically unrelated, but important to perform before detection
driver.SetLibvirtURI(viper.GetString(kvmQemuURI))
if viper.GetString("vm-driver") != "" {
ds := driver.Status(viper.GetString("vm-driver"))
out.T(out.Sparkle, `Using the {{.driver}} driver based on user configuration`, out.V{"driver": ds.String()})
return ds
}
// By default, the driver is whatever we used last time
if existing != nil && existing.Driver != "" {
ds := driver.Status(existing.Driver)
@ -449,6 +443,12 @@ func selectDriver(existing *config.ClusterConfig) registry.DriverState {
return ds
}
if viper.GetString("vm-driver") != "" {
ds := driver.Status(viper.GetString("vm-driver"))
out.T(out.Sparkle, `Using the {{.driver}} driver based on user configuration`, out.V{"driver": ds.String()})
return ds
}
pick, alts := driver.Suggest(driver.Choices())
if pick.Name == "" {
exit.WithCodeT(exit.Config, "Unable to determine a default driver to use. Try specifying --vm-driver, or see https://minikube.sigs.k8s.io/docs/start/")

View File

@ -7,8 +7,8 @@ menu "System tools"
source "$BR2_EXTERNAL_MINIKUBE_PATH/package/crictl-bin/Config.in"
source "$BR2_EXTERNAL_MINIKUBE_PATH/package/automount/Config.in"
source "$BR2_EXTERNAL_MINIKUBE_PATH/package/docker-bin/Config.in"
source "$BR2_EXTERNAL_MINIKUBE_PATH/package/cni-bin/Config.in"
source "$BR2_EXTERNAL_MINIKUBE_PATH/package/cni-plugins-bin/Config.in"
source "$BR2_EXTERNAL_MINIKUBE_PATH/package/cni/Config.in"
source "$BR2_EXTERNAL_MINIKUBE_PATH/package/cni-plugins/Config.in"
source "$BR2_EXTERNAL_MINIKUBE_PATH/package/hyperv-daemons/Config.in"
source "$BR2_EXTERNAL_MINIKUBE_PATH/package/gluster/Config.in"
source "$BR2_EXTERNAL_MINIKUBE_PATH/package/vbox-guest/Config.in"

View File

@ -1,4 +0,0 @@
config BR2_PACKAGE_CNI_BIN
bool "cni-bin"
default y
depends on BR2_x86_64

View File

@ -1,29 +0,0 @@
################################################################################
#
# cni-bin
#
################################################################################
CNI_BIN_VERSION = v0.6.0
CNI_BIN_SITE = https://github.com/containernetworking/cni/releases/download/$(CNI_BIN_VERSION)
CNI_BIN_SOURCE = cni-amd64-$(CNI_BIN_VERSION).tgz
define CNI_BIN_INSTALL_TARGET_CMDS
$(INSTALL) -D -m 0755 \
$(@D)/noop \
$(TARGET_DIR)/opt/cni/bin/noop
ln -sf \
../../opt/cni/bin/noop \
$(TARGET_DIR)/usr/bin/noop
$(INSTALL) -D -m 0755 \
$(@D)/noop \
$(TARGET_DIR)/opt/cni/bin/cnitool
ln -sf \
../../opt/cni/bin/cnitool \
$(TARGET_DIR)/usr/bin/cnitool
endef
$(eval $(generic-package))

View File

@ -1,4 +0,0 @@
config BR2_PACKAGE_CNI_PLUGINS_BIN
bool "cni-plugins-bin"
default y
depends on BR2_x86_64

View File

@ -0,0 +1,5 @@
config BR2_PACKAGE_CNI_PLUGINS
bool "cni-plugins"
default y
depends on BR2_x86_64
depends on BR2_PACKAGE_HOST_GO_ARCH_SUPPORTS

View File

@ -1 +1,2 @@
sha256 f04339a21b8edf76d415e7f17b620e63b8f37a76b2f706671587ab6464411f2d cni-plugins-amd64-v0.6.0.tgz
sha256 8589670f7f9b211a351dfcd211d4fe0b961d77283a7415443dc188f3dbf05668 v0.6.0.tar.gz

View File

@ -1,16 +1,30 @@
################################################################################
#
# cni-plugins-bin
# cni-plugins
#
################################################################################
CNI_PLUGINS_BIN_VERSION = v0.6.0
CNI_PLUGINS_BIN_SITE = https://github.com/containernetworking/plugins/releases/download/$(CNI_PLUGINS_BIN_VERSION)
CNI_PLUGINS_BIN_SOURCE = cni-plugins-amd64-$(CNI_PLUGINS_BIN_VERSION).tgz
CNI_PLUGINS_VERSION = v0.6.0
CNI_PLUGINS_SITE = https://github.com/containernetworking/plugins/archive
CNI_PLUGINS_SOURCE = $(CNI_PLUGINS_VERSION).tar.gz
CNI_PLUGINS_LICENSE = Apache-2.0
CNI_PLUGINS_LICENSE_FILES = LICENSE
define CNI_PLUGINS_BIN_INSTALL_TARGET_CMDS
CNI_PLUGINS_DEPENDENCIES = host-go
CNI_PLUGINS_MAKE_ENV = \
CGO_ENABLED=0 \
GO111MODULE=off
CNI_PLUGINS_BUILDFLAGS = -a --ldflags '-extldflags \"-static\"'
define CNI_PLUGINS_BUILD_CMDS
(cd $(@D); $(CNI_PLUGINS_MAKE_ENV) ./build.sh $(CNI_PLUGINS_BUILDFLAGS))
endef
define CNI_PLUGINS_INSTALL_TARGET_CMDS
$(INSTALL) -D -m 0755 \
$(@D)/bridge \
$(@D)/bin/bridge \
$(TARGET_DIR)/opt/cni/bin/bridge
ln -sf \
@ -18,7 +32,7 @@ define CNI_PLUGINS_BIN_INSTALL_TARGET_CMDS
$(TARGET_DIR)/usr/bin/bridge
$(INSTALL) -D -m 0755 \
$(@D)/vlan \
$(@D)/bin/vlan \
$(TARGET_DIR)/opt/cni/bin/vlan
ln -sf \
@ -26,7 +40,7 @@ define CNI_PLUGINS_BIN_INSTALL_TARGET_CMDS
$(TARGET_DIR)/usr/bin/vlan
$(INSTALL) -D -m 0755 \
$(@D)/tuning \
$(@D)/bin/tuning \
$(TARGET_DIR)/opt/cni/bin/tuning
ln -sf \
@ -34,7 +48,7 @@ define CNI_PLUGINS_BIN_INSTALL_TARGET_CMDS
$(TARGET_DIR)/usr/bin/tuning
$(INSTALL) -D -m 0755 \
$(@D)/sample \
$(@D)/bin/sample \
$(TARGET_DIR)/opt/cni/bin/sample
ln -sf \
@ -42,7 +56,7 @@ define CNI_PLUGINS_BIN_INSTALL_TARGET_CMDS
$(TARGET_DIR)/usr/bin/sample
$(INSTALL) -D -m 0755 \
$(@D)/ptp \
$(@D)/bin/ptp \
$(TARGET_DIR)/opt/cni/bin/ptp
ln -sf \
@ -50,7 +64,7 @@ define CNI_PLUGINS_BIN_INSTALL_TARGET_CMDS
$(TARGET_DIR)/usr/bin/ptp
$(INSTALL) -D -m 0755 \
$(@D)/portmap \
$(@D)/bin/portmap \
$(TARGET_DIR)/opt/cni/bin/portmap
ln -sf \
@ -58,7 +72,7 @@ define CNI_PLUGINS_BIN_INSTALL_TARGET_CMDS
$(TARGET_DIR)/usr/bin/portmap
$(INSTALL) -D -m 0755 \
$(@D)/macvlan \
$(@D)/bin/macvlan \
$(TARGET_DIR)/opt/cni/bin/macvlan
ln -sf \
@ -66,7 +80,7 @@ define CNI_PLUGINS_BIN_INSTALL_TARGET_CMDS
$(TARGET_DIR)/usr/bin/macvlan
$(INSTALL) -D -m 0755 \
$(@D)/loopback \
$(@D)/bin/loopback \
$(TARGET_DIR)/opt/cni/bin/loopback
ln -sf \
@ -74,7 +88,7 @@ define CNI_PLUGINS_BIN_INSTALL_TARGET_CMDS
$(TARGET_DIR)/usr/bin/loopback
$(INSTALL) -D -m 0755 \
$(@D)/ipvlan \
$(@D)/bin/ipvlan \
$(TARGET_DIR)/opt/cni/bin/ipvlan
ln -sf \
@ -82,7 +96,7 @@ define CNI_PLUGINS_BIN_INSTALL_TARGET_CMDS
$(TARGET_DIR)/usr/bin/ipvlan
$(INSTALL) -D -m 0755 \
$(@D)/host-local \
$(@D)/bin/host-local \
$(TARGET_DIR)/opt/cni/bin/host-local
ln -sf \
@ -90,7 +104,7 @@ define CNI_PLUGINS_BIN_INSTALL_TARGET_CMDS
$(TARGET_DIR)/usr/bin/host-local
$(INSTALL) -D -m 0755 \
$(@D)/flannel \
$(@D)/bin/flannel \
$(TARGET_DIR)/opt/cni/bin/flannel
ln -sf \
@ -99,7 +113,7 @@ define CNI_PLUGINS_BIN_INSTALL_TARGET_CMDS
$(INSTALL) -D -m 0755 \
$(@D)/dhcp \
$(@D)/bin/dhcp \
$(TARGET_DIR)/opt/cni/bin/dhcp
ln -sf \

View File

@ -0,0 +1,5 @@
config BR2_PACKAGE_CNI
bool "cni"
default y
depends on BR2_x86_64
depends on BR2_PACKAGE_HOST_GO_ARCH_SUPPORTS

View File

@ -1,3 +1,4 @@
sha256 b1ae09833a238c51161918a8849031efdb46cf0068ea5b752e362d9836e2af7d cni-v0.3.0.tgz
sha256 84c9a0a41b59211d560bef14bf3f53bb370156f9ac7762270b3848fed96e1be8 cni-v0.4.0.tgz
sha256 a7f84a742c8f3a95843b3cc636444742554a4853835649ec371a07c841daebab cni-amd64-v0.6.0.tgz
sha256 802f4a002b4eb774624a9dc1c859d3c9926eb2d862e66a673fc99cfc8bcd7494 v0.6.0.tar.gz

View File

@ -0,0 +1,43 @@
################################################################################
#
# cni
#
################################################################################
CNI_VERSION = v0.6.0
CNI_SITE = https://github.com/containernetworking/cni/archive
CNI_SOURCE = $(CNI_VERSION).tar.gz
CNI_LICENSE = Apache-2.0
CNI_LICENSE_FILES = LICENSE
CNI_DEPENDENCIES = host-go
CNI_MAKE_ENV = \
CGO_ENABLED=0 \
GO111MODULE=off
CNI_BUILDFLAGS = -a --ldflags '-extldflags \"-static\"'
define CNI_BUILD_CMDS
(cd $(@D); $(CNI_MAKE_ENV) ./build.sh $(CNI_BUILDFLAGS))
endef
define CNI_INSTALL_TARGET_CMDS
$(INSTALL) -D -m 0755 \
$(@D)/bin/noop \
$(TARGET_DIR)/opt/cni/bin/noop
ln -sf \
../../opt/cni/bin/noop \
$(TARGET_DIR)/usr/bin/noop
$(INSTALL) -D -m 0755 \
$(@D)/bin/cnitool \
$(TARGET_DIR)/opt/cni/bin/cnitool
ln -sf \
../../opt/cni/bin/cnitool \
$(TARGET_DIR)/usr/bin/cnitool
endef
$(eval $(generic-package))

View File

@ -1,4 +1,5 @@
# falco
sha256 87c60273c35d544256e471b403497be33f24df662673338236ec92ba3fc1f8b7 0.19.0.tar.gz
sha256 b873e3590e56ead740ed905108221f98da6100da3c5b7acf2355ea1cf628d931 0.20.0.tar.gz
# sysdig
sha256 6e477ac5fe9d3110b870bd4495f01541373a008c375a1934a2d1c46798b6bad6 146a431edf95829ac11bfd9c85ba3ef08789bffe.tar.gz

View File

@ -4,7 +4,7 @@
#
########################################################################
FALCO_PROBE_VERSION = 0.19.0
FALCO_PROBE_VERSION = 0.20.0
FALCO_PROBE_SITE = https://github.com/falcosecurity/falco/archive
FALCO_PROBE_SOURCE = $(FALCO_PROBE_VERSION).tar.gz
FALCO_PROBE_DEPENDENCIES += ncurses libyaml
@ -22,7 +22,6 @@ endef
FALCO_PROBE_POST_EXTRACT_HOOKS += FALCO_PROBE_SYSDIG_SRC
FALCO_PROBE_CONF_OPTS = -DFALCO_VERSION=$(FALCO_PROBE_VERSION)
FALCO_PROBE_CONF_OPTS += -DSYSDIG_VERSION=$(FALCO_PROBE_SYSDIG_VERSION)
FALCO_PROBE_CONF_OPTS += -DUSE_BUNDLED_DEPS=ON
FALCO_PROBE_MAKE_OPTS = driver KERNELDIR=$(LINUX_DIR)

View File

@ -33,7 +33,7 @@ export PATH=$PATH:"/usr/local/bin/:/usr/local/go/bin/:$GOPATH/bin"
# installing golang so we could do go get for gopogh
sudo ./installers/check_install_golang.sh "1.13.6" "/usr/local" || true
docker rm -f $(docker ps -aq) >/dev/null 2>&1 || true
docker rm -f -v $(docker ps -aq) >/dev/null 2>&1 || true
docker volume prune -f || true
docker system df || true

View File

@ -41,6 +41,13 @@ logger "cleanup_and_reboot is happening!"
# kill jenkins to avoid an incoming request
killall java
# clean docker left overs
docker rm -f -v $(docker ps -aq) >/dev/null 2>&1 || true
docker volume prune -f || true
docker volume ls || true
docker system df || true
# macOS specific cleanup
sudo rm /var/db/dhcpd_leases || echo "could not clear dhcpd leases"
sudo softwareupdate -i -a -R

View File

@ -36,6 +36,12 @@ logger "cleanup_and_reboot is happening!"
# kill jenkins to avoid an incoming request
killall java
# clean docker left overs
docker rm -f -v $(docker ps -aq) >/dev/null 2>&1 || true
docker volume prune -f || true
docker volume ls || true
docker system df || true
# Linux-specific cleanup
# disable localkube, kubelet

View File

@ -41,6 +41,7 @@ jobs=(
'KVM_Linux'
'none_Linux'
'Docker_Linux'
'Docker_macOS'
'Podman_Linux'
)

View File

@ -0,0 +1,44 @@
#!/bin/bash
# Copyright 2016 The Kubernetes Authors All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# This script runs the integration tests on an OSX machine for the Hyperkit Driver
# The script expects the following env variables:
# MINIKUBE_LOCATION: GIT_COMMIT from upstream build.
# COMMIT: Actual commit ID from upstream build
# EXTRA_BUILD_ARGS (optional): Extra args to be passed into the minikube integrations tests
# access_token: The Github API access token. Injected by the Jenkins credential provider.
set -e
OS_ARCH="darwin-amd64"
VM_DRIVER="docker"
JOB_NAME="Docker_macOS"
EXTRA_START_ARGS=""
EXPECTED_DEFAULT_DRIVER="hyperkit"
# restart docker on mac for a fresh test
osascript -e 'quit app "Docker"'; open -a Docker ; while [ -z "$(docker info 2> /dev/null )" ]; do printf "."; sleep 1; done; echo "" || true
mkdir -p cron && gsutil -qm rsync "gs://minikube-builds/${MINIKUBE_LOCATION}/cron" cron || echo "FAILED TO GET CRON FILES"
install cron/cleanup_and_reboot_Darwin.sh $HOME/cleanup_and_reboot.sh || echo "FAILED TO INSTALL CLEANUP"
echo "*/30 * * * * $HOME/cleanup_and_reboot.sh" | crontab
crontab -l
source common.sh

View File

@ -21,9 +21,20 @@ import (
"fmt"
"os"
"os/exec"
"path"
"path/filepath"
"runtime"
"github.com/pkg/errors"
"golang.org/x/sync/errgroup"
"k8s.io/minikube/pkg/drivers/kic"
"k8s.io/minikube/pkg/drivers/kic/oci"
"k8s.io/minikube/pkg/minikube/bootstrapper/images"
"k8s.io/minikube/pkg/minikube/constants"
"k8s.io/minikube/pkg/minikube/driver"
"k8s.io/minikube/pkg/minikube/localpath"
"k8s.io/minikube/pkg/minikube/machine"
"k8s.io/minikube/pkg/minikube/vmpath"
)
const (
@ -55,9 +66,81 @@ func executePreloadImages() error {
fmt.Println(err)
}
}()
if err := startMinikube(); err != nil {
driver := kic.NewDriver(kic.Config{
KubernetesVersion: kubernetesVersion,
ContainerRuntime: driver.Docker,
OCIBinary: oci.Docker,
MachineName: profile,
ImageDigest: kic.BaseImage,
StorePath: localpath.MiniPath(),
CPU: 2,
Memory: 4000,
APIServerPort: 8080,
})
baseDir := filepath.Dir(driver.GetSSHKeyPath())
defer os.Remove(baseDir)
if err := os.MkdirAll(baseDir, 0755); err != nil {
return err
}
if err := driver.Create(); err != nil {
return errors.Wrap(err, "creating kic driver")
}
// Now, get images to pull
imgs, err := images.Kubeadm("", kubernetesVersion)
if err != nil {
return errors.Wrap(err, "kubeadm images")
}
for _, img := range append(imgs, kic.OverlayImage) {
cmd := exec.Command("docker", "exec", profile, "docker", "pull", img)
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
if err := cmd.Run(); err != nil {
return errors.Wrapf(err, "downloading %s", img)
}
}
// Transfer in binaries
var g errgroup.Group
dir := filepath.Join(vmpath.GuestPersistentDir, "binaries")
mkdirCmd := exec.Command("docker", "exec", profile, "mkdir", "-p", dir)
if err := mkdirCmd.Run(); err != nil {
return err
}
for _, name := range constants.KubernetesReleaseBinaries {
name := name
g.Go(func() error {
src, err := machine.CacheBinary(name, kubernetesVersion, "linux", runtime.GOARCH)
if err != nil {
return errors.Wrapf(err, "downloading %s", name)
}
dst := path.Join(dir, name)
copyCmd := exec.Command("docker", "cp", src, fmt.Sprintf("%s:%s", profile, dst))
copyCmd.Stdout = os.Stdout
copyCmd.Stderr = os.Stderr
fmt.Println(copyCmd.Args)
if err := copyCmd.Run(); err != nil {
return errors.Wrapf(err, "copybinary %s -> %s", src, dst)
}
return nil
})
}
if err := g.Wait(); err != nil {
return errors.Wrap(err, "pulling binaries")
}
// Delete /var/lib/docker/network
if err := deleteDirInMinikube("/var/lib/docker/network"); err != nil {
return errors.Wrap(err, "deleting dir")
}
// Create image tarball
if err := createImageTarball(); err != nil {
return err
}
@ -65,13 +148,13 @@ func executePreloadImages() error {
}
func startMinikube() error {
cmd := exec.Command(minikubePath, "start", "-p", profile, "--memory", "4000", "--kubernetes-version", kubernetesVersion, "--wait=false", "--vm-driver=docker")
cmd := exec.Command(minikubePath, "start", "-p", profile, "--memory", "4000", "--kubernetes-version", kubernetesVersion, "--vm-driver=docker")
cmd.Stdout = os.Stdout
return cmd.Run()
}
func createImageTarball() error {
cmd := exec.Command(minikubePath, "ssh", "-p", profile, "--", "cd", "/var", "&&", "sudo", "tar", "-I", "lz4", "-cvf", tarballFilename, "./lib/docker", "./lib/minikube/binaries")
cmd := exec.Command("docker", "exec", profile, "sudo", "tar", "-I", "lz4", "-C", "/var/lib/docker", "-cvf", tarballFilename, "./")
cmd.Stdout = os.Stdout
if err := cmd.Run(); err != nil {
return errors.Wrap(err, "creating image tarball")
@ -79,9 +162,18 @@ func createImageTarball() error {
return nil
}
func deleteDirInMinikube(dir string) error {
cmd := exec.Command("docker", "exec", profile, "sudo", "rm", "-rf", dir)
cmd.Stdout = os.Stdout
if err := cmd.Run(); err != nil {
return errors.Wrapf(err, "deleting %s", dir)
}
return nil
}
func copyTarballToHost() error {
dest := filepath.Join("out/", tarballFilename)
cmd := exec.Command("docker", "cp", fmt.Sprintf("%s:/var/%s", profile, tarballFilename), dest)
cmd := exec.Command("docker", "cp", fmt.Sprintf("%s:/%s", profile, tarballFilename), dest)
cmd.Stdout = os.Stdout
if err := cmd.Run(); err != nil {
return errors.Wrap(err, "copying tarball to host")

View File

@ -118,6 +118,9 @@ func enableOrDisableAddon(name, val, profile string) error {
if alreadySet {
glog.Warningf("addon %s should already be in state %v", name, val)
if !enable {
return nil
}
}
if name == "istio" && enable {

View File

@ -17,6 +17,7 @@ limitations under the License.
package kic
import (
"context"
"fmt"
"net"
"os/exec"
@ -30,13 +31,12 @@ import (
"github.com/docker/machine/libmachine/state"
"github.com/golang/glog"
"github.com/pkg/errors"
"github.com/spf13/viper"
pkgdrivers "k8s.io/minikube/pkg/drivers"
"k8s.io/minikube/pkg/drivers/kic/oci"
"k8s.io/minikube/pkg/minikube/assets"
"k8s.io/minikube/pkg/minikube/command"
"k8s.io/minikube/pkg/minikube/config"
"k8s.io/minikube/pkg/minikube/constants"
"k8s.io/minikube/pkg/minikube/preload"
)
// Driver represents a kic driver https://minikube.sigs.k8s.io/docs/reference/drivers/docker
@ -91,22 +91,22 @@ func (d *Driver) Create() error {
ContainerPort: constants.DockerDaemonPort,
},
)
t := time.Now()
glog.Infof("Starting creating preloaded images volume")
volumeName, err := oci.CreatePreloadedImagesVolume(d.NodeConfig.KubernetesVersion, d.NodeConfig.ContainerRuntime, BaseImage, viper.GetString(config.MachineProfile))
if err != nil {
glog.Infof("Unable to create preloaded images volume: %v", err)
}
glog.Infof("Finished creating preloaded images volume in %f seconds", time.Since(t).Seconds())
params.PreloadedVolume = volumeName
err = oci.CreateContainerNode(params)
if err != nil {
if err := oci.CreateContainerNode(params); err != nil {
return errors.Wrap(err, "create kic node")
}
if err := d.prepareSSH(); err != nil {
return errors.Wrap(err, "prepare kic ssh")
}
t := time.Now()
glog.Infof("Starting extracting preloaded images to volume")
// Extract preloaded images to container
if err := oci.ExtractTarballToVolume(preload.TarballFilepath(d.NodeConfig.KubernetesVersion), params.Name, BaseImage); err != nil {
return errors.Wrap(err, "extracting tarball to volume")
}
glog.Infof("Took %f seconds to extract preloaded images to volume", time.Since(t).Seconds())
return nil
}
@ -192,11 +192,18 @@ func (d *Driver) GetURL() (string, error) {
// GetState returns the state that the host is in (running, stopped, etc)
func (d *Driver) GetState() (state.State, error) {
if err := oci.PointToHostDockerDaemon(); err != nil {
return state.Error, errors.Wrap(err, "point host docker-daemon")
return state.Error, errors.Wrap(err, "point host docker daemon")
}
// allow no more than 2 seconds for this. when this takes long this means deadline passed
ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
defer cancel()
cmd := exec.Command(d.NodeConfig.OCIBinary, "inspect", "-f", "{{.State.Status}}", d.MachineName)
cmd := exec.CommandContext(ctx, d.NodeConfig.OCIBinary, "inspect", "-f", "{{.State.Status}}", d.MachineName)
out, err := cmd.CombinedOutput()
if ctx.Err() == context.DeadlineExceeded {
glog.Errorf("GetState for %s took longer than normal. Restarting your %s daemon might fix this issue.", d.MachineName, d.OCIBinary)
return state.Error, fmt.Errorf("inspect %s timeout", d.MachineName)
}
o := strings.TrimSpace(string(out))
if err != nil {
return state.Error, errors.Wrapf(err, "get container %s status", d.MachineName)

245
pkg/drivers/kic/oci/info.go Normal file
View File

@ -0,0 +1,245 @@
/*
Copyright 2019 The Kubernetes Authors All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package oci
import (
"encoding/json"
"os/exec"
"strings"
"time"
"github.com/pkg/errors"
)
// SysInfo Info represents common system Information between docker and podman that minikube cares
type SysInfo struct {
CPUs int // CPUs is Number of CPUs
TotalMemory int64 // TotalMemory Total available ram
}
// DaemonInfo returns common docker/podman daemon system info that minikube cares about
func DaemonInfo(ociBin string) (SysInfo, error) {
var info SysInfo
if ociBin == Podman {
p, err := podmanSystemInfo()
info.CPUs = p.Host.Cpus
info.TotalMemory = p.Host.MemTotal
return info, err
}
d, err := dockerSystemInfo()
info.CPUs = d.NCPU
info.TotalMemory = d.MemTotal
return info, err
}
// dockerSysInfo represents the output of docker system info --format '{{json .}}'
type dockerSysInfo struct {
ID string `json:"ID"`
Containers int `json:"Containers"`
ContainersRunning int `json:"ContainersRunning"`
ContainersPaused int `json:"ContainersPaused"`
ContainersStopped int `json:"ContainersStopped"`
Images int `json:"Images"`
Driver string `json:"Driver"`
DriverStatus [][]string `json:"DriverStatus"`
SystemStatus interface{} `json:"SystemStatus"`
Plugins struct {
Volume []string `json:"Volume"`
Network []string `json:"Network"`
Authorization interface{} `json:"Authorization"`
Log []string `json:"Log"`
} `json:"Plugins"`
MemoryLimit bool `json:"MemoryLimit"`
SwapLimit bool `json:"SwapLimit"`
KernelMemory bool `json:"KernelMemory"`
KernelMemoryTCP bool `json:"KernelMemoryTCP"`
CPUCfsPeriod bool `json:"CpuCfsPeriod"`
CPUCfsQuota bool `json:"CpuCfsQuota"`
CPUShares bool `json:"CPUShares"`
CPUSet bool `json:"CPUSet"`
PidsLimit bool `json:"PidsLimit"`
IPv4Forwarding bool `json:"IPv4Forwarding"`
BridgeNfIptables bool `json:"BridgeNfIptables"`
BridgeNfIP6Tables bool `json:"BridgeNfIp6tables"`
Debug bool `json:"Debug"`
NFd int `json:"NFd"`
OomKillDisable bool `json:"OomKillDisable"`
NGoroutines int `json:"NGoroutines"`
SystemTime time.Time `json:"SystemTime"`
LoggingDriver string `json:"LoggingDriver"`
CgroupDriver string `json:"CgroupDriver"`
NEventsListener int `json:"NEventsListener"`
KernelVersion string `json:"KernelVersion"`
OperatingSystem string `json:"OperatingSystem"`
OSType string `json:"OSType"`
Architecture string `json:"Architecture"`
IndexServerAddress string `json:"IndexServerAddress"`
RegistryConfig struct {
AllowNondistributableArtifactsCIDRs []interface{} `json:"AllowNondistributableArtifactsCIDRs"`
AllowNondistributableArtifactsHostnames []interface{} `json:"AllowNondistributableArtifactsHostnames"`
InsecureRegistryCIDRs []string `json:"InsecureRegistryCIDRs"`
IndexConfigs struct {
DockerIo struct {
Name string `json:"Name"`
Mirrors []interface{} `json:"Mirrors"`
Secure bool `json:"Secure"`
Official bool `json:"Official"`
} `json:"docker.io"`
} `json:"IndexConfigs"`
Mirrors []interface{} `json:"Mirrors"`
} `json:"RegistryConfig"`
NCPU int `json:"NCPU"`
MemTotal int64 `json:"MemTotal"`
GenericResources interface{} `json:"GenericResources"`
DockerRootDir string `json:"DockerRootDir"`
HTTPProxy string `json:"HttpProxy"`
HTTPSProxy string `json:"HttpsProxy"`
NoProxy string `json:"NoProxy"`
Name string `json:"Name"`
Labels []interface{} `json:"Labels"`
ExperimentalBuild bool `json:"ExperimentalBuild"`
ServerVersion string `json:"ServerVersion"`
ClusterStore string `json:"ClusterStore"`
ClusterAdvertise string `json:"ClusterAdvertise"`
Runtimes struct {
Runc struct {
Path string `json:"path"`
} `json:"runc"`
} `json:"Runtimes"`
DefaultRuntime string `json:"DefaultRuntime"`
Swarm struct {
NodeID string `json:"NodeID"`
NodeAddr string `json:"NodeAddr"`
LocalNodeState string `json:"LocalNodeState"`
ControlAvailable bool `json:"ControlAvailable"`
Error string `json:"Error"`
RemoteManagers interface{} `json:"RemoteManagers"`
} `json:"Swarm"`
LiveRestoreEnabled bool `json:"LiveRestoreEnabled"`
Isolation string `json:"Isolation"`
InitBinary string `json:"InitBinary"`
ContainerdCommit struct {
ID string `json:"ID"`
Expected string `json:"Expected"`
} `json:"ContainerdCommit"`
RuncCommit struct {
ID string `json:"ID"`
Expected string `json:"Expected"`
} `json:"RuncCommit"`
InitCommit struct {
ID string `json:"ID"`
Expected string `json:"Expected"`
} `json:"InitCommit"`
SecurityOptions []string `json:"SecurityOptions"`
ProductLicense string `json:"ProductLicense"`
Warnings interface{} `json:"Warnings"`
ClientInfo struct {
Debug bool `json:"Debug"`
Plugins []interface{} `json:"Plugins"`
Warnings interface{} `json:"Warnings"`
} `json:"ClientInfo"`
}
// podmanSysInfo represents the output of podman system info --format '{{json .}}'
type podmanSysInfo struct {
Host struct {
BuildahVersion string `json:"BuildahVersion"`
CgroupVersion string `json:"CgroupVersion"`
Conmon struct {
Package string `json:"package"`
Path string `json:"path"`
Version string `json:"version"`
} `json:"Conmon"`
Distribution struct {
Distribution string `json:"distribution"`
Version string `json:"version"`
} `json:"Distribution"`
MemFree int `json:"MemFree"`
MemTotal int64 `json:"MemTotal"`
OCIRuntime struct {
Name string `json:"name"`
Package string `json:"package"`
Path string `json:"path"`
Version string `json:"version"`
} `json:"OCIRuntime"`
SwapFree int `json:"SwapFree"`
SwapTotal int `json:"SwapTotal"`
Arch string `json:"arch"`
Cpus int `json:"cpus"`
Eventlogger string `json:"eventlogger"`
Hostname string `json:"hostname"`
Kernel string `json:"kernel"`
Os string `json:"os"`
Rootless bool `json:"rootless"`
Uptime string `json:"uptime"`
} `json:"host"`
Registries struct {
Search []string `json:"search"`
} `json:"registries"`
Store struct {
ConfigFile string `json:"ConfigFile"`
ContainerStore struct {
Number int `json:"number"`
} `json:"ContainerStore"`
GraphDriverName string `json:"GraphDriverName"`
GraphOptions struct {
} `json:"GraphOptions"`
GraphRoot string `json:"GraphRoot"`
GraphStatus struct {
BackingFilesystem string `json:"Backing Filesystem"`
NativeOverlayDiff string `json:"Native Overlay Diff"`
SupportsDType string `json:"Supports d_type"`
UsingMetacopy string `json:"Using metacopy"`
} `json:"GraphStatus"`
ImageStore struct {
Number int `json:"number"`
} `json:"ImageStore"`
RunRoot string `json:"RunRoot"`
VolumePath string `json:"VolumePath"`
} `json:"store"`
}
// dockerSystemInfo returns docker system info --format '{{json .}}'
func dockerSystemInfo() (dockerSysInfo, error) {
var ds dockerSysInfo
if err := PointToHostDockerDaemon(); err != nil {
return ds, errors.Wrap(err, "point host docker-daemon")
}
cmd := exec.Command(Docker, "system", "info", "--format", "{{json .}}")
out, err := cmd.CombinedOutput()
if err != nil {
return ds, errors.Wrap(err, "get docker system info")
}
if err := json.Unmarshal([]byte(strings.TrimSpace(string(out))), &ds); err != nil {
return ds, errors.Wrapf(err, "unmarshal docker system info")
}
return ds, nil
}
// podmanSysInfo returns podman system info --format '{{json .}}'
func podmanSystemInfo() (podmanSysInfo, error) {
var ps podmanSysInfo
cmd := exec.Command(Podman, "system", "info", "--format", "'{{json .}}'")
out, err := cmd.CombinedOutput()
if err != nil {
return ps, errors.Wrap(err, "get podman system info")
}
if err := json.Unmarshal([]byte(strings.TrimSpace(string(out))), &ps); err != nil {
return ps, errors.Wrapf(err, "unmarshal podman system info")
}
return ps, nil
}

View File

@ -43,7 +43,7 @@ func RoutableHostIPFromInside(ociBin string, containerName string) (net.IP, erro
// digDNS will get the IP record for a dns
func digDNS(ociBin, containerName, dns string) (net.IP, error) {
if err := PointToHostDockerDaemon(); err != nil {
return nil, errors.Wrap(err, "point host docker-daemon")
return nil, errors.Wrap(err, "point host docker daemon")
}
cmd := exec.Command(ociBin, "exec", "-t", containerName, "dig", "+short", dns)
out, err := cmd.CombinedOutput()
@ -59,7 +59,7 @@ func digDNS(ociBin, containerName, dns string) (net.IP, error) {
// gets the ip from user's host docker
func dockerGatewayIP() (net.IP, error) {
if err := PointToHostDockerDaemon(); err != nil {
return nil, errors.Wrap(err, "point host docker-daemon")
return nil, errors.Wrap(err, "point host docker daemon")
}
cmd := exec.Command(Docker, "network", "ls", "--filter", "name=bridge", "--format", "{{.ID}}")
out, err := cmd.CombinedOutput()

View File

@ -99,15 +99,11 @@ func CreateContainerNode(p CreateParams) error {
runArgs = append(runArgs, "--volume", fmt.Sprintf("%s:/var:exec", hostVarVolPath))
}
if p.OCIBinary == Docker {
volumeName := p.PreloadedVolume
if volumeName == "" {
if err := createDockerVolume(p.Name); err != nil {
return errors.Wrapf(err, "creating volume for %s container", p.Name)
}
glog.Infof("Successfully created a docker volume %s", p.Name)
volumeName = p.Name
if err := createDockerVolume(p.Name); err != nil {
return errors.Wrapf(err, "creating volume for %s container", p.Name)
}
runArgs = append(runArgs, "--volume", fmt.Sprintf("%s:/var", volumeName))
glog.Infof("Successfully created a docker volume %s", p.Name)
runArgs = append(runArgs, "--volume", fmt.Sprintf("%s:%s", p.Name, "/var"))
// setting resource limit in privileged mode is only supported by docker
// podman error: "Error: invalid configuration, cannot set resources with rootless containers not using cgroups v2 unified mode"
runArgs = append(runArgs, fmt.Sprintf("--cpus=%s", p.CPUs), fmt.Sprintf("--memory=%s", p.Memory))

View File

@ -19,9 +19,11 @@ package oci
import (
"bufio"
"bytes"
"context"
"fmt"
"os/exec"
"strings"
"time"
"github.com/golang/glog"
"github.com/pkg/errors"
@ -35,7 +37,7 @@ func DeleteAllVolumesByLabel(ociBin string, label string) []error {
glog.Infof("trying to delete all %s volumes with label %s", ociBin, label)
if ociBin == Docker {
if err := PointToHostDockerDaemon(); err != nil {
return []error{errors.Wrap(err, "point host docker-daemon")}
return []error{errors.Wrap(err, "point host docker daemon")}
}
}
@ -43,9 +45,15 @@ func DeleteAllVolumesByLabel(ociBin string, label string) []error {
if err != nil {
return []error{fmt.Errorf("listing volumes by label %q: %v", label, err)}
}
for _, v := range vs {
cmd := exec.Command(ociBin, "volume", "rm", "--force", v)
// allow no more than 3 seconds for this. when this takes long this means deadline passed
ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
defer cancel()
cmd := exec.CommandContext(ctx, ociBin, "volume", "rm", "--force", v)
if ctx.Err() == context.DeadlineExceeded {
glog.Warningf("removing volume with label %s took longer than normal. Restarting your %s daemon might fix this issue.", label, ociBin)
deleteErrs = append(deleteErrs, fmt.Errorf("delete deadline exceeded for %s", label))
}
if out, err := cmd.CombinedOutput(); err != nil {
deleteErrs = append(deleteErrs, fmt.Errorf("deleting volume %s: output: %s", v, string(out)))
}
@ -61,15 +69,22 @@ func PruneAllVolumesByLabel(ociBin string, label string) []error {
glog.Infof("trying to prune all %s volumes with label %s", ociBin, label)
if ociBin == Docker {
if err := PointToHostDockerDaemon(); err != nil {
return []error{errors.Wrap(err, "point host docker-daemon")}
return []error{errors.Wrap(err, "point host docker daemon")}
}
}
// allow no more than 3 seconds for this. when this takes long this means deadline passed
ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
defer cancel()
// try to prune afterwards just in case delete didn't go through
cmd := exec.Command(ociBin, "volume", "prune", "-f", "--filter", "label="+label)
cmd := exec.CommandContext(ctx, ociBin, "volume", "prune", "-f", "--filter", "label="+label)
if out, err := cmd.CombinedOutput(); err != nil {
deleteErrs = append(deleteErrs, errors.Wrapf(err, "prune volume by label %s: %s", label, string(out)))
}
if ctx.Err() == context.DeadlineExceeded {
glog.Warningf("pruning volume with label %s took longer than normal. Restarting your %s daemon might fix this issue.", label, ociBin)
deleteErrs = append(deleteErrs, fmt.Errorf("prune deadline exceeded for %s", label))
}
return deleteErrs
}
@ -108,7 +123,7 @@ func CreatePreloadedImagesVolume(k8sVersion, cRuntime, baseImage, profile string
}
tarballPath := preload.TarballFilepath(k8sVersion)
if err := extractTarballToVolume(tarballPath, volumeName, baseImage); err != nil {
if err := ExtractTarballToVolume(tarballPath, volumeName, baseImage); err != nil {
// If the extraction didn't work, delete the corrupt docker volume
if err := deleteDockerVolume(volumeName); err != nil {
glog.Warningf("Corrupt docker volume %s was not deleted successfully. You may need to delete it manually via `docker volume rm %s` for minikube to continue to work.", volumeName, volumeName)
@ -137,9 +152,9 @@ func dockerVolumeExists(name string) bool {
return false
}
// extractTarballToVolume runs a docker image imageName which extracts the tarball at tarballPath
// ExtractTarballToVolume runs a docker image imageName which extracts the tarball at tarballPath
// to the volume named volumeName
func extractTarballToVolume(tarballPath, volumeName, imageName string) error {
func ExtractTarballToVolume(tarballPath, volumeName, imageName string) error {
if err := PointToHostDockerDaemon(); err != nil {
return errors.Wrap(err, "point host docker-daemon")
}
@ -155,7 +170,7 @@ func extractTarballToVolume(tarballPath, volumeName, imageName string) error {
// TODO: this should be fixed as a part of https://github.com/kubernetes/minikube/issues/6530
func createDockerVolume(name string) error {
if err := PointToHostDockerDaemon(); err != nil {
return errors.Wrap(err, "point host docker-daemon")
return errors.Wrap(err, "point host docker daemon")
}
cmd := exec.Command(Docker, "volume", "create", name, "--label", fmt.Sprintf("%s=%s", ProfileLabelKey, name), "--label", fmt.Sprintf("%s=%s", CreatedByLabelKey, "true"))
if out, err := cmd.CombinedOutput(); err != nil {

View File

@ -21,6 +21,7 @@ import (
"io/ioutil"
"os"
"path/filepath"
"runtime"
"strings"
"time"
@ -36,11 +37,17 @@ import (
"k8s.io/minikube/pkg/minikube/constants"
)
var defaultPlatform = v1.Platform{
Architecture: runtime.GOARCH,
OS: "linux",
}
// DigestByDockerLib uses client by docker lib to return image digest
// img.ID in as same as image digest
func DigestByDockerLib(imgClient *client.Client, imgName string) string {
ctx, cancel := context.WithTimeout(context.Background(), time.Second*10)
defer cancel()
imgClient.NegotiateAPIVersion(ctx)
img, _, err := imgClient.ImageInspectWithRaw(ctx, imgName)
if err != nil && !client.IsErrNotFound(err) {
glog.Infof("couldn't find image digest %s from local daemon: %v ", imgName, err)
@ -111,7 +118,8 @@ func retrieveImage(ref name.Reference) (v1.Image, error) {
glog.Infof("daemon lookup for %+v: %v", ref, err)
}
img, err = remote.Image(ref, remote.WithAuthFromKeychain(authn.DefaultKeychain))
platform := defaultPlatform
img, err = remote.Image(ref, remote.WithAuthFromKeychain(authn.DefaultKeychain), remote.WithPlatform(platform))
if err == nil {
return img, nil
}

View File

@ -17,7 +17,9 @@ limitations under the License.
package machine
import (
"context"
"os/exec"
"time"
"github.com/docker/machine/libmachine"
"github.com/docker/machine/libmachine/mcnerror"
@ -29,10 +31,30 @@ import (
"k8s.io/minikube/pkg/minikube/out"
)
// deleteOrphanedKIC attempts to delete an orphaned docker instance
func deleteOrphanedKIC(name string) {
cmd := exec.Command(oci.Docker, "rm", "-f", "-v", name)
err := cmd.Run()
// deleteOrphanedKIC attempts to delete an orphaned docker instance for machines without a config file
// used as last effort clean up not returning errors, wont warn user.
func deleteOrphanedKIC(ociBin string, name string) {
if !(ociBin == oci.Podman || ociBin == oci.Docker) {
return
}
if ociBin == oci.Docker {
if err := oci.PointToHostDockerDaemon(); err != nil {
glog.Infof("Failed to point to host docker-damon: %v", err)
return
}
}
_, err := oci.ContainerStatus(ociBin, name)
if err != nil {
glog.Infof("couldn't inspect container %q before deleting, %s-daemon might needs a restart!: %v", name, ociBin, err)
return
}
// allow no more than 5 seconds for delting the container
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
cmd := exec.CommandContext(ctx, ociBin, "rm", "-f", "-v", name)
err = cmd.Run()
if err == nil {
glog.Infof("Found stale kic container and successfully cleaned it up!")
}
@ -42,7 +64,8 @@ func deleteOrphanedKIC(name string) {
func DeleteHost(api libmachine.API, machineName string) error {
host, err := api.Load(machineName)
if err != nil && host == nil {
deleteOrphanedKIC(machineName)
deleteOrphanedKIC(oci.Docker, machineName)
deleteOrphanedKIC(oci.Podman, machineName)
// Keep going even if minikube does not know about the host
}

View File

@ -29,13 +29,13 @@ import (
)
type hostInfo struct {
Memory int
Memory int64
CPUs int
DiskSize int
DiskSize int64
}
func megs(bytes uint64) int {
return int(bytes / 1024 / 1024)
func megs(bytes uint64) int64 {
return int64(bytes / 1024 / 1024)
}
func getHostInfo() (*hostInfo, error) {

View File

@ -32,6 +32,7 @@ import (
"github.com/juju/mutex"
"github.com/pkg/errors"
"github.com/spf13/viper"
"k8s.io/minikube/pkg/drivers/kic/oci"
"k8s.io/minikube/pkg/minikube/command"
"k8s.io/minikube/pkg/minikube/config"
"k8s.io/minikube/pkg/minikube/constants"
@ -259,10 +260,13 @@ func showHostInfo(cfg config.ClusterConfig) {
}
return
}
if driver.IsKIC(cfg.Driver) {
info, err := getHostInfo() // TODO medyagh: get docker-machine info for non linux
if driver.IsKIC(cfg.Driver) { // TODO:medyagh add free disk space on docker machine
s, err := oci.DaemonInfo(cfg.Driver)
if err == nil {
out.T(out.StartingVM, "Creating Kubernetes in {{.driver_name}} container with (CPUs={{.number_of_cpus}}), Memory={{.memory_size}}MB ({{.host_memory_size}}MB available) ...", out.V{"driver_name": cfg.Driver, "number_of_cpus": cfg.CPUs, "number_of_host_cpus": info.CPUs, "memory_size": cfg.Memory, "host_memory_size": info.Memory})
var info hostInfo
info.CPUs = s.CPUs
info.Memory = megs(uint64(s.TotalMemory))
out.T(out.StartingVM, "Creating Kubernetes in {{.driver_name}} container with (CPUs={{.number_of_cpus}}) ({{.number_of_host_cpus}} available), Memory={{.memory_size}}MB ({{.host_memory_size}}MB available) ...", out.V{"driver_name": cfg.Driver, "number_of_cpus": cfg.CPUs, "number_of_host_cpus": info.CPUs, "memory_size": cfg.Memory, "host_memory_size": info.Memory})
}
return
}

View File

@ -154,12 +154,15 @@ func trySSH(h *host.Host, ip string) {
func tryLookup(r command.Runner) {
// DNS check
if rr, err := r.RunCmd(exec.Command("nslookup", "kubernetes.io", "-type=ns")); err != nil {
if rr, err := r.RunCmd(exec.Command("nslookup", "-type=ns", "kubernetes.io")); err != nil {
glog.Infof("%s failed: %v which might be okay will retry nslookup without query type", rr.Args, err)
// will try with without query type for ISOs with different busybox versions.
if _, err = r.RunCmd(exec.Command("nslookup", "kubernetes.io")); err != nil {
glog.Warningf("nslookup failed: %v", err)
out.WarningT("Node may be unable to resolve external DNS records")
// try with the older "host" command, instead of the newer "nslookup"
if _, err = r.RunCmd(exec.Command("host", "kubernetes.io")); err != nil {
out.WarningT("Node may be unable to resolve external DNS records")
}
}
}
}

View File

@ -85,14 +85,22 @@ func status() registry.State {
return registry.State{Error: err}
}
// Allow no more than 2 seconds for querying state
ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
ctx, cancel := context.WithTimeout(context.Background(), 8*time.Second)
defer cancel()
cmd := exec.CommandContext(ctx, path, "Get-WindowsOptionalFeature", "-FeatureName", "Microsoft-Hyper-V-All", "-Online")
out, err := cmd.CombinedOutput()
if err != nil {
return registry.State{Installed: false, Error: fmt.Errorf("%s failed:\n%s", strings.Join(cmd.Args, " "), out), Fix: "Start PowerShell as Administrator, and run: 'Enable-WindowsOptionalFeature -Online -FeatureName Microsoft-Hyper-V -All'", Doc: docURL}
errorMessage := fmt.Errorf("%s failed:\n%s", strings.Join(cmd.Args, " "), out)
fixMessage := "Start PowerShell as Administrator, and run: 'Enable-WindowsOptionalFeature -Online -FeatureName Microsoft-Hyper-V -All'"
// If timed out, prompt different error and suggestion messages
// See https://github.com/kubernetes/minikube/issues/6579
if ctx.Err() != nil {
errorMessage = fmt.Errorf("%s exited unexpectedly:\n%s", strings.Join(cmd.Args, " "), ctx.Err())
fixMessage = "If you have Hyper-V configured correctly, please try start again with `--force` specified"
}
return registry.State{Installed: false, Error: errorMessage, Fix: fixMessage, Doc: docURL}
}
return registry.State{Installed: true, Healthy: true}
}

View File

@ -48,9 +48,9 @@ import (
const (
defaultK8sClientTimeout = 60 * time.Second
// DefaultWait is the default wait time, in seconds
DefaultWait = 20
DefaultWait = 2
// DefaultInterval is the default interval, in seconds
DefaultInterval = 6
DefaultInterval = 1
)
// K8sClient represents a kubernetes client

View File

@ -0,0 +1,81 @@
/*
Copyright 2020 The Kubernetes Authors All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package kic
import (
"fmt"
"github.com/golang/glog"
"github.com/pkg/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
typed_core "k8s.io/client-go/kubernetes/typed/core/v1"
)
// ServiceTunnel ...
type ServiceTunnel struct {
sshPort string
sshKey string
v1Core typed_core.CoreV1Interface
sshConn *sshConn
}
// NewServiceTunnel ...
func NewServiceTunnel(sshPort, sshKey string, v1Core typed_core.CoreV1Interface) *ServiceTunnel {
return &ServiceTunnel{
sshPort: sshPort,
sshKey: sshKey,
v1Core: v1Core,
}
}
// Start ...
func (t *ServiceTunnel) Start(svcName, namespace string) ([]string, error) {
svc, err := t.v1Core.Services(namespace).Get(svcName, metav1.GetOptions{})
if err != nil {
return nil, errors.Wrap(err, "getting service")
}
t.sshConn, err = createSSHConnWithRandomPorts(svcName, t.sshPort, t.sshKey, svc)
if err != nil {
return nil, errors.Wrap(err, "creating ssh conn")
}
go func() {
err = t.sshConn.startAndWait()
if err != nil {
glog.Errorf("error starting ssh tunnel: %v", err)
}
}()
urls := make([]string, 0, len(svc.Spec.Ports))
for _, port := range t.sshConn.ports {
urls = append(urls, fmt.Sprintf("http://127.0.0.1:%d", port))
}
return urls, nil
}
// Stop ...
func (t *ServiceTunnel) Stop() error {
err := t.sshConn.stop()
if err != nil {
return errors.Wrap(err, "stopping ssh tunnel")
}
return nil
}

View File

@ -1,26 +1,52 @@
/*
Copyright 2020 The Kubernetes Authors All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package kic
import (
"fmt"
"os/exec"
"github.com/phayes/freeport"
v1 "k8s.io/api/core/v1"
"k8s.io/minikube/pkg/minikube/out"
)
type sshConn struct {
name string
cmd *exec.Cmd
name string
service string
cmd *exec.Cmd
ports []int
}
func createSSHConn(name, sshPort, sshKey string, svc v1.Service) *sshConn {
func createSSHConn(name, sshPort, sshKey string, svc *v1.Service) *sshConn {
// extract sshArgs
sshArgs := []string{
// TODO: document the options here
"-o", "UserKnownHostsFile=/dev/null",
"-o", "StrictHostKeyChecking no",
"-N",
"docker@127.0.0.1",
"-p", sshPort,
"-i", sshKey,
}
askForSudo := false
var privilegedPorts []int32
for _, port := range svc.Spec.Ports {
arg := fmt.Sprintf(
"-L %d:%s:%d",
@ -29,23 +55,96 @@ func createSSHConn(name, sshPort, sshKey string, svc v1.Service) *sshConn {
port.Port,
)
// check if any port is privileged
if port.Port < 1024 {
privilegedPorts = append(privilegedPorts, port.Port)
askForSudo = true
}
sshArgs = append(sshArgs, arg)
}
command := "ssh"
if askForSudo {
out.T(
out.WarningType,
"The service {{.service}} requires privileged ports to be exposed: {{.ports}}",
out.V{"service": svc.Name, "ports": fmt.Sprintf("%v", privilegedPorts)},
)
out.T(out.Permissions, "sudo permission will be asked for it.")
command = "sudo"
sshArgs = append([]string{"ssh"}, sshArgs...)
}
cmd := exec.Command(command, sshArgs...)
return &sshConn{
name: name,
service: svc.Name,
cmd: cmd,
}
}
func createSSHConnWithRandomPorts(name, sshPort, sshKey string, svc *v1.Service) (*sshConn, error) {
// extract sshArgs
sshArgs := []string{
// TODO: document the options here
"-o", "UserKnownHostsFile=/dev/null",
"-o", "StrictHostKeyChecking no",
"-N",
"docker@127.0.0.1",
"-p", sshPort,
"-i", sshKey,
}
usedPorts := make([]int, 0, len(svc.Spec.Ports))
for _, port := range svc.Spec.Ports {
freeport, err := freeport.GetFreePort()
if err != nil {
return nil, err
}
arg := fmt.Sprintf(
"-L %d:%s:%d",
freeport,
svc.Spec.ClusterIP,
port.Port,
)
sshArgs = append(sshArgs, arg)
usedPorts = append(usedPorts, freeport)
}
cmd := exec.Command("ssh", sshArgs...)
return &sshConn{
name: name,
cmd: cmd,
}
name: name,
service: svc.Name,
cmd: cmd,
ports: usedPorts,
}, nil
}
func (c *sshConn) run() error {
fmt.Printf("starting tunnel for %s\n", c.name)
return c.cmd.Run()
func (c *sshConn) startAndWait() error {
out.T(out.Running, "Starting tunnel for service {{.service}}.", out.V{"service": c.service})
err := c.cmd.Start()
if err != nil {
return err
}
// we ignore wait error because the process will be killed
_ = c.cmd.Wait()
return nil
}
func (c *sshConn) stop() error {
fmt.Printf("stopping tunnel for %s\n", c.name)
out.T(out.Stopping, "Stopping tunnel for service {{.service}}.", out.V{"service": c.service})
return c.cmd.Process.Kill()
}

View File

@ -1,3 +1,19 @@
/*
Copyright 2020 The Kubernetes Authors All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package kic
import (
@ -88,15 +104,14 @@ func (t *SSHTunnel) startConnection(svc v1.Service) {
}
// create new ssh conn
newSSHConn := createSSHConn(uniqName, t.sshPort, t.sshKey, svc)
newSSHConn := createSSHConn(uniqName, t.sshPort, t.sshKey, &svc)
t.conns[newSSHConn.name] = newSSHConn
go func() {
err := newSSHConn.run()
err := newSSHConn.startAndWait()
if err != nil {
glog.Errorf("error starting ssh tunnel: %v", err)
}
}()
err := t.LoadBalancerEmulator.PatchServiceIP(t.v1Core.RESTClient(), svc, "127.0.0.1")
@ -118,7 +133,7 @@ func (t *SSHTunnel) stopMarkedConnections() {
// sshConnName creates a uniq name for the tunnel, using its name/clusterIP/ports.
// This allows a new process to be created if an existing service was changed,
// the new process will support the IP/Ports change ocurred.
// the new process will support the IP/Ports change occurred.
func sshConnUniqName(service v1.Service) string {
n := []string{
service.Name,

View File

@ -6,7 +6,7 @@ description: >
Development Roadmap
---
This roadmap is a living document outlining the major technical improvements which we would like to see in minikube during 2019, divided by how they apply to our [guiding principles](principles.md)
This roadmap is a living document outlining the major technical improvements which we would like to see in minikube during 2020, divided by how they apply to our [guiding principles](principles.md)
Please send a PR to suggest any improvements to it.

View File

@ -14,7 +14,7 @@ A LoadBalancer service is the standard way to expose a service to the internet.
## Using `minikube tunnel`
Services of type `LoadBalancer` can be exposed via the `minikube tunnel` command. It will run in a separate terminal until Ctrl-C is hit.
Services of type `LoadBalancer` can be exposed via the `minikube tunnel` command. It must be run in a separate terminal window to keep the `LoadBalancer` running. Ctrl-C in the terminal can be used to terminate the process at which time the network routes will be cleaned up.
## Example
@ -25,7 +25,7 @@ it will ask for password.
minikube tunnel
```
`minikube tunnel` runs as a separate daemon, creating a network route on the host to the service CIDR of the cluster using the cluster's IP address as a gateway. The tunnel command exposes the external IP directly to any program running on the host operating system.
`minikube tunnel` runs as a process, creating a network route on the host to the service CIDR of the cluster using the cluster's IP address as a gateway. The tunnel command exposes the external IP directly to any program running on the host operating system.
<details>

View File

@ -281,19 +281,19 @@
"Log into or run a command on a machine with SSH; similar to 'docker-machine ssh'": "",
"Log into or run a command on a machine with SSH; similar to 'docker-machine ssh'.": "",
"Message Size: {{.size}}": "",
"Minikube is a CLI tool that provisions and manages single-node Kubernetes clusters optimized for development workflows.": "",
"Minikube is a CLI tool that provisions and manages single-node Kubernetes clusters optimized for development workflows.": "Minikube 是一个命令行工具,它提供和管理针对开发工作流程优化的单节点 Kubernetes 集群。",
"Minikube is a tool for managing local Kubernetes clusters.": "",
"Modify minikube config": "",
"Modify minikube's kubernetes addons": "",
"Modify minikube config": "修改 minikube 配置",
"Modify minikube's kubernetes addons": "修改 minikube 的 kubernetes 插件",
"Mount type: {{.name}}": "",
"Mounting host path {{.sourcePath}} into VM as {{.destinationPath}} ...": "",
"Mounts the specified directory into minikube": "",
"Mounts the specified directory into minikube.": "",
"Mounts the specified directory into minikube": "将指定的目录挂载到 minikube",
"Mounts the specified directory into minikube.": "将指定的目录挂载到 minikube。",
"Multiple errors deleting profiles": "删除配置文件时出现多个错误",
"Multiple minikube profiles were found -": "发现了多个 minikube 配置文件 -",
"NIC Type used for host only network. One of Am79C970A, Am79C973, 82540EM, 82543GC, 82545EM, or virtio (virtualbox driver only)": "网卡类型仅用于主机网络。Am79C970A, Am79C973, 82540EM, 82543GC, 82545EM 之一,或 virtio(仅限 VirtualBox 驱动程序)",
"NOTE: This process must stay alive for the mount to be accessible ...": "",
"Networking and Connectivity Commands:": "",
"Networking and Connectivity Commands:": "网络和连接命令:",
"No minikube profile was found. You can create one using `minikube start`.": "",
"Node may be unable to resolve external DNS records": "",
"Node operations": "",
@ -314,11 +314,11 @@
"Options: {{.options}}": "",
"Outputs minikube shell completion for the given shell (bash or zsh)": "",
"Outputs minikube shell completion for the given shell (bash or zsh)\n\n\tThis depends on the bash-completion binary. Example installation instructions:\n\tOS X:\n\t\t$ brew install bash-completion\n\t\t$ source $(brew --prefix)/etc/bash_completion\n\t\t$ minikube completion bash \u003e ~/.minikube-completion # for bash users\n\t\t$ minikube completion zsh \u003e ~/.minikube-completion # for zsh users\n\t\t$ source ~/.minikube-completion\n\tUbuntu:\n\t\t$ apt-get install bash-completion\n\t\t$ source /etc/bash-completion\n\t\t$ source \u003c(minikube completion bash) # for bash users\n\t\t$ source \u003c(minikube completion zsh) # for zsh users\n\n\tAdditionally, you may want to output the completion to a file and source in your .bashrc\n\n\tNote for zsh users: [1] zsh completions are only supported in versions of zsh \u003e= 5.2": "",
"Pause": "",
"Paused kubelet and {{.count}} containers": "",
"Paused kubelet and {{.count}} containers in: {{.namespaces}}": "",
"Permissions: {{.octalMode}} ({{.writtenMode}})": "",
"Please enter a value:": "",
"Pause": "暂停",
"Paused kubelet and {{.count}} containers": "已暂停 kubelet 和 {{.count}} 个容器",
"Paused kubelet and {{.count}} containers in: {{.namespaces}}": "已暂停 {{.namespaces}} 中的 kubelet 和 {{.count}} 个容器",
"Permissions: {{.octalMode}} ({{.writtenMode}})": "权限: {{.octalMode}} ({{.writtenMode}})",
"Please enter a value:": "请输入一个值:",
"Please install the minikube hyperkit VM driver, or select an alternative --vm-driver": "",
"Please install the minikube kvm2 VM driver, or select an alternative --vm-driver": "",
"Please make sure the service you are looking for is deployed or is in the correct namespace.": "",
@ -327,23 +327,23 @@
"Populates the specified folder with documentation in markdown about minikube": "",
"Powering off \"{{.profile_name}}\" via SSH ...": "正在通过 SSH 关闭“{{.profile_name}}”…",
"Preparing Kubernetes {{.k8sVersion}} on {{.runtime}} {{.runtimeVersion}} ...": "正在 {{.runtime}} {{.runtimeVersion}} 中准备 Kubernetes {{.k8sVersion}}…",
"Print current and latest version number": "",
"Print the version of minikube": "",
"Print the version of minikube.": "",
"Problems detected in {{.entry}}:": "",
"Problems detected in {{.name}}:": "",
"Profile gets or sets the current minikube profile": "",
"Print current and latest version number": "打印当前和最新版本版本",
"Print the version of minikube": "打印 minikube 版本",
"Print the version of minikube.": "打印 minikube 版本。",
"Problems detected in {{.entry}}:": "在 {{.entry}} 中 检测到问题:",
"Problems detected in {{.name}}:": "在 {{.name}} 中 检测到问题:",
"Profile gets or sets the current minikube profile": "获取或设置当前的 minikube 配置文件",
"Profile name \"{{.profilename}}\" is minikube keyword. To delete profile use command minikube delete -p \u003cprofile name\u003e": "配置文件名称 \"{{.profilename}}\" 是 minikube 的一个关键字。使用 minikube delete -p \u003cprofile name\u003e 命令 删除配置文件",
"Provide VM UUID to restore MAC address (hyperkit driver only)": "提供虚拟机 UUID 以恢复 MAC 地址(仅限 hyperkit 驱动程序)",
"Pulling images ...": "拉取镜像 ...",
"Reboot to complete VirtualBox installation, verify that VirtualBox is not blocked by your system, and/or use another hypervisor": "重启以完成 VirtualBox 安装,检查 VirtualBox 未被您的操作系统禁用,或者使用其他的管理程序。",
"Rebuild libvirt with virt-network support": "",
"Received {{.name}} signal": "",
"Reconfiguring existing host ...": "",
"Received {{.name}} signal": "收到 {{.name}} 信号",
"Reconfiguring existing host ...": "重新配置现有主机",
"Registry mirrors to pass to the Docker daemon": "传递给 Docker 守护进程的注册表镜像",
"Reinstall VirtualBox and reboot. Alternatively, try the kvm2 driver: https://minikube.sigs.k8s.io/docs/reference/drivers/kvm2/": "",
"Reinstall VirtualBox and verify that it is not blocked: System Preferences -\u003e Security \u0026 Privacy -\u003e General -\u003e Some system software was blocked from loading": "",
"Related issues:": "",
"Related issues:": "相关问题:",
"Relaunching Kubernetes using {{.bootstrapper}} ...": "正在使用 {{.bootstrapper}} 重新启动 Kubernetes…",
"Removed all traces of the \"{{.name}}\" cluster.": "",
"Removing {{.directory}} ...": "正在移除 {{.directory}}…",
@ -351,15 +351,15 @@
"Requested disk size {{.requested_size}} is less than minimum of {{.minimum_size}}": "请求的磁盘大小 {{.requested_size}} 小于最小值 {{.minimum_size}}",
"Requested memory allocation ({{.memory}}MB) is less than the default memory allocation of {{.default_memorysize}}MB. Beware that minikube might not work correctly or crash unexpectedly.": "请求的内存分配 ({{.memory}}MB) 小于默认内存分配 {{.default_memorysize}}MB。请注意 minikube 可能无法正常运行或可能会意外崩溃。",
"Requested memory allocation {{.requested_size}} is less than the minimum allowed of {{.minimum_size}}": "请求的内存分配 {{.requested_size}} 小于允许的 {{.minimum_size}} 最小值",
"Retrieve the ssh identity key path of the specified cluster": "",
"Retrieve the ssh identity key path of the specified cluster.": "",
"Retrieves the IP address of the running cluster": "",
"Retrieve the ssh identity key path of the specified cluster": "检索指定集群的 ssh 密钥路径",
"Retrieve the ssh identity key path of the specified cluster.": "检索指定集群的 ssh 密钥路径。",
"Retrieves the IP address of the running cluster": "检索正在运行的群集的 IP 地址",
"Retrieves the IP address of the running cluster, and writes it to STDOUT.": "",
"Retrieves the IP address of the running cluster, checks it\n\t\t\twith IP in kubeconfig, and corrects kubeconfig if incorrect.": "",
"Returns the value of PROPERTY_NAME from the minikube config file. Can be overwritten at runtime by flags or environmental variables.": "",
"Run 'kubectl describe pod coredns -n kube-system' and check for a firewall or DNS conflict": "",
"Run 'minikube delete' to delete the stale VM, or and ensure that minikube is running as the same user you are issuing this command with": "执行 'minikube delete' 以删除过时的虚拟机,或者确保 minikube 以与您发出此命令的用户相同的用户身份运行",
"Run kubectl": "",
"Run kubectl": "运行 kubectl",
"Run minikube from the C: drive.": "",
"Run the kubernetes client, download it if necessary. Remember -- after kubectl!\n\nExamples:\nminikube kubectl -- --help\nminikube kubectl -- get pods --namespace kube-system": "",
"Run the minikube command as an Administrator": "",
@ -372,11 +372,11 @@
"Set this flag to delete the '.minikube' folder from your user directory.": "设置这个标志来删除您用户目录下的 '.minikube' 文件夹。",
"Sets an individual value in a minikube config file": "",
"Sets the PROPERTY_NAME config value to PROPERTY_VALUE\n\tThese values can be overwritten by flags or environment variables at runtime.": "",
"Sets up docker env variables; similar to '$(docker-machine env)'": "",
"Sets up docker env variables; similar to '$(docker-machine env)'.": "",
"Sets up podman env variables; similar to '$(podman-machine env)'": "",
"Sets up podman env variables; similar to '$(podman-machine env)'.": "",
"Setting profile failed": "",
"Sets up docker env variables; similar to '$(docker-machine env)'": "设置 docker env 变量;类似于 '$(docker-machine env)'",
"Sets up docker env variables; similar to '$(docker-machine env)'.": "设置 docker env 变量;类似于 '$(docker-machine env)'。",
"Sets up podman env variables; similar to '$(podman-machine env)'": "设置 podman env 变量;类似于 '$(podman-machine env)'",
"Sets up podman env variables; similar to '$(podman-machine env)'.": "设置 podman env 变量;类似于 '$(podman-machine env)'。",
"Setting profile failed": "设置配置文件失败",
"Show a list of global command-line options (applies to all commands).": "显示全局命令行选项列表 (应用于所有命令)。",
"Show only log entries which point to known problems": "",
"Show only the most recent journal entries, and continuously print new entries as they are appended to the journal.": "",
@ -400,7 +400,7 @@
"Stopping \"{{.profile_name}}\" in {{.driver_name}} ...": "",
"Stops a local kubernetes cluster running in Virtualbox. This command stops the VM\nitself, leaving all files intact. The cluster can be started again with the \"start\" command.": "",
"Stops a node in a cluster.": "",
"Stops a running local kubernetes cluster": "",
"Stops a running local kubernetes cluster": "停止正在运行的本地 kubernetes 集群",
"Successfully deleted all profiles": "成功删除所有配置文件",
"Successfully deleted profile \\\"{{.name}}\\\"": "成功删除配置文件 \\\"{{.name}}\\\"",
"Successfully mounted {{.sourcePath}} to {{.destinationPath}}": "",
@ -418,8 +418,8 @@
"The 'none' driver does not respect the --memory flag": "'none' 驱动程序不遵循 --memory 标志",
"The 'none' driver does not support multiple profiles: https://minikube.sigs.k8s.io/docs/reference/drivers/none/": "",
"The 'none' driver provides limited isolation and may reduce system security and reliability.": "“none”驱动程序提供有限的隔离功能并且可能会降低系统安全性和可靠性。",
"The '{{.addonName}}' addon is enabled": "",
"The '{{.driver}}' driver requires elevated permissions. The following commands will be executed:\\n\\n{{ .example }}\\n": "",
"The '{{.addonName}}' addon is enabled": "启动 '{{.addonName}}' 插件",
"The '{{.driver}}' driver requires elevated permissions. The following commands will be executed:\\n\\n{{ .example }}\\n": "'{{.driver}}' 驱动程序需要提升权限,将执行以下命令:\\n\\n{{ .example }}\\n",
"The CIDR to be used for service cluster IPs.": "需要用于服务集群 IP 的 CIDR。",
"The CIDR to be used for the minikube VM (virtualbox driver only)": "需要用于 minikube 虚拟机的 CIDR仅限 virtualbox 驱动程序)",
"The KVM QEMU connection URI. (kvm2 driver only)": "KVM QEMU 连接 URI。仅限 kvm2 驱动程序)",
@ -479,7 +479,7 @@
"To see addons list for other profiles use: `minikube addons -p name list`": "",
"To start minikube with HyperV Powershell must be in your PATH`": "",
"To use kubectl or minikube commands as your own user, you may need to relocate them. For example, to overwrite your own settings, run:": "如需以您自己的用户身份使用 kubectl 或 minikube 命令,您可能需要重新定位该命令。例如,如需覆盖您的自定义设置,请运行:",
"Troubleshooting Commands:": "",
"Troubleshooting Commands:": "故障排除命令ƒ",
"Trying to delete invalid profile {{.profile}}": "尝试删除无效的配置文件 {{.profile}}",
"Unable to bind flags": "无法绑定标志",
"Unable to determine a default driver to use. Try specifying --vm-driver, or see https://minikube.sigs.k8s.io/docs/start/": "无法确定要使用的默认驱动。尝试通过 --vm-dirver 指定,或者查阅 https://minikube.sigs.k8s.io/docs/start/",
@ -515,33 +515,33 @@
"Update server returned an empty list": "",
"Upgrade to QEMU v3.1.0+, run 'virt-host-validate', or ensure that you are not running in a nested VM environment.": "",
"Upgrading from Kubernetes {{.old}} to {{.new}}": "正在从 Kubernetes {{.old}} 升级到 {{.new}}",
"Usage": "",
"Usage: minikube completion SHELL": "",
"Usage: minikube delete": "",
"Usage": "使用方法",
"Usage: minikube completion SHELL": "使用方法minikube completion SHELL",
"Usage: minikube delete": "使用方法minikube delete",
"Usage: minikube delete --all --purge": "使用方法minikube delete --all --purge",
"Usage: minikube node [add|start|stop|delete]": "",
"Use \"{{.CommandPath}} [command] --help\" for more information about a command.": "",
"Usage: minikube node [add|start|stop|delete]": "使用方法minikube node [add|start|stop|delete]",
"Use \"{{.CommandPath}} [command] --help\" for more information about a command.": "使用 \"{{.CommandPath}} [command] --help\" 可以获取有关命令的更多信息",
"Use 'kubect get po -A' to find the correct and namespace name": "使用 'kubect get po -A' 来查询正确的命名空间名称",
"Use -A to specify all namespaces": "",
"Use VirtualBox to remove the conflicting VM and/or network interfaces": "",
"Use -A to specify all namespaces": "使用 -A 指定所有 namespaces",
"Use VirtualBox to remove the conflicting VM and/or network interfaces": "使用 VirtualBox 删除有冲突的 虚拟机 和/或 网络接口",
"Use native Golang SSH client (default true). Set to 'false' to use the command line 'ssh' command when accessing the docker machine. Useful for the machine drivers when they will not start with 'Waiting for SSH'.": "",
"User ID: {{.userID}}": "",
"User ID: {{.userID}}": "用户 ID {{.userID}}",
"Userspace file server is shutdown": "",
"Userspace file server:": "",
"Using image repository {{.name}}": "正在使用镜像存储库 {{.name}}",
"Using the '{{.runtime}}' runtime with the 'none' driver is an untested configuration!": "同时使用 'none' 驱动以及 '{{.runtime}}' 运行时是未经测试过的配置!",
"Using the running {{.driver_name}} \"{{.profile_name}}\" VM ...": "",
"Using the {{.driver}} driver based on existing profile": "",
"Using the {{.driver}} driver based on user configuration": "",
"Using the running {{.driver_name}} \"{{.profile_name}}\" VM ...": "使用正在运行的 {{.driver_name}} \"{{.profile_name}}\" 虚拟机",
"Using the {{.driver}} driver based on existing profile": "根据现有的配置文件使用 {{.driver}} 驱动程序",
"Using the {{.driver}} driver based on user configuration": "根据用户配置使用 {{.driver}} 驱动程序",
"VM driver is one of: %v": "虚拟机驱动程序是以下项之一:%v",
"VM is unable to access {{.repository}}, you may need to configure a proxy or set --image-repository": "虚拟机无权访问 {{.repository}},或许您需要配置代理或者设置 --image-repository",
"VM may be unable to resolve external DNS records": "虚拟机可能无法解析外部 DNS 记录",
"Verify that your HTTP_PROXY and HTTPS_PROXY environment variables are set correctly.": "",
"Verify the IP address of the running cluster in kubeconfig.": "",
"Verifying dashboard health ...": "",
"Verifying proxy health ...": "",
"Verify that your HTTP_PROXY and HTTPS_PROXY environment variables are set correctly.": "验证是否正确设置了 HTTP_PROXY 和 HTTPS_PROXY 环境变量。",
"Verify the IP address of the running cluster in kubeconfig.": "在 kubeconfig 中验证正在运行的集群 IP 地址。",
"Verifying dashboard health ...": "正在验证 dashboard 运行情况 ...",
"Verifying proxy health ...": "正在验证 proxy 运行状况 ...",
"Verifying:": "正在验证:",
"Version: {{.version}}": "",
"Version: {{.version}}": "版本: {{.version}}",
"VirtualBox and Hyper-V are having a conflict. Use '--vm-driver=hyperv' or disable Hyper-V using: 'bcdedit /set hypervisorlaunchtype off'": "",
"VirtualBox cannot create a network, probably because it conflicts with an existing network that minikube no longer knows about. Try running 'minikube delete'": "",
"VirtualBox is broken. Disable real-time anti-virus software, reboot, and reinstall VirtualBox if the problem continues.": "",
@ -577,10 +577,10 @@
"config view failed": "",
"creating api client": "",
"dashboard service is not running: {{.error}}": "",
"disable failed": "",
"disable failed": "禁用失败",
"dry-run mode. Validates configuration, but does not mutate system state": "",
"dry-run validation complete!": "",
"enable failed": "",
"enable failed": "开启失败",
"error creating clientset": "",
"error creating machine client": "",
"error parsing the input ip address for mount": "",
@ -594,7 +594,7 @@
"loading config": "",
"logdir set failed": "",
"machine '{{.name}}' does not exist. Proceeding ahead with recreating VM.": "",
"max time to wait per Kubernetes core services to be healthy.": "",
"max time to wait per Kubernetes core services to be healthy.": "每个 Kubernetes 核心服务保持健康所需的最长时间。",
"minikube addons list --output OUTPUT. json, list": "",
"minikube is exiting due to an error. If the above message is not useful, open an issue:": "由于出错 minikube 正在退出。如果以上信息没有帮助,请提交问题反馈:",
"minikube is unable to access the Google Container Registry. You may need to configure it to use a HTTP proxy.": "",
@ -610,7 +610,7 @@
"namespaces to pause": "",
"namespaces to unpause": "",
"not enough arguments ({{.ArgCount}}).\\nusage: minikube config set PROPERTY_NAME PROPERTY_VALUE": "",
"pause containers": "",
"pause containers": "暂停容器",
"profile sets the current minikube profile, or gets the current profile if no arguments are provided. This is used to run and manage multiple minikube instance. You can return to the default minikube profile by running `minikube profile default`": "",
"reload cached images.": "重新加载缓存的镜像",
"reloads images previously added using the 'cache add' subcommand": "重新加载之前通过子命令 'cache add' 添加的镜像",
@ -621,16 +621,16 @@
"status text failure": "",
"toom any arguments ({{.ArgCount}}).\\nusage: minikube config set PROPERTY_NAME PROPERTY_VALUE": "",
"tunnel creates a route to services deployed with type LoadBalancer and sets their Ingress to their ClusterIP. for a detailed example see https://minikube.sigs.k8s.io/docs/tasks/loadbalancer": "",
"tunnel makes services of type LoadBalancer accessible on localhost": "",
"tunnel makes services of type LoadBalancer accessible on localhost": "隧道使本地主机上可以访问 LoadBalancer 类型的服务",
"unable to bind flags": "",
"unable to delete minikube config folder": "无法删除 minikube 配置目录",
"unable to set logtostderr": "",
"unpause Kubernetes": "",
"unpause Kubernetes": "恢复 Kubernetes",
"unset failed": "",
"unsets PROPERTY_NAME from the minikube config file. Can be overwritten by flags or environmental variables": "",
"unsets an individual value in a minikube config file": "",
"unsupported or missing driver: {{.name}}": "不支持或者缺失驱动:{{.name}}",
"update config": "",
"update config": "更新配置",
"usage: minikube addons configure ADDON_NAME": "",
"usage: minikube addons disable ADDON_NAME": "",
"usage: minikube addons enable ADDON_NAME": "",