Skip to content

Commit

Permalink
Add tilt-based development tooling
Browse files Browse the repository at this point in the history
Signed-off-by: Andy Goldstein <goldsteina@vmware.com>
  • Loading branch information
ncdc committed Dec 13, 2019
1 parent e9ec746 commit 4ffe024
Show file tree
Hide file tree
Showing 7 changed files with 253 additions and 17 deletions.
4 changes: 4 additions & 0 deletions .dockerignore
Expand Up @@ -2,9 +2,13 @@
.github
.vscode
bin/
!bin/manager-tilt
config/
hack/
docs/
logos/
scripts/
**/.md
tilt-settings.json
tilt.d/
Tiltfile
4 changes: 4 additions & 0 deletions .gitignore
Expand Up @@ -48,3 +48,7 @@ cmd/clusterctl/config/manifest
# The golang vendor directory that contains local copies of external
# dependencies that satisfy Go imports in this project.
vendor

# User-supplied Tiltfile extensions & settings
tilt.d
tilt-settings.json
20 changes: 15 additions & 5 deletions Dockerfile
Expand Up @@ -23,25 +23,35 @@ ENV GOPROXY=$goproxy
# Copy the Go Modules manifests
COPY go.mod go.mod
COPY go.sum go.sum

# Cache deps before building and copying source so that we don't need to re-download as much
# and so that source changes don't invalidate our downloaded layer
RUN go mod download

# Copy the sources
COPY ./ ./

RUN wget --output-document /restart.sh --quiet https://raw.githubusercontent.com/windmilleng/rerun-process-wrapper/master/restart.sh && \
wget --output-document /start.sh --quiet https://raw.githubusercontent.com/windmilleng/rerun-process-wrapper/master/start.sh && \
chmod +x /start.sh && chmod +x /restart.sh

# Build
ARG ARCH
RUN CGO_ENABLED=0 GOOS=linux GOARCH=${ARCH} \
go build -a -ldflags '-extldflags "-static"' \
-o manager .

# Tilt image
FROM golang:1.12.10 as tilt-helper
# Support live reloading with Tilt
RUN wget --output-document /restart.sh --quiet https://raw.githubusercontent.com/windmilleng/rerun-process-wrapper/master/restart.sh && \
wget --output-document /start.sh --quiet https://raw.githubusercontent.com/windmilleng/rerun-process-wrapper/master/start.sh && \
chmod +x /start.sh && chmod +x /restart.sh

FROM debian:stretch-slim as tilt
WORKDIR /workspace
COPY --from=tilt-helper /start.sh /start.sh
COPY --from=tilt-helper /restart.sh /restart.sh
COPY ./bin/manager-tilt /workspace/manager
ENTRYPOINT [ "/start.sh", "/workspace/manager" ]

# Copy the controller-manager into a thin image
# Production image
FROM gcr.io/distroless/static:latest
WORKDIR /
COPY --from=builder /workspace/manager .
Expand Down
105 changes: 105 additions & 0 deletions Tiltfile
@@ -0,0 +1,105 @@
# -*- mode: Python -*-

# Read from the user's configuration file.
settings = read_json('tilt-settings.json', default={})

allow_k8s_contexts(settings.get('allowed_contexts'))
default_registry(settings.get('default_registry'))

providers = {
'core': {
'context': '.',
'image': 'gcr.io/k8s-staging-cluster-api/cluster-api-controller',
'ignore': ['test/infrastructure/docker'],
'live_reload_deps': ['main.go', 'go.mod', 'go.sum', 'api', 'bootstrap', 'cmd', 'controllers', 'errors', 'util']
},
'aws': {
'context': '../cluster-api-provider-aws',
'image': 'gcr.io/k8s-staging-cluster-api-aws/cluster-api-aws-controller',
'ignore': ['../cluster-api-provider-aws/config/manager/credentials.env'],
'live_reload_deps': ['main.go', 'go.mod', 'go.sum', 'api', 'cmd', 'controllers', 'pkg']
},
'docker': {
'context': '.',
'kustomize_dir': 'test/infrastructure/docker',
'dockerfile': 'test/infrastructure/docker/Dockerfile',
'image': 'gcr.io/k8s-staging-capi-docker/capd-manager',
'sync_build_path': 'test/infrastructure/docker',
'manager_dir': 'test/infrastructure/docker/bin',
'live_reload_deps': ['main.go', 'go.mod', 'go.sum', 'api', 'cloudinit', 'controllers', 'pkg']
}
}


def enable_provider(name):
p = providers.get(name)

sync_build_path = p.get('sync_build_path', '.')

manager_dir = p.get('manager_dir', 'bin')

manager_build_path = p.get('sync_build_path', p.get('context'))
live_reload_deps=[]
for d in p.get('live_reload_deps', []):
live_reload_deps += manager_build_path + '/' + d
local_resource(name + "_manager",
cmd='cd ' + manager_build_path + '; CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -a -ldflags \'-extldflags "-static"\' -o ' + manager_dir + '/manager-tilt',
deps=live_reload_deps)

docker_build(
ref=p.get('image'),
context=p.get('context'),
dockerfile=p.get('dockerfile', 'Dockerfile'),
target='tilt',
build_args={'manager_dir': manager_dir},
entrypoint='/start.sh /workspace/manager',
only=p.get('only'),
ignore=p.get('live_reload_deps', []) + p.get('ignore', []),
live_update=[
sync('bin/manager-tilt', '/workspace/manager'),
run('/restart.sh')
]
)

# default to kustomize_dir, fall back to context
kustomize_dir = p.get('kustomize_dir', p.get('context'))
k8s_yaml(kustomize(kustomize_dir + '/config/default'))


def deploy_cert_manager():
registry = 'quay.io/jetstack'
version = 'v0.11.0'
images = ['cert-manager-controller', 'cert-manager-cainjector', 'cert-manager-webhook']

for image in images:
local('docker pull {}/{}:{}'.format(registry, image, version))
local('kind load docker-image {}/{}:{}'.format(registry, image, version))

local('kubectl apply -f https://github.com/jetstack/cert-manager/releases/download/v0.11.0/cert-manager.yaml')

# wait for the service to become available
local('kubectl wait --for=condition=Available --timeout=300s apiservice v1beta1.webhook.cert-manager.io')


def include_user_tilt_files():
user_tiltfiles = listdir('tilt.d')
for f in user_tiltfiles:
include(f)


def enable_providers():
for name in ['core'] + settings.get('enable_providers', []):
enable_provider(name)


#def set_aws_credentials(aws_dir):
#if str(read_file(aws_dir + 'config/manager/credentials.env', '')) == '':
#local_resource('aws_credentials', aws_dir + "/hack/generate-manager-credentials-file.sh")


##############################
# Actual work happens here
##############################
include_user_tilt_files()
deploy_cert_manager()
enable_providers()
1 change: 1 addition & 0 deletions docs/book/src/SUMMARY.md
Expand Up @@ -10,6 +10,7 @@
- [Generating a Kubeconfig](./tasks/certs/generate-kubeconfig.md)
- [Developer Guide](./architecture/developer-guide.md)
- [Repository Layout](./architecture/repository-layout.md)
- [Rapid iterative development with Tilt](./developer/tilt.md)
- [Controllers](./architecture/controllers.md)
- [Bootstrap](./architecture/controllers/bootstrap.md)
- [Cluster](./architecture/controllers/cluster.md)
Expand Down
99 changes: 99 additions & 0 deletions docs/book/src/developer/tilt.md
@@ -0,0 +1,99 @@
# Developing Cluster API with Tilt

## Overview

This document describes how to use [kind](https://kind.sigs.k8s.io) and [Tilt](https://tilt.dev) for a simplified
workflow that offers easy deployments and rapid iterative builds.

## Prerequisites

1. [Docker](https://docs.docker.com/install/)
1. [kind](https://kind.sigs.k8s.io) v0.6 or newer
1. [Tilt](https://docs.tilt.dev/install.html)
1. Clone the [Cluster API](https://github.com/kubernetes-sigs/cluster-api) repository locally
1. Clone the provider(s) you want to deploy locally as well

## Getting started

### Create a kind cluster
First, make sure you have a kind cluster and that your `KUBECONFIG` is set up correctly:

```
$ kind create cluster
```

### Create a tilt-settings.json file
Next, create a `tilt-settings.json` file and place it in your local copy of `cluster-api`. Here is an example:

```json
{
"allowed_contexts": ["kind-kind"],
"default_registry": "gcr.io/your-project-name-here",
"enable_providers": ["aws", "docker"]
}
```

#### tilt-settings.json fields
**allowed_contexts**: A list of kubeconfig contexts Tilt is allowed to use. See the Tilt documentation on
*[allow_k8s_contexts](https://docs.tilt.dev/api.html#api.allow_k8s_contexts) for more details.

**default_registry**: The image registry to use if you need to push images. See the [Tilt
*documentation](https://docs.tilt.dev/api.html#api.default_registry) for more details.

**enable_providers**: A list of the providers to enable. See [available providers](#available-providers) for more details.

### Run Tilt!

To launch your development environment, run

```
tilt up
```

This will open the command-line HUD as well as a web browser interface. You can monitor Tilt's status in either
location. After a brief amount of time, you should have a running development environment, and you should now be able to
create a cluster. Please see the [Usage section in the Quick
Start](https://cluster-api.sigs.k8s.io/user/quick-start.html#usage) for more information on creating workload clusters.

## Available providers

The following providers are currently defined in the Tiltfile:

- **core**: cluster-api itself (Cluster/Machine/MachineDeployment/MachineSet/KubeadmConfig/KubeadmControlPlane)
- **aws**: AWS provider (AWSCluster/AWSMachine)
- **docker**: Docker provider (DockerCluster/DockerMachine)

### Provider map field definitions

TODO

## Customizing Tilt

If you need to customize Tilt's behavior, you can create files in cluster-api's `tilt.d` directory. This file is ignored
by git so you can be assured that any files you place here will never be checked in to source control.

These files are included after the `providers` map has been defined and after all the helper function definitions. This
is immediately before the "real work" happens.

## Under the covers, a.k.a "the real work"

At a high level, the Tiltfile performs the following actions:

1. Read `tilt-settings.json`
1. Configure the allowed Kubernetes contexts
1. Set the default registry
1. Define the `providers` map
1. Include user-defined Tilt files
1. Deploy cert-manager
1. Enable providers (`core` + what is listed in `tilt-settings.json`)
1. Build the manager binary locally as a `local_resource`
1. Invoke `docker_build` for the provider
1. Invoke `kustomize` for the provider's `config/default` directory

### Live updates

Each provider in the `providers` map has a `live_reload_deps` list. This defines the files and/or directories that Tilt
should monitor for changes. When a dependency is modified, Tilt rebuilds the provider's manager binary **on your local
machine**, copies the binary to the running container, and executes a restart script. This is significantly faster
than rebuilding the container image for each change. It also helps keep the size of each development image as small as
possible (the container images do not need the entire go toolchain, source code, module dependencies, etc.).
37 changes: 25 additions & 12 deletions test/infrastructure/docker/Dockerfile
Expand Up @@ -14,27 +14,40 @@

FROM golang:1.12.10 as builder

# default the go proxy
# Run this with docker build --build_arg $(go env GOPROXY) to override the goproxy
ARG goproxy=https://proxy.golang.org
ARG project=test/infrastructure/docker

# run this with docker build --build_arg $(go env GOPROXY) to override the goproxy
ENV GOPROXY=$goproxy

WORKDIR /workspace
# Copy the go source
COPY ./ ./
WORKDIR /workspace/$project
WORKDIR /workspace/test/infrastructure/docker
COPY go.mod go.mod
COPY go.sum go.sum
RUN go mod download
WORKDIR /workspace
COPY . .

# Build
RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 GO111MODULE=on go build -a -o manager main.go
RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -a -o /workspace/manager main.go


# Tilt image
FROM golang:1.12.10 as tilt-helper
# Support live reloading with Tilt
RUN wget --output-document /restart.sh --quiet https://raw.githubusercontent.com/windmilleng/rerun-process-wrapper/master/restart.sh && \
wget --output-document /start.sh --quiet https://raw.githubusercontent.com/windmilleng/rerun-process-wrapper/master/start.sh && \
chmod +x /start.sh && chmod +x /restart.sh

FROM debian:stretch-slim as tilt
ARG manager_dir=.
WORKDIR /workspace
COPY --from=tilt-helper /start.sh /start.sh
COPY --from=tilt-helper /restart.sh /restart.sh
COPY $manager_dir/bin/manager-tilt /workspace/manager
ENTRYPOINT [ "/start.sh", "/workspace/manager" ]


# Use alpine:latest as minimal base image to package the manager binary and its dependencies
FROM alpine:latest

ARG project=test/infrastructure/docker

# install a couple of dependencies
WORKDIR /tmp
RUN apk add --update \
Expand All @@ -50,6 +63,6 @@ RUN curl -LO https://download.docker.com/linux/static/stable/x86_64/docker-19.03
rm docker-19.03.1.tgz

WORKDIR /
COPY --from=builder /workspace/$project/manager .
COPY --from=builder /workspace/manager .

ENTRYPOINT ["/manager"]

0 comments on commit 4ffe024

Please sign in to comment.