Skip to content

Commit

Permalink
feat: support and documentation for Minikube
Browse files Browse the repository at this point in the history
  • Loading branch information
edvald committed May 23, 2018
1 parent 0fc4ee4 commit b2c632c
Show file tree
Hide file tree
Showing 8 changed files with 116 additions and 8 deletions.
4 changes: 4 additions & 0 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,10 @@ jobs:
# fallback to using the latest cache if no exact match is found
- v2-dependencies-

- run:
command: |
curl -Lo kubectl https://storage.googleapis.com/kubernetes-release/release/v1.10.0/bin/linux/amd64/kubectl && chmod +x kubectl && sudo mv kubectl /usr/local/bin/
- run: sudo apt install rsync ruby ruby-dev cmake libicu-dev pkg-config
- run: sudo gem install --no-document copyright-header
- run: npm install
Expand Down
42 changes: 42 additions & 0 deletions docs/minikube.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
## Using Garden with Minikube

Garden can be used with [Minikube](https://github.com/kubernetes/minikube) on supported platforms.

### Installation

For installation instructions, please see the [official guide](https://github.com/kubernetes/minikube#installation).
You'll likely also need to install a driver to run the Minikube VM, please follow the
[instructions here](https://github.com/kubernetes/minikube/blob/master/docs/drivers.md#hyperkit-driver)
and note the name of the driver.

Once Minikube and the appropriate driver for your OS is installed, you can start it by running:

minikube start --vm-driver=<your vm driver> # e.g. hyperkit on macOS

You'll also need to have Docker (for macOS, we recommend [Docker for Mac](https://docs.docker.com/engine/installation/))
and [kubectl](https://kubernetes.io/docs/tasks/tools/install-kubectl/) installed.

_NOTE: Garden is not yet officially supported on Windows, but we have every intention to support it.
Please file any issues and we will try and respond promptly._

### Usage

The `local-kubernetes` plugin attempts to automatically detect if it is installed and set the appropriate context
for connecting to the local Kubernetes instance. In most cases you should not have to update your `garden.yml`
since it uses the `local-kubernetes` plugin by default, but you can configure it explicitly in your project
`garden.yml` like so:

```yaml
project:
environments:
- name: local
providers:
- name: local-kubernetes
context: minikube
```

_Note: If you happen to have installed both Minikube and the Docker for Mac version with Kubernetes enabled,
`garden` will choose whichever one is configured as the current context in your `kubectl` configuration, and if neither
is set as the current context, Docker for Mac is preferred by default._

Once configured, the `local-kubernetes` plugin will automatically configure everything Garden needs to work.
1 change: 0 additions & 1 deletion examples/hello-world/garden.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ project:
- name: local
providers:
- name: local-kubernetes
context: docker-for-desktop
- name: local-google-cloud-functions
- name: dev
providers:
Expand Down
2 changes: 2 additions & 0 deletions garden.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,5 @@ project:
providers:
- name: container
- name: local-kubernetes
# note: this context is not actually used for anything
context: docker-for-desktop
2 changes: 1 addition & 1 deletion src/garden.ts
Original file line number Diff line number Diff line change
Expand Up @@ -380,8 +380,8 @@ export class Garden {

try {
plugin = factory({
garden: this,
config,
logEntry: this.log,
})
} catch (error) {
throw new PluginError(`Unexpected error when loading plugin "${pluginName}": ${error}`, {
Expand Down
70 changes: 66 additions & 4 deletions src/plugins/kubernetes/local.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,15 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/

import { execSync } from "child_process"
import { readFileSync } from "fs"
import { safeLoad } from "js-yaml"
import {
every,
values,
} from "lodash"
import * as Joi from "joi"
import { join } from "path"
import { validate } from "../../types/common"
import {
ConfigureEnvironmentParams,
Expand All @@ -32,6 +36,11 @@ import {
isSystemGarden,
} from "./system"

// note: this is in order of preference, in case neither is set as the current kubectl context
// and none is explicitly configured in the garden.yml
const supportedContexts = ["docker-for-desktop", "minikube"]
const kubeConfigPath = join(process.env.HOME || "~", ".kube", "config")

// extend the environment configuration to also set up an ingress controller and dashboard
export async function getLocalEnvironmentStatus(
{ ctx, provider, env, logEntry }: GetEnvironmentStatusParams,
Expand Down Expand Up @@ -78,19 +87,72 @@ async function configureLocalEnvironment(
}
}

export const name = "local-kubernetes"
function getKubeConfig(): any {
try {
return safeLoad(readFileSync(kubeConfigPath).toString())
} catch {
return {}
}
}

function setMinikubeDockerEnv() {
const minikubeEnv = execSync("minikube docker-env --shell=bash").toString()
for (const line of minikubeEnv.split("\n")) {
const matched = line.match(/^export (\w+)="(.+)"$/)
if (matched) {
process.env[matched[1]] = matched[2]
}
}
}

const configSchema = providerConfigBase.keys({
context: Joi.string().default("docker-for-desktop"),
context: Joi.string(),
_system: Joi.any(),
})

export function gardenPlugin({ config }): GardenPlugin {
export const name = "local-kubernetes"

export function gardenPlugin({ config, logEntry }): GardenPlugin {
config = validate(config, configSchema, { context: "kubernetes provider config" })

let context = config.context

if (!context) {
// automatically detect supported kubectl context if not explicitly configured
const kubeConfig = getKubeConfig()
const currentContext = kubeConfig["current-context"]

if (currentContext && supportedContexts.includes(currentContext)) {
// prefer current context if set and supported
context = currentContext
logEntry.debug({ section: name, msg: `Using current context: ${context}` })
} else if (kubeConfig.contexts) {
const availableContexts = kubeConfig.contexts.map(c => c.name)

for (const supportedContext of supportedContexts) {
if (availableContexts.includes(supportedContext)) {
context = supportedContext
logEntry.debug({ section: name, msg: `Using detected context: ${context}` })
break
}
}
}
}

if (!context) {
context = supportedContexts[0]
logEntry.debug({ section: name, msg: `No kubectl context auto-deteced, using default: ${context}` })
}

if (context === "minikube") {
// automatically set docker environment variables for minikube
// TODO: it would be better to explicitly provide those to docker instead of using process.env
setMinikubeDockerEnv()
}

const k8sConfig: KubernetesConfig = {
name: config.name,
context: config.context,
context,
ingressHostname: "local.app.garden",
ingressClass: "nginx",
// TODO: support SSL on local deployments
Expand Down
2 changes: 1 addition & 1 deletion src/types/plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -318,7 +318,7 @@ export interface GardenPlugin {
}

export interface PluginFactory {
({ garden: Garden, config: object }): GardenPlugin
({ config: object, logEntry: LogEntry }): GardenPlugin
pluginName?: string
}
export type RegisterPluginParam = string | PluginFactory
Expand Down
1 change: 0 additions & 1 deletion src/types/project.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,6 @@ export const defaultEnvironments: EnvironmentConfig[] = [
providers: [
{
name: "local-kubernetes",
context: "docker-for-desktop",
},
],
variables: {},
Expand Down

0 comments on commit b2c632c

Please sign in to comment.