cluster: add support for vmwarefusion driver

Add support for the vmwarefusion driver which is greatly more stable on
OSX. Also, document it in the README as an option.
pull/184/head
Brandon Philips 2016-06-08 22:14:39 -07:00
parent 9d65272511
commit 53ee8642f8
9 changed files with 115 additions and 20 deletions

View File

@ -11,7 +11,7 @@ a single-node Kubernetes cluster inside a VM on your laptop for users looking
to try out Kubernetes or develop with it day-to-day. to try out Kubernetes or develop with it day-to-day.
## Requirements For Running Minikube ## Requirements For Running Minikube
* VirtualBox installation * [VirtualBox](https://www.virtualbox.org/wiki/Downloads) or [VMware Fusion](https://www.vmware.com/products/fusion) installation
* VT-x/AMD-v virtualization must be enabled in BIOS * VT-x/AMD-v virtualization must be enabled in BIOS
## Installation ## Installation
@ -20,6 +20,8 @@ See the installation instructions for the [latest release](https://github.com/ku
## Usage ## Usage
Here's a brief demo of minikube usage. We're using the code from this [Kubernetes tutorial](http://kubernetes.io/docs/hellonode/). Here's a brief demo of minikube usage. We're using the code from this [Kubernetes tutorial](http://kubernetes.io/docs/hellonode/).
If you want to change the VM driver to VMware Fusion add the `--vm-driver=vmwarefusion` flag to `minikube start`.
Note that the IP below is dynamic and can change. It can be retrieved with `minikube ip`. Note that the IP below is dynamic and can change. It can be retrieved with `minikube ip`.
```shell ```shell

View File

@ -34,6 +34,7 @@ import (
var ( var (
minikubeISO string minikubeISO string
vmDriver string
) )
// startCmd represents the start command // startCmd represents the start command
@ -52,6 +53,7 @@ func runStart(cmd *cobra.Command, args []string) {
config := cluster.MachineConfig{ config := cluster.MachineConfig{
MinikubeISO: minikubeISO, MinikubeISO: minikubeISO,
VMDriver: vmDriver,
} }
var host *host.Host var host *host.Host
@ -150,5 +152,6 @@ func setupKubeconfig(name, server, certAuth, cliCert, cliKey string) (activeCont
func init() { func init() {
startCmd.Flags().StringVarP(&minikubeISO, "iso-url", "", constants.DefaultIsoUrl, "Location of the minikube iso") startCmd.Flags().StringVarP(&minikubeISO, "iso-url", "", constants.DefaultIsoUrl, "Location of the minikube iso")
startCmd.Flags().StringVarP(&vmDriver, "vm-driver", "", constants.DefaultVMDriver, fmt.Sprintf("VM driver is one of: %v", constants.SupportedVMDrivers))
RootCmd.AddCommand(startCmd) RootCmd.AddCommand(startCmd)
} }

View File

@ -16,6 +16,7 @@ minikube start
``` ```
--iso-url="https://storage.googleapis.com/minikube/minikube-0.3.iso": Location of the minikube iso --iso-url="https://storage.googleapis.com/minikube/minikube-0.3.iso": Location of the minikube iso
--vm-driver="virtualbox": VM driver is one of: [virtualbox vmwarefusion]
``` ```
### Options inherited from parent commands ### Options inherited from parent commands

View File

@ -155,6 +155,7 @@ type sshAble interface {
// MachineConfig contains the parameters used to start a cluster. // MachineConfig contains the parameters used to start a cluster.
type MachineConfig struct { type MachineConfig struct {
MinikubeISO string MinikubeISO string
VMDriver string
} }
// StartCluster starts a k8s cluster on the specified Host. // StartCluster starts a k8s cluster on the specified Host.
@ -261,15 +262,25 @@ func SetupCerts(d drivers.Driver) error {
} }
func createHost(api libmachine.API, config MachineConfig) (*host.Host, error) { func createHost(api libmachine.API, config MachineConfig) (*host.Host, error) {
driver := virtualbox.NewDriver(constants.MachineName, constants.Minipath) var driver drivers.Driver
driver.Boot2DockerURL = config.MinikubeISO
switch config.VMDriver {
case "virtualbox":
d := virtualbox.NewDriver(constants.MachineName, constants.Minipath)
d.Boot2DockerURL = config.MinikubeISO
driver = d
case "vmwarefusion":
driver = createVMwareFusionHost(config)
default:
glog.Exitf("Unsupported driver: %s\n", config.VMDriver)
}
data, err := json.Marshal(driver) data, err := json.Marshal(driver)
if err != nil { if err != nil {
return nil, err return nil, err
} }
driverName := "virtualbox" h, err := api.NewHost(config.VMDriver, data)
h, err := api.NewHost(driverName, data)
if err != nil { if err != nil {
return nil, fmt.Errorf("Error creating new host: %s", err) return nil, fmt.Errorf("Error creating new host: %s", err)
} }

View File

@ -0,0 +1,34 @@
/*
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.
*/
package cluster
import (
"github.com/docker/machine/drivers/vmwarefusion"
"github.com/docker/machine/libmachine/drivers"
"k8s.io/minikube/pkg/minikube/constants"
)
func createVMwareFusionHost(config MachineConfig) drivers.Driver {
d := vmwarefusion.NewDriver(constants.MachineName, constants.Minipath).(*vmwarefusion.Driver)
d.Boot2DockerURL = config.MinikubeISO
// TODO(philips): push these defaults upstream to fixup this driver
d.CPU = 1
d.SSHPort = 22
d.ISO = d.ResolveStorePath("boot2docker.iso")
return d
}

View File

@ -0,0 +1,25 @@
// +build !darwin
/*
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.
*/
package cluster
import "github.com/docker/machine/libmachine/drivers"
func createVMwareFusionHost(config MachineConfig) drivers.Driver {
panic("vmwarefusion not supported")
}

View File

@ -32,6 +32,8 @@ import (
"k8s.io/minikube/pkg/minikube/tests" "k8s.io/minikube/pkg/minikube/tests"
) )
var defaultMachineConfig = MachineConfig{VMDriver: constants.DefaultVMDriver}
func TestCreateHost(t *testing.T) { func TestCreateHost(t *testing.T) {
api := tests.NewMockAPI() api := tests.NewMockAPI()
@ -39,7 +41,7 @@ func TestCreateHost(t *testing.T) {
if exists { if exists {
t.Fatal("Machine already exists.") t.Fatal("Machine already exists.")
} }
_, err := createHost(api, MachineConfig{}) _, err := createHost(api, defaultMachineConfig)
if err != nil { if err != nil {
t.Fatalf("Error creating host: %v", err) t.Fatalf("Error creating host: %v", err)
} }
@ -57,8 +59,16 @@ func TestCreateHost(t *testing.T) {
t.Fatalf("Machine is not running. State is: %s", s) t.Fatalf("Machine is not running. State is: %s", s)
} }
if h.DriverName != "virtualbox" { found := false
t.Fatalf("Wrong driver name: %v. Should be virtualbox.", h.DriverName) for _, driver := range constants.SupportedVMDrivers {
if h.DriverName == driver {
found = true
break
}
}
if !found {
t.Fatalf("Wrong driver name: %v. Should be virtualbox or vmwarefusion.", h.DriverName)
} }
} }
@ -117,7 +127,7 @@ func TestStartClusterError(t *testing.T) {
func TestStartHostExists(t *testing.T) { func TestStartHostExists(t *testing.T) {
api := tests.NewMockAPI() api := tests.NewMockAPI()
// Create an initial host. // Create an initial host.
_, err := createHost(api, MachineConfig{}) _, err := createHost(api, defaultMachineConfig)
if err != nil { if err != nil {
t.Fatalf("Error creating host: %v", err) t.Fatalf("Error creating host: %v", err)
} }
@ -129,7 +139,7 @@ func TestStartHostExists(t *testing.T) {
} }
// This should pass without calling Create because the host exists already. // This should pass without calling Create because the host exists already.
h, err := StartHost(api, MachineConfig{}) h, err := StartHost(api, defaultMachineConfig)
if err != nil { if err != nil {
t.Fatal("Error starting host.") t.Fatal("Error starting host.")
} }
@ -144,7 +154,7 @@ func TestStartHostExists(t *testing.T) {
func TestStartStoppedHost(t *testing.T) { func TestStartStoppedHost(t *testing.T) {
api := tests.NewMockAPI() api := tests.NewMockAPI()
// Create an initial host. // Create an initial host.
h, err := createHost(api, MachineConfig{}) h, err := createHost(api, defaultMachineConfig)
if err != nil { if err != nil {
t.Fatalf("Error creating host: %v", err) t.Fatalf("Error creating host: %v", err)
} }
@ -152,7 +162,7 @@ func TestStartStoppedHost(t *testing.T) {
h.Driver = &d h.Driver = &d
d.CurrentState = state.Stopped d.CurrentState = state.Stopped
h, err = StartHost(api, MachineConfig{}) h, err = StartHost(api, defaultMachineConfig)
if err != nil { if err != nil {
t.Fatal("Error starting host.") t.Fatal("Error starting host.")
} }
@ -172,7 +182,7 @@ func TestStartStoppedHost(t *testing.T) {
func TestStartHost(t *testing.T) { func TestStartHost(t *testing.T) {
api := tests.NewMockAPI() api := tests.NewMockAPI()
h, err := StartHost(api, MachineConfig{}) h, err := StartHost(api, defaultMachineConfig)
if err != nil { if err != nil {
t.Fatal("Error starting host.") t.Fatal("Error starting host.")
} }
@ -196,7 +206,7 @@ func TestStopHostError(t *testing.T) {
func TestStopHost(t *testing.T) { func TestStopHost(t *testing.T) {
api := tests.NewMockAPI() api := tests.NewMockAPI()
h, _ := createHost(api, MachineConfig{}) h, _ := createHost(api, defaultMachineConfig)
if err := StopHost(api); err != nil { if err := StopHost(api); err != nil {
t.Fatal("An error should be thrown when stopping non-existing machine.") t.Fatal("An error should be thrown when stopping non-existing machine.")
} }
@ -227,7 +237,7 @@ Error 2`
func TestDeleteHost(t *testing.T) { func TestDeleteHost(t *testing.T) {
api := tests.NewMockAPI() api := tests.NewMockAPI()
createHost(api, MachineConfig{}) createHost(api, defaultMachineConfig)
if err := DeleteHost(api); err != nil { if err := DeleteHost(api); err != nil {
t.Fatalf("Unexpected error deleting host: %s", err) t.Fatalf("Unexpected error deleting host: %s", err)
@ -236,7 +246,7 @@ func TestDeleteHost(t *testing.T) {
func TestDeleteHostErrorDeletingVM(t *testing.T) { func TestDeleteHostErrorDeletingVM(t *testing.T) {
api := tests.NewMockAPI() api := tests.NewMockAPI()
h, _ := createHost(api, MachineConfig{}) h, _ := createHost(api, defaultMachineConfig)
d := &tests.MockDriver{RemoveError: true} d := &tests.MockDriver{RemoveError: true}
@ -250,7 +260,7 @@ func TestDeleteHostErrorDeletingVM(t *testing.T) {
func TestDeleteHostErrorDeletingFiles(t *testing.T) { func TestDeleteHostErrorDeletingFiles(t *testing.T) {
api := tests.NewMockAPI() api := tests.NewMockAPI()
api.RemoveError = true api.RemoveError = true
createHost(api, MachineConfig{}) createHost(api, defaultMachineConfig)
if err := DeleteHost(api); err == nil { if err := DeleteHost(api); err == nil {
t.Fatal("Expected error deleting host.") t.Fatal("Expected error deleting host.")
@ -260,7 +270,7 @@ func TestDeleteHostErrorDeletingFiles(t *testing.T) {
func TestDeleteHostMultipleErrors(t *testing.T) { func TestDeleteHostMultipleErrors(t *testing.T) {
api := tests.NewMockAPI() api := tests.NewMockAPI()
api.RemoveError = true api.RemoveError = true
h, _ := createHost(api, MachineConfig{}) h, _ := createHost(api, defaultMachineConfig)
d := &tests.MockDriver{RemoveError: true} d := &tests.MockDriver{RemoveError: true}
@ -295,7 +305,7 @@ func TestGetHostStatus(t *testing.T) {
checkState("Does Not Exist") checkState("Does Not Exist")
createHost(api, MachineConfig{}) createHost(api, defaultMachineConfig)
checkState(state.Running.String()) checkState(state.Running.String())
StopHost(api) StopHost(api)
@ -335,7 +345,7 @@ func TestSetupCerts(t *testing.T) {
func TestGetHostDockerEnv(t *testing.T) { func TestGetHostDockerEnv(t *testing.T) {
api := tests.NewMockAPI() api := tests.NewMockAPI()
h, err := createHost(api, MachineConfig{}) h, err := createHost(api, defaultMachineConfig)
if err != nil { if err != nil {
t.Fatalf("Error creating host: %v", err) t.Fatalf("Error creating host: %v", err)
} }

View File

@ -46,6 +46,12 @@ var LogFlags = [...]string{
} }
const DefaultIsoUrl = "https://storage.googleapis.com/minikube/minikube-0.3.iso" const DefaultIsoUrl = "https://storage.googleapis.com/minikube/minikube-0.3.iso"
const DefaultVMDriver = "virtualbox"
var SupportedVMDrivers = [...]string{
"virtualbox",
"vmwarefusion",
}
const ( const (
RemoteLocalKubeErrPath = "/var/log/localkube.err" RemoteLocalKubeErrPath = "/var/log/localkube.err"

View File

@ -20,6 +20,7 @@ import (
"os" "os"
"github.com/docker/machine/drivers/virtualbox" "github.com/docker/machine/drivers/virtualbox"
"github.com/docker/machine/drivers/vmwarefusion"
"github.com/docker/machine/libmachine/drivers/plugin" "github.com/docker/machine/libmachine/drivers/plugin"
"github.com/docker/machine/libmachine/drivers/plugin/localbinary" "github.com/docker/machine/libmachine/drivers/plugin/localbinary"
"github.com/golang/glog" "github.com/golang/glog"
@ -32,6 +33,8 @@ func StartDriver() {
switch driverName { switch driverName {
case "virtualbox": case "virtualbox":
plugin.RegisterDriver(virtualbox.NewDriver("", "")) plugin.RegisterDriver(virtualbox.NewDriver("", ""))
case "vmwarefusion":
plugin.RegisterDriver(vmwarefusion.NewDriver("", ""))
default: default:
glog.Exitf("Unsupported driver: %s\n", driverName) glog.Exitf("Unsupported driver: %s\n", driverName)
} }