Skip to content

Commit

Permalink
fix: use built-in ingress controller and dashboard for minikube
Browse files Browse the repository at this point in the history
  • Loading branch information
edvald committed May 24, 2018
1 parent 4871022 commit 879bce2
Show file tree
Hide file tree
Showing 5 changed files with 75 additions and 12 deletions.
14 changes: 12 additions & 2 deletions docs/minikube.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@ Garden can be used with [Minikube](https://github.com/kubernetes/minikube) on su

### Installation

For installation instructions, please see the [official guide](https://github.com/kubernetes/minikube#installation).
For Minikube 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.
Expand Down Expand Up @@ -39,4 +40,13 @@ _Note: If you happen to have installed both Minikube and the Docker for Mac vers
`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.
### Hostname

Garden needs the Kubernetes instance to have a hostname. By default Garden will use `<minikube-ip>.nip.io`. If you'd
like to use a custom hostname, you can specify it via the `ingressHostname` in the `local-kubernetes` provider config
(see above).

### Anything else?

Once the above is set up, the `local-kubernetes` plugin will automatically configure everything else Garden needs to
work. The built-in nginx ingress controller will be automatically enabled and used to route requests to services.
3 changes: 2 additions & 1 deletion src/plugins/kubernetes/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,16 +43,17 @@ export const name = "kubernetes"
export interface KubernetesConfig extends ProviderConfig {
context: string
ingressHostname: string
ingressPort: number
ingressClass: string
forceSsl: boolean
_system?: Symbol
}

export interface KubernetesProvider extends Provider<KubernetesConfig> { }

const configSchema = providerConfigBase.keys({
context: Joi.string().required(),
ingressHostname: Joi.string().hostname().required(),
ingressPort: Joi.number().default(80),
ingressClass: Joi.string(),
forceSsl: Joi.boolean().default(true),
_system: Joi.any(),
Expand Down
67 changes: 60 additions & 7 deletions src/plugins/kubernetes/local.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ import {
} from "lodash"
import * as Joi from "joi"
import { join } from "path"
import { PluginError } from "../../exceptions"
import { DeployTask } from "../../tasks/deploy"
import { validate } from "../../types/common"
import {
GardenPlugin,
Expand All @@ -38,6 +40,8 @@ import {
isSystemGarden,
} from "./system"

// TODO: split this into separate plugins to handle Docker for Mac and Minikube

// 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"]
Expand All @@ -63,29 +67,50 @@ export async function getLocalEnvironmentStatus(
}

async function configureLocalEnvironment(
{ ctx, provider, env, status, logEntry }: ConfigureEnvironmentParams,
{ ctx, provider, env, force, status, logEntry }: ConfigureEnvironmentParams,
) {
await configureEnvironment({ ctx, provider, env, status, logEntry })
await configureEnvironment({ ctx, provider, env, force, status, logEntry })

if (!isSystemGarden(provider)) {
const sysGarden = await getSystemGarden(provider)
const sysCtx = sysGarden.pluginContext
const sysProvider = {
name: provider.name,
config: findByName(sysGarden.config.providers, provider.name)!,
}

const sysStatus = await getEnvironmentStatus({
ctx: sysGarden.pluginContext,
ctx: sysCtx,
provider: sysProvider,
env,
})

await configureEnvironment({
ctx: sysGarden.pluginContext,
ctx: sysCtx,
env: sysGarden.getEnvironment(),
provider: sysProvider,
force,
status: sysStatus,
logEntry,
})
await sysGarden.pluginContext.deployServices({ logEntry })

const services = await sysCtx.getServices(provider.config._systemServices)

const results = await sysCtx.processServices({
services,
watch: false,
process: async (service) => {
return [await DeployTask.factory({ ctx: sysCtx, service, force, forceBuild: false })]
},
})

const failed = values(results).filter(r => !!r.error).length

if (failed) {
throw new PluginError(`local-kubernetes: ${failed} errors occurred when configuring environments`, {
results,
})
}
}

return {}
Expand All @@ -109,9 +134,16 @@ function setMinikubeDockerEnv() {
}
}

export interface LocalKubernetesConfig extends KubernetesConfig {
_system?: Symbol
_systemServices?: string[]
}

const configSchema = providerConfigBase.keys({
context: Joi.string(),
ingressHostname: Joi.string(),
_system: Joi.any(),
_systemServices: Joi.array().items(Joi.string()),
})

export const name = "local-kubernetes"
Expand All @@ -120,6 +152,9 @@ export function gardenPlugin({ config, logEntry }): GardenPlugin {
config = validate(config, configSchema, { context: "kubernetes provider config" })

let context = config.context
let systemServices
let ingressHostname
let ingressPort

if (!context) {
// automatically detect supported kubectl context if not explicitly configured
Expand Down Expand Up @@ -149,19 +184,37 @@ export function gardenPlugin({ config, logEntry }): GardenPlugin {
}

if (context === "minikube") {
execSync("minikube addons enable ingress")

ingressHostname = config.ingressHostname

if (!ingressHostname) {
// use the nip.io service to give a hostname to the instance, if none is explicitly configured
const minikubeIp = execSync("minikube ip").toString().trim()
ingressHostname = minikubeIp + ".nip.io"
}

ingressPort = 80
systemServices = []

// automatically set docker environment variables for minikube
// TODO: it would be better to explicitly provide those to docker instead of using process.env
setMinikubeDockerEnv()
} else {
ingressHostname = config.ingressHostname || "local.app.garden"
ingressPort = 32000
}

const k8sConfig: KubernetesConfig = {
const k8sConfig: LocalKubernetesConfig = {
name: config.name,
context,
ingressHostname: "local.app.garden",
ingressHostname,
ingressPort,
ingressClass: "nginx",
// TODO: support SSL on local deployments
forceSsl: false,
_system: config._system,
_systemServices: systemServices,
}

const plugin = k8sPlugin({ config: k8sConfig })
Expand Down
2 changes: 1 addition & 1 deletion src/plugins/kubernetes/status.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@ import {
import { getServiceHostname } from "./ingress"
import { KUBECTL_DEFAULT_TIMEOUT } from "./kubectl"
import { getAppNamespace } from "./namespace"
import { localIngressPort } from "./system"

export async function checkDeploymentStatus(
{ ctx, provider, service, resourceVersion }:
Expand All @@ -42,6 +41,7 @@ export async function checkDeploymentStatus(
const endpoints = service.spec.endpoints.map((e: ServiceEndpointSpec) => {
// TODO: this should be HTTPS, once we've set up TLS termination at the ingress controller level
const protocol: ServiceProtocol = "http"
const localIngressPort = provider.config.ingressPort

return {
protocol,
Expand Down
1 change: 0 additions & 1 deletion src/plugins/kubernetes/system.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ import { Garden } from "../../garden"
import { KubernetesProvider } from "./index"

export const GARDEN_SYSTEM_NAMESPACE = "garden-system"
export const localIngressPort = 32000

const systemProjectPath = join(STATIC_DIR, "kubernetes", "system")
const systemSymbol = Symbol()
Expand Down

0 comments on commit 879bce2

Please sign in to comment.