Use go.skia.org/infra/go/login paired with infra-sk/modules/login.js (Legacy Polymer apps use res/imp/login.html) and/or go.skia.org/infra/go/webhook for authentication. When using OAuth, see the secrets section below for including client secrets.

Wrap your http.Handler (many services use mux.NewRouter() with go.skia.org/infra/go/httputils.LoggingGzipRequestResponse to provide monitoring and logging of HTTP requests and responses. Then, wrap it in go.skia.org/infra/go/httputils.HealthzAndHTTPS to add an unlogged /healthz endpoint for use with GKE health monitoring and various HTTPS configuration. Use go.skia.org/infra/go/httputils.NewTimeoutClient for HTTP clients, because the default httpClient doesn't have good defaults for timeouts.

Any calls to external APIs should use an http.Client wrapped with httputils.AddMetricsToClient. This allows us to track how much load we place on external services.

If you add any critical TODOs while you're coding, file a blocking bug for the issue.

Makefiles

It is customary to have the following commands in a Makefile for the service.

build : Build a development version of the front end.

serve : Run the demo pages of the front end in a “watch” mode. This command is for primary development of front end pages.

core : Build the server components.

watch : Build a development version of the front end in watch mode. This command is for running the server, but also making changes to the front end.

release : Build a Docker container with the front end and backend parts in it (see below).

push : Depends on release, and then pushes to GKE using pushk.

Docker

Running apps in Docker makes deployment and local testing much much easier. It additionally allows integration with GKE. Some legacy apps are not yet run in Docker, but it is the goal to have everything on GKE+Docker.

Create a Dockerfile for your app in the root of the project folder (e.g. jsfiddle/Dockerfile). If there are multiple services, put them in a named folder (e.g. fiddlek/fiddle/Dockerfile, fiddlek/fiddler/Dockerfile).

When choosing a base image, consider our light wrappers, found in kube/*. For example, kube/basealpine/Dockerfile which can be used by having FROM gcr.io/skia-public/basealpine:3.8 as the first line in a Dockerfile.

We have a helper script for ‘installing’ an app into a Docker container, bash/docker_build.sh. A call to this script is customarily put in a bash script which is called by make release. See jsfiddle/build_release for an example. To integrate docker_build.sh into the actual container, add a COPY . / to copy the executable(s) and HTML/JS/CSS from the build context into the container. Legacy apps have a similar set-up, but for building a Debian package instead of a container.

It is customary to include an ENTRYPOINT and CMD with sensible defaults for the app. It's also a best practice to run the app as USER skia unless root is absolutely needed.

Putting all the above together, a bare-bones Dockerfile would look something like:

Secrets and Service Accounts

If your app needs access to a GCS bucket or other similar things, it is recommended you create a new service account for your app. See below for linking it into the container.

Use an existing create-sa.sh script (e.g. create-jsfiddle-sa.sh) and tweak the name, committing it into the app's root directory. Run this once to create the service account and create the secrets in GKE.

Launching

Write/update design doc so that others understand how to use, maintain, and improve your service. DESIGN.md typically has high level design structures (e.g. where is data stored, how do the pieces of software interact, etc). PROD.md has an overview of the alerts and any other notes for maintaining the service.

Do some back-of-the-envelope calculations to make sure your service can handle the expected load. If your service is latency-sensitive, measure the latency under load.

Test on browsers that your users will be using, at least Chrome on desktop and ideally Chrome on Android.

Create an app.yaml in skia-public-config This controls how your app will be run in GKE. See these docs for more on the schema. Commit this, then run pushk appname to make the configuration active.

Metrics are customarily made available at port 20000. To configure metrics scraping, add the following to the app.yaml under spec -> template -> metadata:

annotations:
prometheus.io.scrape: "true"
prometheus.io.port: "20000"

Metrics will be available on prom2.skia.org. Legacy apps report metrics to prom.skia.org and require updating prometheus/sys/prometheus.yml.

The metrics will be labeled app=<foo> where foo is the first argument to common.InitWithMust.

If you have secrets (like a service account), bind it to the deployment by adding the following to app.yaml: