redhat-developer / opencompose

OpenCompose - A higher level abstraction for Kubernetes Resource
Apache License 2.0
64 stars 12 forks source link

Consider a syntax that's somewhat less fragile than yaml #51

Open pradeepto opened 7 years ago

pradeepto commented 7 years ago

How about HCL? jsonnet?

tnozicka commented 7 years ago

I don't like any of them. We want the tool to be user friendly and json-like syntax is not going to do the job. Yeah, yaml can be fragile, but still the best choice IMO.

kadel commented 7 years ago

Yaml might be best option for use, but I don't want to dismiss other formats without doing some research and gathering some pros and cons.

tnozicka commented 7 years ago

@kadel feel free to do so :)

ant31 commented 7 years ago

Jsonnet syntax isn't that terrible

{
  version: "0.1-dev",
  services: [
   {
     name: "helloworld",
     containers: [{
       image: "tomaskral/nonroot-nginx",
       ports: [{
         port: "8080:80",
         type: "external",
         }]
      }]
    }]
}

And you'll gain immediatly templating/lint/variables without doing it internally. which is a great to share and reuse opencompose packages

{
  version: "0.1-dev",
  variables:: {
     image: "tomaskral/nonroot-nginx"
  }
  services: [
   {
     name: "helloworld",
     containers: [{
       image: $.variables.image,
       labels: ["service-version": $.version],
       ports: [{
         port: "8080:80",
         type: "external",
         }]
      }]
    }]
}
pradeepto commented 7 years ago

@ant31 True that. It is not terrible.

But what do you think will happen when the file grows a bit more? Those {,[ s are already getting me worried. As discussed with you, we see the power jsonnet has but I am worried about the readability of jsonnet based examples. But I am not still ruling it out.

I really need to be convinced before we move to jsonnet or anything else. Would you have other suggestions as well?

pradeepto commented 7 years ago

Just found out about https://github.com/vstakhov/libucl @ant31 @kadel @surajssd @containscafeine From it's readme :

Each UCL object can be serialized to one of the three supported formats: JSON - canonic json notation (with spaces indented structure); Compacted JSON - compact json notation (without spaces or newlines); Configuration - nginx like notation; YAML - yaml inlined notation.

Have a look.

ant31 commented 7 years ago

Speaking of the transformation your are doing in the Go-code, they can all be done on the jsonnet side. IMO it would be awesome: configuration part would embed it's own library and let opencompose evolve freely and quickly without retro-compat issues. currently the flow is:

yaml-conf -> opencompose(transformation) -> kubernetes-resources -> opencompose/kubectl(management part)

Moving/embedding the transformation to the configuration is going to be a big win. You'll be able to reuse other jsonnet libraries and as said configuration becomes autonomous and users can extend easily and write new API that match better their usecase.

Is it going to be more complex for users ?

It depend on how the jsonnet library is created. It can be very light changes from current open-compose yaml syntax:

local opencompose = import opencompose.v1.jsonnet    

opencompose.generate({
  version: "0.1-dev",
  services: [
   {
     name: "helloworld",
     containers: [{
       image: "tomaskral/nonroot-nginx",
       ports: [{
         port: "8080:80",
         type: "external",
         }]
      }]
    }]
})

The above example could generate all kubernetes resources without using the go client at all: the configuration embed what it needs:

jsonnet-conf -> kubernetes-resources -> opencompose/kubectl(management-part) 
Why it is key?

I already see several tickets like Need secret, Need imagePullPolicy etc... In one/two years, if the project continue I think that the whole opencompose api will not be simple anymore OR too limited from what Kubernetes offers.

I believe to be successful, opencompose should expose the full kubernetes power. Jsonnet would allow you to do it without mitigated your goal of having a Higher Level and extremely easy API to use.

example:
The user wants to add hostNetwork: true but opencompose does't have constructor/api for it

local opencompose = import opencompose.v1.jsonnet    

local resources = opencompose.generate({
  version: "0.1-dev",
  services: [
   {
     name: "helloworld",
     containers: [{
       image: "tomaskral/nonroot-nginx",
       ports: [{
         port: "8080:80",
         type: "external",
         }]
      }]
    }]
});

resources+: {
  deployment+: {spec: {template: {spec: {hostNetwork: true}}}}
}

(Yes, it looks more complex, but it is only for advances usage when opencompose isn't offering abstraction)

The great thing here, is that we can also reuse existing efforts to abstract lower level API (like https://github.com/heptio/kube.libsonnet):

local kube = import "kube.libsonnet"
resources+: {deployment+: kube.DeploySpec.hostNework(true)}
ant31 commented 7 years ago

Those {,[ s are already getting me worried

On the other hand I've seen so many people complaining about indentation from Yaml :) I can't count how many time I indented with the wrong key.

Jsonnet provide stackstrace and can be nicely integrated with IDE. So yes on first glance it's less attractive but in practice it is very convenient and easy to use.

# Missing templating variable
$ jsonnet wordpress/no-storage.jsonnet 
RUNTIME ERROR: Field does not exist: badvar
  no-storage.jsonnet:29:30-56   thunk <b>

# Missing a comma
$ jsonnet no-storage.jsonnet
STATIC ERROR: no-storage.jsonnet:31:8-26: Expected a comma before next array element.
kadel commented 7 years ago

Jsonnet is really powerful and has a tun of benefits. But I see one big problem with it:

If I'm ordinary web developer doing NodeJS or Ruby on Rails whole day and I see Jsonnet syntax I would probably be much more confused and scared from how complicated it looks then from looking at regular Kubernetes primitives :-(

ant31 commented 7 years ago

If I'm ordinary web developer doing NodeJS

Json based configurations are pretty present: e.g package.json (http://browsenpm.org/package.json).

With all the above implemented (which are good) and I'm sure more will come, user will only switch from: looking in kubernetes doc to know how to do XXX in Kubernetes primitives, to opencompose documentation.

eg: this isn't obvious:

    mounts:
    - volumeName: db
      mountPath: /app/store
      volumeSubPath: foo/bar
      readOnly: true

IMO there is no useless fields in the Kubernetes API, my concern is that overtime you'll going to rewrite the complete API. Probably in a more mnemonic and succinct way but still large and complex to learn.

On the other hand I completely understand your comments about Jsonnet/non-yaml and you're maybe right about them.

kadel commented 7 years ago

If I'm ordinary web developer doing NodeJS Json based configurations are pretty present: e.g package.json (http://browsenpm.org/package.json).

OK, I shouldn't have use NodeJS as example :smile:

IMO there is no useless fields in the Kubernetes API, my concern is that overtime you'll going to rewrite the complete API. Probably in a more mnemonic and succinct way but still large and complex to learn.

yep :unamused:, you are completely right. Those are valid concerns and this is the biggest risk with our current approach. If we end up rewriting everything from API we failed big time. Even I'm not convinced that this is best way to do it, right now we just don't have anything better :-(

I'm afraid that just adding templating in form of Jsonnet on top of Kubernetes primitives is not going to make it easier to write. I would even say that opposite is true :disappointed: But don't have any data to prove it, that is just my feeling

ant31 commented 7 years ago

adding templating in form of Jsonnet on top of Kubernetes primitives is not going to make it easier to write

I did a small 'working' poc to show a concrete example, I tried to reuse more-or-less opencompose syntax: https://gist.github.com/ant31/882b642e8f6c29123919d92eca993590

kadel commented 7 years ago

that looks interesting 👍 can you share lib/opencompose.libsonnet?

ant31 commented 7 years ago

@kadel source: https://github.com/ant31/opencompose-jsonnet (it's like ~1 hour work so it's messy)

$ jsonnet cookieapp-opencompose.jsonnet
cdrage commented 7 years ago

@kadel @ant31 @tnozicka @pradeepto

This is a really good and long discussion on how they decided what format to use for the dep tool for Golang.

In the end they chose TOML over YAML and other formats.

cdrage commented 7 years ago

Although their use-case was different (it was originally debating about comments in yaml/json), it gradually turned into a good analysis of all the different formats.

cdrage commented 7 years ago

Besides, if we pick YAML it's still a superset of JSON so we'll get that too, regardless what the user chooses to write.