# note that helm tempates are converted into yaml and a kubectl apply is run on the yaml object, ie `helm ls` will not show anything
# TODO move these to config files
settings = {
"start_kind": True,
"preload_images_for_kind": True,
"deploy_metallb": True,
"deploy_ambassador_api": False,
"deploy_ambassador_edge_gateway": False,
"deploy_vault": False,
"deploy_consul": False,
}
demo_settings = {
"deploy_demo_ambassador_quote": False,
"deploy_demo_argo": False,
"deploy_demo_basic_ingress": False,
"deploy_demo_consul_demo": False,
"deploy_demo_oneup": False,
"deploy_demo_vault_demo": False,
"deploy_demo_polaris": True,
}
# this assumes that you are running a local registry and your images are been pulled from "localhost:5000"
# example: 'repository: localhost:5000/datawire/ambassador'
# https://github.com/onzyone/k8s-kind#troubleshooting
app_settings = {
"local_registry": "localhost:5000"
}
def deploy_metallb():
# TODO only install metallb only if running in a local env like kind (metallb is used for a local LB)
if settings.get("preload_images_for_kind"):
get_images(registry = "docker.io", images = ["metallb/controller:v0.9.3", "metallb/speaker:v0.9.3"])
include("metallb/Tiltfile")
def deploy_ambassador_api():
## This is Ambassador API Gateway
if settings.get("preload_images_for_kind"):
get_images(registry = "quay.io", images = ["datawire/ambassador:0.86.1"])
print('Installing Ambassador')
ambassador_crds = listdir("charts/stable/ambassador/crds/")
for each in ambassador_crds:
k8s_yaml(each)
yaml_ambassador = helm(
'charts/stable/ambassador',
# The release name, equivalent to helm --name
name='ambassador',
# The namespace to install in, equivalent to helm --namespace
namespace='ambassador',
# The values file to substitute into the chart.
values=['./helm-values/ambassador/values-local.yaml'],
)
k8s_yaml(yaml_ambassador)
def deploy_ambassador_edge_gateway():
# This is Ambassador Edge Gateway
print('Installing Ambassador Edge Gateway')
# donwload images:
if settings.get("preload_images_for_kind"):
get_images(registry = "quay.io", images = ["datawire/aes:1.4.2"])
local("helm repo add datawire https://www.getambassador.io")
local("kubectl create ns ambassador")
#k8s_yaml("./helm-values/ambassador-chart/namespace.yaml")
local("helm install ambassador --namespace ambassador datawire/ambassador --set image.repository=localhost:5000/datawire/aes --set image.tag=1.4.2")
def deploy_vault():
print('Installing vault')
if settings.get("preload_images_for_kind"):
get_images(registry = "docker.io", images = ["hashicorp/vault-k8s:0.1.1", "vault:1.3.1"])
k8s_yaml('helm-values/vault-helm/namespace.yaml')
yaml_vault = helm(
'charts/stable/vault-helm',
# The release name, equivalent to helm --name
name='vault-helm',
# The namespace to install in, equivalent to helm --namespace
namespace='vault',
# The values file to substitute into the chart.
values=['./helm-values/vault-helm/values-local.yaml'],
)
k8s_yaml(yaml_vault)
watch_file('charts/stable/vault-helm')
watch_file('./helm-values/vault-helm/values-local.yaml')
local_resource('vault-init', cmd='vault-demo/sbin/vault-local.sh', resource_deps=['vault-helm'])
def deploy_consul():
print('Installing consul')
if settings.get("preload_images_for_kind"):
get_images(registry = "docker.io", images = ["hashicorp/consul-k8s:0.10.1", "consul:1.6.2"])
k8s_yaml('helm-values/consul-helm/namespace.yaml')
yaml_consul = helm(
'charts/stable/consul-helm',
# The release name, equivalent to helm --name
name='consul-helm',
# The namespace to install in, equivalent to helm --namespace
namespace='consul',
# The values file to substitute into the chart.
values=['./helm-values/consul-helm/values-local.yaml'],
)
k8s_yaml(yaml_consul)
watch_file('charts/stable/consul-helm')
watch_file('./helm-values/consul-helm/values-local.yaml')
k8s_yaml("helm-values/consul-helm/ambassador-crd.yaml")
def get_images(registry, images):
for image in images:
local_resource("docker pull {} from internet".format(image), cmd='docker pull {}/{}'.format(registry, image))
local_resource("docker tag {}".format(image), cmd='docker tag {}/{} {}/{}'.format(registry, image, app_settings.get("local_registry"), image))
local_resource("docker push {} to local registry".format(image), cmd='docker push {}/{}'.format(app_settings.get("local_registry"), image))
# local_resource("kind load docker-image {}/{}".format(registry, image))
def start_kind():
print('what a great idea')
##############################
# Actual work happens here
##############################
if settings.get("start_kind"):
start_kind()
if settings.get("deploy_metallb"):
deploy_metallb()
if settings.get("deploy_ambassador_api"):
deploy_ambassador_api()
if settings.get("deploy_ambassador_edge_gateway"):
deploy_ambassador_edge_gateway()
if settings.get("deploy_vault"):
deploy_vault()
if settings.get("deploy_consul"):
deploy_consul()
##############################
# demo apps
##############################
if demo_settings.get("deploy_demo_ambassador_quote"):
if settings.get("preload_images_for_kind"):
get_images(registry = "quay.io", images = ["datawire/quote:0.2.7"])
include("ambassador-quote/Tiltfile")
if demo_settings.get("deploy_demo_argo"):
include("argo/Tiltfile")
if demo_settings.get("deploy_demo_basic_ingress"):
include("basic-ingress/Tiltfile")
if demo_settings.get("deploy_demo_consul_demo"):
if settings.get("preload_images_for_kind"):
get_images(registry = "docker.io", images = ["hashicorp/counting-service:0.0.2", "hashicorp/dashboard-service:0.0.4"])
#TODO ensure consul is running before running this
include("consul-demo/Tiltfile")
if demo_settings.get("deploy_demo_oneup"):
include("oneup/Tiltfile")
if demo_settings.get("deploy_demo_vault_demo"):
if settings.get("preload_images_for_kind"):
get_images(registry = "docker.io", images = ["jweissig/app:0.0.1"])
include("vault-demo/Tiltfile")
if demo_settings.get("deploy_demo_polaris"):
if settings.get("preload_images_for_kind"):
get_images(registry = "quay.io", images = ["fairwinds/polaris:0.6"])
include("polaris/Tiltfile")
K8S_NAMESPACE = "devenv-matt"
allow_k8s_contexts('kind-kind')
def create_namespace(namespace):
k8s_yaml(helm("tilt/k8s/namespace", namespace=namespace))
def intake(namespace, live_update=False):
k8s_yaml(helm("apps/intake/k8s", namespace=namespace, name="intake"))
k8s_resource("intake", port_forwards=["9999"])
custom_build(
'localhost:5000/intake',
'cd apps/intake && docker build -t $EXPECTED_REF .',
deps=[
'./apps/intake/Dockerfile',
'./apps/intake/bin/intake'
],
live_update=[
sync('./apps/intake/bin', '/bin'),
run('restart.sh'),
],
)
if live_update:
local_resource(
name="intake-liveupdate",
cmd="./tilt/go_build_temp_location.sh intake",
deps=[
"./apps/intake/",
],
ignore=[
"**",
"!**/*.go"
],
auto_init=False,
trigger_mode=TRIGGER_MODE_MANUAL
)
def emitter(namespace):
k8s_yaml(helm("apps/emitter/k8s", namespace=namespace, name="emitter"))
docker_build(
"localhost:5000/emitter",
"apps/emitter",
live_update=[
sync('./apps/emitter/main.py', '/app/main.py'),
run('restart.sh'),
],
)
def mysql(namespace):
k8s_yaml(helm("tilt/k8s/mysql", namespace=namespace, name="mysql"))
k8s_resource("mysql", port_forwards=["3306"])
def intake_db_workflows(namespace):
k8s_yaml(helm("apps/intake-db-workflows/k8s", namespace=namespace))
docker_build(
"localhost:5000/intake-db-workflows",
"apps/intake-db-workflows",
dockerfile="apps/intake-db-workflows/Dockerfile",
)
k8s_resource("intake-db-drop", trigger_mode=TRIGGER_MODE_MANUAL)
k8s_resource("intake-db-migrate", trigger_mode=TRIGGER_MODE_MANUAL, resource_deps=['intake-db-drop'])
create_namespace(K8S_NAMESPACE)
#intake(K8S_NAMESPACE, live_update=False)
#emitter(K8S_NAMESPACE)
#mysql(K8S_NAMESPACE)
#intake_db_workflows(K8S_NAMESPACE)
# -*- mode: Python -*-
local_resource(
'backend-compile',
'./gradlew bootJar && ' +
'unzip -o build/libs/backend-0.0.1-SNAPSHOT.jar -d build/jar-staging && ' +
'rsync --inplace --checksum -r build/jar-staging/ build/jar',
deps=['src', 'build.gradle'])
docker_build(
'backend-image',
'./build/jar',
dockerfile='./Dockerfile',
live_update=[
sync('./build/jar/BOOT-INF/lib', '/app/lib'),
sync('./build/jar/META-INF', '/app/META-INF'),
sync('./build/jar/BOOT-INF/classes', '/app'),
],
entrypoint = 'find . | entr -r java -Dspring.profiles.active=k8s -noverify -cp .:./lib/* org.google.callmeback.CallMeBackApp')
k8s_yaml('k8s.yml')
k8s_resource('backend', port_forwards=8000, resource_deps=['backend-compile','database'])
https://github.com/michaelkacher/k8cher/blob/main/src/k8cher.auth/Tiltfile
# This tiltfile sets up an auth service
docker_build('k8cher-auth', './')
# if .net sdk of proper version is on local machine can speed up buildtime by switching out the docker build
# for building on host machine and replacing the line above with the commented out code
# For more on Extensions, see: https://docs.tilt.dev/extensions.html
#load('ext://restart_process', 'docker_build_with_restart')
# watch source code and on change, rebuild artifacts (dlls, etc.) and place in builds folder
#local_resource(
# 'build',
# 'dotnet publish k8cher.auth.csproj -c Release -o ../../builds/k8cher-auth-build',
# deps=['./'],
# ignore=['k8cher.auth.sln', 'k8cher.auth.csproj.user', 'obj', 'bin', '.vs'],
# trigger_mode=TRIGGER_MODE_AUTO,
# labels=['auth'],
#)
# keeps a docker image named 'k8cher-auth' updated
#docker_build_with_restart(
# 'k8cher-auth',
# '../../builds/k8cher-auth-build',
# entrypoint=['dotnet', 'k8cher.auth.dll'],
# dockerfile='DevelopmentDockerfile',
# live_update=[
# sync('../../builds/k8cher-auth-build', '/app/out'),
# ],
#)
# deploys to kubernetes using the 'generic' service-chart
yaml = helm(
'../../charts/service-chart',
# The release name, equivalent to helm --name
name='k8cher-auth',
# The namespace to install in, equivalent to helm --namespace
namespace='default',
# The values file to substitute into the chart.
values=['./values.yaml']
)
k8s_yaml(yaml)
k8s_resource(
'k8cher-auth-service-chart',
links=[link('http://localhost:8088/auth/swagger', 'auth swagger')],
labels=['auth'],
resource_deps=['dapr-sidecar-injector', 'k8cher-db-postgresql']
)
# disabling until pgsql rc.1 released
#docker_build('k8cher-db-migrate', '../k8cher.auth', dockerfile='./MigrationDockerfile')
# This tiltfile sets up a postgres database, pg admin, and database migrations
# allow for remote helm charts
load('ext://helm_remote', 'helm_remote')
# Add Bitnami helm charts for postgres, this is the artificact to deploy postgres on the cluster
helm_remote('postgresql', release_name='k8cher-db', repo_name='bitnami', repo_url='https://charts.bitnami.com/bitnami',
set='postgresqlDatabase=k8cher,postgresqlUsername=postgres,postgresqlPassword=postgres')
# port forward for local development access
k8s_resource('k8cher-db-postgresql', port_forwards='5432:5432', labels=['database'])
# disabling until pgsql rc.1 released
# k8s_yaml('./kubernetes/k8cher-db-migrate.yaml')
# k8s_resource(
# 'k8cher-db-migrate',
# trigger_mode=TRIGGER_MODE_MANUAL,
# labels=['database'],
# resource_deps=['k8cher-db-postgresql']
# )
k8s_yaml('./kubernetes/pg-admin.yaml')
k8s_resource(
'pgadmin',
port_forwards=[port_forward(5555, 80, name='pg admin dashboard')],
labels=['database'],
resource_deps=['k8cher-db-postgresql']
)
# allow for remote helm charts
load('ext://helm_remote', 'helm_remote')
# don't hide secrets for development only environment
secret_settings ( disable_scrub=True )
# Create a local kubernetes secret store. This is only for local development and not secure!!!
# For production implement a a dapr secret store component (https://docs.dapr.io/reference/components-reference/supported-secret-stores/)
# such as HashiCorp Vault, Azure Key Vault, GPC Secret Manager, or AWS Secret Manager
k8s_yaml(local(
["kubectl", "create", "secret", "generic", "secret-store",
"--from-literal=pgadmin-password=bouncingcow",
"[email protected]",
"--from-literal=pg-host=k8cher-db-postgresql",
"--from-literal=pg-connection-string=Host=k8cher-db-postgresql;Port=5432;Database=k8cher;Username=postgres;Password=postgres;",
"--from-literal=password=Y4nys7f11",
"--from-literal=signing-key=NO5U308H!@#SI2ZXCVSDSDNDln",
"--from-literal=jwt-issuer=http://localhost:8088",
"--from-literal=jwt-audience=http://localhost:8088",
"--from-literal=ingress=http://localhost:8088/",
"--from-literal=smtp-user=mike",
"--from-literal=smtp-password=Password_",
"[email protected]",
"--from-literal=web-login-redirect=http://localhost:3000/login",
"--from-literal=web-confirmation-expired=http://localhost:3000/tokenexpired",
"-o=yaml", "--dry-run=client"]
))
# Proxy for incoming traffic
include('./src/k8cher.proxy/Tiltfile')
# Auth Service
include('./src/k8cher.auth/Tiltfile')
# Auth Service postgresql database and tools
include('./src/k8cher.auth.db/Tiltfile')
# Service to sync Svelte Store database
include('./src/k8cher.store/Tiltfile')
# maildev development mail server
include('./src/maildev/Tiltfile')
# Dapr
helm_remote('dapr', release_name='dapr', repo_name='dapr', repo_url='https://dapr.github.io/helm-charts/')
k8s_resource('dapr-dashboard', port_forwards=[port_forward(8080, 8080, name='dapr dashboard')], labels=['dapr'])
k8s_resource('dapr-operator', labels=['dapr'])
k8s_resource('dapr-sentry', labels=['dapr'])
k8s_resource('dapr-placement-server', labels=['dapr'])
k8s_resource('dapr-sidecar-injector', labels=['dapr'])
# Dapr Components
k8s_yaml('./daprComponents/pg-store.yaml')
k8s_yaml('./daprComponents/email.yaml')
# -*- mode: Python -*-
trigger_mode(TRIGGER_MODE_MANUAL)
load("./bin/_tilt", "images", "linkerd_yaml", "settings")
if settings.get("default_registry"):
default_registry(settings.get("default_registry"))
if settings.get("allow_k8s_context"):
allow_k8s_contexts(settings.get("allow_k8s_contexts"))
k8s_yaml(linkerd_yaml())
for image in images:
if "live_update" in image:
sync_from = image["live_update"]["sync"]["from"]
sync_to = image["live_update"]["sync"]["to"]
custom_build(
image["image"],
"ACTUAL_REF=$(./bin/docker-build-%s) && docker tag $ACTUAL_REF $EXPECTED_REF" % image["name"],
image["deps"],
live_update=[
sync(sync_from, sync_to),
],
)
else:
custom_build(
image["image"],
"ACTUAL_REF=$(./bin/docker-build-%s) && docker tag $ACTUAL_REF $EXPECTED_REF" % image["name"],
image["deps"],
)
# Load the extension for helm_remote
load('ext://helm_remote', 'helm_remote')
# Load the cert manager helpers
load('../cert-manager/Tiltfile', 'generate_certificate')
# Load the password helpers
load('../../libraries/password/Tiltfile', 'generate_password')
# Load the secret helpers
load('../../libraries/secrets/Tiltfile', 'secret_exists', 'create_secret_if_not_exists')
def deploy_registry(name='docker-registry', user='user', password="", url="", ip='192.168.1.1', cert_issuer='ca', cert_name='registry-certificate', pod_annotations='', credentials_secret_name='registry-credentials'):
if password == "":
password=generate_password()
if url == "":
url=ip+':5000'
create_secret_if_not_exists(credentials_secret_name, USERNAME=user, PASSWORD=password, URL=url)
password = str(local("kubectl get secret "+credentials_secret_name+" -o jsonpath='{.data.PASSWORD}' | base64 -d", quiet=True))
htpasswd = str(local('docker run --entrypoint htpasswd registry:2.6 -Bbn '+user+' '+password, quiet=True))
generate_certificate(
issuer=cert_issuer,
name=cert_name,
dnsNames=[
name,
name+'.default',
name+'.default.svc',
name+'.default.svc.cluster.local',
],
ipAddresses=[ip]
)
set_values = [
'persistence.enabled=true',
'service.port=443',
'tlsSecretName='+cert_name,
'secrets.htpasswd='+htpasswd,
]
if pod_annotations != "":
set_values.append('podAnnotations.'+pod_annotations)
helm_remote(
'docker-registry',
release_name=name,
repo_url='https://charts.helm.sh/stable',
repo_name='docker-registry',
set=set_values,
)
k8s_resource(
workload=name,
objects=[
name+':persistentvolumeclaim',
name+'-config:configmap',
name+'-secret:secret'
],
port_forwards=[
port_forward(5000, 5000, "registry_port_forward")
],
resource_deps=[cert_name]
)
def image_resource(name, img, credentials_secret_name='registry-credentials', resource_deps=[]):
user = str(local("kubectl get secret "+credentials_secret_name+" -o jsonpath='{.data.USERNAME}' | base64 -d", quiet=True))
password = str(local("kubectl get secret "+credentials_secret_name+" -o jsonpath='{.data.PASSWORD}' | base64 -d", quiet=True))
local_resource(
name,
'skopeo copy --dest-tls-verify=false --dest-creds='+user+':'+password+' docker-daemon:'+img+' docker://localhost:5000/'+img,
resource_deps=resource_deps
)
# Load the extension for helm_remote
load('ext://helm_remote', 'helm_remote')
# Load the password helpers
load('../../libraries/password/Tiltfile', 'generate_password')
# Load the secret helpers
load('../../libraries/secrets/Tiltfile', 'secret_exists', 'create_secret_if_not_exists')
def deploy_database(db_name="db", db_user="user", db_password="", admin_password="", credentials_secret_name="db-credentials", resource_deps=[]):
if db_password == "":
db_password=generate_password()
if admin_password == "":
admin_password=generate_password()
create_secret_if_not_exists(credentials_secret_name, DB=db_name, USERNAME=db_user, PASSWORD=db_password, ADMIN_PASSWORD=admin_password)
db_password = str(local("kubectl get secret "+credentials_secret_name+" -o jsonpath='{.data.PASSWORD}' | base64 -d", quiet=True))
admin_password = str(local("kubectl get secret "+credentials_secret_name+" -o jsonpath='{.data.ADMIN_PASSWORD}' | base64 -d", quiet=True))
set_values = [
'postgresqlUsername='+db_user,
'postgresqlDatabase='+db_name,
'postgresqlPassword='+db_password,
'postgresqlPostgresPassword='+admin_password,
]
helm_remote(
'postgresql',
release_name='db',
repo_url='https://charts.bitnami.com/bitnami',
repo_name='postgresql',
set=set_values,
)
k8s_resource(
workload='db-postgresql',
new_name='db',
objects=[
'db-postgresql:secret'
],
resource_deps=resource_deps
)
# Load the extension for local_output
load('ext://local_output', 'local_output')
def generate_password():
return local_output("head -c 12 /dev/urandom | shasum -a 256 | cut -d' ' -f1")
def secret_exists(name, namespace="default"):
result = local("kubectl get secret --ignore-not-found -n "+namespace+" "+name, quiet=True)
return str(result) != ""
def create_secret_if_not_exists(name, namespace="default", **kwargs):
if secret_exists(name, namespace):
return
secret = {
'apiVersion': 'v1',
'kind': 'Secret',
'metadata': {
'name': name,
'namespace': namespace
},
'type': 'Opaque',
'stringData': {}
}
for key, val in kwargs.items():
secret['stringData'][key] = val
local('echo "'+str(encode_yaml(secret))+'" | kubectl create -f -')
Tiltfile.global
### Helpers Start ###
def getAbsoluteDir(relativeDir):
return str(local('mkdir -p {dir} && cd {dir} && pwd'.format(dir=relativeDir))).strip()
def getNested(dict, path, fallback=None):
value = dict
for path_segment in path.split('.'):
value = value.get(path_segment, {})
return value or fallback
def getHelmValuesFile():
return './Tiltconfig.yaml'
def getHelmOverridesFile():
tidepool_helm_overrides_file = getHelmValuesFile()
localOverrides = read_yaml('./local/Tiltconfig.yaml', False)
if type(localOverrides) == 'dict':
tidepool_helm_overrides_file = './local/Tiltconfig.yaml'
return tidepool_helm_overrides_file
def getConfig():
config = read_yaml(getHelmValuesFile())
overrides = read_yaml(getHelmOverridesFile())
config.update(overrides)
return config
def isShutdown():
return bool(int(str(local('printf ${SHUTTING_DOWN-0}'))))
### Helpers End ###
allow_k8s_contexts("kind-cf")
# Allow for installing other helm charts
load("ext://helm_remote", "helm_remote")
# Restart golang process without needing to install a process watcher
load("ext://restart_process", "docker_build_with_restart")
helm_remote("postgresql",
repo_name="bitnami",
repo_url="https://charts.bitnami.com/bitnami",
# This chart version pulls in app version 11.11.0
version="10.3.11",
set=[
"postgresqlPassword=local_password",
"postgresqlPostgresPassword=local_password",
"rbac.create=true"
]
)
helm_remote("traefik",
repo_name="traefik",
repo_url="https://helm.traefik.io/traefik",
version="9.12.3",
set=[
"service.type=ClusterIP"
]
)
# When running locally through Tilt, we want to run in dev mode
docker_build_with_restart(
ref="api",
context="../", # From location of Tiltfile
dockerfile="./Dockerfile.api",
live_update=[
# From location of Tiltfile
sync("../", "/app/"),
# Ran within container
run("cd /app/ && go mod download", trigger=["./go.sum"]),
],
# From docker context
ignore=["web/"],
# Override Dockerfile so that we stay on the build layer with dev
# dependencies and hot reloading
target="build",
entrypoint="go run cmd/cf.go api",
)
# When running locally through Tilt, we want to run in dev mode
docker_build(
ref="frontend",
context="../web/frontend",
dockerfile="./Dockerfile.frontend",
live_update=[
sync("../web/frontend/", "/app/"),
run("cd /app && yarn install", trigger=["../web/frontend/yarn.lock"]),
],
# Override Dockerfile so that we stay on the build layer with dev
# dependencies and hot reloading
target="build",
entrypoint="yarn start",
)
twilio_host = str(local("pulumi -s dev --cwd ../deployment/pulumi config get twilio:host")).strip()
twilio_account_sid = str(local("pulumi -s dev --cwd ../deployment/pulumi config get twilio:account_sid")).strip()
twilio_auth_token = str(local("pulumi -s dev --cwd ../deployment/pulumi config get twilio:auth_token")).strip()
twilio_phone_number = str(local("pulumi -s dev --cwd ../deployment/pulumi config get twilio:phone_number")).strip()
api_yaml = helm(
"../deployment/helm/api/",
name="api",
values=["../deployment/helm/api/values.yaml"],
set=[
"env.CF_TWILIO_HOST="+twilio_host,
"env.CF_TWILIO_ACCOUNT_SID="+twilio_account_sid,
"env.CF_TWILIO_AUTH_TOKEN="+twilio_auth_token,
"env.CF_TWILIO_PHONE_NUMBER="+twilio_phone_number
],
)
k8s_yaml(api_yaml)
frontend_yaml = helm(
"../deployment/helm/frontend/",
name="frontend",
values=["../deployment/helm/frontend/values.yaml"],
)
k8s_yaml(frontend_yaml)
k8s_resource("postgresql-postgresql", port_forwards=["5432"])
k8s_resource("traefik", port_forwards=["8000", "9000"])
...
...
...
...
...
...
https://github.com/onzyone/k8s-tilt/blob/master/Tiltfile