{"id":876,"date":"2018-12-07T04:28:23","date_gmt":"2018-12-07T04:28:23","guid":{"rendered":"https:\/\/www.appservgrid.com\/paw93\/?p=876"},"modified":"2018-12-11T03:10:49","modified_gmt":"2018-12-11T03:10:49","slug":"simplifying-kubernetes-with-docker-compose-and-friends","status":"publish","type":"post","link":"https:\/\/www.appservgrid.com\/paw93\/index.php\/2018\/12\/07\/simplifying-kubernetes-with-docker-compose-and-friends\/","title":{"rendered":"Simplifying Kubernetes with Docker Compose and Friends"},"content":{"rendered":"<p>Today we\u2019re happy to announce we\u2019re open sourcing our support for using Docker <a href=\"https:\/\/github.com\/docker\/compose-on-kubernetes\">Compose on Kubernetes<\/a>. We\u2019ve had this capability in Docker Enterprise for a little while but as of today you will be able to use this on any Kubernetes cluster you choose.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/i1.wp.com\/blog.docker.com\/wp-content\/uploads\/2018\/12\/Compose-on-Kubernetes-1.png?resize=474%2C347&amp;ssl=1\" alt=\"Compose on Kubernetes\" width=\"474\" height=\"347\" \/><\/p>\n<h3><b>Why do I need Compose if I already have Kubernetes?<\/b><\/h3>\n<p>The Kubernetes API is really quite large. There are more than 50 first-class objects in the latest release, from Pods and Deployments to ValidatingWebhookConfiguration and ResourceQuota. This can lead to a verbosity in configuration, which then needs to be managed by you, the developer. Let\u2019s look at a concrete example of that.<\/p>\n<p>The <a href=\"https:\/\/github.com\/microservices-demo\/microservices-demo\">Sock Shop<\/a> is the canonical example of a microservices application. It consists of multiple services using different technologies and backends, all packaged up as Docker images. It also provides example configurations using different tools, including both Compose and raw Kubernetes configuration. Let\u2019s have a look at the relative sizes of those configurations:<\/p>\n<p>$ git clone https:\/\/github.com\/microservices-demo\/microservices-demo.git<br \/>\n$ cd deployment\/kubernetes\/manifests<br \/>\n$ (Get-ChildItem -Recurse -File | Get-Content | Measure-Object -line).Lines<br \/>\n908<br \/>\n$ cd ..\/..\/docker-compose<br \/>\n$ (Get-Content docker-compose.yml | Measure-Object -line).Lines<br \/>\n174<\/p>\n<p>Describing the exact same multi-service application using just the raw Kubernetes objects takes more than 5 times the amount of configuration than with Compose. That\u2019s not just an upfront cost to author \u2013 it\u2019s also an ongoing cost to maintain. The Kubernetes API is amazingly general purpose \u2013 it exposes low-level primitives for building the full range of distributed systems. Compose meanwhile isn\u2019t an API but a high-level tool focused on developer productivity. That\u2019s why combining them together makes sense. For the common case of a set of interconnected web services, Compose provides an abstraction that simplifies Kubernetes configuration. For everything else you can still drop down to the raw Kubernetes API primitives. Let\u2019s see all that in action.<\/p>\n<p>First we need to install the Compose on Kubernetes controller into your Kubernetes cluster. This controller uses the standard Kubernetes extension points to introduce the `Stack` to the Kubernetes API. You can use any Kubernetes cluster you like, but if you don\u2019t already have one available then remember that <a href=\"https:\/\/www.docker.com\/products\/docker-desktop\">Docker Desktop<\/a> comes with Kubernetes and the Compose controller built-in, and enabling it is as simple as ticking a box in the settings.<\/p>\n<p>To install the controller manually on any Kubernetes cluster, see the <a href=\"https:\/\/github.com\/docker\/compose-on-kubernetes\">full documentation<\/a> for the current installation instructions.<\/p>\n<p>Next let\u2019s write a simple Compose file:<\/p>\n<p>version: &#8220;3.7&#8221;<br \/>\nservices:<br \/>\nweb:<br \/>\nimage: dockerdemos\/lab-web<br \/>\nports:<br \/>\n&#8211; &#8220;33000:80&#8221;<br \/>\nwords:<br \/>\nimage: dockerdemos\/lab-words<br \/>\ndeploy:<br \/>\nreplicas: 3<br \/>\nendpoint_mode: dnsrr<br \/>\ndb:<br \/>\nimage: dockerdemos\/lab-db<\/p>\n<p>We\u2019ll then use the docker client to deploy this to a Kubernetes cluster running the controller:<\/p>\n<p>$ docker stack deploy &#8211;orchestrator=kubernetes -c docker-compose.yml words<br \/>\nWaiting for the stack to be stable and running&#8230;<br \/>\ndb: Ready [pod status: 1\/1 ready, 0\/1 pending, 0\/1 failed]<br \/>\nweb: Ready [pod status: 1\/1 ready, 0\/1 pending, 0\/1 failed]<br \/>\nwords: Ready [pod status: 1\/3 ready, 2\/3 pending, 0\/3 failed]<br \/>\nStack words is stable and running<\/p>\n<p>We can then interact with those objects via the Kubernetes API. Here you can see we\u2019ve created the lower-level objects like Services, Pods, Deployments and ReplicaSets automatically:<\/p>\n<p>$ kubectl get all<br \/>\nNAME READY STATUS RESTARTS AGE<br \/>\npod\/db-85849797f6-bhpm8 1\/1 Running 0 57s<br \/>\npod\/web-7974f485b7-j7nvt 1\/1 Running 0 57s<br \/>\npod\/words-8fd6c974-44r4s 1\/1 Running 0 57s<br \/>\npod\/words-8fd6c974-7c59p 1\/1 Running 0 57s<br \/>\npod\/words-8fd6c974-zclh5 1\/1 Running 0 57s<\/p>\n<p>NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE<br \/>\nservice\/db ClusterIP None &lt;none&gt; 55555\/TCP 57s<br \/>\nservice\/kubernetes ClusterIP 10.96.0.1 &lt;none&gt; 443\/TCP 4d<br \/>\nservice\/web ClusterIP None &lt;none&gt; 55555\/TCP 57s<br \/>\nservice\/web-published LoadBalancer 10.102.236.49 localhost 33000:31910\/TCP 57s<br \/>\nservice\/words ClusterIP None &lt;none&gt; 55555\/TCP 57s<\/p>\n<p>NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE<br \/>\ndeployment.apps\/db 1 1 1 1 57s<br \/>\ndeployment.apps\/web 1 1 1 1 57s<br \/>\ndeployment.apps\/words 3 3 3 3 57s<\/p>\n<p>NAME DESIRED CURRENT READY AGE<br \/>\nreplicaset.apps\/db-85849797f6 1 1 1 57s<br \/>\nreplicaset.apps\/web-7974f485b7 1 1 1 57s<br \/>\nreplicaset.apps\/words-8fd6c974 3 3 3 57s<\/p>\n<p>It\u2019s important to note that this isn\u2019t a one-time conversion. The Compose on Kubernetes API Server introduces the Stack resource to the Kubernetes API. So we can query and manage everything at the same level of abstraction as we\u2019re building the application. That makes delving into the details above useful for understanding how things work, or debugging issues, but not required most of the time:<\/p>\n<p>$ kubectl get stack<br \/>\nNAME STATUS PUBLISHED PORTS PODS AGE<br \/>\nwords Running 33000 5\/5 4m<\/p>\n<h3><b>Integration with other Kubernetes tools<\/b><\/h3>\n<p>Because Stack is now a native Kubernetes object, you can work with it using other Kubernetes tools. As an example, save the as `stack.yaml`:<\/p>\n<p>kind: Stack<br \/>\napiVersion: compose.docker.com\/v1beta2<br \/>\nmetadata:<br \/>\nname: hello<br \/>\nspec:<br \/>\nservices:<br \/>\n&#8211; name: hello<br \/>\nimage: garethr\/skaffold-example<br \/>\nports:<br \/>\n&#8211; mode: ingress<br \/>\ntarget: 5678<br \/>\npublished: 5678<br \/>\nprotocol: tcp<\/p>\n<p>You can use a tool like <a href=\"https:\/\/github.com\/GoogleContainerTools\/skaffold\">Skaffold<\/a> to have the image automatically rebuild and the Stack automatically redeployed whenever you change any of the details of your application. This makes for a great local inner-loop development experience. The following `skaffold.yaml` configuration file is all you need.<\/p>\n<p>apiVersion: skaffold\/v1alpha5<br \/>\nkind: Config<br \/>\nbuild:<br \/>\ntagPolicy:<br \/>\nsha256: {}<br \/>\nartifacts:<br \/>\n&#8211; image: garethr\/skaffold-example<br \/>\nlocal:<br \/>\nuseBuildkit: true<br \/>\ndeploy:<br \/>\nkubectl:<br \/>\nmanifests:<br \/>\n&#8211; stack.yaml<\/p>\n<h3><b>The future<\/b><\/h3>\n<p>We already have some thoughts about a Helm plugin to make describing your application with Compose and deploying with Helm as easy as possible. We have lots of other ideas for helping to simplify the developer experience of working with Kubernetes too, without losing any of the power of the platform. We also want to work with the wider Cloud Native community, so if you have ideas and suggestions please let us know.<\/p>\n<p>Kubernetes is designed to be extended, and we hope you like what we\u2019ve been able to release today. If you\u2019re one of the millions of Compose users you can now more easily move to and manage your applications on Kubernetes. If you\u2019re a Kubernetes user struggling with too much low-level configuration then give Compose a try. Let us know in the comments what you think, and head over to GitHub to try things out and even open your first PR:<\/p>\n<ul>\n<li><a href=\"https:\/\/github.com\/docker\/compose-on-kubernetes\">Compose on Kubernetes controller<\/a><\/li>\n<\/ul>\n<p><a href=\"https:\/\/blog.docker.com\/2018\/12\/simplifying-kubernetes-with-docker-compose-and-friends\/\" target=\"_blank\" rel=\"noopener\">Source<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Today we\u2019re happy to announce we\u2019re open sourcing our support for using Docker Compose on Kubernetes. We\u2019ve had this capability in Docker Enterprise for a little while but as of today you will be able to use this on any Kubernetes cluster you choose. Why do I need Compose if I already have Kubernetes? The &hellip; <\/p>\n<p class=\"link-more\"><a href=\"https:\/\/www.appservgrid.com\/paw93\/index.php\/2018\/12\/07\/simplifying-kubernetes-with-docker-compose-and-friends\/\" class=\"more-link\">Continue reading<span class=\"screen-reader-text\"> &#8220;Simplifying Kubernetes with Docker Compose and Friends&#8221;<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[2],"tags":[],"class_list":["post-876","post","type-post","status-publish","format-standard","hentry","category-docker"],"_links":{"self":[{"href":"https:\/\/www.appservgrid.com\/paw93\/index.php\/wp-json\/wp\/v2\/posts\/876","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.appservgrid.com\/paw93\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.appservgrid.com\/paw93\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.appservgrid.com\/paw93\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.appservgrid.com\/paw93\/index.php\/wp-json\/wp\/v2\/comments?post=876"}],"version-history":[{"count":1,"href":"https:\/\/www.appservgrid.com\/paw93\/index.php\/wp-json\/wp\/v2\/posts\/876\/revisions"}],"predecessor-version":[{"id":891,"href":"https:\/\/www.appservgrid.com\/paw93\/index.php\/wp-json\/wp\/v2\/posts\/876\/revisions\/891"}],"wp:attachment":[{"href":"https:\/\/www.appservgrid.com\/paw93\/index.php\/wp-json\/wp\/v2\/media?parent=876"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.appservgrid.com\/paw93\/index.php\/wp-json\/wp\/v2\/categories?post=876"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.appservgrid.com\/paw93\/index.php\/wp-json\/wp\/v2\/tags?post=876"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}