Kubernetes

Garden can apply Kubernetes manifests via the kubernetes module type. In many cases you'll want to use a kubernetes module to deploy a container module. You can do this by referencing the image ID of the container module in your Kubernetes manifests.

The kubernetes module works very similar to the helm module and you'll find a lot of similarities between the two guides.

You'll find the full spec for the kubernetes module in our reference docs.

Basics

First off, a couple of things to note on how Kubernetes support is implemented, with respect to Garden primitives:

  1. One kubernetes module maps to a single Garden service (not to be confused with the Kubernetes Service resources), with the same name as the module.

  2. Because a Kubernetes manifest does not contain actual code (i.e. your containers/images), you'll often need to make two Garden modules for a single deployed service, e.g. one container module for your image, and then the kubernetes module that references it.

Referencing manifests

When configuring a kubernetes module, you have a choice between pointing Garden to the actual manifest files via the files directive or simply adding the manifests inline in your Garden config under the manifests directive.

Manifest files

If your project structure looks something like this:

.
├── api
   ├── garden.yml
   ├── manifests
      ├── prod 
      ├── Deployment.yaml
      ├── Ingress.yaml
      └── Service.yaml
      ├── dev 
      ├── Deployment.yaml
      ├── Ingress.yaml
      └── Service.yaml
   └── src
└── project.garden.yml

You can reference the manifests like so:

kind: module
type: kubernetes
name: api
files: 
  - ./manifests/Deployment.yaml
  - ./manifests/Ingress.yaml
  - ./manifests/Service.yaml

Due to a current limitation you need to list all the manifests. There's an open issue for addressing this.

You can also use templating to reference different manifests based on environment. For example, if your project structure looks like this:

.
├── api
│   ├── garden.yml
│   ├── manifests
│   │   ├── dev
│   │   │   ├── Deployment.yaml
│   │   │   ├── Ingress.yaml
│   │   │   └── Service.yaml
│   │   └── prod
│   │       ├── Deployment.yaml
│   │       ├── Ingress.yaml
│   │       └── Service.yaml
│   └── src
└── project.garden.yml

You can reference the manifests like so:

kind: module
type: kubernetes
name: api
files: 
  - ./manifests/${environment.name}/Deployment.yaml
  - ./manifests/${environment.name}/Ingress.yaml
  - ./manifests/${environment.name}/Service.yaml

Inline

You can also include the manifests inline with your Garden configuration. For example:

kind: module
type: kubernetes
name: api
manifests:
- apiVersion: apps/v1
  kind: Deployment
  metadata:
    name: api
    labels:
      app: api
  spec:
    # ...

- apiVersion: v1
  kind: Service
  metadata:
  labels:
    app: api
    name: api
  spec:
    # ...
- apiVersion: networking.k8s.io/v1
  kind: Ingress
  metadata:
    name: api
    labels:
      app: api
  spec:
    # ...

Using variables

Whether you have your manifests inline or reference them as files, you can use Garden template strings. For example:

# This will work inside api/garden.yml and manifests/garden.yml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: api
  labels:
    app: api
spec:
  replicas: ${var.numberOfReplicas}
  # ...

Tasks and tests

You may also want to define tests and/or tasks that execute in one of the containers defined in the manifest. For example:

kind: Module
type: kubernetes
name: postgres
manifests: [./manifests/postgres.yaml]
serviceResource:
  kind: StatefulSet
  name: postgres
tasks:
  - name: db-init
    args: [ psql, -w, -U, postgres, ..., -c, "'CREATE TABLE IF NOT EXISTS my-table ..." ]
    env:
      PGPASSWORD: postgres
    dependencies:
      - postgres
  - name: db-clear
    args: [ psql, -w, -U, postgres, ..., -c, "'TRUNCATE my-table'" ]
    env:
      PGPASSWORD: postgres
    dependencies:
      - postgres

Note first the serviceResource field. This tells Garden which Kubernetes Deployment, DaemonSet or StatefulSet to regard as the primary resource of the manifest. In this case, it is simply the postgres application itself. When running the db-init and db-clear tasks, Garden will find the appropriate container spec in the manifest based on the serviceResource spec, and then execute that container with the task's args and (optionally) the specified env variables.

The same applies to any tests that you specify. For example:

kind: Module
type: postgres
name: vote
serviceResource:
  kind: Deployment
...
tests:
  - name: integ
    args: [npm, run, test:integ]
    dependencies:
      - api

Instead of the top-level serviceResource you can also add a resource field with the same schema to any individual task or test specification. This can be useful if you have different containers in the chart that you want to use for different scenarios.

Linking container modules and Kuberneretes modules

When your project also contains one or more container modules that build the images used by a kubernetes module, you want to make sure the containers are built ahead of applying the Kubernetes manifests, and that the correct image tag is used when deploying. For example:

kind: Module
type: postgres
name: api
...
build:
  dependencies: [api-image]
manifests:
- apiVersion: apps/v1
  kind: Deployment
  metadata:
    name: api
    labels:
      app: api
    spec:
      containers:
      - name: api
        image: ${modules.api-image.outputs.deployment-image-id} # <--- Here we're referencing the output from the api-image module. This will also work in manifest files.
        # ...
kind: Module
type: container
name: api-image

Here the api module specifies the image as a build dependency, and additionally injects the api-image version into the Kubernetes manifest.

Code Synchronization (Dev Mode)

When your project contains the container module referenced by a kubernetes module, you can even use Garden's live code synchronization (dev mode) feature for a Kubernetes manifest. For example:

kind: Module
type: kubernetes
name: api
devMode:
  command: [npm, run, dev]
  sync:
    - target: /app
    - source: /tmp/somedir
      target: /somedir
serviceResource:
  kind: Deployment
  name: api 
  containerModule: api-image # <--- The name of container module
  containerName: api 

For dev mode to work you must specify serviceResource.containerModule, so that Garden knows which module contains the sources to use for code syncing. You can also use the devMode.command directive to, for example, start the container with automatic reloading or in development mode.

For the above example, you could then run garden deploy -w --dev=api to start the api service in hot-reloading mode. When you then change the sources in the api-image module, Garden syncs the changes to the running container from the Helm chart.

Production environments

You can define a remote environment as a production environment by setting the production flag to true. This affects some default behavior when deploying kubernetes modules. See the Deploying to production guide for details.

Next steps

Check out the full Kubernetes module reference.

Also check out the Helm module for a more flexible alternative.

Last updated