Skip to content

Commit

Permalink
Merge pull request #103 from garden-io/minikube
Browse files Browse the repository at this point in the history
feat: support and documentation for Minikube
  • Loading branch information
edvald authored May 23, 2018
2 parents 7a81cf9 + 5e1b4bc commit b97528f
Show file tree
Hide file tree
Showing 9 changed files with 182 additions and 12 deletions.
58 changes: 56 additions & 2 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
#
version: 2
jobs:
build:
unit-tests:
docker:
# specify the version you desire here
- image: circleci/node:9
Expand All @@ -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 All @@ -47,4 +51,54 @@ jobs:
# run tests
- run: npm test
- run: ./bin/integ

minikube-tests:
# got this from https://github.com/gavinzhou/ci-minikube/blob/master/.circleci/config.yml
machine: true
environment:
CHANGE_MINIKUBE_NONE_USER: true
BASH_ENV: ~/.bashrc
steps:
- checkout
- 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:
command: |
## only run 0.25.0 , not work after 0.25.0+
## because circleci machine run ubuntu 14
curl -Lo minikube https://storage.googleapis.com/minikube/releases/v0.25.0/minikube-linux-amd64 && chmod +x minikube && sudo mv minikube /usr/local/bin/
- run: sudo minikube start --vm-driver=none
- run: sudo minikube update-context
- run:
name: Install node@8
# https://discuss.circleci.com/t/how-to-change-node-version-in-circleci-2-0/17455
command: |
set +e
touch $BASH_ENV
curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.33.5/install.sh | bash
echo 'export NVM_DIR="$HOME/.nvm"' >> $BASH_ENV
echo '[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"' >> $BASH_ENV
echo 'nvm install 8' >> $BASH_ENV
echo 'nvm alias default 8' >> $BASH_ENV
- run:
# for some reason we need to manually source $BASH_ENV (CircleCI machine executer is poorly documented...)
command: |
source $BASH_ENV
npm install
npm run build
- run:
command: |
JSONPATH='{range .items[*]}{@.metadata.name}:{range @.status.conditions[*]}{@.type}={@.status};{end}{end}'; until sudo kubectl get nodes -o jsonpath="$JSONPATH" 2>&1 | grep -q "Ready=True"; do sleep 1; done
- run: sudo kubectl cluster-info
- run:
command: |
source $BASH_ENV
./bin/integ
workflows:
version: 2
all-tests:
jobs:
- unit-tests
# - minikube-tests
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
16 changes: 14 additions & 2 deletions gulpfile.ts
Original file line number Diff line number Diff line change
Expand Up @@ -80,10 +80,22 @@ gulp.task("add-version-files", (cb) => {
proc.on("error", err => cb(err))

let output = ""
proc.stdout.on("data", d => output += d)
let outputWithError = ""
proc.stdout.on("data", d => {
output += d
outputWithError += d
})
proc.stderr.on("data", d => outputWithError += d)

proc.on("close", () => {
const results = JSON.parse(output)
let results
try {
results = JSON.parse(output)
} catch {
const msg = "Got unexpected output from `garden scan`"
console.error(msg + "\n" + outputWithError)
return cb(msg)
}

for (const module of <any>results.result) {
const relPath = relative(__dirname, module.path)
Expand Down
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 b97528f

Please sign in to comment.