Spinnaker application, pipeline and projects as code, inspired by kube-libsonnet.
NOTE: this is a different take to the upstream library: spinnaker/sponnet
Install dependencies:
go install github.com/google/go-jsonnet/cmd/jsonnet@latest
go install github.com/google/go-jsonnet/cmd/jsonnetfmt@latest
go install github.com/google/go-jsonnet/cmd/jsonnet-lint@latest
go install github.com/spinnaker/spin@latest
Create working directory:
mkdir -p tutorial
cd tutorial/
Create application:
cat <<EOF > myapp.jsonnet
local spin = import '../spin.libsonnet';
spin.application('myapp', '[email protected]')
EOF
# render jsonnet to json
jsonnet myapp.jsonnet > myapp.json
Optionally save application to Spinnaker:
spin application save --application-name myapp --file myapp.json
Create pipeline with a Wait stage:
cat <<EOF > mypipeline.jsonnet
local spin = import '../spin.libsonnet';
spin.pipeline('mypipeline', 'myapp') + {
stages+: [
spin.wait(),
],
}
EOF
# render jsonnet to json
jsonnet mypipeline.jsonnet > mypipeline.json
Optionally save pipeline to Spinnaker:
spin pipeline save --file mypipeline.json
See CONTRIBUTING.md.
There are other Spinnaker pipeline solutions available:
Initially we assisted with the sponnet project and used it to generate all applications and pipelines. Each pipeline looked something like the example pipeline in the sponnet repository.
This client-side pipeline templating was a good improvement from our previous
roer
pipeline templating but presented challenges.
For our platform team, making changes to all pipeline files was tedious. This was a common occurrence as we added new target accounts and other pipeline functionality.
For our product teams, changing an application name and updating artifact names was awkward. We declared these variables at the top of the file, but the entire pipeline complexity was exposed. This was at odds with our desire to scale our platform team sublinearly and enable product teams to self service.
We decided to approach the problem from first principles and looked around for inspiration with the following requirements:
- client-side templating that enables a git workflow
- supports a simple DSL for product teams with ability to extend
- uses jsonnet composition (
myObject+: { newKey: someValue }
) to enable adhoc extension or replacement anywhere in json object (explorable compexity) - basic constructors of common elements
The Sponnet library (application.libsonnet, pipeline.libsonnet) resembles the one of the largest open source jsonnet projects around; Ksonnet.
The Ksonnet library uses a object.withKey1(value),withKey2(value)
builder pattern,
chaining attributes together.
This has two main drawbacks:
- duplication of key names in function definitions: withKey1(Key1)
- referencing other keys within a
.with...()
method is hard to follow.
See the below contrast between a builder
pattern and jsonnet composition.
{
local doSomeConvention(v) = std.asciiUpper(v),
// builder pattern
object():: {
key1: 'some-default-value',
withKey1(key1):: self + { key1: key1 },
withKey2(key2):: self + { key2: key2 },
},
myObject: $.object() // plus chained values below
.withKey1('some value') // overwrite default
.withKey2(doSomeConvention($.myObject.key1)) // full path required!
{ key3: 'extra value' }, // still possible to compose
// composition pattern
object2:: {
key1: 'some-default-value',
},
myObject2: $.object2 {
key1: 'some override value', // overwrite default
key2: doSomeConvention(self.key1), // use of self keyword
key3: 'extra value',
},
}
Builder example: https://github.com/grafana/jsonnet-libs/blob/master/oauth2-proxy/oauth2-proxy.libsonnet
Composition example: https://github.com/bitnami-labs/kube-libsonnet/blob/master/examples/wordpress/frontend.jsonnet