Skip to content

Latest commit

 

History

History
180 lines (133 loc) · 9.11 KB

dep-006.md

File metadata and controls

180 lines (133 loc) · 9.11 KB

+++ dep = 6 title = "draft.toml Format" authors = [ "Matt Fisher matt.fisher@microsoft.com" ] created = 2017-10-23 +++

Abstract

Draft configuration is stored in an application's root directory as draft.toml. This file contains configuration that affects the behaviour of draft up and draft connect. This document describes the format of draft.toml and the reasoning behind the use of TOML.

Motivation

Draft users need a way to persist feature flags to draft up without having to invoke the same feature flags every time they call draft up. Similarly, users that want to collaborate on an app using Draft want to share the same feature flags they used, allowing others to repeat the same feature flags that were enabled on their machine to replicate the same environment.

Specification

The format of this file is as follows:

[environments]
    [environments.development]
    name = "example-go"
    registry = "microsoft"
    set = ["foo=bar", "car=star"]
    wait = true
    watch = false
    watch-delay = 1
    override-ports = ["8080:8080", "9229:9229"]
    auto-connect = false
    custom-tags = ["backend-dev"]
    chart = "charts/my-app-dev"
    dockerfile = "Dockerfile.dev"

    [environments.staging]
    name = "example-go"
    namespace = "kube-system"
    build-tar = "build.tar.gz"
    chart-tar = "chart.tar.gz"
    custom-tags = ["latest", "backend-staging"]
    override-ports = ["8080:8080"]
    image-build-args = { BUILD_TIME_ARG = "build-time-argument-value",  HTTP_PROXY = "http://my-proxy" }
    chart = "charts/my-app-staging"

Let's break it down by section:

[environments]

The root of the TOML file. Each definition under this node is considered an "environment". More on that in a second.

    [environments.development]

This is the environment name. Applications deployed by Draft can be configured in different manners based on the present environment. By default, draft up deploys using the development environment, but this can be tweaked by either setting $DRAFT_ENV or by supplying the environment name at runtime using draft up --environment=staging.

    name = "example-go"
    registry = "microsoft"
    namespace = "kube-system"
    build-tar = "build.tar.gz"
    chart-tar = "chart.tar.gz"
    container-builder = "docker"
    set = ["foo=bar", "car=star"]
    wait = true
    watch = false
    watch-delay = 2
    override-ports = ["8080:8080", "9229:9229"]
    auto-connect = false
    custom-tags = ["latest", "backend-staging"]
    chart = "charts/javascript"
    dockerfile = "Dockerfile"
    image-build-args = { BUILD_TIME_ARG = "build-time-argument-value",  HTTP_PROXY = "http://my-proxy" }
    resource-group-name = "foo"

Here is a run-down on each of the fields:

  • name: the name of the application. This will map directly with the name of the Helm release.
  • registry: the name of the Docker registry to publish the image to.
    • This can also be set globally by setting the registry field with draft config set registry <name>. However, the registry field in draft.toml takes precedence.
  • namespace: the kubernetes namespace where the application will be deployed.
  • build-tar: path to a gzipped build tarball. chart-tar must also be set.
  • chart-tar: path to a gzipped chart tarball. build-tar must also be set.
  • container-builder: the container image builder used to build the container. Setting this to acrbuild uses ACR Build; any other value uses Docker.
  • set: set custom Helm values.
  • wait: specifies whether or not to wait for all resources to be ready when Helm installs the chart.
  • watch: whether or not to deploy the app automatically when local files change.
  • watch-delay: the delay for local file changes to have stopped before deploying again (in seconds).
  • override-ports: the configuration to be passed to the draft connect command, in the format LOCALHOST_PORT:CONTAINER_PORT
  • auto-connect: specifies whether Draft should automatically connect to the application after the deplyoment is successful. The local ports are configurable through the override-ports field.
  • custom-tags: specifies the custom tags Draft will push to the container registry. Note that Draft will push and use the computed SHA of the application as the tag of your image for the Helm chart.
  • chart: the chart (local path, relative to draft.toml) that will be used to release the application for this environment. If no value is specified, Draft will try to use the first directory from charts/.
  • dockerfile: the name of the Dockerfile that will be used to build the image for this environment
  • image-build-args: arguments to pass at image build time. Follow Docker best practices about passing build time argumetns
  • resource-group-name: the name of the resource group hosting the container registry. Only used when the container builder is set to acrbuild

Note: It is recommended to avoid fixed image tags (like latest, canary, dev) in production, and if the image tag is the same in your chart, Helm will not upgrade your release.

For more information on configuring draft connect, check dep-007.md.

Note: All updates to draft.toml will take effect the next time draft <command> --environment=<affected environment> is invoked. This way, you can execute draft up, draft connect, draft delete, draft logs with different environments and work on your application with different configuration.

Note: The namespace key/value pair cannot be modified if the value is changed in draft.toml. Once a deployment has occurred in the original namespace, it won't be transferred over to another namespace. To do this, you can delete your application using draft delete --environment=<affected environment> and then re-create it using draft up --environment=<affected environment> .

Examples

Here are some more examples of how each field can be used:

Set

Set must be a map, but can have multiple key/value pairs set such as set = [ "key1"="val1", "key2"="val2"]. If you want to set fields within a map in the Helm values.yaml, then use a dotted notation.

For example, if the Helm values.yaml defines a service:

...
service:
  name: website
  type: ClusterIP
  externalPort: 8080
  internalPort: 80

And you want to override the type and externalPort values, you would include both of them in the map for set in draft.toml

  [environments.live]
    ...
    set = ["service.type=LoadBalancer", "service.externalPort=80"]

Rationale

Why TOML

TOML is a minimal configuration file format that is easy to read due to obvious semantics. TOML is designed to map unambiguously to a hash table. TOML should be easy to parse into data structures in a wide variety of languages without ambiguity.

Why not support other formats like YAML/JSON

We've learned a few things from using YAML/JSON across multiple OSS projects. Here's a few war stories that justify why we are using TOML instead of other conventional markup languages commonly used.

YAML

From personal experience, debugging a YAML file written with improper or mixed indentation has caused more frustration than working with any other markup language. There have been countless times where users broke their manifests by accidentally using tabs instead of spaces (and vice versa) and end up with obscure YAML parser errors. TOML does not care about indentation, which is a really welcome change for a simple markup language.

Secondly, the YAML spec is over 23,000 words. It's bloated, complex, and not at all "simple" or "obvious" to the user on its syntax. There are over 9 different ways to skin the proverbial cat in YAML, and because it is so complex most parsers will not support every feature (or in certain cases, parse it in another format). draft.toml only needs to support 1 way to write a multi-line string. In TOML, it's just

message = """This is
a multi-line
string."""

There is an excellent blog post by Martin Tournoij who explains the many intricacies and pitfalls of YAML that goes into greater detail.

JSON

JSON certainly has its place and is stricter than YAML on field types, but it is not a human-readable markup language. You can't write comments in JSON. That's a non-starter for a file that's meant to be used by developers to express how their application is deployed to production. At the end of the day, we're writing a tool for developers, not machines. For projects that stand up infrastructure like acs-engine or kops, JSON is an excellent fit.